new two advisories and sprints work on them
This commit is contained in:
@@ -52,7 +52,7 @@ WebSocket /api/v1/doctor/stream
|
||||
|
||||
## Available Checks
|
||||
|
||||
The Doctor system includes 48+ diagnostic checks across 7 plugins:
|
||||
The Doctor system includes 60+ diagnostic checks across 9 plugins:
|
||||
|
||||
| Plugin | Category | Checks | Description |
|
||||
|--------|----------|--------|-------------|
|
||||
@@ -60,10 +60,32 @@ The Doctor system includes 48+ diagnostic checks across 7 plugins:
|
||||
| `stellaops.doctor.database` | Database | 8 | Connectivity, migrations, schema, connection pool |
|
||||
| `stellaops.doctor.servicegraph` | ServiceGraph | 6 | Gateway, routing, service health |
|
||||
| `stellaops.doctor.security` | Security | 9 | OIDC, LDAP, TLS, Vault |
|
||||
| `stellaops.doctor.attestation` | Security | 4 | Rekor connectivity, Cosign keys, clock skew, offline bundle |
|
||||
| `stellaops.doctor.verification` | Security | 5 | Artifact pull, signatures, SBOM, VEX, policy engine |
|
||||
| `stellaops.doctor.scm.*` | Integration.SCM | 8 | GitHub, GitLab connectivity/auth/permissions |
|
||||
| `stellaops.doctor.registry.*` | Integration.Registry | 6 | Harbor, ECR connectivity/auth/pull |
|
||||
| `stellaops.doctor.observability` | Observability | 4 | OTLP, logs, metrics |
|
||||
|
||||
### Setup Wizard Essential Checks
|
||||
|
||||
The following checks are mandatory for the setup wizard to validate a new installation:
|
||||
|
||||
1. **DB connectivity + schema version** (`stellaops.doctor.database`)
|
||||
- `check.db.connection` - Database is reachable
|
||||
- `check.db.schema.version` - Schema version matches expected
|
||||
|
||||
2. **Attestation store availability** (`stellaops.doctor.attestation`)
|
||||
- `check.attestation.rekor.connectivity` - Rekor transparency log reachable
|
||||
- `check.attestation.cosign.keymaterial` - Signing keys available (file/KMS/keyless)
|
||||
- `check.attestation.clock.skew` - System clock synchronized (<5s skew)
|
||||
|
||||
3. **Artifact verification pipeline** (`stellaops.doctor.verification`)
|
||||
- `check.verification.artifact.pull` - Test artifact accessible by digest
|
||||
- `check.verification.signature` - DSSE signatures verifiable
|
||||
- `check.verification.sbom.validation` - SBOM (CycloneDX/SPDX) valid
|
||||
- `check.verification.vex.validation` - VEX document valid
|
||||
- `check.verification.policy.engine` - Policy evaluation passes
|
||||
|
||||
### Check ID Convention
|
||||
|
||||
```
|
||||
@@ -75,6 +97,8 @@ Examples:
|
||||
- `check.database.migrations.pending`
|
||||
- `check.services.gateway.routing`
|
||||
- `check.integration.scm.github.auth`
|
||||
- `check.attestation.rekor.connectivity`
|
||||
- `check.verification.sbom.validation`
|
||||
|
||||
## CLI Reference
|
||||
|
||||
|
||||
@@ -866,6 +866,119 @@ curl https://rekor.sigstore.dev/api/v1/log/publicKey > fixtures/rekor-pubkey.pem
|
||||
|
||||
---
|
||||
|
||||
## 9A. PERIODIC VERIFICATION (Background Job)
|
||||
|
||||
**Sprint Reference**: `SPRINT_20260117_001_ATTESTOR_periodic_rekor_verification`
|
||||
|
||||
### 9A.1 Overview
|
||||
|
||||
The Periodic Verification system provides continuous validation of previously logged Rekor entries. This addresses the gap where entries are logged but never re-verified, enabling detection of:
|
||||
|
||||
- Signature tampering or key compromise
|
||||
- Merkle tree rollbacks (split-view attacks)
|
||||
- Time skew violations indicating replay attempts
|
||||
- Root consistency drift between stored and remote state
|
||||
|
||||
### 9A.2 Architecture
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────────┐
|
||||
│ Periodic Verification Job │
|
||||
├─────────────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ ┌─────────────────────┐ ┌─────────────────────┐ │
|
||||
│ │ RekorVerification │───►│ IRekorVerification │ │
|
||||
│ │ Job (Scheduler) │ │ Service │ │
|
||||
│ └─────────┬───────────┘ └──────────┬──────────┘ │
|
||||
│ │ │ │
|
||||
│ │ batch query │ verify │
|
||||
│ ▼ ▼ │
|
||||
│ ┌─────────────────────┐ ┌─────────────────────┐ │
|
||||
│ │ IRekorEntry │ │ RekorVerification │ │
|
||||
│ │ Repository │ │ Metrics │ │
|
||||
│ └─────────────────────┘ └──────────┬──────────┘ │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ ┌─────────────────────┐ │
|
||||
│ │ IRekorVerification │ │
|
||||
│ │ StatusProvider │ │
|
||||
│ └─────────────────────┘ │
|
||||
└─────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 9A.3 Configuration
|
||||
|
||||
```yaml
|
||||
attestor:
|
||||
rekor:
|
||||
verification:
|
||||
enabled: true
|
||||
intervalMinutes: 60 # Run every hour
|
||||
batchSize: 100 # Entries per batch
|
||||
sampleRate: 0.1 # 10% sampling for large deployments
|
||||
maxTimeSkewSeconds: 300 # 5 minute tolerance
|
||||
alertOnRootInconsistency: true
|
||||
```
|
||||
|
||||
### 9A.4 Verification Checks
|
||||
|
||||
| Check | Description | Failure Severity |
|
||||
|-------|-------------|------------------|
|
||||
| Signature | Verify entry signature against stored public key | Critical |
|
||||
| Inclusion Proof | RFC 6962 Merkle inclusion proof verification | Critical |
|
||||
| Time Skew | Validate integrated_time within tolerance | Warning |
|
||||
| Root Consistency | Compare stored tree root with remote | Critical |
|
||||
|
||||
### 9A.5 Metrics (OpenTelemetry)
|
||||
|
||||
```
|
||||
# Meter: StellaOps.Attestor.RekorVerification
|
||||
|
||||
attestor.rekor.verification.runs # Counter
|
||||
attestor.rekor.verification.entries.verified # Counter
|
||||
attestor.rekor.verification.entries.failed # Counter
|
||||
attestor.rekor.verification.entries.skipped # Counter
|
||||
attestor.rekor.verification.time_skew_violations # Counter
|
||||
attestor.rekor.verification.signature_failures # Counter
|
||||
attestor.rekor.verification.inclusion_proof_failures # Counter
|
||||
attestor.rekor.verification.root_consistency_checks # Counter
|
||||
attestor.rekor.verification.entry_duration # Histogram
|
||||
attestor.rekor.verification.batch_duration # Histogram
|
||||
```
|
||||
|
||||
### 9A.6 Health Check Integration
|
||||
|
||||
The `RekorVerificationHealthCheck` integrates with the Doctor diagnostic system:
|
||||
|
||||
```
|
||||
Check ID: check.attestation.rekor.verification.job
|
||||
|
||||
Status Levels:
|
||||
- Healthy: Last run within expected window, failure rate < 1%
|
||||
- Degraded: Failure rate 1-5%, or last run overdue
|
||||
- Unhealthy: Failure rate > 5%, root inconsistency detected, or job not running
|
||||
```
|
||||
|
||||
### 9A.7 Alerting
|
||||
|
||||
| Condition | Alert Level | Action |
|
||||
|-----------|-------------|--------|
|
||||
| Root inconsistency | P1 Critical | Immediate investigation required |
|
||||
| Signature failure rate > 5% | P2 High | Review key material |
|
||||
| Job not running > 3x interval | P3 Medium | Check scheduler |
|
||||
| Time skew violations > 10% | P3 Medium | Check NTP sync |
|
||||
|
||||
### 9A.8 Offline Verification
|
||||
|
||||
When network access to Rekor is unavailable, the system falls back to stored inclusion proofs:
|
||||
|
||||
1. Read stored `inclusion_proof` from database
|
||||
2. Verify Merkle path locally against stored root
|
||||
3. Log verification as "offline" mode
|
||||
4. Schedule online re-verification when connectivity returns
|
||||
|
||||
---
|
||||
|
||||
## 10. MIGRATION GUIDE
|
||||
|
||||
### 10.1 Database Migrations
|
||||
|
||||
@@ -589,7 +589,120 @@ Pre-computed test cases with known results:
|
||||
|
||||
---
|
||||
|
||||
## 15. References
|
||||
## 15. Delta-Sig Predicate Attestation
|
||||
|
||||
**Sprint Reference**: `SPRINT_20260117_003_BINDEX_delta_sig_predicate`
|
||||
|
||||
Delta-sig predicates provide a supply chain attestation format for binary patches, enabling policy-gated releases based on function-level change scope.
|
||||
|
||||
### 15.1 Predicate Structure
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"_type": "https://in-toto.io/Statement/v1",
|
||||
"predicateType": "https://stellaops.io/delta-sig/v1",
|
||||
"subject": [
|
||||
{
|
||||
"name": "libexample-1.1.so",
|
||||
"digest": {
|
||||
"sha256": "abc123..."
|
||||
}
|
||||
}
|
||||
],
|
||||
"predicate": {
|
||||
"before": {
|
||||
"name": "libexample-1.0.so",
|
||||
"digest": { "sha256": "def456..." }
|
||||
},
|
||||
"after": {
|
||||
"name": "libexample-1.1.so",
|
||||
"digest": { "sha256": "abc123..." }
|
||||
},
|
||||
"diff": [
|
||||
{
|
||||
"function": "process_input",
|
||||
"changeType": "modified",
|
||||
"beforeHash": "sha256:old...",
|
||||
"afterHash": "sha256:new...",
|
||||
"bytesDelta": 48,
|
||||
"semanticSimilarity": 0.87
|
||||
},
|
||||
{
|
||||
"function": "new_handler",
|
||||
"changeType": "added",
|
||||
"afterHash": "sha256:new...",
|
||||
"bytesDelta": 256
|
||||
}
|
||||
],
|
||||
"summary": {
|
||||
"functionsAdded": 1,
|
||||
"functionsRemoved": 0,
|
||||
"functionsModified": 1,
|
||||
"totalBytesChanged": 304
|
||||
},
|
||||
"timestamp": "2026-01-16T12:00:00Z"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 15.2 Policy Gate Integration
|
||||
|
||||
The `DeltaScopePolicyGate` enforces limits on patch scope:
|
||||
|
||||
```yaml
|
||||
policy:
|
||||
deltaSig:
|
||||
maxAddedFunctions: 10
|
||||
maxRemovedFunctions: 5
|
||||
maxModifiedFunctions: 20
|
||||
maxBytesChanged: 50000
|
||||
minSemanticSimilarity: 0.5
|
||||
requireSemanticAnalysis: false
|
||||
```
|
||||
|
||||
### 15.3 Attestor Integration
|
||||
|
||||
Delta-sig predicates integrate with the Attestor module:
|
||||
|
||||
1. **Generate** - Create predicate from before/after binary analysis
|
||||
2. **Sign** - Create DSSE envelope with cosign/fulcio signature
|
||||
3. **Submit** - Log to Rekor transparency log
|
||||
4. **Verify** - Validate signature and inclusion proof
|
||||
|
||||
### 15.4 CLI Commands
|
||||
|
||||
```bash
|
||||
# Generate delta-sig predicate
|
||||
stella binary diff --before old.so --after new.so --output delta.json
|
||||
|
||||
# Generate and attest in one step
|
||||
stella binary attest --before old.so --after new.so --sign --rekor
|
||||
|
||||
# Verify attestation
|
||||
stella binary verify --predicate delta.json --signature sig.dsse
|
||||
|
||||
# Check against policy gate
|
||||
stella binary gate --predicate delta.json --policy policy.yaml
|
||||
```
|
||||
|
||||
### 15.5 Semantic Similarity Scoring
|
||||
|
||||
When `requireSemanticAnalysis` is enabled, the gate also checks:
|
||||
|
||||
| Threshold | Meaning |
|
||||
|-----------|---------|
|
||||
| > 0.9 | Near-identical (cosmetic changes) |
|
||||
| 0.7 - 0.9 | Similar (refactoring, optimization) |
|
||||
| 0.5 - 0.7 | Moderate changes (significant logic) |
|
||||
| < 0.5 | Major rewrite (requires review) |
|
||||
|
||||
### 15.6 Evidence Storage
|
||||
|
||||
Delta-sig predicates are stored in the Evidence Locker and can be included in portable bundles for air-gapped verification.
|
||||
|
||||
---
|
||||
|
||||
## 16. References
|
||||
|
||||
### Internal
|
||||
|
||||
@@ -604,8 +717,10 @@ Pre-computed test cases with known results:
|
||||
- [ghidriff Tool](https://github.com/clearbluejar/ghidriff)
|
||||
- [SemDiff Paper (arXiv)](https://arxiv.org/abs/2308.01463)
|
||||
- [SEI Semantic Equivalence Research](https://www.sei.cmu.edu/annual-reviews/2022-research-review/semantic-equivalence-checking-of-decompiled-binaries/)
|
||||
- [in-toto Attestation Framework](https://in-toto.io/)
|
||||
- [SLSA Provenance Spec](https://slsa.dev/provenance/v1)
|
||||
|
||||
---
|
||||
|
||||
*Document Version: 1.0.1*
|
||||
*Last Updated: 2026-01-14*
|
||||
*Document Version: 1.1.0*
|
||||
*Last Updated: 2026-01-16*
|
||||
|
||||
@@ -132,3 +132,101 @@ All observation documents are immutable. New information creates a new observati
|
||||
- `EXCITITOR-GRAPH-24-*` relies on this schema to build overlays.
|
||||
- `DOCS-LNM-22-002` (Link-Not-Merge documentation) references this file.
|
||||
- `EXCITITOR-ATTEST-73-*` uses `document.digest` + `signature` to embed provenance in attestation payloads.
|
||||
|
||||
---
|
||||
|
||||
## Rekor Transparency Log Linkage
|
||||
|
||||
**Sprint Reference**: `SPRINT_20260117_002_EXCITITOR_vex_rekor_linkage`
|
||||
|
||||
VEX observations can be attested to the Sigstore Rekor transparency log, providing an immutable, publicly verifiable record of when each observation was recorded. This supports:
|
||||
|
||||
- **Auditability**: Independent verification that an observation existed at a specific time
|
||||
- **Non-repudiation**: Cryptographic proof of observation provenance
|
||||
- **Supply chain compliance**: Evidence for regulatory and security requirements
|
||||
- **Offline verification**: Stored inclusion proofs enable air-gapped verification
|
||||
|
||||
### Rekor Linkage Fields
|
||||
|
||||
The following fields are added to `vex_observations` when an observation is attested:
|
||||
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| `rekor_uuid` | TEXT | Rekor entry UUID (64-char hex) |
|
||||
| `rekor_log_index` | BIGINT | Monotonically increasing log position |
|
||||
| `rekor_integrated_time` | TIMESTAMPTZ | When entry was integrated into log |
|
||||
| `rekor_log_url` | TEXT | Rekor server URL where submitted |
|
||||
| `rekor_inclusion_proof` | JSONB | RFC 6962 inclusion proof for offline verification |
|
||||
| `rekor_linked_at` | TIMESTAMPTZ | When linkage was recorded locally |
|
||||
|
||||
### Schema Extension
|
||||
|
||||
```sql
|
||||
-- V20260117__vex_rekor_linkage.sql
|
||||
ALTER TABLE excititor.vex_observations
|
||||
ADD COLUMN IF NOT EXISTS rekor_uuid TEXT,
|
||||
ADD COLUMN IF NOT EXISTS rekor_log_index BIGINT,
|
||||
ADD COLUMN IF NOT EXISTS rekor_integrated_time TIMESTAMPTZ,
|
||||
ADD COLUMN IF NOT EXISTS rekor_log_url TEXT,
|
||||
ADD COLUMN IF NOT EXISTS rekor_inclusion_proof JSONB,
|
||||
ADD COLUMN IF NOT EXISTS rekor_linked_at TIMESTAMPTZ;
|
||||
|
||||
-- Indexes for Rekor queries
|
||||
CREATE INDEX idx_vex_observations_rekor_uuid
|
||||
ON excititor.vex_observations(rekor_uuid)
|
||||
WHERE rekor_uuid IS NOT NULL;
|
||||
|
||||
CREATE INDEX idx_vex_observations_pending_rekor
|
||||
ON excititor.vex_observations(created_at)
|
||||
WHERE rekor_uuid IS NULL;
|
||||
```
|
||||
|
||||
### API Endpoints
|
||||
|
||||
| Endpoint | Method | Description |
|
||||
|----------|--------|-------------|
|
||||
| `/attestations/rekor/observations/{id}` | POST | Attest observation to Rekor |
|
||||
| `/attestations/rekor/observations/batch` | POST | Batch attestation |
|
||||
| `/attestations/rekor/observations/{id}/verify` | GET | Verify Rekor linkage |
|
||||
| `/attestations/rekor/pending` | GET | List observations pending attestation |
|
||||
|
||||
### CLI Commands
|
||||
|
||||
```bash
|
||||
# Show observation with Rekor details
|
||||
stella vex observation show <id> --show-rekor
|
||||
|
||||
# Attest an observation to Rekor
|
||||
stella vex observation attest <id> [--rekor-url URL]
|
||||
|
||||
# Verify Rekor linkage
|
||||
stella vex observation verify-rekor <id> [--offline]
|
||||
|
||||
# List pending attestations
|
||||
stella vex observation list-pending
|
||||
```
|
||||
|
||||
### Inclusion Proof Structure
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"treeSize": 1234567,
|
||||
"rootHash": "base64-encoded-root-hash",
|
||||
"logIndex": 12345,
|
||||
"hashes": [
|
||||
"base64-hash-1",
|
||||
"base64-hash-2",
|
||||
"base64-hash-3"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Verification Modes
|
||||
|
||||
| Mode | Network | Use Case |
|
||||
|------|---------|----------|
|
||||
| Online | Required | Full verification against live Rekor |
|
||||
| Offline | Not required | Verify using stored inclusion proof |
|
||||
|
||||
Offline mode uses the stored `rekor_inclusion_proof` to verify the Merkle path locally. This is essential for air-gapped environments.
|
||||
|
||||
|
||||
@@ -1,309 +0,0 @@
|
||||
Here’s a short, implementation‑ready plan to turn your SBOMs into enforceable, cryptographic gates in Stella Ops—sequence, gate checks, and a compact threat model you can wire into a sprint.
|
||||
|
||||
---
|
||||
|
||||
# Minimal sequence (do now)
|
||||
|
||||
1. **CI build → Scanner/Sbomer**
|
||||
Compute `sha256` of each artifact and emit CycloneDX 1.6 SBOM with `components[].hashes[]`. ([CycloneDX][1])
|
||||
2. **Authority (DSSE sign)**
|
||||
Canonicalize SBOM JSON; wrap as DSSE `payloadType` for attestations and sign (HSM/KMS key). ([in-toto][2])
|
||||
3. **Router (Rekor v2)**
|
||||
Upload DSSE / in‑toto Statement to Rekor v2; persist returned `uuid`, `logIndex`, `integratedTime`. ([Sigstore Blog][3])
|
||||
4. **Vexer/Excititor (VEX)**
|
||||
Emit OpenVEX/CSAF (or in‑toto predicate) referencing CycloneDX `serialNumber`/`bom-ref` and the Rekor `uuid`. ([in-toto][2])
|
||||
5. **CI gate (OPA/Rego)**
|
||||
Verify (a) DSSE signature chain, (b) `payloadType` matches expected, (c) Rekor inclusion (via `logIndex`/UUID), (d) allowed `predicateType`, (e) component hash equals subject digest. ([Witness][4])
|
||||
|
||||
---
|
||||
|
||||
# Paste‑in Rego (gate)
|
||||
|
||||
```rego
|
||||
package stella.gate
|
||||
|
||||
deny[msg] {
|
||||
input.attestation.payloadType != "application/vnd.cyclonedx+json"
|
||||
msg = "unexpected payloadType"
|
||||
}
|
||||
|
||||
deny[msg] {
|
||||
not input.rekor.logIndex
|
||||
msg = "missing rekor logIndex"
|
||||
}
|
||||
|
||||
/* extend:
|
||||
- verify DSSE signature against Authority key
|
||||
- verify Rekor inclusion proof/integratedTime
|
||||
- ensure predicateType ∈ {
|
||||
"https://cyclonedx.org/schema/bom-1.6",
|
||||
"https://openvex.org/v1"
|
||||
}
|
||||
- ensure subject digest == components[].hashes[].content
|
||||
*/
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
# Compact threat model (top 3 + mitigations)
|
||||
|
||||
* **Tampering at rest** → Anchor in Rekor v2; verify inclusion + `integratedTime`; require DSSE signature with Authority HSM key. ([Sigstore Blog][3])
|
||||
* **Time‑shift / backdating** → Reject if `integratedTime` < pipeline build time − skew; optional RFC‑3161 timestamping on uploads. (Policy check in Scheduler.) ([Sigstore Blog][3])
|
||||
* **Provenance spoofing** → Enforce valid `predicateType` (in‑toto/OpenVEX), and map `signatures[].keyid` to trusted Authority keys (Fulcio/HSM). ([in-toto][2])
|
||||
|
||||
---
|
||||
|
||||
# Where this lands in Stella
|
||||
|
||||
* **Scanner**: compute subject digests; emit artifact metadata.
|
||||
* **Sbomer**: produce CycloneDX 1.6 with hashes, CBOM/attestations support ready. ([CycloneDX][1])
|
||||
* **Authority**: create DSSE envelope + sign; maintain key roster & rotation. ([Gradle Documentation][5])
|
||||
* **Router**: call Rekor v2; persist `uuid`/`logIndex`/`integratedTime` and expose `verifyRekor(uuid)`. ([Sigstore Blog][3])
|
||||
* **Vexer/Excititor**: emit OpenVEX / in‑toto predicates linking `bom-ref` and Rekor `uuid`. ([in-toto][2])
|
||||
|
||||
---
|
||||
|
||||
# Final sprint checklist
|
||||
|
||||
* Enable DSSE wrapping + Authority signing in one CI pipeline; push to Rekor v2; store `logIndex`. ([Sigstore Blog][3])
|
||||
* Add OPA policy to verify `payloadType`, Rekor presence, and digest match; fail CI on violation. ([Witness][4])
|
||||
* Add Scheduler job to periodically re‑verify Rekor roots and enforce time‑skew rules. ([Sigstore Blog][3])
|
||||
|
||||
**Why now:** CycloneDX 1.6 added attestations/CBOM, making SBOMs first‑class, signed evidence; Rekor v2 lowers cost and simplifies ops—ideal for anchoring these facts and gating releases. ([CycloneDX][1])
|
||||
|
||||
If you want, I can drop this into `docs/policies/OPA/stella.gate.rego` and a sample CI job for your GitLab pipeline next.
|
||||
|
||||
[1]: https://cyclonedx.org/news/cyclonedx-v1.6-released/?utm_source=chatgpt.com "CycloneDX v1.6 Released, Advances Software Supply ..."
|
||||
[2]: https://in-toto.io/docs/specs/?utm_source=chatgpt.com "Specifications"
|
||||
[3]: https://blog.sigstore.dev/rekor-v2-ga/?utm_source=chatgpt.com "Rekor v2 GA - Cheaper to run, simpler to maintain"
|
||||
[4]: https://witness.dev/docs/docs/concepts/policy/?utm_source=chatgpt.com "Policies"
|
||||
[5]: https://docs.gradle.com/develocity/dpg/current/?utm_source=chatgpt.com "Develocity Provenance Governor"
|
||||
|
||||
|
||||
|
||||
---
|
||||
Here’s a compact, engineer‑first guide to emitting a CycloneDX SBOM, wrapping it in a DSSE/in‑toto attestation, and anchoring it in Rekor v2—so you can copy/paste shapes straight into your Sbomer → Authority → Router flow.
|
||||
|
||||
---
|
||||
|
||||
# Why this matters (quick background)
|
||||
|
||||
* **CycloneDX**: the SBOM format you’ll emit.
|
||||
* **DSSE**: minimal, unambiguous envelope for signing arbitrary payloads (your SBOM).
|
||||
* **in‑toto Statement**: standard wrapper with `subject` + `predicate` so policy engines can reason about artifacts.
|
||||
* **Rekor (v2)**: transparency log anchor (UUID, index, integrated time) to verify later at gates.
|
||||
|
||||
---
|
||||
|
||||
# Minimal CycloneDX 1.6 SBOM (emit from `Sbomer`)
|
||||
|
||||
```json
|
||||
{
|
||||
"$schema": "http://cyclonedx.org/schema/bom-1.6.schema.json",
|
||||
"bomFormat": "CycloneDX",
|
||||
"specVersion": "1.6",
|
||||
"serialNumber": "urn:uuid:11111111-2222-3333-4444-555555555555",
|
||||
"metadata": {
|
||||
"component": {
|
||||
"bom-ref": "stella-app",
|
||||
"type": "application",
|
||||
"name": "stella-app",
|
||||
"version": "1.2.3"
|
||||
}
|
||||
},
|
||||
"components": [
|
||||
{
|
||||
"bom-ref": "lib-a",
|
||||
"type": "library",
|
||||
"name": "lib-a",
|
||||
"version": "0.1.0",
|
||||
"hashes": [
|
||||
{ "alg": "SHA-256", "content": "<hex-hash>" }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**Must‑emit fields (Sbomer):** `specVersion`, `serialNumber`, `components[].bom-ref`, `components[].hashes[].(alg,content)`.
|
||||
|
||||
---
|
||||
|
||||
# Wrap SBOM with DSSE (signed by `Authority`)
|
||||
|
||||
```json
|
||||
{
|
||||
"payloadType": "application/vnd.cyclonedx+json",
|
||||
"payload": "<base64(cyclonedx-bom.json)>",
|
||||
"signatures": [
|
||||
{ "keyid": "cosign:sha256:abcd...", "sig": "<base64-signature>" }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**Must‑emit (Authority):** `payloadType`, `payload` (base64), `signatures[].keyid`, `signatures[].sig`.
|
||||
|
||||
---
|
||||
|
||||
# Optional: in‑toto Statement (produced by `Excititor/Vexer`)
|
||||
|
||||
```json
|
||||
{
|
||||
"_type": "https://in-toto.io/Statement/v0.1",
|
||||
"subject": [
|
||||
{ "name": "stella-app", "digest": { "sha256": "<artifact-sha256>" } }
|
||||
],
|
||||
"predicateType": "https://cyclonedx.org/schema/bom-1.6",
|
||||
"predicate": {
|
||||
"bomRef": "stella-app",
|
||||
"uri": "oci://registry.example.com/stella-app@sha256:<digest>#sbom"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Must‑emit (Excititor/Vexer):** `predicateType` and a `predicate` your policy engine can dereference (embed SBOM or provide a pointer).
|
||||
|
||||
---
|
||||
|
||||
# Rekor v2 anchor (persist in `Router`, verify at gates)
|
||||
|
||||
```json
|
||||
{
|
||||
"uuid": "c3f2e4a8-...",
|
||||
"logIndex": 123456,
|
||||
"integratedTime": "2026-01-15T12:34:56Z"
|
||||
}
|
||||
```
|
||||
|
||||
**Must‑store (Router):** `uuid`, `logIndex`, `integratedTime`.
|
||||
|
||||
---
|
||||
|
||||
# End‑to‑end checks (put these in your CI gate)
|
||||
|
||||
* **SBOM shape**: JSON Schema validate CycloneDX; ensure `serialNumber` + per‑component hashes exist.
|
||||
* **DSSE**: verify signature over `payload` and `payloadType`; match `keyid` to trusted keys/profile.
|
||||
* **in‑toto**: confirm `subject.digest` equals the release OCI digest; `predicateType` matches CycloneDX 1.6/1.7.
|
||||
* **Rekor v2**: look up `uuid` → confirm `logIndex` & `integratedTime` and verify inclusion proof.
|
||||
|
||||
---
|
||||
|
||||
# Stella Ops module contract (TL;DR)
|
||||
|
||||
* **Sbomer** → emits CycloneDX 1.6/1.7 with `bom-ref` + hashes.
|
||||
* **Authority** → DSSE sign (`payloadType=application/vnd.cyclonedx+json`).
|
||||
* **Excititor/Vexer** → optional in‑toto Statement with CycloneDX predicate or pointer.
|
||||
* **Router** → store Rekor v2 tuple; expose verify endpoint for gates.
|
||||
|
||||
If you want, I can turn this into ready‑to‑run .NET 10 DTOs + validation (FluentValidation) and a tiny verifier CLI that checks all four layers in one go.
|
||||
Here’s a compact, auditor‑friendly way to sign **binary diffs** so they fit cleanly into today’s supply‑chain tooling (DSSE, in‑toto, Sigstore/Rekor) without inventing a new envelope.
|
||||
|
||||
---
|
||||
|
||||
# DSSE “delta‑sig” predicate for signed binary diffs (what & why)
|
||||
|
||||
* **Goal:** prove *exactly what changed* in a compiled artifact (per‑function patching, hotfixes/backports) and who signed it—using the standard **DSSE** (Dead Simple Signing Envelope) + **in‑toto predicate typing** so verifiers and transparency logs work out‑of‑the‑box.
|
||||
* **Why not just hash the whole file?** Full‑file hashes miss *where* and *how* a patch changed code. A delta predicate captures function‑level changes with canonical digests, so auditors can verify the patch is minimal and intentional, and policy can gate on “only approved backports applied.”
|
||||
|
||||
---
|
||||
|
||||
# Envelope strategy
|
||||
|
||||
* Keep the **DSSE envelope** as usual (`payloadType`, `payload`, `signatures`).
|
||||
* The DSSE `payload` is a **canonical JSON** object typed as an in‑toto predicate.
|
||||
* Predicate type (minimal): `stellaops/delta-sig/v1`.
|
||||
|
||||
This keeps interoperability with:
|
||||
|
||||
* **Sigstore/Rekor** (log DSSE envelopes),
|
||||
* **in‑toto** (predicate typing & subject semantics),
|
||||
* existing verification flows (cosign/sigstore‑python/in‑toto‑verify).
|
||||
|
||||
---
|
||||
|
||||
# Minimal predicate schema
|
||||
|
||||
```json
|
||||
{
|
||||
"predicateType": "stellaops/delta-sig/v1",
|
||||
"subject": [
|
||||
{
|
||||
"uri": "oci://registry.example.com/app@sha256:…",
|
||||
"digest": { "algo": "sha256", "hex": "<artifact_sha256>" },
|
||||
"filename": "bin/app",
|
||||
"arch": "linux-amd64"
|
||||
}
|
||||
],
|
||||
"delta": [
|
||||
{
|
||||
"function_id": "foo::bar(int,char)",
|
||||
"addr": 140737488355328,
|
||||
"old_hash": "<sha256_of_old_bytes>",
|
||||
"new_hash": "<sha256_of_new_bytes>",
|
||||
"hash_algo": "sha256",
|
||||
"diff_len": 112,
|
||||
"patch_offset": 4096,
|
||||
"compressed_diff_b64": "<optional_zstd_or_gzip_b64>"
|
||||
}
|
||||
],
|
||||
"tooling": {
|
||||
"lifter": "ghidra",
|
||||
"lifter_version": "11.1",
|
||||
"canonical_ir": "llvm-ir-15"
|
||||
},
|
||||
"canonicalization": {
|
||||
"json_canonicalization_version": "RFC8785"
|
||||
},
|
||||
"signer": {
|
||||
"keyid": "SHA256:…",
|
||||
"signer_name": "Release Engineering"
|
||||
},
|
||||
"signed_digest": {
|
||||
"algo": "sha256",
|
||||
"hex": "<sha256_of_canonical_payload_bytes>"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Notes**
|
||||
|
||||
* Use **SHA‑256** for `subject.digest`, `old_hash`, `new_hash`, and `signed_digest` to maximize compatibility with Rekor/Sigstore. (If you control both ends, **BLAKE2b‑256** is a fine faster alternative.)
|
||||
* `function_id` should be a **stable signature** (normalized symbol or demangled prototype); fall back to address + size if needed.
|
||||
* `compressed_diff_b64` is optional but handy for reproducible patch replay.
|
||||
|
||||
---
|
||||
|
||||
# Signing & verification (practical)
|
||||
|
||||
1. **Produce canonical payload**
|
||||
|
||||
* Serialize JSON with **RFC 8785** canonicalization (no insignificant whitespace, deterministic key order).
|
||||
2. **Wrap in DSSE**
|
||||
|
||||
* `payloadType`: `application/vnd.in-toto+json` (common) or a dedicated type string if you prefer.
|
||||
* `payload`: base64 of canonical JSON bytes.
|
||||
3. **Sign**
|
||||
|
||||
* Use **cosign** or **sigstore‑python** to sign DSSE; store in **Rekor** (transparency).
|
||||
4. **Verify**
|
||||
|
||||
* Check DSSE signature → decode predicate → verify each `old_hash`/`new_hash` against the target bytes → optionally replay `compressed_diff_b64` and re‑hash to confirm `new_hash`.
|
||||
|
||||
Policy examples you can enforce:
|
||||
|
||||
* Only allow releases whose delta predicate touches **≤ N functions** and **no control‑flow edges** outside whitelisted modules.
|
||||
* Require `tooling.lifter` in an approved set and `signed_digest.algo == "sha256"`.
|
||||
|
||||
---
|
||||
|
||||
# Why this fits your stack (Stella Ops, CI/CD, auditors)
|
||||
|
||||
* **Auditable:** function‑level intent captured, reproducible verification, deterministic hashing.
|
||||
* **Composable:** works with existing DSSE/in‑toto pipelines; attach to OCI artifacts or release manifests.
|
||||
* **Gate‑able:** let release policy check the delta surface and signer identity before promotion.
|
||||
* **Future‑proof:** can add PQC keys later without changing the predicate.
|
||||
|
||||
If you want, I can generate:
|
||||
|
||||
* A JSON Schema (`$id`, types, enums, bounds) for `stellaops/delta-sig/v1`.
|
||||
* A tiny reference **signer** (CLI) that emits canonical JSON + DSSE, and a **verifier** that checks function‑level diffs against a binary.
|
||||
Reference in New Issue
Block a user