Skip to content

0.2.0 — Paper Moon

Choose a tag to compare

@github-actions github-actions released this 15 Oct 09:43
· 7 commits to main since this release
v0.2.0
edb4077

attest runs your build, hashes every declared input and output, and writes a
receipt that can be signed and verified offline. Anyone holding that receipt
can check its signature and recompute the recorded hashes against a workspace.

Paper Moon makes trust portable: a producer can share signed keys and
revocations with a disconnected verifier. It also makes verification policy
explicit, records which isolation controls were enforced, and separates
producing evidence from signing it.

0.2 reads existing 0.1 receipts without changing the canonical bytes behind
their signatures. Acceptance still depends on the recipient's trust store
and policy.

Install

Take a binary from the assets below: Linux and macOS, x86-64 and arm64,
each tested in CI before it ships. Or install this exact release from its tag:

cargo install --locked \
  --git https://github.com/Alien6-Studio/continuum-attest \
  --tag v0.2.0 continuum-attest

The command is attest; the crate is continuum-attest because attest was
already taken. Building from source needs Rust 1.89 or later. --locked uses
the dependency graph shipped with the release.

Sixty seconds

attest init
attest keys generate --name laptop
attest run --sign
attest verify .attest/receipts/*.yaml --recompute --require signature,recompute

--recompute re-derives the pipeline hash and each step's input and output
hashes from your workspace. --require refuses unless every named property
was established: a skipped check never satisfies a requirement. timestamp,
trust, success and archive linkage can be required too. The JSON result
states the requested policy, unmet requirements, execution outcome and trust
material's freshness.

Trust you can hand over

attest trust bundle --output trust.json --key <issuer>
attest trust show trust.json
attest trust import trust.json --issuer <issuer-key-id>
attest trust refresh trust-2.json

The producer signs a bundle containing public keys, dated revocations, an
issuer, a validity window and a sequence number. The recipient pins the first
issuer through a separate trusted channel; later imports refuse rollback and
unauthorized authority replacement. A departing authority can name its
successor in its own signed bundle.

Revocation can only become stricter: an earlier date wins, and a local
revocation without a date continues to reject every signature. Verification
remains offline. Every verdict says which bundle covers the signer, whether
it is current, expired or not yet valid, and that freshness is judged by the
verifier's local clock.

What is new

  • Explicit verification policy. Receipts, archives and in-toto imports
    use the same requirement names. Image verification requires an explicit
    property; keyless signatures need a pinned certificate identity and OIDC
    issuer, and missing required revision evidence is a failure.
  • Isolation reported control by control. The signed isolation block
    distinguishes enforced controls from unavailable or unenforced ones.
    Process isolation applies configured resource limits; it does not restrict
    network or filesystem access.
  • Frozen capsule inputs. Declared inputs are copied into a verified
    snapshot outside the writable workspace and mounted read-only at their
    top-level directory. Workspace-root inputs (. or empty paths) are
    refused. Local steps get permission-bit protection and a post-run hash
    check; a local change restored before that check can escape detection,
    and the receipt does not claim enforced input immutability for those runs.
  • Separate receipt signing. attest sign signs evidence produced by
    another process. attest run --sign loads the key after the last step,
    and ATTEST_KEYS_DIR lets a producer keep key files outside the workspace.
    Input permissions are changed through verified file descriptors so a
    replaced path cannot redirect cleanup onto another file.
  • Bounded untrusted evidence. Archive limits cover compressed size,
    unpacked size, entry count and entry size; tar extension records are
    refused. Receipts and DSSE envelopes are capped at 16 MiB. Resource
    refusals are distinguished from verification failures in JSON.
  • Release evidence bound to the published files. The release includes
    per-platform build information, a locked source package, an SBOM,
    checksums, signatures, provenance and signed, timestamped receipts.
    The maintained serde_norway parser replaces deprecated serde_yaml
    while preserving existing receipts' signing bytes.

Check this release before you run it

The example uses the Linux x86-64 archive; substitute the matching asset name
for another platform.

shasum -a 256 -c SHA256SUMS

cosign verify-blob \
  --bundle attest-v0.2.0-linux-x86_64.tar.gz.sigstore.json \
  --certificate-identity-regexp '^https://github\.com/Alien6-Studio/continuum-attest/' \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com \
  attest-v0.2.0-linux-x86_64.tar.gz

gh attestation verify attest-v0.2.0-linux-x86_64.tar.gz \
  --repo Alien6-Studio/continuum-attest

The .yaml assets are attest's own receipts: one for its build pipeline,
and one over the published binaries, checksums, build information, SBOM and
source package. A separate signing job installs the key after building its
verifier, then signs and timestamps the receipts. Before publication, the
workflow verifies the receipt and recomputes the artifact-set input manifest;
a difference prevents publication.

What a receipt does not establish

  • Revocation travels only as far as a bundle is carried. An offline
    verifier cannot know about updates it has not imported. Bundle freshness
    uses the local clock; an RFC 3161 timestamp supplies independent evidence
    of signature time when verified against a separately pinned authority.
  • The causal root is anchored, not published. The signature and optional
    timestamp cover it, but no external log records that a receipt existed.
    A withheld receipt can go unnoticed.
  • The signer is a key, not a person.
  • Matching hashes prove consistency with signed claims. They do not prove
    the runner was uncompromised; the isolation block says what was controlled.

ROADMAP.md
says what comes next and in which order.

Apache-2.0.