Skip to content

Commit e2b8ea5

Browse files
authored
Merge pull request github#387 from github/droidpl/outdated-clients
Adds block-outdated-clients pre-receive hook
2 parents 9de211b + 33df05e commit e2b8ea5

File tree

1 file changed

+140
-0
lines changed

1 file changed

+140
-0
lines changed
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
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

Comments
 (0)