A universal SLSA evidence engine and verifier — and the release engine that produces the evidence. Both halves in one binary is the point. It derives what a release ships (the version and changelog from conventional commits — it retired git-cliff across its home org — version-mirror bumps, per-artifact SBOMs, VEX), emits the attestable JSON that gets signed, and then verifies that evidence the way a stranger would, fail-closed: the thing that makes a release and the thing that judges it share one set of types, so neither can drift from the other. Standard formats live in code — DSSE, in-toto, SLSA provenance and VSAs, OpenVEX, SPDX — with every organisation-specific convention (signer identities, chain layout, completeness policy, what a release owes) in a committed policy file the tool consumes. monumental-archive is its first conforming consumer, not a hardcoded name.
Four verbs and a judge:
| Command | Owns |
|---|---|
derive |
versions and changelogs from conventional commits, version-mirror bumps, per-artifact SBOMs (SPDX), VEX from triage decisions, OCI image facts, control claims from the forge's live enforcement state |
assert |
evidence against a declaration, over an org or one repo: image facts, evidence-bundle completeness, advisory blast radius against VEX, release tags, chain coverage of the whole population, pre-publish inventory plans against the same obligations the post-publish walk reads, and the caller/callee permissions: join across a workflow tree — exit 0 pass, 1 fail, 4 could-not-judge |
emit |
source-chain links, VSA predicates, the release evidence manifest — the JSON that gets signed |
verify |
every attestation against a pinned signer identity, the published verdict, the source-chain walk, and the reproducibility rebuild's typed verdict |
level |
what a repository's live, publicly fetchable evidence actually supports, per SLSA track — no clone, no policy, no trusted root, no declaration taken |
Workflows orchestrate, the platform signs, stele computes and checks. It holds no key, mints no certificate, and never runs caller code: the capability boundary lives strictly above it.
The tool eats first. Its own releases run entirely through it —
version and notes from derive, evidence from emit, each release
built and attested by the version before it, and the published
result verified by the same walk it asks of everyone else.
Day one is one flag:
stele level --repo you/yoursIt measures and reports; it gates nothing. From there, stele verify
is the verification recipe as an executable: point it at a release
and a policy, and it checks what the documentation says a stranger
can check — fail-closed, byte-for-byte the same data model the
emitter used, because verifier and emitter are one binary sharing one
set of types. Adopting it in a repository with no org behind it is
docs/adoption.md, whose minimal policies the test
suite executes.
stele began as the port of ~8,000 lines of release and audit bash in
its first consumer's org
(.github#392).
The port is complete: all four verbs plus level shipped verb by
verb under one bar — shadow mode against real artifacts before
authority — and every release and evidence-judging audit there now
runs this binary. The formats are pre-v1: correctness wins every tie,
and schemas change to the correct shape without compatibility shims.
The gate, the lint canon (golangci-lint at default: all),
coverage ratchet and hermetic build have been live since the first
commit.
docs/adoption.md is the front door for anyone who
is not us — day one, the delivery layer, the policy floors (executed
by the test suite), the real couplings, what to skip. The rest of
docs/ specifies mechanisms: the
verify policy and
assert policy schemas, the
chain note format, the
report document every judging verb speaks,
how level judges, the
VEX join's identity rules, the
trust anchor stance,
versioning and the
binary SBOM design. stele help carries the
full flag reference.
mise trust && mise install && mise run hooks:install
mise run ciDependencies are pinned by go.sum — byte-identical modules or a
failed build — and fetched through the checksummed proxy, the one
network dependency in the gate. Everything else is a pure function of
this tree and the pinned toolchain: CGO_ENABLED=0,
GOTOOLCHAIN=local, -trimpath, and no committed vendor/ by
deliberate decision.
Apache-2.0. See REUSE.toml — per-file headers are refused by design; the tree-level declaration governs.