Skip to content

Instantly share code, notes, and snippets.

@nauar
Last active March 13, 2024 08:45
Show Gist options
  • Save nauar/826f85d25d692d9bc009312cb71577dd to your computer and use it in GitHub Desktop.
Save nauar/826f85d25d692d9bc009312cb71577dd to your computer and use it in GitHub Desktop.
GIT pre-receive hook for checking file size and filename extensions
#!/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
@kdevineni
Copy link

kdevineni commented Feb 2, 2023

@nauar

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?

@srinivas974
Copy link

srinivas974 commented Feb 7, 2023

@nauar Thanks for your script.
@kdevineni Can you try this command?
git show --pretty="" --name-only <new_ref>

@kdevineni
Copy link

@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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment