Woot4Moo
Woot4Moo

Reputation: 24316

How to push a pre-commit hook to all existing repositories

In GHE (GitHub Enterprise), is it possible to share pre-commit hooks across all existing (and new) repositories? For example I want to deny JKS files being committed in the first place.

I understand these can be by-passed and simply want to make it harder to do the wrong thing.

Upvotes: 1

Views: 1912

Answers (1)

bk2204
bk2204

Reputation: 76449

There is no way to do what you're requesting.

First, hooks aren't transferred as part of the repository. Because they can execute arbitrary code, Git doesn't provide a way to transfer them as part of the repository or automatically change them. You can include a set of hooks in a repository, but it's up to the user (or a part of your build system) to install them or not. Oftentimes users have custom hooks as part of the development process, and your build system would overwrite those.

Second, GitHub provides templating mechanisms, but doesn't provide a way to automatically install a file in all new repositories. Even if they did, it would be easy for a user pushing a new repository to simply push over it.

Third, to modify all existing repositories, you'd need to make a commit in each one. You could script this using the API, but it would require permissions for each repository, so you'd have to be an administrator to do that. And as mentioned before, you'd still have to have a way for each one to install hooks.

What you can do is use a pre-receive hook on the server (enabled for all repositories) which rejects a push which contains these files. Since these files could have any name, you'd likely need to iterate over every blob in every commit that was pushed and see if it starts with the appropriate magic byte sequence. If you're happy with just looking for file patterns, you could do something like the following:

#!/bin/sh -e

while read old new ref
do
    # Deleted ref.
    if echo "$new" | grep -qsE '^0+$'
    then
        continue
    fi

    if echo "$old" | grep -qsE '^0+$'
    then
        # Newly created ref.
        start=
    else
        # Updated ref.
        start="$old.."
    fi
    git rev-list "$start$new" | (while read rev
    do
        output=$(git ls-tree -r --name-only "$rev" | grep '.jks$') || true
        if [ -n "$output" ]
        then
            echo "Revision $rev from $ref contains forbidden files:"
            echo "$output"
            exit 1
        fi
    done)
done

Upvotes: 3

Related Questions