up
Some checks failed
AOC Guard CI / aoc-guard (push) Has been cancelled
AOC Guard CI / aoc-verify (push) Has been cancelled
Concelier Attestation Tests / attestation-tests (push) Has been cancelled
Docs CI / lint-and-preview (push) Has been cancelled
Export Center CI / export-ci (push) Has been cancelled
devportal-offline / build-offline (push) Has been cancelled
Some checks failed
AOC Guard CI / aoc-guard (push) Has been cancelled
AOC Guard CI / aoc-verify (push) Has been cancelled
Concelier Attestation Tests / attestation-tests (push) Has been cancelled
Docs CI / lint-and-preview (push) Has been cancelled
Export Center CI / export-ci (push) Has been cancelled
devportal-offline / build-offline (push) Has been cancelled
This commit is contained in:
121
docs/airgap/manifest.schema.json
Normal file
121
docs/airgap/manifest.schema.json
Normal file
@@ -0,0 +1,121 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://stellaops.local/airgap/manifest.schema.json",
|
||||
"title": "Offline Kit Manifest",
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"schemaVersion",
|
||||
"bundleId",
|
||||
"tenant",
|
||||
"environment",
|
||||
"createdAt",
|
||||
"stalenessWindowHours",
|
||||
"tools",
|
||||
"feeds",
|
||||
"policies",
|
||||
"chunks",
|
||||
"hashes"
|
||||
],
|
||||
"properties": {
|
||||
"schemaVersion": { "type": "string", "pattern": "^1\\.\\d+\\.\\d+$" },
|
||||
"bundleId": { "type": "string", "pattern": "^offline-kit:[A-Za-z0-9._:-]+$" },
|
||||
"tenant": { "type": "string", "minLength": 1 },
|
||||
"environment": { "type": "string", "enum": ["prod", "stage", "dev", "test"] },
|
||||
"createdAt": { "type": "string", "format": "date-time" },
|
||||
"stalenessWindowHours": { "type": "integer", "minimum": 0 },
|
||||
"tools": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": ["name", "version", "sha256"],
|
||||
"properties": {
|
||||
"name": { "type": "string" },
|
||||
"version": { "type": "string" },
|
||||
"sha256": { "type": "string", "pattern": "^[A-Fa-f0-9]{64}$" }
|
||||
}
|
||||
},
|
||||
"uniqueItems": true
|
||||
},
|
||||
"feeds": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": ["name", "snapshot", "sha256"],
|
||||
"properties": {
|
||||
"name": { "type": "string" },
|
||||
"snapshot": { "type": "string" },
|
||||
"sha256": { "type": "string", "pattern": "^[A-Fa-f0-9]{64}$" },
|
||||
"stalenessHours": { "type": "integer", "minimum": 0 }
|
||||
}
|
||||
},
|
||||
"uniqueItems": true
|
||||
},
|
||||
"policies": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": ["name", "version", "sha256"],
|
||||
"properties": {
|
||||
"name": { "type": "string" },
|
||||
"version": { "type": "string" },
|
||||
"sha256": { "type": "string", "pattern": "^[A-Fa-f0-9]{64}$" }
|
||||
}
|
||||
},
|
||||
"uniqueItems": true
|
||||
},
|
||||
"chunks": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": ["path", "sha256", "size"],
|
||||
"properties": {
|
||||
"path": { "type": "string" },
|
||||
"sha256": { "type": "string", "pattern": "^[A-Fa-f0-9]{64}$" },
|
||||
"size": { "type": "integer", "minimum": 0 },
|
||||
"kind": { "type": "string", "enum": ["advisory", "sbom", "vex", "policy", "graph", "tooling", "other"] }
|
||||
}
|
||||
},
|
||||
"uniqueItems": true
|
||||
},
|
||||
"avScan": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": ["status"],
|
||||
"properties": {
|
||||
"status": { "type": "string", "enum": ["not_run", "clean", "findings"] },
|
||||
"scanner": { "type": "string" },
|
||||
"scanAt": { "type": "string", "format": "date-time" },
|
||||
"reportPath": { "type": "string" },
|
||||
"reportSha256": { "type": "string", "pattern": "^[A-Fa-f0-9]{64}$" }
|
||||
}
|
||||
},
|
||||
"hashes": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": ["manifestSha256", "bundleSha256"],
|
||||
"properties": {
|
||||
"manifestSha256": { "type": "string", "pattern": "^[A-Fa-f0-9]{64}$" },
|
||||
"bundleSha256": { "type": "string", "pattern": "^[A-Fa-f0-9]{64}$" }
|
||||
}
|
||||
},
|
||||
"signatures": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": ["type", "keyId", "signature"],
|
||||
"properties": {
|
||||
"type": { "type": "string", "enum": ["dsse", "jws-detached"] },
|
||||
"keyId": { "type": "string" },
|
||||
"signature": { "type": "string" },
|
||||
"envelopeDigest": { "type": "string", "pattern": "^sha256:[A-Fa-f0-9]{64}$" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,30 +1,40 @@
|
||||
# AirGap Import & Verify (runbook outline)
|
||||
# Offline Kit Import Verification Runbook
|
||||
|
||||
Related advisory: `docs/product-advisories/25-Nov-2025 - Air‑gap deployment playbook for StellaOps.md` (AG1–AG12). Implements AIRGAP-VERIFY-510-014.
|
||||
This runbook supports AIRGAP-MANIFEST-510-010/014. It validates bundle integrity before import, fully offline.
|
||||
|
||||
## Prerequisites
|
||||
- `offline-kit/manifest.json` + `manifest.dsse` and `mirror.manifest` present.
|
||||
- Trust roots: Rekor/TUF roots, Authority signing roots, AV/YARA public keys.
|
||||
- Tools: `cosign` (or Stella verifier), `sha256sum`, `yara`, `python3`.
|
||||
## Inputs
|
||||
- Manifest: `offline-kit/manifest.json`
|
||||
- Bundle archive: e.g., `offline-kit/bundle.tar.gz`
|
||||
- Optional DSSE/JWS signature + public key for the manifest.
|
||||
|
||||
## Steps
|
||||
1) Verify manifest signature
|
||||
- `cosign verify-blob --key trust-roots/manifest.pub --signature manifest.dsse manifest.json`
|
||||
- Sample helper: `scripts/airgap/verify-offline-kit.sh <kit-root>`
|
||||
2) Check staleness and policy/graph hashes
|
||||
- Compare `feeds[*].snapshot` dates to allowed window; ensure `policyHash`/`graphHash` match target site config; fail closed on mismatch unless override signed.
|
||||
3) Verify chunks and Merkle root
|
||||
- For each chunk listed in manifest, `sha256sum -c`; recompute Merkle root per manifest recipe; compare to `rootHash` field.
|
||||
4) AV/YARA validation
|
||||
- Run `yara -r rules/offline-kit.yar kit/`; confirm `avReport.sha256` matches signed report in manifest; block on any detection.
|
||||
5) Replay depth selection
|
||||
- Modes: `hash-only` (default), `full-recompute`, `policy-freeze`. Select via `--replay-mode`; enforce exit codes 0=pass, 3=stale, 4=hash-drift, 5=av-fail.
|
||||
6) Ingress/egress receipts
|
||||
- Generate DSSE receipt `{hash, operator, time, decision}`; store in Proof Graph; verify incoming receipts before import.
|
||||
## Quick steps (offline)
|
||||
|
||||
```bash
|
||||
src/AirGap/scripts/verify-manifest.sh offline-kit/manifest.json offline-kit/bundle.tar.gz \
|
||||
offline-kit/manifest.sig offline-kit/manifest.pub.pem
|
||||
```
|
||||
|
||||
What it does:
|
||||
1. Computes SHA-256 of manifest and bundle, compares with `hashes.manifestSha256` and `hashes.bundleSha256`.
|
||||
2. If signature + pubkey are provided, verifies the manifest signature with OpenSSL.
|
||||
|
||||
## Expected manifest fields
|
||||
- `tools[]`, `feeds[]`, `policies[]` with SHA-256.
|
||||
- `chunks[]` entries for every payload file (path, sha256, size, kind).
|
||||
- `stalenessWindowHours` and `avScan` status.
|
||||
- `hashes.manifestSha256` and `hashes.bundleSha256` must match the files on disk.
|
||||
- Optional `signatures[]` (dsse/jws-detached) with `envelopeDigest`.
|
||||
|
||||
## Failure handling
|
||||
- Hash mismatch → stop; regenerate bundle.
|
||||
- Signature failure → stop; re-validate trust roots.
|
||||
- Missing AV scan → treat as policy violation; rerun scans and update manifest.
|
||||
|
||||
## Outputs
|
||||
- Exit code per replay mode outcome.
|
||||
- Receipt DSSE stored at `receipts/{tenant}/{timestamp}.dsse`.
|
||||
- Optional report `verify-report.json` summarizing checks.
|
||||
- Exit 0 when all checks pass.
|
||||
- Exit 2–5 for missing tools/hash/signature verification issues (see script).
|
||||
|
||||
> Expand with concrete scripts once tasks 510-010..014 land.
|
||||
## References
|
||||
- Schema: `docs/airgap/manifest.schema.json`
|
||||
- Sample: `docs/airgap/samples/offline-kit-manifest.sample.json`
|
||||
- Script: `src/AirGap/scripts/verify-manifest.sh`
|
||||
|
||||
43
docs/airgap/samples/offline-kit-manifest.sample.json
Normal file
43
docs/airgap/samples/offline-kit-manifest.sample.json
Normal file
@@ -0,0 +1,43 @@
|
||||
{
|
||||
"$schema": "../manifest.schema.json",
|
||||
"schemaVersion": "1.0.0",
|
||||
"bundleId": "offline-kit:concelier:2025-12-02",
|
||||
"tenant": "default",
|
||||
"environment": "prod",
|
||||
"createdAt": "2025-12-02T00:00:00Z",
|
||||
"stalenessWindowHours": 168,
|
||||
"tools": [
|
||||
{ "name": "concelier-exporter", "version": "2.5.0", "sha256": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcd" },
|
||||
{ "name": "trivy-db", "version": "0.48.0", "sha256": "89abcdef0123456789abcdef0123456789abcdef0123456789abcdef01234567" }
|
||||
],
|
||||
"feeds": [
|
||||
{ "name": "redhat-csaf", "snapshot": "2025-12-01", "sha256": "fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210", "stalenessHours": 72 },
|
||||
{ "name": "osv", "snapshot": "2025-12-01T23:00:00Z", "sha256": "0f0e0d0c0b0a09080706050403020100ffeeddccbbaa99887766554433221100", "stalenessHours": 24 }
|
||||
],
|
||||
"policies": [
|
||||
{ "name": "policy-bundle", "version": "1.4.2", "sha256": "aa55aa55aa55aa55aa55aa55aa55aa55aa55aa55aa55aa55aa55aa55aa55aa55" }
|
||||
],
|
||||
"chunks": [
|
||||
{ "path": "chunks/advisories-0001.tzst", "sha256": "1234123412341234123412341234123412341234123412341234123412341234", "size": 1048576, "kind": "advisory" },
|
||||
{ "path": "chunks/vex-0001.tzst", "sha256": "4321432143214321432143214321432143214321432143214321432143214321", "size": 524288, "kind": "vex" }
|
||||
],
|
||||
"avScan": {
|
||||
"status": "clean",
|
||||
"scanner": "clamav 1.4.1",
|
||||
"scanAt": "2025-12-02T00:05:00Z",
|
||||
"reportPath": "reports/av-scan.txt",
|
||||
"reportSha256": "bb66bb66bb66bb66bb66bb66bb66bb66bb66bb66bb66bb66bb66bb66bb66bb66"
|
||||
},
|
||||
"hashes": {
|
||||
"manifestSha256": "29d58b9fdc5c4e65b26c03f3bd9f442ff0c7f8514b8a9225f8b6417ffabc0101",
|
||||
"bundleSha256": "d3c3f6c75c6a3f0906bcee457cc77a2d6d7c0f9d1a1d7da78c0d2ab8e0dba111"
|
||||
},
|
||||
"signatures": [
|
||||
{
|
||||
"type": "dsse",
|
||||
"keyId": "airgap-manifest-dev",
|
||||
"signature": "MEQCIGVyb3JrZXktc2lnbmF0dXJlLXNob3J0",
|
||||
"envelopeDigest": "sha256:cc77cc77cc77cc77cc77cc77cc77cc77cc77cc77cc77cc77cc77cc77cc77cc77"
|
||||
}
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user