10 KiB
10 KiB
Evidence Bundle Export Format Specification
Version: 1.0.0
Status: FINAL
Sprint Reference: SPRINT_20260106_003_003
Overview
This document specifies the standard export format for StellaOps evidence bundles. The export format enables offline verification of software supply chain artifacts including SBOMs, VEX statements, attestations, and policy verdicts.
Export Archive Format
Filename Convention
evidence-bundle-<bundle-id>.tar.gz
Where <bundle-id> follows the pattern: eb-<YYYY-MM-DD>-<unique-suffix>
Example: evidence-bundle-eb-2026-01-06-abc123.tar.gz
Compression
- Format: gzip-compressed tar archive
- Compression level: Configurable (1-9, default: 6)
- Determinism: Fixed gzip header timestamp (
2026-01-01T00:00:00Z) - Permissions: All files
0644, directories0755, uid/gid0:0
Directory Structure
evidence-bundle-<id>/
├── manifest.json # Bundle manifest with all artifact refs
├── metadata.json # Bundle metadata (provenance, timestamps)
├── README.md # Human-readable verification instructions
├── verify.sh # Bash verification script (POSIX-compliant)
├── verify.ps1 # PowerShell verification script
├── checksums.sha256 # BSD-format SHA256 checksums
├── keys/
│ ├── signing-key-001.pem # Public key(s) for DSSE verification
│ ├── signing-key-002.pem # Additional keys (multi-signature)
│ └── trust-bundle.pem # CA chain (if applicable)
├── sboms/
│ ├── image.cdx.json # Aggregated CycloneDX SBOM
│ ├── image.spdx.json # Aggregated SPDX SBOM
│ └── layers/
│ ├── <layer-digest>.cdx.json # Per-layer CycloneDX
│ └── <layer-digest>.spdx.json # Per-layer SPDX
├── vex/
│ ├── statements/
│ │ └── <statement-id>.openvex.json
│ └── consensus/
│ └── image-consensus.json # VEX consensus result
├── attestations/
│ ├── sbom.dsse.json # SBOM attestation envelope
│ ├── vex.dsse.json # VEX attestation envelope
│ ├── policy.dsse.json # Policy verdict attestation
│ └── rekor-proofs/
│ └── <uuid>.proof.json # Rekor inclusion proofs
├── findings/
│ ├── scan-results.json # Vulnerability findings
│ └── gate-results.json # VEX gate decisions
└── audit/
└── timeline.ndjson # Audit event timeline
Core Artifacts
manifest.json
The manifest provides a complete inventory of all artifacts in the bundle.
{
"manifestVersion": "1.0.0",
"bundleId": "eb-2026-01-06-abc123",
"createdAt": "2026-01-06T10:30:00.000000Z",
"subject": {
"type": "container-image",
"digest": "sha256:abcdef1234567890...",
"name": "registry.example.com/app:v1.2.3"
},
"artifacts": [
{
"path": "sboms/image.cdx.json",
"type": "sbom",
"format": "cyclonedx-1.7",
"digest": "sha256:...",
"size": 45678
},
{
"path": "attestations/sbom.dsse.json",
"type": "attestation",
"format": "dsse-v1",
"predicateType": "StellaOps.SBOMAttestation@1",
"digest": "sha256:...",
"size": 12345,
"signedBy": ["sha256:keyabc..."]
}
],
"verification": {
"merkleRoot": "sha256:...",
"algorithm": "sha256",
"checksumFile": "checksums.sha256"
}
}
metadata.json
Provides provenance and chain information.
{
"bundleId": "eb-2026-01-06-abc123",
"exportedAt": "2026-01-06T10:35:00.000000Z",
"exportedBy": "stella evidence export",
"exportVersion": "2026.04",
"provenance": {
"tenantId": "tenant-xyz",
"scanId": "scan-abc123",
"pipelineId": "pipeline-def456",
"sourceRepository": "https://github.com/example/app",
"sourceCommit": "abc123def456..."
},
"chainInfo": {
"previousBundleId": "eb-2026-01-05-xyz789",
"sequenceNumber": 42
},
"transparency": {
"rekorLogUrl": "https://rekor.sigstore.dev",
"rekorEntryUuids": ["uuid1", "uuid2"]
}
}
checksums.sha256
BSD-format SHA256 checksums for all artifacts:
SHA256 (manifest.json) = abc123...
SHA256 (metadata.json) = def456...
SHA256 (sboms/image.cdx.json) = 789abc...
SHA256 (attestations/sbom.dsse.json) = cde012...
Verification Scripts
verify.sh (Bash)
POSIX-compliant bash script for Unix/Linux/macOS verification:
#!/bin/bash
set -euo pipefail
BUNDLE_DIR="$(cd "$(dirname "$0")" && pwd)"
MANIFEST="$BUNDLE_DIR/manifest.json"
CHECKSUMS="$BUNDLE_DIR/checksums.sha256"
echo "=== StellaOps Evidence Bundle Verification ==="
echo "Bundle: $(basename "$BUNDLE_DIR")"
echo ""
# Step 1: Verify checksums
echo "[1/4] Verifying artifact checksums..."
cd "$BUNDLE_DIR"
sha256sum -c "$CHECKSUMS" --quiet
echo " OK: All checksums match"
# Step 2: Verify Merkle root
echo "[2/4] Verifying Merkle root..."
COMPUTED_ROOT=$(compute-merkle-root "$CHECKSUMS")
EXPECTED_ROOT=$(jq -r '.verification.merkleRoot' "$MANIFEST")
if [ "$COMPUTED_ROOT" = "$EXPECTED_ROOT" ]; then
echo " OK: Merkle root verified"
else
echo " FAIL: Merkle root mismatch"
exit 1
fi
# Step 3: Verify DSSE signatures
echo "[3/4] Verifying attestation signatures..."
for dsse in "$BUNDLE_DIR"/attestations/*.dsse.json; do
verify-dsse "$dsse" --keys "$BUNDLE_DIR/keys/"
echo " OK: $(basename "$dsse")"
done
# Step 4: Verify Rekor proofs (if online)
echo "[4/4] Verifying Rekor proofs..."
if [ "${OFFLINE:-false}" = "true" ]; then
echo " SKIP: Offline mode, Rekor verification skipped"
else
for proof in "$BUNDLE_DIR"/attestations/rekor-proofs/*.proof.json; do
verify-rekor-proof "$proof"
echo " OK: $(basename "$proof")"
done
fi
echo ""
echo "=== Verification Complete: PASSED ==="
verify.ps1 (PowerShell)
Windows PowerShell verification script:
#Requires -Version 5.1
$ErrorActionPreference = 'Stop'
$BundleDir = Split-Path -Parent $MyInvocation.MyCommand.Path
$Manifest = Join-Path $BundleDir 'manifest.json'
$Checksums = Join-Path $BundleDir 'checksums.sha256'
Write-Host "=== StellaOps Evidence Bundle Verification ===" -ForegroundColor Cyan
Write-Host "Bundle: $(Split-Path -Leaf $BundleDir)"
Write-Host ""
# Step 1: Verify checksums
Write-Host "[1/4] Verifying artifact checksums..." -ForegroundColor Yellow
Push-Location $BundleDir
try {
Get-Content $Checksums | ForEach-Object {
if ($_ -match 'SHA256 \((.+)\) = (.+)') {
$File = $Matches[1]
$Expected = $Matches[2]
$Actual = (Get-FileHash -Path $File -Algorithm SHA256).Hash.ToLower()
if ($Actual -ne $Expected) {
throw "Checksum mismatch: $File"
}
}
}
Write-Host " OK: All checksums match" -ForegroundColor Green
} finally {
Pop-Location
}
# Step 2-4: Continue verification...
Write-Host ""
Write-Host "=== Verification Complete: PASSED ===" -ForegroundColor Green
Determinism Requirements
Timestamp Handling
- All timestamps MUST be UTC ISO-8601 with microsecond precision
- Format:
YYYY-MM-DDTHH:MM:SS.ffffffZ - Archive metadata timestamps are fixed for reproducibility
Ordering
- Manifest artifacts: sorted lexicographically by
path - Checksum entries: sorted lexicographically by filename
- JSON object keys: sorted lexicographically (RFC 8785)
- NDJSON records: sorted by primary key (e.g.,
observationId)
Hash Computation
- Algorithm: SHA-256 (lowercase hex)
- Input: raw file bytes (no BOM, LF line endings)
- Merkle tree: RFC 6962 compliant binary Merkle tree
Artifact Types
SBOMs
| Format | File Extension | MIME Type |
|---|---|---|
| CycloneDX 1.7 | .cdx.json |
application/vnd.cyclonedx+json |
| SPDX 3.0.1 | .spdx.json |
application/spdx+json |
Attestations
| Type | Predicate Type | File Pattern |
|---|---|---|
| SBOM | StellaOps.SBOMAttestation@1 |
sbom.dsse.json |
| VEX | StellaOps.VEXAttestation@1 |
vex.dsse.json |
| Policy | StellaOps.PolicyEvaluation@1 |
policy.dsse.json |
| Gate | StellaOps.VexGate@1 |
gate.dsse.json |
VEX Statements
- Format: OpenVEX 0.2.0+
- File extension:
.openvex.json - Location:
vex/statements/
Export Options
CLI Command
# Basic export
stella evidence export --bundle <bundle-id> --output ./audit-bundle.tar.gz
# With options
stella evidence export --bundle <bundle-id> \
--output ./bundle.tar.gz \
--include-layers \
--include-rekor-proofs \
--compression 9
# Verify exported bundle
stella evidence verify ./audit-bundle.tar.gz
# Verify offline (skip Rekor)
stella evidence verify ./audit-bundle.tar.gz --offline
API Endpoint
POST /api/v1/bundles/{bundleId}/export
Content-Type: application/json
{
"format": "tar.gz",
"compression": "gzip",
"compressionLevel": 6,
"includeRekorProofs": true,
"includeLayerSboms": true
}
Offline Verification
For air-gapped environments:
- Transfer
evidence-bundle-<id>.tar.gzto isolated system - Extract archive:
tar -xzf evidence-bundle-<id>.tar.gz - Run verification:
./verify.sh(Unix) or.\verify.ps1(Windows) - Pass
OFFLINE=trueto skip Rekor verification:OFFLINE=true ./verify.sh
Compatibility
- StellaOps CLI: 2026.04+
- Export Library: StellaOps.EvidenceLocker.Export 1.0.0+
- Verify scripts: bash 4.0+ / PowerShell 5.1+
Related Documentation
- Bundle Packaging - Internal bundle structure
- Evidence Bundle v1 - Core bundle contract
- Verify Offline - Offline verification procedures
- Attestation Contract - DSSE envelope format
Change Log
| Date | Version | Author | Description |
|---|---|---|---|
| 2026-01-07 | 1.0.0 | StellaOps | Initial specification for Sprint 003_003 |