The Gap Between Source and Artefact
Provenance · June 25, 2026 · 9 min read
Every control most teams put on their code operates on source. Review happens on a diff. Static analysis reads a repository. Branch protection guards a ref. All of it is about text in version control.
Production does not run text in version control. It runs a binary, an image, a bundle — something a build system produced. The relationship between the two is asserted rather than demonstrated, and the assertion is usually just: well, it came out of the pipeline.
That gap is where provenance lives. It is not a compliance artefact and it is not signing. It is the question of whether anyone can establish, after the fact, which source produced a given artefact, on what machine, with which inputs — and whether that establishment survives someone lying about it.
A signature is a smaller claim than it looks
Signing is the first thing teams reach for, and it is worth being precise about what a valid signature actually establishes.
It establishes that a holder of a particular private key performed an operation over particular bytes. That is all. It says nothing about whether the bytes are good, whether the build that produced them was clean, whether the source was reviewed, or whether the key holder understood what they were signing. The signature is a statement of who, not of what happened.
This matters because of where signing keys usually live. If the key sits in the build system, then anyone who can influence the build system can obtain a valid signature. The signature is then an assertion by the compromised component about itself, which is worth nothing at all. A signature is only as meaningful as the isolation of the thing holding the key, and in most pipelines that isolation has never been examined.
What provenance adds
An attestation is a signed statement about an artefact rather than merely over it. The useful ones bind a handful of facts together: the digest of the artefact produced, the source repository and exact commit, the identity of the builder, the build parameters and entry point, and the digests of the material inputs the build consumed.
The value is in the binding. Any one of those facts on its own is weak. Bound together and signed by something other than the code being built, they support a question you can actually pose at deployment time: does this image claim to have come from a commit on our default branch, built by our builder, with no external parameters injected? That is a decision procedure. “It came out of the pipeline” is not.
Note the direction of travel. Provenance does not make a build trustworthy. It makes a build checkable, which means an untrustworthy build becomes visible to a policy rather than invisible to everyone.
The verification gap
Here is the failure mode that eats most of the value: organisations generate signatures and attestations diligently, then never check them anywhere that matters.
A signature that is produced and stored is a log entry. A signature verified before an artefact is allowed to run is a control. The second is much harder, because verification has to happen at a point that can actually refuse — an admission gate on the cluster, a check in the deployment tool, a release step that halts — and that point has to be one nobody can route around when a release is late.
The test is simple and uncomfortable: take an unsigned artefact, or one signed by the wrong key, and try to deploy it. If it goes out, you have a generation pipeline, not a verification pipeline.
Reproducibility is the independent check
Provenance tells you what a builder claims. Reproducible builds are the only mechanism that lets anyone check the claim without trusting the builder.
The property is stark: given the same source and the same declared inputs, the build produces byte-identical output, every time, on any machine. If that holds, a second party can rebuild independently and compare digests. A build system that has been tampered with to insert code cannot survive that comparison, because the rebuild will not match — and this is the one check that does not depend on the compromised component behaving honestly.
Achieving it is a long fight against small sources of non-determinism, and the list is fairly consistent across ecosystems. Embedded timestamps. Filesystem iteration order. Absolute paths baked into debug information. Locale and timezone affecting sort order. Parallel compilation producing different link orders. Random seeds, build counters, hostnames. Archives storing modification times and ownership.
Each is individually trivial and collectively a genuine engineering project, which is why partial reproducibility is worth pursuing on its own terms: the ability to rebuild a release and get a nearly identical artefact, with a known and explained set of differing bytes, is far better than having no reference point at all.
Hermetic builds and why ambient anything is a problem
A build that reaches out to the network mid-run to fetch a dependency has an input that is not recorded, not pinned and not stable. It cannot be reproduced and its provenance is incomplete by construction — the attestation lists the inputs the builder knew about, and this one arrived after the accounting.
A hermetic build declares all its inputs up front, fetches them before the build begins, verifies them against digests, and then runs with the network closed. This is restrictive and it is the thing that makes everything else work: the input set becomes finite and known, so the attestation can be complete and the rebuild can be faithful.
The same logic applies to credentials. A build agent holding long-lived registry tokens, cloud credentials and signing keys as ambient environment gives every step of every build — including the install script of a transitive dependency — the ability to use them, which turns any dependency compromise into a pipeline compromise. Ephemeral agents destroyed after each run, with credentials scoped to the specific build and expiring with it, are not a hardening nicety; they are what keeps a bad package’s reach inside the build rather than inside the release.
Transparency changes the economics
Signatures recorded in an append-only public log have a property private ones do not: a malicious artefact signed with a stolen key leaves a permanent, discoverable trace. The attacker must either log the signature and be observable, or not log it and fail any policy requiring log inclusion.
That does not prevent the compromise. It changes what the attacker gets — a window instead of indefinite silence — and it gives “was anything else signed with this key” an answer, which is exactly the question you cannot answer today when a key is suspected.
The order of operations
Reproducibility before signing, if you have to choose. A signature over an artefact nobody can independently rebuild is a statement about a black box. Reproducibility without signing still gives you a check that anyone can run.
Verification before generation, always. A pipeline that produces attestations nobody enforces has spent the engineering effort and bought none of the property. Pick one deployment path, make it refuse an artefact that fails policy, and confirm the refusal by trying it. Everything else — more artefact types, more claims in the attestation, more gates — is expansion of something that already works.