avoigt1121
Claude Opus 5.5
feat: governed ToolUniverse core for the knowledge specialist (s1)
377417d Download scripts/hooks/pre-push from anne-voigt/pdac-knowledge-agent-dev: direct link, hf CLI and curl.
- Browser
- Download file 9.27 kB
-
https://huggingface.co/spaces/anne-voigt/pdac-knowledge-agent-dev/resolve/main/scripts/hooks/pre-push
- Command line
-
hf download hf://spaces/anne-voigt/pdac-knowledge-agent-dev/scripts/hooks/pre-push
-
curl -L -o pre-push https://huggingface.co/spaces/anne-voigt/pdac-knowledge-agent-dev/resolve/main/scripts/hooks/pre-push
9.27 kB
| # Two jobs, in this order (the genomics-agent pattern): | |
| # 1. ADR-0014 security gate β runs on EVERY push. Blocks on findings. | |
| # 2. GitHub mirror sync β only on a PROD deploy (`main` to `origin`). Warns, never blocks. | |
| # The gate runs first, so a blocked deploy can never have already updated the mirror. | |
| # | |
| # --- 1. ADR-0014 pre-push security gate ---------------------------------------------------- | |
| # | |
| # `origin` and `hf-dev` ARE HuggingFace Spaces β a push builds a live Space β so there is | |
| # no CI merge gate in front of them. This hook is the enforced check: it runs the shared | |
| # scan (scripts/security_scan.sh) before anything leaves the machine. | |
| # | |
| # It scans the commit being PUSHED, not the working tree it happens to run from. The | |
| # sibling hooks scan the working tree, and on 2026-09-21 that went wrong in the | |
| # orchestrator: pushed from a checkout parked on another lane's branch, the scan audited | |
| # THAT branch's requirements.txt instead of the commit being shipped. Here each pushed sha | |
| # is checked out into a throwaway worktree and scanned there; reports (and the cached | |
| # audit venv) are written to this checkout's security/ so they outlive it. | |
| # | |
| # Install with: make install-hooks | |
| # Bypass (e.g. a docs-only push, knowingly): git push --no-verify | |
| # Set SECURITY_SCAN_STRICT=1 to fail on skipped stages. | |
| set -euo pipefail | |
| # The mirror push below sets this, so that nested push is neither rescanned nor re-mirrored. | |
| [[ -n "${SECURITY_SCAN_DONE:-}" ]] && exit 0 | |
| remote_name="${1:-}" | |
| remote_url="${2:-}" | |
| mirror_remote="${MIRROR_REMOTE:-github}" | |
| dev_remote="${DEV_REMOTE:-hf-dev}" | |
| repo_root="$(git rev-parse --show-toplevel)" | |
| # stdin: "<local ref> <local sha> <remote ref> <remote sha>" per ref being pushed. Git sends it | |
| # once and both jobs need it, so it is read here and replayed from the variable. | |
| push_lines="$(cat)" | |
| shas=() | |
| while read -r _lref lsha _rref _rsha; do | |
| [[ -n "${lsha:-}" ]] || continue | |
| case "$lsha" in *[!0]*) ;; *) continue ;; esac # all-zero = a delete; nothing to scan | |
| [[ " ${shas[*]-} " == *" $lsha "* ]] || shas+=("$lsha") | |
| done <<< "$push_lines" | |
| [[ ${#shas[@]} -gt 0 ]] || exit 0 | |
| # Sweep leaks from earlier interrupted pushes. Named (not `mktemp -d`) so a leak is | |
| # identifiable, and keyed on LIVENESS rather than age: each scan dir records its hook's PID | |
| # and its scan child's, so a dir whose hook is gone is swept at once while a CONCURRENT | |
| # push's dir is never touched. A dir with no .hookpid predates this and is by definition a | |
| # leak. (2026-09-23: a leaked worktree was found with `git worktree add`'s inner | |
| # `git reset --hard` still sleeping after 2 days 7 hours, in a directory macOS had reaped.) | |
| for stale in "${TMPDIR:-/tmp}"/pre-push-scan.*; do | |
| [[ -d "$stale" ]] || continue | |
| stale_pid="$(cat "$stale/.hookpid" 2>/dev/null || true)" | |
| if [[ -z "$stale_pid" ]] || ! kill -0 "$stale_pid" 2>/dev/null; then | |
| stale_scan="$(cat "$stale/.scanpid" 2>/dev/null || true)" | |
| if [[ -n "$stale_scan" ]] && kill -0 "$stale_scan" 2>/dev/null; then | |
| kill -TERM "-$stale_scan" 2>/dev/null || kill -TERM "$stale_scan" 2>/dev/null || true | |
| sleep 1 | |
| if kill -0 "$stale_scan" 2>/dev/null; then | |
| kill -KILL "-$stale_scan" 2>/dev/null || kill -KILL "$stale_scan" 2>/dev/null || true | |
| fi | |
| fi | |
| for wt in "$stale"/wt-*; do | |
| [[ -d "$wt" ]] && git worktree remove --force "$wt" >/dev/null 2>&1 | |
| done | |
| rm -rf "$stale" | |
| echo "[pre-push] swept a leaked scan directory from an interrupted push: $(basename "$stale")" | |
| fi | |
| done | |
| git worktree prune >/dev/null 2>&1 || true | |
| tmp="$(mktemp -d "${TMPDIR:-/tmp}/pre-push-scan.XXXXXX")" | |
| echo "$$" > "$tmp/.hookpid" | |
| scan_pid="" | |
| cleanup() { | |
| # Kill the scan BEFORE its directory disappears: deleting the tree under a live child is | |
| # how a gitleaks or `git reset --hard` ends up running in a path that no longer exists. | |
| if [[ -n "$scan_pid" ]] && kill -0 "$scan_pid" 2>/dev/null; then | |
| # Negative pid = the whole process group. run_scan starts the job with `set -m` so it | |
| # gets its own group; signalling the group takes gitleaks / pip-audit / bandit down with | |
| # the shell that launched them, instead of reparenting them to init. | |
| kill -TERM "-$scan_pid" 2>/dev/null || kill -TERM "$scan_pid" 2>/dev/null || true | |
| wait "$scan_pid" 2>/dev/null || true | |
| fi | |
| for wt in "$tmp"/wt-*; do [[ -d "$wt" ]] && git worktree remove --force "$wt" >/dev/null 2>&1; done | |
| git worktree prune >/dev/null 2>&1 || true | |
| rm -rf "$tmp" | |
| } | |
| # EXIT alone is not enough: a non-interactive bash killed by an UNTRAPPED signal dies | |
| # without running its EXIT trap, so Ctrl-C, a closed terminal or a terminated agent session | |
| # left the worktree registered and its directory behind. `trap - EXIT` stops a double run. | |
| # Nothing in-process survives SIGKILL β that case is what the sweep above is for. | |
| on_signal() { | |
| cleanup | |
| trap - EXIT | |
| echo "[pre-push] interrupted β scan worktree cleaned up; push aborted." >&2 | |
| exit 130 | |
| } | |
| trap cleanup EXIT | |
| trap on_signal INT TERM HUP | |
| # Run the scan as a background job and `wait`: bash defers a trap handler until the running | |
| # FOREGROUND command returns, so a Ctrl-C during a multi-minute scan would not be acted on | |
| # until the scan finished. `wait` IS interruptible, so cleanup runs at once. | |
| run_scan() { | |
| set -m # give the job its own process group, so cleanup can signal the tree | |
| "$@" & | |
| scan_pid=$! | |
| set +m | |
| echo "$scan_pid" > "$tmp/.scanpid" | |
| local rc=0 | |
| wait "$scan_pid" || rc=$? | |
| scan_pid="" | |
| rm -f "$tmp/.scanpid" | |
| return "$rc" | |
| } | |
| for sha in "${shas[@]}"; do | |
| short="${sha:0:7}" | |
| # Branches that predate the scan have no script β skip them cleanly rather than block. | |
| if ! git cat-file -e "$sha:scripts/security_scan.sh" 2>/dev/null; then | |
| echo "[pre-push] $short has no scripts/security_scan.sh β skipping scan for it." | |
| continue | |
| fi | |
| echo "[pre-push] running ADR-0014 security scan on the pushed commit $short (git push --no-verify to skip)β¦" | |
| wt="$tmp/wt-$short" | |
| git worktree add --detach --quiet "$wt" "$sha" | |
| # Git exports GIT_DIR & co. into hooks; left set, the scan's own git calls (bandit's | |
| # target discovery, gitleaks) would read the wrong checkout. | |
| scan_job() { | |
| env -u GIT_DIR -u GIT_WORK_TREE -u GIT_INDEX_FILE -u GIT_PREFIX \ | |
| SECURITY_SCAN_OUT="$repo_root/security" bash "$wt/scripts/security_scan.sh" | |
| } | |
| if run_scan scan_job; then | |
| echo "[pre-push] $short: security scan clean." | |
| else | |
| echo "[pre-push] $short: security scan reported findings β push blocked." >&2 | |
| echo "[pre-push] triage the reports in security/, or 'git push --no-verify' to override." >&2 | |
| exit 1 | |
| fi | |
| done | |
| echo "[pre-push] security scan clean β proceeding." | |
| # --- 2. GitHub mirror sync ----------------------------------------------------------------- | |
| # `origin` IS the prod Space and `github` is a source mirror that only runs CI; nothing links | |
| # them, so the mirror fell behind prod by hand-sync on 2026-10-01 more than once. A stale mirror | |
| # means CI runs a SUBSET of production, which reads as a pass. This syncs the mirror's `main` | |
| # at the only moment git offers: when a prod deploy is about to go out. | |
| # | |
| # Two honest limitations (as in pdac-genomics-agent): | |
| # 1. The mirror is pushed FIRST: git has no post-push hook. If the `origin` push then fails, | |
| # `github` is briefly AHEAD of prod. That self-corrects on the next deploy, and CI running a | |
| # superset of production is the milder error. | |
| # 2. A mirror failure WARNS; it does not block. The mirror is CI; `origin` is production. It is | |
| # pushed without force, so a mirror that has moved on (another lane synced it) is left alone. | |
| # | |
| # Only `main` on `origin` is mirrored. `git push hf-dev dev:main` also targets refs/heads/main on | |
| # a huggingface.co URL, so the dev Space is excluded by name AND by URL first β mirroring it | |
| # would put dev code on the mirror's `main`, where CI reads it as production. | |
| case "$remote_name$remote_url" in | |
| "$dev_remote"*|*-dev|*-dev.git|*-dev/) exit 0 ;; | |
| esac | |
| case "$remote_name$remote_url" in | |
| origin*|*huggingface.co/spaces/anne-voigt/pdac-knowledge-agent) ;; | |
| *) exit 0 ;; | |
| esac | |
| main_sha="" | |
| while read -r _lref lsha rref _rsha; do | |
| [[ "${rref:-}" == "refs/heads/main" ]] || continue | |
| case "${lsha:-}" in *[!0]*) main_sha="$lsha" ;; esac # all-zero = a DELETE; never mirror it | |
| done <<< "$push_lines" | |
| [[ -n "$main_sha" ]] || exit 0 # nothing headed for main: not a deploy | |
| if ! git remote get-url "$mirror_remote" >/dev/null 2>&1; then | |
| echo "[pre-push] no '$mirror_remote' remote β the GitHub mirror will fall behind this deploy." >&2 | |
| echo "[pre-push] git remote add $mirror_remote https://github.com/Anne-Voigt/pdac-knowledge-agent.git" >&2 | |
| exit 0 | |
| fi | |
| echo "[pre-push] mirroring ${main_sha:0:7} to '$mirror_remote' main so the mirror matches prodβ¦" | |
| if SECURITY_SCAN_DONE=1 git push --quiet "$mirror_remote" "$main_sha:refs/heads/main"; then | |
| echo "[pre-push] mirror in sync β proceeding with the deploy." | |
| else | |
| echo "[pre-push] WARNING: mirror push failed (often: it already moved on). The deploy proceeds." >&2 | |
| echo "[pre-push] Check it after the deploy: git fetch $mirror_remote && git log --oneline -1 $mirror_remote/main" >&2 | |
| fi | |
| exit 0 | |