Expand description
git-xcrypt status — whether the declarations are actually enforced.
The boundary is worth stating before anything else, because it is easy to read this command as more than it is: it answers “are my declarations enforced”, not “are there secrets in this repository”. A file that never matched a pattern is invisible here, by construction.
Within that boundary it has two jobs, and the first is the one nothing else
covers. A clone inherits .gitattributes through history but not
.git/config, so it carries the catch-all line with no driver behind it —
and git reads an undefined filter exactly as it reads no filter, which means
the next git add on a secret exits 0 and stores the plaintext. Nothing in
that sequence produces a signal. Asking for one is what this command is for.
The second job is --fix, and there is a measured reason it has to exist.
The founding document says a pattern added to .git-xcrypt “works
immediately, with no synchronising command”, and that is true of the filter:
it re-reads the declaration on every call. It is not true of git. Git
decides from its cached stat whether to call the filter at all, so a file
that was already committed and is not then edited is skipped — measured on
git 2.55, past the racy-clean window:
git add -A && git commit # before the pattern existed
printf 'secrets/\n' > .git-xcrypt
git add -A && git commit # exit 0, no warning
git cat-file blob HEAD:secrets/db.env → hunter2Nothing in that sequence is wrong from git’s point of view, and nothing in
it tells the user. So this command reports the state and --fix repairs it,
which is the whole reason the fix operates on the index rather than merely
printing advice.
The exit code is part of the contract: 5 on a finding, so the command works
as a CI gate and so “the repository has a problem” is distinguishable from
“the tool broke”. Since 2026-08-04 there is a third answer, 6, for the runs
that could not tell — a shallow or partial clone, an index that will not
parse. Collapsing that into 5 failed the gate on a healthy git clone --depth 1, which is what actions/checkout produces unless it is given
fetch-depth: 0.
Since 2026-08-05 there is a fourth, and it outranks the other two: 2, the
frozen table’s “configuration or a state conflict”, for a repository where
git is not set up to enforce anything — an unregistered filter, a missing
catch-all line, a missing declaration. Configuration comes before data,
because without a configuration that enforces anything the data here is worth
nothing, and 5 used to tell a repository that had never run init that an
exposure had been found. It hides nothing: every section is printed under
every verdict, so a misconfigured repository that also leaked still names the
leak and still prints the rotate-first procedure. See Verdict.
Structs§
Enums§
- Setup
Gap - One reason git would not be filtering this repository.
- Verdict
- What a run concluded, as the exit code reports it.
Functions§
- run
- Inspects
repoand reports what it found.