Skip to content

Guardrails / Collectors

Build provenance attestations ​

What the build attested about the artifacts it produced, read from the in-toto statements it already wrote (bare or inside a DSSE envelope) and recorded exactly as each document states it. Nothing here verifies a signature.

Facts keyprovenance
Versionv1
Scriptprovenance.py
Timeout60 seconds

Inputs ​

InputDescriptionDefaultEnvironment
reportsComma separated globs matched against every file in the working directory and against bare file names, naming the attestations to read.*.intoto.jsonl,*.att.json,attestation*.json,provenance*.json,*.dsse.jsonGUARDRAIL_INPUT_REPORTS

When a guardrail declares an input with the same name, it passes its value through. That means you set these values in the guardrail's configuration in buildnote.json.

A guardrail asks for these facts by name and reads them back by the same name:

json
{
  "collect": ["provenance"]
}
python
provenance = guardrail.facts("provenance")

Facts ​

These are the fields of the document provenance collects. In a path, [] means each entry of the list before it, and [path] means a key of the object before it.

FactMeaning
sourcereport when an attestation was read, none when there was none.
reasonWhy nothing was read, present only when source is none.
reportsEvery file that was read, in path order. One file can carry several attestations.
reports[].pathPath of the file, relative to the directory the CLI runs in.
reports[].modifiedWhen it was last written, ISO 8601, so an attestation older than the build is recognisable.
reports[].formatFormat it was read as, always intoto.
counts.totalAttestations across every file that was read.
counts.signedAttestations that arrived inside a DSSE envelope. The envelope is recorded, never verified, so this counts attestations carrying a signature rather than attestations whose signature was checked.
attestationsThe attestations themselves.
attestations[].predicateTypeWhat the statement claims to be, such as https://slsa.dev/provenance/v1, or null when it names none.
attestations[].builderIdentity the statement gives the builder that produced the subjects, or null when it names none.
attestations[].sourceUriSource the statement says was built, or null when it names none.
attestations[].sourceDigestDigest of that source, or null when the statement carries none.
attestations[].subjectsThe artifacts the statement is about.
attestations[].subjects[].nameName the statement gives the artifact, empty when it gives none.
attestations[].subjects[].digestDigest of the artifact, by algorithm, as the statement carries it.
attestations[].envelopetrue when the statement arrived inside a DSSE envelope, false when it arrived bare.

If a collector can't finish, it prints what it gathered so far along with an incomplete key that says why. Facts after the point where it stopped are missing, so a check that depends on them should read incomplete first.

Example facts ​

Here are the facts the provenance collector gathers from an example project:

json
{
  "source": "report",
  "reports": [
    {
      "path": "provenance.json",
      "modified": "2026-03-04T10:15:00Z",
      "format": "intoto"
    }
  ],
  "counts": {
    "total": 1,
    "signed": 0
  },
  "attestations": [
    {
      "predicateType": "https://slsa.dev/provenance/v1",
      "subjects": [
        {
          "name": "widget-1.4.0.jar",
          "digest": {
            "sha256": "3f786850e387550fdab836ed7e6dc881de23001b5b6e9f0b1ad1a4f0e0d0a1c2"
          }
        }
      ],
      "builder": "https://github.com/actions/runner/github-hosted",
      "sourceUri": "git+https://github.com/company/widget@refs/tags/v1.4.0",
      "sourceDigest": "9b2c1d4e6f8a0b3c5d7e9f1a2b4c6d8e0f1a2b3c",
      "envelope": false
    }
  ]
}

All collectors

Buildnote Limited
Registered in England and Wales, Reg: 16140412