Git, CI/CD & GitOpsLXV · Software Supply Chain SecuritySourceTrust
Source trust and repository attestation — branch protection, signed commits, the trust chain
What you'll learn
- Define source trust as the human-to-commit link at the start of the supply chain
- Identify the controls that establish source trust - branch protection, signed commits, required reviewers, signed tags
- Recognise the difference between a signed commit and a verified commit, and why the distinction matters
- Map a commit signature to a developer identity, and recognise what the signature does not attest
Prerequisites
Verified against Git 2.55.x teaching target; 2.40+ minimum · GitHub Actions continuous service; Aug 2026 documentation baseline · Argo CD v3.5.x teaching target; v3.0+ minimum · Flux v2.9.x · Sigstore Cosign v3.1.x · SLSA v1.2 · OCI Distribution Specification v1.1 · Git LFS v3.7.1 · Kubernetes (cross-course target) 1.36.x
Source trust is the human-to-commit link at the start of the supply chain. The chain begins when a developer writes code and ends when the artifact runs in production. Every link in the chain is verifiable; the first link is the link between the developer and the commit. The controls that establish this link are branch protection on the repository, signed commits by the author, and required reviewers who also attest. A commit that is not signed is a commit that cannot be verified at the next boundary. A repository without branch protection is a repository where any credential can substitute a commit.
The trust chain at the source boundary
The trust chain at the source boundary is the chain that takes the developer’s intent and produces a commit that the next boundary can verify. The chain has four links:
flowchart LR
A["Developer identity"] --> B["Signing key"]
B --> C["Signed commit"]
C --> D["Branch protection"]
D --> E["Verified commit"]
E --> F["Consumer: CI / artifact"]
- Developer identity. The human (or the CI identity) that authored the change. The identity is bound to a signing key.
- Signing key. The key that signs the commit. For individuals, this is typically a GPG key or an SSH key. For CI, this is the build platform’s identity (e.g., Sigstore Fulcio).
- Signed commit. The commit object with a signature over its contents. The signature binds the commit to the signing key.
- Branch protection. The repository-level rule that requires signed commits, requires reviews, and forbids direct pushes to the default branch. The rule is enforced by the host (GitHub, GitLab, etc.) and cannot be bypassed by a developer who has push access.
- Verified commit. A commit that has a valid signature and was merged through a protected branch. The consumer (CI, downstream verifier) treats the commit as trusted.
Signed commits and verified commits
A signed commit has a cryptographic signature over its contents. The signature binds the commit to the signing key. A verified commit is a signed commit whose signature has been checked against a trusted key — typically the developer’s public key published to the host (GitHub, GitLab) or to a key server. The distinction matters:
- A signed commit is a commit that has a signature. The signature can be valid, expired, or revoked; the signature binds the commit to the key, but the key’s trust is a separate question.
- A verified commit is a signed commit whose signature is valid, whose key is trusted by the host, and whose commit message and contents match the signature. The host displays “Verified” badge next to verified commits.
The production discipline is to require verified commits on the default branch. A merge that contains an unverified commit is a merge that introduces unverified source into the chain. The rule is enforced by branch protection, not by convention.
The git commands
The git commands that produce signed commits are git commit -S (GPG) and git commit -S with an SSH key configured. The
developer signs the commit with their private key; the host
verifies the signature against the developer’s published public
key. The host records the verification result next to the
commit.
git config --global commit.gpgsign true
git config --global user.signingkey $KEY_ID
git commit -S -m "fix: correct the rotate-credentials CronJob"
The first command tells git to sign every commit by default. The second command names the signing key. The third command creates a signed commit. The host records the signature and verifies it against the published key when the commit is pushed.
Repository attestation
Repository attestation is the act of the host producing a signed statement about the repository state: which commits exist, which branches are protected, which reviewers approved which PRs. The attestation is what makes the repository state externally verifiable — a verifier outside the repository can check the attestation and confirm that the commit the CI pipeline is about to build came from a protected branch.
GitHub and GitLab both expose the data needed for attestation through their APIs and through signed webhooks. The production discipline is to feed the repository state into the artifact’s provenance attestation, so that a verifier can confirm the artifact was built from a verified commit on a protected branch — not just from a commit whose signature happens to be valid.
Production discipline
- Enforce branch protection on the default branch. Require signed commits, require reviews, forbid direct pushes. The rules live in the host, not in developer configuration.
- Require verified commits on the default branch. A merge that contains an unverified commit is a merge that introduces unverified source.
- Treat the developer’s signature as authentication, not as authorisation. The signature proves who wrote the commit; the review proves who approved it.
- Feed repository state into the artifact’s provenance. The verification at the artifact boundary should be able to confirm the commit was reviewed and merged through a protected branch.
Cross-course references
- Git, CI/CD & GitOps — Part LXV-01 (Trust Boundaries) maps the source boundary this lesson covers.
- Git, CI/CD & GitOps — Part IV (Commit DAG) establishes the commit object model that signature verification checks.
- Git, CI/CD & GitOps — Part XXVIII (Branch Protection) covers the host-level rules in detail.
- Linux for Production Sysadmins — Part XII (RepoSecurity) covers the OS-level analogue of package signing.
Quiz
Knowledge check · 4 questions
Q1. What is the difference between a signed commit and a verified commit?
Q2. A signed commit signed by the developer's key is not sufficient to attest that the commit was reviewed and approved.
Q3. Name the four controls that, together, establish source trust at the human-to-commit link.
Q4. Identify the gap in the team's source-trust posture and the rule that closes it.
Team T maintains a critical infrastructure repository. Branch protection is enabled on the default branch. The rule requires one reviewer before merge. The team does not require signed commits. An attacker compromises a developer's GitHub account through a stolen personal access token. The attacker pushes a pull request that contains a malicious change to a Terraform module. The pull request is reviewed by a second developer who, busy with an incident, approves the change without a full diff review. The change is merged, the build pipeline runs, and the malicious Terraform module is deployed. The post-incident investigation reveals the change was approved but was not signed by the attacker.
Passing score: 75%. Answers are checked in this browser.