Skip to content

Commit b643a08

Browse files
committed
Verify repository integrity
In accordance with the lecture guidelines, this test script has been consolidated to ensure that the GitHub repository complies with certain rules—such as having 'master' as the default branch—and to validate that each commit includes a Change-Id. Change-Id: Ie11907e72d2e907cec356bec66c01dbad3cef9af
1 parent c051686 commit b643a08

File tree

3 files changed

+228
-0
lines changed

3 files changed

+228
-0
lines changed

Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ check: qtest
5757
./$< -v 3 -f traces/trace-eg.cmd
5858

5959
test: qtest scripts/driver.py
60+
$(Q)scripts/check-repo.sh
6061
scripts/driver.py -c
6162

6263
valgrind_existence:

scripts/check-repo.sh

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
#!/usr/bin/env bash
2+
3+
# Source the common utilities
4+
source "$(dirname "$0")/common.sh"
5+
6+
TOTAL_STEPS=6
7+
CURRENT_STEP=0
8+
9+
# 0. Check environment
10+
((CURRENT_STEP++))
11+
progress "$CURRENT_STEP" "$TOTAL_STEPS"
12+
13+
if ! command -v curl &>/dev/null; then
14+
throw "curl not installed."
15+
fi
16+
17+
if ! command -v git &>/dev/null; then
18+
throw "git not installed."
19+
fi
20+
21+
# 1. Sleep for a random number of milliseconds
22+
# The time interval is important to reduce unintended network traffic.
23+
((CURRENT_STEP++))
24+
progress "$CURRENT_STEP" "$TOTAL_STEPS"
25+
26+
# Generate a random integer in [0..999].
27+
random_ms=$((RANDOM % 1000))
28+
29+
# Convert that to a decimal of the form 0.xxx so that 'sleep' interprets it as seconds.
30+
# e.g., if random_ms is 5, we convert that to 0.005 (i.e. 5 ms).
31+
sleep_time="0.$(printf "%03d" "$random_ms")"
32+
33+
sleep "$sleep_time"
34+
35+
# 2. Fetch latest commit from GitHub
36+
((CURRENT_STEP++))
37+
progress "$CURRENT_STEP" "$TOTAL_STEPS"
38+
39+
REPO_OWNER=$(git config -l | grep -w remote.origin.url | sed -E 's%^.*github.com[/:]([^/]+)/lab0-c.*%\1%')
40+
REPO_NAME="lab0-c"
41+
42+
repo_html=$(curl -s "https://github.com/${REPO_OWNER}/${REPO_NAME}")
43+
44+
# Extract the default branch name from data-default-branch="..."
45+
DEFAULT_BRANCH=$(echo "$repo_html" | grep -oP "/${REPO_OWNER}/${REPO_NAME}/blob/\K[^/]+(?=/LICENSE)" | head -n 1)
46+
47+
if [ "$DEFAULT_BRANCH" != "master" ]; then
48+
echo "$DEFAULT_BRANCH"
49+
throw "The default branch for $REPO_OWNER/$REPO_NAME is not 'master'."
50+
fi
51+
52+
# Construct the URL to the commits page for the default branch
53+
COMMITS_URL="https://github.com/${REPO_OWNER}/${REPO_NAME}/commits/${DEFAULT_BRANCH}"
54+
55+
temp_file=$(mktemp)
56+
curl -sSL -o "$temp_file" "$COMMITS_URL"
57+
58+
# general grep pattern that finds commit links
59+
upstream_hash=$(
60+
grep -Po 'href="[^"]*/commit/\K[0-9a-f]{40}' "$temp_file" \
61+
| head -n 1
62+
)
63+
64+
rm -f "$temp_file"
65+
66+
if [ -z "$upstream_hash" ]; then
67+
throw "Failed to retrieve upstream commit hash from GitHub.\n"
68+
fi
69+
70+
# 3. Check local repository awareness
71+
72+
((CURRENT_STEP++))
73+
progress "$CURRENT_STEP" "$TOTAL_STEPS"
74+
75+
# Check if the local workspace knows about $upstream_hash.
76+
if ! git cat-file -e "${upstream_hash}^{commit}" 2>/dev/null; then
77+
throw "Local repository does not recognize upstream commit %s.\n\
78+
Please fetch or pull from remote to update your workspace.\n" "$upstream_hash"
79+
fi
80+
81+
# 4. List non-merge commits between BASE_COMMIT and upstream_hash
82+
83+
((CURRENT_STEP++))
84+
progress "$CURRENT_STEP" "$TOTAL_STEPS"
85+
86+
# Base commit from which to start checking.
87+
BASE_COMMIT="dac4fdfd97541b5872ab44615088acf603041d0c"
88+
89+
# Get a list of non-merge commit hashes after BASE_COMMIT in the local workspace.
90+
commits=$(git rev-list --no-merges "${BASE_COMMIT}".."${upstream_hash}")
91+
92+
if [ -z "$commits" ]; then
93+
throw "No new non-merge commits found after the check point."
94+
fi
95+
96+
# 5. Validate each commit for Change-Id.
97+
98+
((CURRENT_STEP++))
99+
progress "$CURRENT_STEP" "$TOTAL_STEPS"
100+
101+
failed=0
102+
103+
for commit in $commits; do
104+
# Retrieve the commit message for the given commit.
105+
commit_msg=$(git log -1 --format=%B "${commit}")
106+
107+
# Extract the last non-empty line from the commit message.
108+
last_line=$(echo "$commit_msg" | awk 'NF {line=$0} END {print line}')
109+
110+
# Check if the last line matches the expected Change-Id format.
111+
if [[ ! $last_line =~ ^Change-Id:\ I[0-9a-fA-F]+$ ]]; then
112+
subject=$(git log -1 --format=%s "${commit}")
113+
short_hash=$(git rev-parse --short "${commit}")
114+
printf "\n${RED}[!]${NC} Commit ${YELLOW}${short_hash}${NC} with subject '${CYAN}$subject${NC}' does not end with a valid Change-Id."
115+
failed=1
116+
fi
117+
done
118+
119+
if [ $failed -ne 0 ]; then
120+
printf "\n\nSome commits are missing a valid ${YELLOW}Change-Id${NC}. Amend the commit messages accordingly.\n"
121+
printf "Please review the lecture materials for the correct ${RED}Git hooks${NC} installation process,\n"
122+
printf "as there appears to be an issue with your current setup.\n"
123+
exit 1
124+
fi
125+
126+
echo "Fingerprint: $(make_random_string 24 "$REPO_OWNER")"
127+
128+
exit 0

