git attestor
Captures the state of the git repository at the working directory — HEAD commit, author/committer identity, refs, remotes, tags pointing at HEAD, parent commits, tree hash, and worktree/staging dirtiness.
| Name | git |
|---|---|
| Predicate type | https://aflock.ai/attestations/git/v0.1 |
| Lifecycle | prematerial |
| Default binary? | Yes |
| Category | source-checkout (primary) |
| Recommended trace | off — no syscall tracing needed |
| Auto-attaches when |
|
The facts in this box are generated from the cilock binary's own catalog (cilock tools list). Do not hand-edit — run npm run gen:catalog.
What it captures
The attestor opens the repo with go-git (using DetectDotGit, so it walks up from --workingdir to find .git) and records:
commithash— SHA-1 of HEAD commit. Also emitted as acommitdigestDigestSet(sha1).author/authoremail—commit.Author.Name/.Email.committername/committeremail—commit.Committer.Name/.Email.commitdate— author timestamp (time.Time.String()format).commitmessage— full commit message.signature— PGP signature on the commit, if present.parenthashes— SHA-1s of parent commits (multiple for merges).treehash— SHA-1 of the root tree.refs— every ref (branches, remote-tracking, tags) whose target equals HEAD.branch— short ref name of HEAD (json key isbranch, struct fieldRefNameShort).remotes— configured remote URLs, with embedded user-info (tokens) stripped.tags— annotated tag objects pointing at HEAD:name,taggername,taggeremail,when(RFC3339),pgpsignature,message.status— map of dirty files to{staging, worktree}codes:unmodified,untracked,modified,added,deleted,renamed,copied,updated.gittool—"go-git+git-bin"when thegitbinary is onPATH, else"go-git".gitbinpath/gitbinhash— path and digest of thegitbinary (only when present). Hash uses the attestation context's configured hashes.
If HEAD cannot be resolved (reference not found — e.g. a brand-new repo with no commits), the attestor returns no error and emits an empty predicate rather than failing the run.
When to use
Almost every CI step that runs inside a git checkout. The captured commithash is the canonical SLSA source identifier most release policies pin against, and the parenthash subjects make the resulting collection traversable along the commit-graph during policy evaluation.
Flags
None. The attestor is configured entirely by the working directory; there are no cobra flag registrations.
Output shape
{
"gittool": "go-git+git-bin",
"gitbinpath": "/usr/bin/git",
"gitbinhash": { "sha256": "..." },
"commithash": "9f1c...",
"author": "Jane Dev",
"committername": "Jane Dev",
"commitdate": "2026-05-20 12:34:56 +0000 UTC",
"commitmessage": "fix: ...",
"commitdigest": { "sha1": "9f1c..." },
"signature": "-----BEGIN PGP SIGNATURE-----\n...",
"parenthashes": ["abcd..."],
"treehash": "1234...",
"refs": ["refs/heads/main", "refs/remotes/origin/main"],
"remotes": ["https://github.com/org/repo"],
"tags": [{"name": "v1.2.3", "taggername": "...", "taggeremail": "...", "when": "2026-05-20T12:34:56Z", "pgpsignature": "...", "message": "..."}],
"branch": "main",
"status": {"path/to/file": {"staging": "modified", "worktree": "unmodified"}}
}
Emitted subjects: commithash:<sha1>, authoremail:<email>, committeremail:<email>, parenthash:<sha1> (one per parent), refnameshort:<branch>, remote:<url>. BackRefs() exposes commithash: and parenthash: with sha1 digests.
Gotchas
- Parent-hash chain semantics.
parenthash:<sha>subjects use the raw SHA-1 of the parent commit — the same encoding used forcommithash:<sha>. This is deliberate (issue #34, PR #37): a downstream collection'sparenthashsubject digest now matches the upstream collection'scommithashsubject digest for the same commit, so policy can traverse the parent chain across collections via subject-graph matching. Earlier builds hashed the string with sha256, which broke the join. - Status detection has two modes. If the
gitbinary is onPATH, status comes fromgit status --porcelain; otherwise it uses go-git's worktree status. The two implementations are not always byte-identical for edge cases (submodules, ignored files). - Shallow clones / missing refs.
refsonly contains refs the local repo knows about. CI checkouts that fetch a single SHA may produce an emptybranchand minimalrefs. Tags must be fetched explicitly (fetch-tags) to appear intags. - Submodules are not traversed — only the outer repo's HEAD is recorded.
- Remote URL scrubbing. URLs are parsed and
Useris cleared before recording, sohttps://x-access-token:[email protected]/...becomeshttps://github.com/.... If parsing fails the raw URL is recorded — review remotes if you've put credentials in non-URL syntax. - Dirty trees still attest. A non-empty
statusmap does not fail the attestor; downstream policy must reject dirty builds explicitly if that is the requirement.
CLI example
Real .git/ discovery. Reads HEAD commit, branch, tag, parent SHA, author, signature.
cilock run --step git-context \
--signer-file-key-path key.pem --outfile attestation.json --workingdir . \
--attestations git \
-- echo "captured git context"
Validated against a real git checkout (rookery). Captures real commit metadata. See the full real-data example at https://github.com/aflock-ai/attestor-compliance-examples/tree/main/05-git.
See also
- Catalog row
- Upstream: witness/git.md