Home Posts In-Toto Attestations Reference [2026 Build Cheat Sheet]
Developer Reference

In-Toto Attestations Reference [2026 Build Cheat Sheet]

In-Toto Attestations Reference [2026 Build Cheat Sheet]
Dillip Chowdary
Dillip Chowdary
Tech Entrepreneur & Innovator · April 30, 2026 · 9 min read

Bottom Line

Treat the layout as policy and each signed link as evidence. A verifiable multi-stage pipeline only works when artifact rules, authorized functionaries, and threshold checks line up across every step.

Key Takeaways

  • PyPI still lists in-toto 3.0.0 as the current Python reference release on April 30, 2026.
  • A step passes on signed evidence plus artifact rules; expected_command is useful but not your strongest control.
  • Use in-toto-run for one command and in-toto-record for manual or multi-part steps.
  • The Link attestation predicate uses https://in-toto.io/attestation/link/v0.3 with Statement v1 wrappers.

In-toto gives you a way to prove that a build pipeline ran the steps you intended, with the identities you approved, over the artifacts you expected. This reference focuses on the Python reference implementation and the current attestation model as of April 30, 2026: PyPI still shows in-toto 3.0.0, while the separate attestation framework repository lists v1.2.0 as its latest release. Use this as a command-first sheet for multi-stage build verification.

  • Layout is policy; link metadata is evidence.
  • Threshold checks require multiple distinct authorized signers when configured.
  • Artifact rules are what make stage-to-stage chaining tamper-evident.
  • DSSE support exists in the reference implementation, but the CLI still documents it as experimental.

Quick Model

Bottom Line

A secure multi-stage pipeline is not just signed output. It is a signed layout, signed per-step links, and verification that the right people touched the right files in the right order.

What the layout enforces

  • Expiration limits how long a layout stays valid.
  • Functionary keys define who may perform each step.
  • Steps bind names, authorized keys, artifact rules, and optional expected commands.
  • Inspections run during verification and can add final gate checks.
  • Threshold raises assurance by requiring evidence from multiple functionaries.

What verification actually checks

  • The layout is signed by the keys you passed to in-toto-verify.
  • The layout has not expired.
  • Each step has the required threshold of link files.
  • Each link is signed by an authorized functionary.
  • Materials and products satisfy the step's artifact rules.
  • Inspections run sequentially and their rules are processed too.

Core object map

  • Layout: top-level supply-chain policy.
  • Step: one required pipeline activity.
  • Inspection: one verification-time command.
  • Link: signed metadata proving one step execution.
  • Statement: attestation wrapper used by the newer framework.

Commands by Purpose

Install the reference implementation

python -m pip install in-toto

Generate evidence for a single command step

in-toto-run \
  --step-name build \
  --signing-key builder.pem \
  --materials pyproject.toml src/ \
  --products dist/ \
  -- python -m build
  • Use --materials for inputs recorded before execution.
  • Use --products for outputs recorded after execution.
  • Use --record-streams only when the wrapped command is not interactive.
  • Use --run-timeout if the default 10 seconds is too low.

Generate evidence for a manual or multi-part step

in-toto-record start \
  --step-name review \
  --signing-key reviewer.pem \
  --materials docs/

# perform manual edits, review, or multiple commands

in-toto-record stop \
  --step-name review \
  --signing-key reviewer.pem \
  --products docs/
  • start creates .<name>.<keyid-prefix>.link-unfinished.
  • stop records products, updates the signature, and emits <name>.<keyid-prefix>.link.

Verify the full supply chain

in-toto-verify \
  --layout root.layout \
  --verification-keys owner.pub \
  --link-dir .
  • Exit code 0 means verification passed.
  • Exit code 1 means verification failed.
  • Exit code 2 means bad CLI arguments.

Useful helper commands

in-toto-match-products \
  --link build.1234abcd.link \
  --paths dist/