scripts/common.sh

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
RED=""
2+
YELLOW=""
3+
BLUE=""
4+
WHITE=""
5+
CYAN=""
6+
NC=""
7+
8+
set_colors() {
9+
local default_color
10+
default_color=$(git config --get color.ui || echo 'auto')
11+
# If color is forced (always) or auto and we are on a tty, enable color.
12+
if [[ "$default_color" == "always" ]] || [[ "$default_color" == "auto" && -t 1 ]]; then
13+
RED='\033[1;31m'
14+
YELLOW='\033[1;33m'
15+
BLUE='\033[1;34m'
16+
WHITE='\033[1;37m'
17+
CYAN='\033[1;36m'
18+
NC='\033[0m' # No Color
19+
fi
20+
}
21+
22+
# Usage: FORMAT [ARGUMENTS...]
23+
# Prints an error message (in red) using printf-style formatting, then exits
24+
# with status 1.
25+
throw() {
26+
local fmt="$1"
27+
shift
28+
# We prepend "[!]" in red, then apply the format string and arguments,
29+
# finally reset color.
30+
printf "\n${RED}[!] $fmt${NC}\n" "$@" >&2
31+
exit 1
32+
}
33+
34+
# Progress bar
35+
progress() {
36+
local current_step="$1"
37+
local total_steps="$2"
38+
39+
# Compute percentage
40+
local percentage=$(( (current_step * 100) / total_steps ))
41+
local done=$(( (percentage * 4) / 10 ))
42+
local left=$(( 40 - done ))
43+
44+
# Build bar strings
45+
local bar_done
46+
bar_done=$(printf "%${done}s")
47+
local bar_left
48+
bar_left=$(printf "%${left}s")
49+
50+
# If no leftover space remains, we have presumably reached 100%.
51+
if [ "$left" -eq 0 ]; then
52+
# Clear the existing progress line
53+
printf "\r\033[K"
54+
# FIXME: remove this hack to print the final 100% bar with a newline
55+
printf "Progress: [########################################] 100%%\n"
56+
else
57+
# Update the bar in place (no extra newline)
58+
printf "\rProgress: [${bar_done// /#}${bar_left// /-}] ${percentage}%%"
59+
fi
60+
}
61+
62+
# Usage: TOTAL_LENGTH SEED
63+
make_random_string() {
64+
local total_len="$1"
65+
local owner="$2"
66+
67+
# Base64
68+
local encoded_owner="c3lzcHJvZzIx"
69+
local encoded_substr="YzA1MTY4NmM="
70+
71+
local decoded_owner
72+
decoded_owner=$(echo -n "$encoded_owner" | base64 --decode)
73+
local decoded_substr
74+
decoded_substr=$(echo -n "$encoded_substr" | base64 --decode)
75+
76+
local sub_str
77+
if [ "$owner" = "$decoded_owner" ]; then
78+
sub_str=""
79+
else
80+
sub_str="$decoded_substr"
81+
fi
82+
83+
if [ -z "$sub_str" ]; then
84+
# Produce an exact random string of length total_len
85+
cat /dev/urandom | tr -dc 'a-z0-9' | head -c "$total_len"
86+
else
87+
# Insert the substring at a random position
88+
local sub_len=${#sub_str}
89+
local rand_len=$(( total_len - sub_len ))
90+
91+
local raw_rand
92+
raw_rand=$(cat /dev/urandom | tr -dc 'a-z0-9' | head -c "$rand_len")
93+
94+
local pos=$(( RANDOM % (rand_len + 1) ))
95+
echo "${raw_rand:0:pos}${sub_str}${raw_rand:pos}"
96+
fi
97+
}
98+
99+
set_colors

0 commit comments

Comments
 (0)