skip to content

In a SLSA v1 provenance predicate, what do buildDefinition and runDetails each describe?

level: juniorimportance: should knowfreq 50%

answer

  1. two halves: the order and the receipt
  2. one describes the request, one the execution
  3. buildType plus the inputs it was given
  4. builder.id, timestamps, extra outputs
  5. only three fields are required overall

basics

~20 s

buildDefinition describes what was requested: the recipe type and the inputs it was given. runDetails describes what actually happened: which builder ran the job, when, and what else the run emitted. One is the order, the other is the receipt.

solid answer

~40 s

A SLSA v1 provenance predicate has exactly two top-level halves. `buildDefinition` is the request: a `buildType` URI naming the kind of build, `externalParameters` holding the inputs whoever triggered the build supplied, an optional `internalParameters` holding settings the platform itself applied, and an optional `resolvedDependencies` listing artifacts the build consumed. `runDetails` is the record of the execution: `builder.id`, a URI naming the build platform that ran it, optional `metadata` with an invocation id and start/finish timestamps, and optional `byproducts` such as logs. Only three fields are required across both halves: `buildType`, `externalParameters`, and `builder.id`. Read together they say "this recipe, with these inputs, was executed by this platform at this time" — which is what provenance means.

go deeper

for a junior

Be ready to name the two halves and one field from each without hesitating: buildDefinition holds buildType and externalParameters, runDetails holds builder.id. Knowing that the split is request versus execution is most of the answer.

for a middle

Expect to walk every field and say which are required and which optional, and to explain why the timestamps and invocation id sit on the run side rather than the definition side.

for a senior

Show that you read a real provenance document in a fixed order and know which fields you would compare against an expectation versus which you would only use for correlation during an incident.

for a principal

Own the framing that the predicate answers how an artifact was made and deliberately answers nothing about what is inside it or whether it is safe, so your assurance story needs other documents beside it.

## The shape Provenance is a claim about **how an artifact came to be**. In SLSA v1 that claim is carried by a predicate with two top-level members and nothing else: ``` buildDefinition buildType (required) URI naming the kind of build externalParameters (required) the caller's inputs internalParameters (optional) the platform's own settings resolvedDependencies (optional) artifacts the build consumed runDetails builder.id (required) URI naming the build platform metadata (optional) invocationId, startedOn, finishedOn byproducts (optional) extra outputs such as logs ``` The split is not cosmetic. `buildDefinition` is meant to be **reproducible input**: in principle, the same `buildType` plus the same parameters plus the same resolved dependencies should describe the same build again. `runDetails` is **observational**: it records one particular execution and could never be reproduced, because a second run has a different invocation id and different timestamps. ## buildDefinition, field by field **`buildType`** is a URI, and it is the schema for everything beside it. It does not point at your source; it points at a document that says which parameters this kind of build accepts and what each one does. Two different platforms can implement the same `buildType`, and one platform can offer many. Without knowing the `buildType`, the other fields are just JSON with plausible names. **`externalParameters`** holds the inputs supplied by whoever asked for the build — typically things like the source repository, the ref or revision, a path to a build config, a version string. This is the security-interesting half, because anything a person who can trigger a build may choose lands here. **`internalParameters`** holds configuration the build platform applied itself, which the requester did not choose — a runner image, a default toolchain version. It is optional and frequently omitted; when it is present it is mostly for completeness and debugging, since a consumer who trusts the platform is implicitly trusting these values anyway. **`resolvedDependencies`** is an unordered collection of artifacts the build needed — a base image, a fetched tarball, a toolchain — each described with a URI and/or a digest. The spec is explicit that this collection **may be incomplete**, so its absence or emptiness means "not stated", never "there were none". ## runDetails, field by field **`builder.id`** is the trust anchor. It is a URI naming the build platform whose security properties you are relying on when you accept the artifact. A verifier's job is to match it against an expected value — and, crucially, to confirm that whoever signed the statement is authorized to speak for that identifier. A `builder.id` that the build's own steps could write is a self-assertion and proves nothing. **`metadata`** carries `invocationId` (a handle back to the specific run and its logs), `startedOn` and `finishedOn`. These are useful for correlation and incident work, and, like `builder.id`, they only mean anything if the platform stamped them rather than the job. **`byproducts`** collects other outputs of the run that are not the artifact being attested — logs, reports, intermediate files. Note the direction: `resolvedDependencies` is what went **in**, `byproducts` is what came **out** besides the artifact. ## What the predicate is not Three confusions are worth naming up front. The predicate is not an inventory of what is **inside** the artifact — that is a component list, a different kind of document, and `resolvedDependencies` only approximates it (a compiler appears in the build but not in the binary). The predicate is not self-protecting: the JSON is a payload wrapped and signed separately, so an unsigned predicate is a text file anyone can write. And the predicate says nothing about **quality** — no field reports a vulnerability, a test result, or a license. Provenance tells you the route the artifact travelled; judging what arrived is a separate exercise. ## Reading one in an interview Handed a provenance document, a strong candidate narrates it in this order: what kind of build is this (`buildType`), who asked for what (`externalParameters`), who ran it (`builder.id`), and does any of that match what I expected? A weak one starts reading digests without asking what recipe produced them.

  • Which fields in the predicate are actually required?
    Three: `buildType` and `externalParameters` inside `buildDefinition`, and `builder.id` inside `runDetails`. Everything else — `internalParameters`, `resolvedDependencies`, `metadata`, `byproducts` — is optional. That matters when you write verification expectations: you cannot demand a field the format does not guarantee will be there, so you must decide in advance what a missing optional field means for your decision.
  • Where would a build log or a coverage report be recorded?
    In `runDetails.byproducts`, which is the collection for additional outputs of the run that are not the artifact being attested. It is easy to confuse with `resolvedDependencies`, but the direction is opposite: `resolvedDependencies` names things the build consumed, `byproducts` names things it produced alongside the artifact. `metadata.invocationId` is the other route to the logs, since it identifies the specific run.
  • Why are the timestamps in runDetails rather than in buildDefinition?
    Because `buildDefinition` is meant to describe an input that could in principle be repeated, while timestamps and the invocation id are facts about one specific execution that a second run could never match. Keeping them apart lets a consumer compare two builds' definitions for equality without the observational noise defeating the comparison.

buildDefinition is the purchase order; runDetails is the packing slip that says which warehouse shipped it and when.

saying these in an interview costs you the question

  • Says buildDefinition lists the components inside the artifact
  • Puts the source repository in runDetails
  • Assumes every field in the predicate is required
  • Treats the predicate as protected without a separate signature
  • Confuses byproducts (outputs) with resolvedDependencies (inputs)

context