Sigstore Interop — in-toto/DSSE Output (REQ-030)¶
Diogenes attestations can be emitted as in-toto Statements wrapped in
DSSE envelopes verifiable by cosign verify-attestation and any
in-toto-compatible tooling, with no Diogenes-specific verifier required.
This page documents:
- The supported predicate types
- The SDK and CLI surfaces
- The
cosign verify-attestationreference workflow - The round-trip guarantee and the
_diogenes_extensionsfield - The Diogenes Key Registry vs. Fulcio cert chain trade-off
Supported predicate types¶
Five predicate types are first-class on output:
| Predicate type URL | Spec |
|---|---|
https://slsa.dev/provenance/v1 |
https://slsa.dev/spec/v1.0/provenance |
https://in-toto.io/attestation/release/v0.1 |
in-toto/attestation spec/predicates/release.md |
https://in-toto.io/attestation/test-result/v0.1 |
in-toto/attestation spec/predicates/test-result.md |
https://in-toto.io/attestation/vulns/v0.2 |
in-toto/attestation spec/predicates/vuln.md |
https://trustdiogenes.com/attestation/v1 |
Diogenes-native passthrough |
Unknown predicate types are rejected at diogenes sign and
DiogenesSDK.sign time with a clear error listing the supported set.
SDK¶
from diogenes.sdk import DiogenesSDK, generate_key_pair
sdk = DiogenesSDK(transparency_log=log)
private_key, _ = generate_key_pair()
result = sdk.sign(
content=b"...artifact bytes...",
private_key=private_key,
output_format="in-toto-dsse",
predicate_type="https://slsa.dev/provenance/v1",
predicate={"buildDefinition": {...}, "runDetails": {...}},
subject_name="myapp.tar.gz",
)
# result is a SignedAttestationBundle:
result.manifest # Diogenes Manifest (with native attestation in .attestations)
result.attestation # Native Diogenes Attestation
result.bundle # DSSE envelope as a dict
result.bundle_json # DSSE envelope JSON string
result.statement_bytes # JCS-canonical in-toto Statement bytes
result.signer_fingerprint # Diogenes Key Registry fingerprint
The default output_format="native" returns the historical
(manifest, attestation) 2-tuple unchanged.
CLI¶
diogenes sign \
--subject ./myapp.tar.gz \
--predicate-type https://slsa.dev/provenance/v1 \
--predicate ./provenance.json \
--format in-toto-dsse \
--output ./myapp.intoto.jsonl \
--key-file ./signer.pem
The output file is a single-line DSSE envelope. The subject SHA-256
digest is computed from the artifact at --subject. The predicate body
in --predicate (a JSON file with an object at the top level) is
emitted as the typed in-toto predicate body alongside the
_diogenes_extensions envelope.
If --predicate is omitted, the typed predicate body is empty (the
extension envelope alone carries the Diogenes-side data).
Reference verification with cosign¶
The Diogenes Phase-3 verification workflow uses cosign with two flags that disable the Sigstore-specific transparency log lookup and Fulcio chain validation, since Diogenes signs with long-lived keys. The canonical invocation pattern is:
A concrete example:
cosign verify-attestation \
--insecure-ignore-tlog \
--certificate diogenes-signer.cert.pem \
--type slsaprovenance \
myapp.tar.gz
--insecure-ignore-tlog— Diogenes does not register attestations in Rekor (the public Sigstore transparency log) by default. The Diogenes log is a separate transparency layer; cosign cannot consult it. Skipping the Rekor lookup is the documented Phase-3 behavior. (Dual-log witnessing — REQ-031 — adds optional Rekor co-anchoring.)--certificate diogenes-signer.cert.pem— the Diogenes Key Registry certificate for the signing key. This replaces the implicit Fulcio chain validation with explicit caller-supplied trust.
The certificate file is a PEM that holds the signer's public key. Diogenes does not mint short-lived Fulcio-style certificates; the signer key is a long-lived registered key in the Diogenes Key Registry.
Long-term goal: cosign or sibling tooling gains native Diogenes-issuer recognition, eliminating the
--insecure-ignore-tlogflag. Tracked under REQ-029-post-GA, not in Phase 3.
Round-trip guarantee¶
Diogenes attestations preserve bitwise identity across a serialize → deserialize round trip through the in-toto-DSSE format, modulo a documented set of non-canonical fields (currently empty — every native field round-trips).
Mechanism: every native :class:Attestation is parked under a
_diogenes_extensions sub-object inside the predicate:
{
"_type": "https://in-toto.io/Statement/v1",
"subject": [{"name": "myapp.tar.gz", "digest": {"sha256": "..."}}],
"predicateType": "https://slsa.dev/provenance/v1",
"predicate": {
"buildDefinition": { ... },
"runDetails": { ... },
"_diogenes_extensions": {
"version": "1",
"attestation": { ...full native Attestation JSON... }
}
}
}
The extension envelope is part of the JCS-canonicalized bytes that the DSSE signature covers, so it cannot be tampered with without breaking verification. Verifiers that do not understand the extension transparently ignore it (cosign verifies the bytes, not the predicate schema).
To recover the native attestation:
from diogenes.interop.sigstore.output import deserialize_from_in_toto_dsse
native = deserialize_from_in_toto_dsse(envelope_json)
# `native` is a fully-populated Attestation pydantic model
deserialize_from_in_toto_dsse raises InTotoDSSEDeserializeError on
non-Diogenes envelopes, on envelopes with a wrong payloadType, on
unknown predicate types, or on malformed extension envelopes.
DSSE conformance¶
The DSSE envelope follows the DSSE v1 spec exactly:
{
"payloadType": "application/vnd.in-toto+json",
"payload": "<base64(canonical-statement-bytes)>",
"signatures": [
{"keyid": "<diogenes-fingerprint>", "sig": "<base64(signature)>"}
]
}
The bytes signed are the DSSE Pre-Authentication Encoding (PAE) of the canonical Statement bytes:
The Statement is canonicalized via RFC 8785 (JCS) prior to signing, so the signed bytes are deterministic across implementations.
Trust-model preservation¶
Diogenes remains long-lived-key. The DSSE envelope is signed by the same long-lived Diogenes key as the native attestation. The certificate chain in the verification flow references the Diogenes Key Registry, not Fulcio. Sigstore is additive to rather than competitive with Diogenes; this output format makes Diogenes attestations consumable by the existing OSS supply-chain ecosystem without changing the Diogenes trust model.
See also¶
- User-facing guide — publisher-oriented walk-through of the
diogenes export-dsseCLI and the manifest-level workflow (issue #308) design/phase3/requirements.md— REQ-030 / SI-02 source specdesign/sigstore-interop-prd.md— Phase-3 PRDtasks/in-toto-dsse-output/— implementation nano-spectasks/dsse-intoto-export-adapter/— manifest-level export nano-spec (#308)tests/features/233-in-toto-dsse-output.feature— BDD scenarios (per-attestation)tests/features/308-dsse-export-round-trips-via-cosign.feature— BDD scenarios (manifest-level + real cosign)