Files
git.stella-ops.org/scripts/packs/test_verify_offline_bundle.py
StellaOps Bot 18d87c64c5 feat: add PolicyPackSelectorComponent with tests and integration
- Implemented PolicyPackSelectorComponent for selecting policy packs.
- Added unit tests for component behavior, including API success and error handling.
- Introduced monaco-workers type declarations for editor workers.
- Created acceptance tests for guardrails with stubs for AT1–AT10.
- Established SCA Failure Catalogue Fixtures for regression testing.
- Developed plugin determinism harness with stubs for PL1–PL10.
- Added scripts for evidence upload and verification processes.
2025-12-05 21:24:34 +02:00

181 lines
7.5 KiB
Python

#!/usr/bin/env python3
import json
import tempfile
import unittest
from pathlib import Path
import runpy
_VERIFIER_PATH = Path(__file__).parent / "verify_offline_bundle.py"
_mod = runpy.run_path(_VERIFIER_PATH.as_posix(), run_name="verify_offline_bundle")
BundleReader = _mod["BundleReader"]
validate_manifest = _mod["validate_manifest"]
verify_files = _mod["verify_files"]
verify_hashes = _mod["verify_hashes"]
sha256_digest = _mod["sha256_digest"]
def _write(path: Path, content: str) -> str:
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text(content, encoding="utf-8")
return sha256_digest(content.encode("utf-8"))
class VerifyOfflineBundleTests(unittest.TestCase):
def setUp(self) -> None:
self.tmp = tempfile.TemporaryDirectory()
self.root = Path(self.tmp.name)
def tearDown(self) -> None:
self.tmp.cleanup()
def _build_manifest(self) -> Path:
plan_hash = _write(self.root / "canonical-plan.json", '{"steps":[]}')
inputs_lock_hash = _write(self.root / "inputs.lock", '{"inputs":{}}')
sbom_hash = _write(self.root / "sbom.json", '{"bom":"demo"}')
attest_hash = _write(self.root / "attestation.dsse", "attestation")
approvals_ledger = json.dumps(
{
"schemaVersion": "stellaops.pack.approval-ledger.v1",
"runId": "run-1",
"gateId": "security-review",
"planHash": plan_hash,
"decision": "approved",
"decidedAt": "2025-12-05T00:00:00Z",
"tenantId": "demo-tenant",
"approver": {"id": "approver@example.com", "summary": "LGTM"},
}
)
approvals_hash = _write(self.root / "approvals-ledger.dsse", approvals_ledger)
revocations_hash = _write(self.root / "revocations.json", '{"revoked":false}')
bundle_dsse_hash = _write(self.root / "bundle.dsse", "bundle-dsse")
att_dsse_hash = _write(self.root / "attestation.dsse.sig", "att-dsse")
redaction_hash = _write(self.root / "redaction-policy.json", '{"mode":"hash"}')
pack_blob_hash = _write(self.root / "packs/my-pack.tgz", "dummy pack")
manifest = {
"schemaVersion": "stellaops.pack.offline-bundle.v1",
"pack": {
"name": "demo-pack",
"version": "1.0.0",
"bundle": "packs/my-pack.tgz",
"digest": pack_blob_hash,
"registry": "demo.local/pack/demo:1.0.0",
"sbom": "sbom.json",
},
"plan": {
"hashAlgorithm": "sha256",
"hash": plan_hash,
"canonicalPlanPath": "canonical-plan.json",
"inputsLock": "inputs.lock",
"rngSeed": "rng-demo",
"timestampSource": "utc-iso8601",
},
"evidence": {
"attestation": "attestation.dsse",
"approvalsLedger": "approvals-ledger.dsse",
"timeline": "timeline.ndjson",
},
"security": {
"sandbox": {
"mode": "sealed",
"egressAllowlist": [],
"cpuLimitMillicores": 250,
"memoryLimitMiB": 256,
"quotaSeconds": 120,
},
"revocations": "revocations.json",
"signatures": {
"bundleDsse": "bundle.dsse",
"attestationDsse": "attestation.dsse.sig",
"registryCertChain": "certs.pem",
},
"secretsRedactionPolicy": "redaction-policy.json",
},
"hashes": [
{"path": "canonical-plan.json", "algorithm": "sha256", "digest": plan_hash},
{"path": "inputs.lock", "algorithm": "sha256", "digest": inputs_lock_hash},
{"path": "sbom.json", "algorithm": "sha256", "digest": sbom_hash},
{"path": "attestation.dsse", "algorithm": "sha256", "digest": attest_hash},
{"path": "approvals-ledger.dsse", "algorithm": "sha256", "digest": approvals_hash},
{"path": "revocations.json", "algorithm": "sha256", "digest": revocations_hash},
{"path": "bundle.dsse", "algorithm": "sha256", "digest": bundle_dsse_hash},
{"path": "attestation.dsse.sig", "algorithm": "sha256", "digest": att_dsse_hash},
{"path": "redaction-policy.json", "algorithm": "sha256", "digest": redaction_hash},
{"path": "packs/my-pack.tgz", "algorithm": "sha256", "digest": pack_blob_hash},
],
"slo": {
"runP95Seconds": 300,
"approvalP95Seconds": 900,
"maxQueueDepth": 1000,
"alertRules": "alerts.yaml",
},
"tenant": "demo-tenant",
"environment": "dev",
"created": "2025-12-05T00:00:00Z",
"expires": "2026-01-05T00:00:00Z",
"verifyScriptVersion": "local-test",
}
manifest_path = self.root / "bundle.json"
manifest_path.write_text(json.dumps(manifest, indent=2), encoding="utf-8")
return manifest_path
def test_good_bundle_passes(self):
manifest_path = self._build_manifest()
reader = BundleReader(self.root.as_posix())
manifest = json.loads(manifest_path.read_text())
errors = []
errors.extend(validate_manifest(manifest))
errors.extend(verify_files(reader, manifest, require_dsse=True))
errors.extend(verify_hashes(reader, manifest))
self.assertFalse(errors, f"Expected no validation errors, got: {errors}")
def test_missing_hash_fails(self):
manifest_path = self._build_manifest()
manifest = json.loads(manifest_path.read_text())
# Corrupt a hash to force a failure.
manifest["hashes"][0]["digest"] = "sha256:" + "0" * 64
reader = BundleReader(self.root.as_posix())
errors = verify_hashes(reader, manifest)
self.assertTrue(errors, "Expected hash verification to fail when hash entry is missing")
def test_missing_quota_fails(self):
manifest_path = self._build_manifest()
manifest = json.loads(manifest_path.read_text())
del manifest["security"]["sandbox"]["quotaSeconds"]
reader = BundleReader(self.root.as_posix())
errors = []
errors.extend(validate_manifest(manifest))
errors.extend(verify_files(reader, manifest, require_dsse=True))
errors.extend(verify_hashes(reader, manifest))
self.assertTrue(
any(err.path == "security.sandbox.quotaSeconds" for err in errors),
"Expected quotaSeconds validation failure"
)
def test_invalid_approval_ledger_plan_hash_fails(self):
manifest_path = self._build_manifest()
manifest = json.loads(manifest_path.read_text())
ledger_path = self.root / "approvals-ledger.dsse"
ledger = json.loads(ledger_path.read_text())
ledger["planHash"] = "not-a-digest"
ledger_path.write_text(json.dumps(ledger), encoding="utf-8")
reader = BundleReader(self.root.as_posix())
errors = []
errors.extend(validate_manifest(manifest))
errors.extend(verify_files(reader, manifest, require_dsse=True))
errors.extend(verify_hashes(reader, manifest))
self.assertTrue(
any(err.path.startswith("approvalsLedger.planHash") for err in errors),
"Expected approval ledger plan hash validation failure"
)
if __name__ == "__main__":
unittest.main()