in-toto-sign -f root.layout -k owner.pem -o root.layout
in-toto-sign -f root.layout -k owner.pub --verify
  • in-toto-match-products compares local artifacts with a link's recorded products.
  • in-toto-sign is useful for re-signing or verifying individual layout or link files.
  • For layout threshold signing, in-toto-sign --append adds signatures instead of replacing them.

Layout Configuration

Minimal Python layout for a two-stage pipeline

from securesystemslib.signer import CryptoSigner
from in_toto.models.layout import Inspection, Layout, Step
from in_toto.models.metadata import Metablock

owner = CryptoSigner.generate_ed25519()
builder = CryptoSigner.generate_ed25519()

def pubkey_dict(signer):
    data = signer.public_key.to_dict()
    data["keyid"] = signer.public_key.keyid
    return data

layout = Layout()
layout.add_functionary_key(pubkey_dict(builder))
layout.set_relative_expiration(months=4)

build = Step(name="build")
build.pubkeys = [builder.public_key.keyid]
build.threshold = 1
build.set_expected_command_from_string("python -m build")
build.add_material_rule_from_string("ALLOW pyproject.toml")
build.add_material_rule_from_string("ALLOW src/*")
build.add_material_rule_from_string("DISALLOW *")
build.add_product_rule_from_string("CREATE dist/*")
build.add_product_rule_from_string("DISALLOW *")

inspect_dist = Inspection(name="check-dist")
inspect_dist.set_run_from_string("test -d dist")
inspect_dist.add_material_rule_from_string("MATCH dist/* WITH PRODUCTS FROM build")

layout.steps = [build]
layout.inspect = [inspect_dist]

root = Metablock(signed=layout)
root.create_signature(owner)
root.dump("root.layout")

Artifact rule patterns worth memorizing

  • CREATE: file must be newly created in this step.
  • DELETE: file must be removed in this step.
  • MODIFY: file must exist and change in this step.
  • ALLOW: file is permitted in the step scope.
  • DISALLOW: file is forbidden in the step scope.
  • REQUIRE: a specific file must exist.
  • MATCH: bind artifacts to materials or products from another step.
Watch out: The reference example notes that expected_command divergence generally warns rather than fails verification. Treat artifact rules, signer authorization, and thresholds as the hard controls.

Path handling and exclusions

in-toto-run \
  --step-name package \
  --signing-key builder.pem \
  --materials /workspace/src \
  --products /workspace/dist \
  --base-path /workspace \
  --lstrip-paths /workspace \
  --exclude '**/.git' '**/__pycache__' \
  -- tar czf dist/app.tar.gz src
  • --base-path changes how relative artifact paths are located.
  • --lstrip-paths keeps recorded paths stable and portable.
  • --exclude uses gitignore-style patterns via pathspec.
  • End most step rule sets with DISALLOW * unless you explicitly want extra files to remain valid.

Live Filter and Shortcuts

Client-side search filter for a long reference page

<input id='cmd-filter' type='search' placeholder='Filter commands: verify, dsse, threshold...' />
<div id='cmd-groups'>
  <section data-tags='run build evidence materials products'>...</section>
  <section data-tags='record manual review multipart'>...</section>
  <section data-tags='verify layout threshold inspections'>...</section>
</div>

<script>
const input = document.getElementById('cmd-filter');
const groups = [...document.querySelectorAll('#cmd-groups [data-tags]')];

function applyFilter() {
  const q = input.value.trim().toLowerCase();
  for (const el of groups) {
    const haystack = `${el.dataset.tags} ${el.textContent}`.toLowerCase();
    el.hidden = Boolean(q) && !haystack.includes(q);
  }
}

input.addEventListener('input', applyFilter);

document.addEventListener('keydown', (e) => {
  if (e.key === '/' && document.activeElement !== input) {
    e.preventDefault();
    input.focus();
  }
  if (e.key === 'Escape') {
    input.value = '';
    applyFilter();
    input.blur();
  }
});
</script>

Keyboard shortcuts table

