|
| 1 | +#!/usr/bin/env bash |
| 2 | + |
| 3 | +# |
| 4 | +# Git Block Outdated Clients pre-receive hook |
| 5 | +# |
| 6 | +# Minimum required version of GHES: 2.22 |
| 7 | +# This is an implementation of a pre-receive hook for GHES that checks if the current version from the |
| 8 | +# user is older than the current version. |
| 9 | +# |
| 10 | +# If the version is outdated it prints a message encouraging the user to update the client. However if this |
| 11 | +# version has a minor diff greater than max_minor_diff the hook fails and |
| 12 | +# the user cannot push the changes. You can also block specific versions by adding them to the |
| 13 | +# block_list. |
| 14 | +# |
| 15 | +# Test this locally setting $GIT_USER_AGENT. ex. GIT_USER_AGENT=git/2.2.23 and exporting it. |
| 16 | +# Also add to the $GH_TOKEN a personal access token for adding more authentication requests on getting the version |
| 17 | +# if you want it dynamically: |
| 18 | +# ``` |
| 19 | +# $ GIT_USER_AGENT=git/2.2.23 |
| 20 | +# $ GH_TOKEN=token |
| 21 | +# $ export GH_TOKEN |
| 22 | +# $ export GIT_USER_AGENT |
| 23 | +# $ sh git_hook_outdated_clients.sh |
| 24 | +# ``` |
| 25 | +# |
| 26 | +# Edit this variables to set the policy for the git version |
| 27 | +# |
| 28 | +# max_minor_diff: the number of git versions allowed from the latest one. |
| 29 | +# block_list: a list containing specific versions that are blocked by policy |
| 30 | +max_minor_diff=3 |
| 31 | +block_list=( |
| 32 | +) |
| 33 | + |
| 34 | +# Edit this variables to get the right version to compare as latest |
| 35 | +# latest_version: add the latest version to check or leave it empty to let the script get it dynamically |
| 36 | +# authentication: provide a PAT on the environment if you want to execute the request to get the version without triggering the rate limit. |
| 37 | +# If you don't provide the latest version we strongly recommend to add a GH_TOKEN to the environment. It requires jq as dependency |
| 38 | +latest_version="" |
| 39 | +authentication=$GH_TOKEN |
| 40 | + |
| 41 | +DEBUG=1 |
| 42 | + |
| 43 | +function block_version { |
| 44 | + echo "#########################################" |
| 45 | + echo "## Outdated git version $1 ##" |
| 46 | + echo "#########################################" |
| 47 | + echo "" |
| 48 | + echo "Update the git version to a newest one: https://git-scm.com/downloads" |
| 49 | + |
| 50 | + exit 1; |
| 51 | +} |
| 52 | + |
| 53 | +################################# |
| 54 | +# Parse the version from the user |
| 55 | +# agent |
| 56 | +################################# |
| 57 | +user_version=$GIT_USER_AGENT |
| 58 | +if [[ $user_version =~ [0-9]+\.[0-9]+\.[0-9]+ ]]; then |
| 59 | + version=${BASH_REMATCH[0]} |
| 60 | + echo "Current git version: $version" |
| 61 | +else |
| 62 | + echo "The user agent used is not supported as it doesn't provide the version it is using" |
| 63 | + exit 1; |
| 64 | +fi |
| 65 | + |
| 66 | +################################# |
| 67 | +# Check if the version belongs to |
| 68 | +# the block list |
| 69 | +################################# |
| 70 | +for i in "${block_list[@]}" |
| 71 | +do |
| 72 | + if [ "$i" == "$version" ]; then |
| 73 | + echo "The version $i is blocked by policy for security reasons. Please update" |
| 74 | + block_version "$version" |
| 75 | + fi |
| 76 | +done |
| 77 | + |
| 78 | +################################# |
| 79 | +# Get the latest version from an |
| 80 | +# external source if not available |
| 81 | +# and validate it |
| 82 | +################################# |
| 83 | +if [ "$latest_version" == "" ]; then |
| 84 | + latest_version=$(curl -s -X GET -H "Authorization: token $authentication" https://api.github.com/repos/git/git/tags \ |
| 85 | + | jq ".[0].name") |
| 86 | + if [[ $latest_version =~ [0-9]+\.[0-9]+\.[0-9]+ ]]; then |
| 87 | + latest_version=${BASH_REMATCH[0]} |
| 88 | + else |
| 89 | + echo "Something went wrong getting the latest version. Try it again in a few moments" |
| 90 | + exit 1; |
| 91 | + fi |
| 92 | +fi |
| 93 | + |
| 94 | +if ! [[ $latest_version =~ [0-9]+\.[0-9]+\.[0-9]+ ]]; then |
| 95 | + echo "The latest version $latest_version doesn't match the version pattern. Review the parameter latest_version and |
| 96 | + add a version following semantic versioning" |
| 97 | + exit 1; |
| 98 | +fi |
| 99 | + |
| 100 | +echo "Latest certified git version: $latest_version" |
| 101 | +IFS="." read -r -a version_match <<< "$latest_version" |
| 102 | +latest_major="${version_match[0]}" |
| 103 | +latest_minor="${version_match[1]}" |
| 104 | + |
| 105 | +################################# |
| 106 | +# Parse the versions |
| 107 | +################################# |
| 108 | +IFS="." read -r -a version_match <<< "$version" |
| 109 | +major="${version_match[0]}" |
| 110 | +minor="${version_match[1]}" |
| 111 | + |
| 112 | +if [ $DEBUG -eq 0 ]; then |
| 113 | + echo " |
| 114 | + Current version |
| 115 | + ===================== |
| 116 | + Major: $major |
| 117 | + Minor: $minor |
| 118 | +
|
| 119 | + Latest version |
| 120 | + ===================== |
| 121 | + Major: $latest_major |
| 122 | + Minor: $latest_minor |
| 123 | + " |
| 124 | +fi |
| 125 | + |
| 126 | +################################# |
| 127 | +# Check for the version policies |
| 128 | +################################# |
| 129 | +# Major versions should be always updated if there is a new one |
| 130 | +if [ "$major" != "$latest_major" ]; then |
| 131 | + block_version "$version" |
| 132 | +fi |
| 133 | + |
| 134 | +# Minor versions can be checked by max_minor_diff |
| 135 | +allowed_minor=$((minor + max_minor_diff)) |
| 136 | +if [ "$allowed_minor" -lt "$latest_minor" ]; then |
| 137 | + block_version "$version" |
| 138 | +fi |
| 139 | + |
| 140 | +exit 0; |
0 commit comments