Why must a build platform fix the build definition before a run starts for its provenance to mean anything?
answer
- the record must outlive the run's choices
- unforgeable means the platform observed it
- recorded steps versus executed steps
- one commit in a helper script
- resolve and pin before user code runs
basics
~20 sProvenance records what the platform decided to run. If the running build can rewrite the definition it is executing, the recorded steps and the executed steps drift apart, and the signed statement describes a build that never happened.
solid answer
~40 sProvenance is only useful if it is unforgeable in the SLSA sense: everything in the statement must be obtained by the build platform itself, and the build must not be able to inject or alter it - apart from the external parameters the platform explicitly records as inputs. Fixing the definition before the run is how that is achieved in practice. The platform resolves the entry point, the source revision and the configuration it will execute, records them, and only then hands control to user-controlled steps. A platform that lets a job regenerate the pipeline file it is currently executing breaks this: one commit in a helper script makes the executed steps differ from the recorded ones, while the signature still verifies. Downstream, every consumer is then checking a document about a different process.
go deeper
Recall that provenance names an entry point and a source revision, and that those must be decided by the platform before the build's own steps start running.
Explain unforgeability: every field comes from the platform, only declared external parameters come from the invoker, and a run that can rewrite its own definition makes the signed record describe something that never executed.
Show you can interrogate a real platform - when the definition is resolved, whether a step can force re-resolution, whether dispatch parameters land in the statement - and restructure generated pipelines into a witnessed two-stage flow.
Frame this as audit truth. Decide what your organisation is willing to assert about its releases, and whether a build platform that cannot pin its own definitions is fit to be the evidence source for customer or regulator claims.
## The property being protected SLSA's build track calls it **unforgeable provenance**: all of the information in the statement must come from the build platform, and users must not be able to inject or alter it. The one sanctioned exception is the set of *external parameters* - the entry point and the inputs the run was invoked with - which the platform records as data it observed, not as data the build asked it to write down. Fixing the build definition before the run starts is the mechanism that makes unforgeability true rather than aspirational. ## What 'fixed before the run' means concretely Before any user-controlled step executes, the platform must have: 1. resolved which definition it is going to execute - the entry point, and the exact source revision the configuration was read from; 2. resolved the parameters that definition was invoked with; 3. recorded those values in the provenance it will sign. After that, the build may do arbitrary work *inside* what the definition describes. What it must not do is change the definition itself, because the statement's whole value is the match between the recorded definition and the executed one. ## The failure mode Picture a platform where a running job can write a new pipeline file and have the platform pick it up mid-run - a 'regenerate the config, then continue' pattern. An attacker who lands a single commit in an unremarkable helper script now controls the steps that execute, while the provenance still names the original entry point and the original revision. Every signature verifies. Every policy check passes. The asset lost here is **audit truth**: the organisation's own record of how its releases were produced is no longer evidence of anything, and the loss is silent, because nothing fails. The attacker position is modest - a compromised build step, not a platform operator - which is exactly why the property is graded as a platform requirement rather than a pipeline nicety. ## Why no pipeline can fix this for itself A carefully written pipeline on such a platform is not protected, because the guarantee is about what the platform *forbids*, not about what one team chose not to do. Verifiers cannot tell a disciplined tenant from an undisciplined one: they see one builder identity and one class of claim. That is why 'our pipeline does not do that' is the wrong answer - the question is whether the platform makes it impossible. ## Dynamic pipelines are not automatically disqualified Generating a pipeline from a script is common and legitimate. What matters is whether something outside the run witnessed the decision. The honest shape is two stages: - a **generator build** whose own provenance records its source revision and entry point, and whose output is the generated definition, published as an artifact with a digest; - an **execution build** whose external parameters record that definition by digest, so what it ran is pinned and independently inspectable. What breaks the property is a single run that both invents and executes its own steps, because there is no record outside that run of what it decided to do. Similarly, parameters supplied when the build is dispatched are fine, provided the platform records them as external parameters. The sin is not dynamism - it is *unrecorded change*. ## What the verifier does with the recorded definition A consumer's policy typically asserts: this artifact digest must have provenance signed by builder X, from source repository Y, through entry point Z. Every one of those checks is a comparison against fields the platform recorded. If the executed definition can drift away from those fields after they are written, all three comparisons become decorative. The direction matters: a signature tells you who vouched, provenance tells you how the artifact came to be - and a mutable definition corrupts the second while leaving the first perfectly intact, which is precisely why the failure is hard to spot. ## Questions worth asking a build platform - At what moment is the definition resolved, and from what revision? - Can a step cause the platform to re-resolve or replace it? - Are dispatch-time parameters recorded in the provenance, or only in the platform's private logs? - Can a step influence the builder identity or the fields written into the statement?
- Many teams generate their pipeline dynamically from a script. Is that automatically disqualifying?No, but it moves where the truth has to live. If the generation runs as its own build - provenance recording its source revision, output published as a definition artifact with a digest - and a second build consumes that definition pinned by digest, the chain holds. What breaks the property is one run that both invents and executes its own steps, because nothing outside that run witnessed what it decided to do.
- What does the platform actually record to capture the fixed definition?The external parameters - the entry point and the inputs the run was invoked with - plus the resolved dependencies of the definition itself, notably the exact source revision the configuration was read from. The point is that these are values the platform observed and wrote down, not values the build handed it.
- How is this different from a build step simply doing something the definition allows, such as running a test suite?A test suite executing arbitrary code is expected and sits inside what the record already says will happen: run this entry point at this revision. The failure is when the executed definition itself changes, because the statement quietly stops describing the process it names. One is scope; the other is a false record.
saying these in an interview costs you the question
- Says provenance records whatever the build writes about itself
- Thinks any dynamic pipeline is fine if the generator is in git
- Confuses fixing the definition with pinning dependency versions
- Believes signing afterwards repairs a mutated definition
- Answers 'our pipeline does not do that' to a platform requirement