hooks
hooks
¶
Sandbox-owned git hooks the gate server injects into every agent push.
The gate's HTTP server historically pointed core.hooksPath at
/dev/null so that no hook inside a gate repo could ever run — repo
content must never become host-side code. This module keeps that
property while inverting the mechanism: hooks now live in a directory the
sandbox owns outside every gate repo, rendered from the constants below
by the supervisor when it composes the gate (the server itself only
receives the path). Repo content still can't inject code; the operator
side gains exactly one enforcement point.
One hook is installed, post-receive, and it does two things:
- Backs up destructive agent updates. For every pushed ref under
refs/heads/that was force-moved or deleted, the old tip is saved asrefs/terok/backup/<branch>/<stamp>-<sha12>— the same scheme the sync model uses, solist_backups()/prune_backups()cover both sides with one retention policy. A backup is a ref, not a copy: the objects it pins arrived with the original push and are already reflog-retained, so the net-new storage is the ref file itself. - Writes the push marker. Every push overwrites
$GIT_DIR/terok-push-markerwith a timestamp and the updated refs, so the host can watch one file's mtime instead of polling refs.
Why post-receive and not update: git quarantines pushed objects
while pre-receive/update run and refuses all ref updates during
that window, so the backup ref cannot be written there. By
post-receive the quarantine is over — and the old tips being backed
up predate the push anyway. The cost is that a failed backup can only
warn (the push is already accepted), not reject; the warning goes to the
agent's push output and into the marker file, and the always-on reflog
remains the last-resort trail.
Identity needs no plumbing at all: only agent pushes traverse the HTTP server, so everything these hooks see is agent-side by construction. Operator pushes from the host use the gate repo's own (empty) hooks dir and behave as before.
HOOKS_DIRNAME = '.terok-hooks'
module-attribute
¶
PUSH_MARKER_FILENAME = 'terok-push-marker'
module-attribute
¶
hooks_dir_for(mirror_root)
¶
install_hooks(hooks_dir)
¶
Idempotently render the hook scripts into hooks_dir.
Writes are atomic (tmp file + rename) because several per-container gate servers may share one mirror root and race here; content-equal installs are skipped so repeated server starts never churn mtimes.