Documentation
¶
Overview ¶
Package gitgate is a git-aware kernel PREFILTER: a registered Adjudicator rung that inspects a shell tool call (Bash / exec / run_shell / ...) carrying a `command` string, recognizes the `git` invocation inside it, and PROVABLY REFUSES the structurally-decidable git hazards BEFORE the command runs. It turns a doomed git command (force-push, commit --amend, add -A, --no-verify, tag -f, rebase -i) from "the process runs, a git hook rejects it, the agent re-plans" into a deny-as-value AT THE CALL BOUNDARY carrying a repairable, law-citing reason the agent loop consumes.
WHY A SEPARATE RUNG (not the monitor's commandWrites). The adjudicator's existing git logic — shellWriteVerbs ("git apply"/"git checkout"/...), and the `git -C <dir>` / `git --git-dir` mutating-subcommand parse — fires ONLY to protect a guarded tree from SELF_MODIFY: it is scoped to "a WRITE into internal/abi/, .git/, dos.toml, ...". These hazards are orthogonal to that. A `git push --force` to the shared trunk touches no guarded tree, so the self-modify floor never sees it. gitgate is the general git-SHAPE floor: the in-kernel dual of the repo's git HOOKS (tools/githooks/*). The hooks bind every actor (Claude Code, Codex, a human) at the git transaction boundary — defense in depth; this rung binds an agent that routes its tool calls THROUGH the kernel, one step earlier, with a machine-readable reason instead of a stderr message.
WHAT IT DELIBERATELY DOES NOT DO (the honest boundary — see the RESEARCH note, docs/notes/RESEARCH-git-in-kernel-prefilters-*.md):
- CONSERVATIVE TOKENIZER, NOT A SHELL PARSER. A git op laundered through an alias (`alias g=git; g push -f`), a wrapper script (`mygit push -f`), shell `eval`, backtick substitution, or command injection is OUT OF SCOPE and remains the git hooks' job. Like the self-modify floor it mirrors, this rung is over-broad where a refusal is cheap and under-precise where a determined agent can evade; it never CLAIMS full coverage.
- ARGV-DECIDABLE HAZARDS ONLY. Laws that need REPO STATE — OFF_TRUNK (the current branch), the shared-tree staging sweep (the live index), a peer's in-flight MERGE_HEAD (a transient .git file) — are NOT decidable in a pure, stateless prefilter. Reading them would couple the fast decide path to disk plus a per-call git spawn and a TOCTOU race, so they stay with the witness resolver (internal/witness, off the fast path) and the git hooks. This rung DEFERS on them — the fold passes to the next link, fail-closed by default.
- ENFORCING ONLY IN-PATH. A client that bypasses the kernel hits the git hooks, not this rung. gitgate is the earlier, in-path complement to the hooks, never their replacement.
It is PURE (a string read + an argv walk); it execs nothing, imports only the frozen ABI, and is cgo-free — so it satisfies architest's interpreter-free / cgo-free / layered-DAG gates exactly as a hot-path rung must.
Index ¶
Constants ¶
This section is empty.
Variables ¶
var Default = New()
Default is the registered instance.
Functions ¶
This section is empty.
Types ¶
type GitGate ¶
type GitGate struct {
// contains filtered or unexported fields
}
GitGate is the registered rung. Construct with New; the package Default instance registers itself in init() unless FAK_GITGATE=off. Stateless: the rule table is read-only after construction, so one instance is safe for the whole process.
func New ¶
func New() *GitGate
New builds a gate carrying the default trunk-discipline hazard table.
func (*GitGate) Adjudicate ¶
Adjudicate refuses a structurally-decidable git hazard in a shell tool call. A non-shell call (no command/cmd arg), a shell call whose command names no git op, and every git op whose hazard needs repo state all DEFER — the rung has no opinion, the fold passes to the next link (fail-closed: a Defer never grants an allow). A recognized hazard returns a PROVABLE Deny citing ReasonPolicyBlock, with the offending law carried as a bounded-disclosure witness Claim (the agent sees the specific rule + the corrective move, never the whole policy).
func (*GitGate) Caps ¶
func (g *GitGate) Caps() []abi.Capability