# Export Attestation Prep — PREP-EXPORT-ATTEST-74-001 Status: **Ready for implementation** (2025-11-20) Owners: Attestation Bundle Guild · Exporter Service Guild Scope: Produce deterministic attestation export bundles for air-gap/offline delivery, leveraging EvidenceLocker DSSE layout and orchestrator events. ## Dependencies - EvidenceLocker packaging & DSSE conventions: `docs/modules/evidence-locker/bundle-packaging.md`. - Attestor air-gap guidance: `docs/modules/attestor/airgap.md` (statement + predicate expectations). - Orchestrator event envelopes (Wave 150/140) for optional timeline/notification mirrors; not required to start packaging. ## Export bundle contract (v1) - **Input**: attestation record id (`attestationId`) referencing a sealed DSSE statement (e.g., in-toto) stored by EvidenceLocker/Attestor. - **Packaging**: create deterministic gzip/tar `export-attestation-bundle-v1.tgz` with fixed mtime `2025-01-01T00:00:00Z`, PAX headers, `0644` perms, owner/group `0`. ``` export-attestation-bundle-v1.tgz ├── attestation.dsse.json # Original DSSE envelope (statement + signature), unchanged ├── statement.json # Extracted statement/predicate for quick inspection ├── transparency.ndjson # Optional Rekor/CT entries (one per line, canonical JSON) ├── metadata.json # exportId, attestationId, subject digests, rootHash, createdAtUtc, sourceUri ├── checksums.txt # SHA256 hashes (lexical order); first line `root ` └── verify-attestation.sh # POSIX script: checksum, DSSE verify (invokes `stella attest verify` if available) ``` - No re-signing; DSSE envelope is copied bit-for-bit from source. - `transparency.ndjson` omitted when no log entries exist; maintain deterministic ordering otherwise. ## API surface (ExportCenter) - `POST /v1/exports/attestations/{attestationId}` → `202 Accepted` with `exportId`, `status=pending`. - `GET /v1/exports/attestations/{exportId}` → status + metadata (`rootHash`, `downloadUri`, `attestationDigests`). - `GET /v1/exports/attestations/{exportId}/download` → `application/gzip`, filename `export-attestation-bundle-v1.tgz`, `ETag`=SHA256. - Auth: `export:write` for POST, `export:read` for GET/Download; tenant scoped. ## Determinism & observability - All timestamps captured once at export creation (UTC ISO-8601) and reused; archive mtimes/gzip mtime pinned. - Structured log on completion `{exportId, attestationId, subjectDigests, rootHash}`; counter `export.attest.completed` and histogram `export.attest.duration_ms`. - Retries for fetch/pack errors use exponential backoff identical to 57-001 portable export. ## Acceptance criteria - Export archive is byte-identical across replays for the same (`attestationId`,`exportId`). - DSSE envelope and statement are unchanged relative to source; hashes in `checksums.txt` match download and DSSE payload. - API responses document 202/404/409/500 paths; `downloadUri` returns sealed artifact with deterministic ETag. - Verification script runs offline using only `tar` + `sha256sum`/`shasum`; optionally calls `stella attest verify` when present. ## Open items / risks - Notification/timeline emission pending envelope schema; add once Wave 150/140 lands. - If attestation format changes (predicate versions), bump `statementVersion` in `metadata.json` and announce. ## Handoff - Implement in `StellaOps.ExportCenter.Worker` export job + WebService endpoints above. - Link this document from Sprint 0162 entry P6 and close PREP when endpoints + packaging align.