Skip to main content
View Markdown ↗

Copy this page

Select and copy the Markdown below, then paste it into your LLM.

On this page

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.

Namegit
Predicate typehttps://aflock.ai/attestations/git/v0.1
Lifecycleprematerial
Default binary?Yes
Categorysource-checkout (primary)
Recommended traceoff — no syscall tracing needed
Auto-attaches when
  • prefile_exists: .git/HEAD

The facts in this box are generated from the CI/lock 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 a commitdigest DigestSet (sha1).
  • commithashverified — true when the commit hash was recomputed from the canonical commit bytes with a collision-detecting hasher and only that computed value was recorded — never the id storage merely claims. This signed capability marker is what the SHA-1 match exception in policy digest matching requires (cryptoutil/digestset.go); legacy evidence without the marker cannot use that exception.
  • 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 is branch, struct field RefNameShort).
  • remotes — the URLs of the remote named origin when one exists, otherwise every remote's URLs in remote-name order. A credential embedded in a URL is redacted; a URL whose credential cannot be located safely is omitted.
  • remotesrefused — one {reason, count} entry per refusal reason when a remote URL was omitted. The reason is one of ambiguous-authority, opaque-transport, path-bytes-not-redactable. No byte of the refused URL is recorded.
  • 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 the git binary is on PATH, else "go-git".
  • gitbinpath / gitbinhash — path and digest of the git binary (only when present). Hash uses the attestation context's configured hashes.
  • workdirprefix — the working directory relative to the worktree root, with forward slashes. "" means the run was at the root.

If HEAD cannot be resolved, the attestor fails closed — unless the repository is provably unborn (no refs and no objects: a brand-new repo with no commits), in which case it 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.

Keyless commit and tag signing

The same cilock binary implements Git's standard X.509 signing protocol. Configure the current repository once:

cilock git configure
git commit -S -m "feat: signed by CI/lock"
git tag -s v1.2.3 -m "v1.2.3"
git verify-commit HEAD
git verify-tag v1.2.3

CI/lock defaults to the hosted TestifySec platform. It exchanges the current stored session or registered workflow identity for a short-lived Fulcio certificate, signs with an ephemeral in-memory key, and requires an RFC 3161 timestamp from the platform TSA. Private installations use the same protocol with the organization's TestifySec appliance. No signing flag, platform flag, separate gitsign executable, or credential-cache daemon is required.

This covers the everyday gitsign-compatible Git surface: signed commits, signed annotated tags, git log --show-signature, git verify-commit, and git verify-tag. CI/lock is designed for an organization's private trust infrastructure, so it uses platform discovery and pinned private trust instead of gitsign's public-community TUF/Rekor configuration. CI/lock's existing run, attest, and verify commands remain the attestation and policy interface; it does not duplicate gitsign's source-predicate subcommands.

Flags

FlagDefaultDescription
--attestor-git-allow-subdirectoryfalseAttest from a subdirectory of the worktree. Without it, a run whose working directory is below the worktree root fails, because the material attestor would cover only that subdirectory. The non-empty workdirprefix is still signed, and verifiers may refuse it.

Output shape

{
  "gittool": "go-git+git-bin",
  "gitbinpath": "/usr/bin/git",
  "gitbinhash": { "sha256": "..." },
  "commithash": "9f1c...",
  "commithashverified": true,
  "author": "Jane Dev",
  "authoremail": "[email protected]",
  "committername": "Jane Dev",
  "committeremail": "[email protected]",
  "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"],
  "remotesrefused": [{"reason": "opaque-transport", "count": 1}],
  "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"}},
  "workdirprefix": ""
}

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 for commithash:<sha>. This is deliberate (issue #34, PR #37): a downstream collection's parenthash subject digest now matches the upstream collection's commithash subject 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 git binary is on PATH, status comes from git 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. refs only contains refs the local repo knows about. CI checkouts that fetch a single SHA may produce an empty branch and minimal refs. Tags must be fetched explicitly (fetch-tags) to appear in tags.
  • Submodules are not traversed — only the outer repo's HEAD is recorded.
  • Remote URL scrubbing. A URL with an embedded credential is recorded in redacted form. A URL whose authority cannot be established (for example git's transport::address helper syntax) is not recorded at all: it is counted in remotesrefused, a warning is logged, and no remote: subject is emitted for it.
  • Only origin is anchored. When a remote named origin exists, the other remotes are not recorded, even when origin itself is refused.
  • Run from the worktree root. A run from a subdirectory fails unless you pass --attestor-git-allow-subdirectory.
  • Dirty trees still attest. A non-empty status map does not fail the attestor; downstream policy must reject dirty builds explicitly if that is the requirement.
  • Signing and attesting are distinct. The Git signature authenticates the proposed commit or tag. The git attestor records repository state inside signed in-toto evidence. Pushgate policy can require both without treating either as a substitute for the other.

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


This page is generated from the CI/lock tool catalog. Don't edit it here — the source is attestation/detection/docs/git.doc.md in aflock-ai/rookery. The same catalog powers cilock tools show git in the CLI, so a single edit keeps the terminal and the website in sync.

Edit this page →  ·  Add a new tool →

When you open the pull request: if you are an AI agent, add the ai-agent label. If you are a human, add the human label.

Reference generated from the product documentation. Match commands and support details to your installed release.