-
-
Save nauar/826f85d25d692d9bc009312cb71577dd to your computer and use it in GitHub Desktop.
#!/bin/bash | |
# This script is a pre-receive hook allowing pushes whose every file: | |
# - is smaller than 20 M | |
# - and its extension is not one of the following: | |
# - dll | |
# - exe | |
# - war | |
# - ear | |
# - jar | |
# and whose directories are not named 'node_modules'. | |
GITCMD="git" | |
NULLSHA="0000000000000000000000000000000000000000" | |
EMPTYTREESHA=$($GITCMD hash-object -t tree /dev/null) # SHA1: "4b825dc642cb6eb9a060e54bf8d69288fbee4904" | |
MAXSIZE="20" | |
MAXBYTES=$(( $MAXSIZE * 1048576 )) | |
EXIT=0 | |
PRIVATELOGFILE="/tmp/git_private.log" | |
function private_log() { | |
moment=`date '+%d/%m/%Y %H:%M:%S'` | |
echo "[ $moment ] [ POLICY CHECK ] $1" >> $PRIVATELOGFILE | |
} | |
function log() { | |
moment=`date '+%d/%m/%Y %H:%M:%S'` | |
echo "[ $moment ] [ POLICY CHECK ] $1" | |
} | |
log "Starting validation..." | |
while read oldref newref refname; do | |
private_log "OLDREF: $oldref NEWREF: $newref REFNAME: $refname" | |
# Avoid removed branches | |
if [ "${newref}" = "${NULLSHA}" ]; then | |
continue | |
fi | |
# Set oldref properly if this is branch creation. | |
if [ "${oldref}" = "${NULLSHA}" ]; then | |
oldref=$EMPTYTREESHA | |
fi | |
# Ignore case | |
shopt -s nocaseglob | |
newFiles=$($GITCMD diff --stat --name-only --diff-filter=ACMRT ${oldref}..${newref}) | |
if [[ $? -ne 0 ]]; then | |
log "Error 101: Repository incosistency. Cancelling push..." | |
exit 1; | |
fi | |
old_IFS=$IFS | |
IFS=' | |
' | |
for filename in $newFiles; do | |
private_log "Filename: $filename" | |
filesize=$($GITCMD cat-file -s "${newref}:${filename}") 2> $PRIVATELOGFILE | |
if [[ -z $filesize ]]; then filesize=0; fi | |
filesize_mb=$(($filesize / 1048576)) | |
if [ "${filesize}" -gt "${MAXBYTES}" ]; then | |
log "File $filename is greater than $MAXSIZE MB. Its size is $filesize_mb MB." | |
exit 1 | |
fi | |
if [[ "$filename" =~ "node_modules" ]]; then | |
log "Folder 'node_modules' not allowed: $filename." | |
exit 1 | |
else | |
if [[ "$filename" =~ \.dll$ ]] || [[ "$filename" =~ \.exe$ ]] || [[ "$filename" =~ \.war$ ]] || [[ "$filename" =~ \.ear$ ]] || [[ "$filename" =~ \.jar$ ]]; then | |
extension="${filename##*.}" | |
log "Files with extension $extension not allowed. Please remove file $filename" | |
exit 1 | |
fi | |
fi | |
done | |
IFS=$old_IFS | |
done |
Hi, I am wondering how to install a pre-receive hook similar to this in my own repo. I tried to rename
pre-receive.sample
topre-receive
the.git/hooks
and pushed it to remote, but doesn't seem working. Thanks.
Hello,
Normally, the git hooks are never pushed as they are not part of the repository code (see this stack overflow question). You have to do it in the server itself and it depends on the type of server (click the links in order to see how to do it in each type):
- a bare git repository server
- a git-enhaced server (Gitlab, Github, Atlassian...).
You should do it in the server in the appropiate way depending on the server type and if it doesn't work properly yet, I'd check the following points:
- Check that you have the interpreter installed in the remote server. Check the path of the shebang (ie: #!/bin/bash) points to an existing interpreter in your remote server.
- Check that your hook has execution permissions. Do chmod u+x in your terminal.
I hope you find this helpful.
Kind regards,
Arnau Oncins
@nauar Thank you for answering my question. It helped me a lot. May I ask another question? How do you come up with EMPTYTREESHA="4b825dc642cb6eb9a060e54bf8d69288fbee4904"
? Is this just a specific commit message from your repo?
Best!
Barton
@donganzh You're welcome! :)
Regarding the empty tree sha, it's the sha that git returns for an empty tree: git hash-object -t tree /dev/null
(see this stack overflow discussion about it). Note: I updated the gist, including this command instead of the constant. With it, the script will be compatible in case GIT developers want to modify the hashing algorithm from SHA1 to another one.
@nauar Nice script! Just one hint: you introduced the variable filesize_mb
but did not use it in the size error message, which leads to outputs that state the size in bytes followed by "MB".
Great work, thanks for sharing!
@nauar Nice script! Just one hint: you introduced the variable
filesize_mb
but did not use it in the size error message, which leads to outputs that state the size in bytes followed by "MB".Great work, thanks for sharing!
Hello @Seifenhenne.
Thanks for detecting this mistake. :) Fixed! ;)
Cheers!
Arnau Oncins
Thank you for sharing!
But line 56 "$newFiles" will somehow cause all strings joined as one variable.
It seems to be the case of SC2066.
I fix this issue By removing quote: for filename in $newFiles
The tested environment is on OSX Catalina, version 3.2.57(1)-release (x86_64-apple-darwin19).
Hello @zmes50416,
I tried without quotes and I had problems with files with spaces. Finally, I used one of the suggested solutions in SC2066 and now it works in all my tests.
Thanks a lot!
This script is great and does the job.....Thanks for the script....
I have a problem when a new branch is pushed , its scan entire changes , I want to scan only the changes in the current(new) branch excluding the master commits from which it was branched.
Here is my case.....
If I create new local branch from master , make some changes/commits and push.
I want to scan only the the commits/changes that are made in this new branch.
Locally I can get the changes using the command
"git cherry master | head -n 2 | tail -1" >> returns the commit of the master that this branch is created.
I want to replace the variable oldref in the script with the output of the cherry command. but the command doesn't return anything when executed from pre-receive hook
Any suggestions on how I can get the oldref with cherry command output?
@nauar Thanks for your script.
@kdevineni Can you try this command?
git show --pretty="" --name-only <new_ref>
@nauar Thanks for your script. @kdevineni Can you try this command? git show --pretty="" --name-only <new_ref>
@srinivas974 "git show --pretty="" --name-only <new_ref>" only returns files from the commit reference specified .
Doesn't return all the changes made in the current branch
Hi, I am wondering how to install a pre-receive hook similar to this in my own repo. I tried to rename
pre-receive.sample
topre-receive
the.git/hooks
and pushed it to remote, but doesn't seem working. Thanks.