ShortcutActionWhy it helps
/Focus searchJump straight to the live command filter.
EscClear filterReset the full reference without touching the mouse.
jNext sectionFast scan through long command groups.
kPrevious sectionBacktrack without losing context.
g gTop of pageUseful when the sticky ToC is long.
cCopy active code blockWorks well with automatic copy buttons on <pre> blocks.

How to group commands for scanning

  • Put evidence generation commands first: in-toto-run, in-toto-record.
  • Put verification next: in-toto-verify, in-toto-match-products.
  • Put maintenance last: in-toto-sign, in-toto-mock.
  • Add searchable tags like threshold, dsse, gpg, inspection, and sublayout.

Advanced Usage

Thresholds and sublayouts

  • A step's threshold is the minimum number of distinct authorized functionaries required to provide evidence.
  • If the layout uses sublayouts, verification recurses into a directory named <step name>.<keyid prefix>.
  • Sublayout metadata must sit alongside the links for the superlayout step.

DSSE and attestation mapping

{
  "_type": "https://in-toto.io/Statement/v1",
  "subject": [
    {
      "name": "dist/app.tar.gz",
      "digest": { "sha256": "..." }
    }
  ],
  "predicateType": "https://in-toto.io/attestation/link/v0.3",
  "predicate": {
    "name": "build",
    "command": ["python", "-m", "build"],
    "materials": [
      {
        "name": "pyproject.toml",
        "digest": { "sha256": "..." }
      }
    ],
    "byproducts": {},
    "environment": {}
  }
}
  • subject corresponds to products of the step.
  • predicate.materials captures inputs as resource descriptors.
  • The reference CLI exposes --use-dsse for in-toto-run, in-toto-record, and in-toto-mock, but the docs still label it experimental.
  • For general provenance, a more specific predicate such as SLSA Provenance may fit better than the generic Link predicate.

Operational hygiene

  • Do not rely on external key metadata during verification; the reference verifier explicitly operates in isolation from outside key state.
  • If you capture stdout or stderr in byproducts, redact secrets before sharing logs or examples. TechBytes' Data Masking Tool is a clean way to sanitize CI output before review.
  • If you need a quick unsigned dry run for demos or layout prototyping, in-toto-mock creates a basic link you can inspect and later sign.
Pro tip: Normalize your step names early. Stable names make link discovery, sublayout organization, and policy code much easier to automate across multiple repositories.

Frequently Asked Questions

What is the difference between an in-toto layout and an in-toto attestation? +
A layout is the policy document that defines what your supply chain must do: steps, authorized keys, artifact rules, inspections, and expiration. An attestation or link is the signed evidence for one executed step. In the newer attestation framework, that evidence is commonly wrapped in a Statement v1 envelope with a predicate type such as https://in-toto.io/attestation/link/v0.3.
When should I use in-toto-run versus in-toto-record? +
Use in-toto-run when one command cleanly represents the step, such as building, testing, or packaging. Use in-toto-record when the step is manual, spans multiple commands, or includes edits and reviews that cannot be modeled as one wrapped command.
Does in-toto fail verification if the executed command differs from expected_command? +
Not necessarily. The official layout creation example notes that verification will generally warn if the expected command diverges from the command that actually ran. The stronger pass/fail controls are the authorized signatures, threshold requirements, and artifact rules that chain materials and products across steps.
How do thresholds work in a multi-stage pipeline? +
A step's threshold is the minimum number of distinct authorized functionaries that must provide signed evidence for that step. If you set a threshold of 2, one signer is not enough even if the link is otherwise valid. This is useful for dual control on sensitive stages like release or promotion.
Is DSSE ready for production use with in-toto? +
The Python reference implementation exposes --use-dsse, but the CLI documentation still marks DSSE generation as experimental. That does not mean you cannot use it; it means you should validate your full producer-and-consumer toolchain, including storage and verification behavior, before standardizing on it.

Get Engineering Deep-Dives in Your Inbox

Weekly breakdowns of architecture, security, and developer tooling — no fluff.

Found this useful? Share it.