In-Toto Attestations Reference [2026 Build Cheat Sheet]
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-totoGenerate 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.
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
| Shortcut | Action | Why it helps |
|---|---|---|
/ | Focus search | Jump straight to the live command filter. |
Esc | Clear filter | Reset the full reference without touching the mouse. |
j | Next section | Fast scan through long command groups. |
k | Previous section | Backtrack without losing context. |
g g | Top of page | Useful when the sticky ToC is long. |
c | Copy active code block | Works 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, andsublayout.
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, andin-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.
Frequently Asked Questions
What is the difference between an in-toto layout and an in-toto attestation? +
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? +
Does in-toto fail verification if the executed command differs from expected_command? +
How do thresholds work in a multi-stage pipeline? +
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? +
--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.
Related Deep-Dives
Supply Chain Security: Automating SBOMs & Signed Attestations
A practical walkthrough for generating signed attestations and SBOMs in a modern CI pipeline.
Security Deep-Dive[Deep Dive] Automated Supply Chain Security: SLSA Level 4 in 2026
A higher-level architectural guide to hardened build systems, provenance, and enterprise supply-chain controls.
Developer ReferenceDevSecOps Reference [2026]: Agentic Pipeline Rules
A broad reference for enforcing trust, identity, and policy across automated delivery systems.