Skip to main content

Module status

Module status 

Source
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  → hunter2

Nothing 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§

Report
What status found.
Scanned
How much of the repository the scan covered.

Enums§

SetupGap
One reason git would not be filtering this repository.
Verdict
What a run concluded, as the exit code reports it.

Functions§

run
Inspects repo and reports what it found.