66 lines
2.7 KiB
Bash
66 lines
2.7 KiB
Bash
#!/bin/sh
|
|
# Caller supplies a sealed, exact path list and known public before/after bytes.
|
|
set +vx
|
|
set -eu
|
|
PATH=/usr/bin:/bin
|
|
export PATH
|
|
area=$1 direction=$2 before_sum=$3 after_sum=$4
|
|
test "$(id -u)" = 1000
|
|
for file in before after paths; do test -f "$area/$file" && test ! -L "$area/$file"; done
|
|
test "$(sha256sum "$area/before" | cut -d ' ' -f 1)" = "$before_sum"
|
|
test "$(sha256sum "$area/after" | cut -d ' ' -f 1)" = "$after_sum"
|
|
case "$direction" in apply) ;; rollback) ;; *) exit 35;; esac
|
|
validate_path() {
|
|
path=$1
|
|
case "$path" in /data/git/gitea-repositories/*/*.git/hooks/pre-receive.d/10-custodian-secret-scan) ;; *) exit 36;; esac
|
|
parent=${path%/*}
|
|
while test "$parent" != /data; do
|
|
test -d "$parent" && test ! -L "$parent"
|
|
parent=${parent%/*}
|
|
done
|
|
test -f "$path" && test ! -L "$path"
|
|
test "$(stat -c %u "$path")" = 1000
|
|
case "$(stat -c %a "$path")" in 755|775) ;; *) exit 37;; esac
|
|
current=$(sha256sum "$path" | cut -d ' ' -f 1)
|
|
if test "$direction" = apply; then test "$current" = "$before_sum"
|
|
else test "$current" = "$before_sum" || test "$current" = "$after_sum"; fi
|
|
}
|
|
# Validate the complete scope before the first write.
|
|
count=0
|
|
while IFS= read -r path; do validate_path "$path"; count=$((count+1)); done < "$area/paths"
|
|
test "$count" -gt 0
|
|
temporary=
|
|
restore_partial() {
|
|
code=$?
|
|
trap - EXIT HUP INT TERM
|
|
if test -n "$temporary"; then rm -f -- "$temporary" || code=38; fi
|
|
# Only our exact replacement may be restored. Unknown drift is retained.
|
|
if test "$direction" = apply && test "$code" != 0; then
|
|
while IFS= read -r path; do
|
|
if test -f "$path" && test ! -L "$path" &&
|
|
test "$(sha256sum "$path" | cut -d ' ' -f 1)" = "$after_sum"; then
|
|
staged=$(mktemp "${path%/*}/.custodian-restore-XXXXXX") || { code=38; continue; }
|
|
if cp "$area/before" "$staged" && chmod --reference="$path" "$staged" && mv -T -- "$staged" "$path"; then :
|
|
else rm -f -- "$staged"; code=38; fi
|
|
fi
|
|
done < "$area/paths"
|
|
fi
|
|
exit "$code"
|
|
}
|
|
trap restore_partial EXIT
|
|
trap 'exit 39' HUP INT TERM
|
|
while IFS= read -r path; do
|
|
validate_path "$path"
|
|
if test "$direction" = rollback; then source="$area/before"; sum=$before_sum; mode=775
|
|
else source="$area/after"; sum=$after_sum; mode=755; fi
|
|
if test "$(sha256sum "$path" | cut -d ' ' -f 1)" != "$sum"; then
|
|
temporary=$(mktemp "${path%/*}/.custodian-replace-XXXXXX")
|
|
cp "$source" "$temporary"
|
|
chmod --reference="$path" "$temporary"
|
|
test "$(sha256sum "$temporary" | cut -d ' ' -f 1)" = "$sum"
|
|
mv -T -- "$temporary" "$path"
|
|
temporary=
|
|
fi
|
|
test "$(sha256sum "$path" | cut -d ' ' -f 1)" = "$sum"
|
|
done < "$area/paths"
|
|
printf '{"hook_files_verified":%s,"direction":"%s"}\n' "$count" "$direction"
|