feat: Add DigestUpsertRequest and LockEntity models
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
Mirror Thin Bundle Sign & Verify / mirror-sign (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
Mirror Thin Bundle Sign & Verify / mirror-sign (push) Has been cancelled
- Introduced DigestUpsertRequest for handling digest upsert requests with properties like ChannelId, Recipient, DigestKey, Events, and CollectUntil. - Created LockEntity to represent a lightweight distributed lock entry with properties such as Id, TenantId, Resource, Owner, ExpiresAt, and CreatedAt. feat: Implement ILockRepository interface and LockRepository class - Defined ILockRepository interface with methods for acquiring and releasing locks. - Implemented LockRepository class with methods to try acquiring a lock and releasing it, using SQL for upsert operations. feat: Add SurfaceManifestPointer record for manifest pointers - Introduced SurfaceManifestPointer to represent a minimal pointer to a Surface.FS manifest associated with an image digest. feat: Create PolicySimulationInputLock and related validation logic - Added PolicySimulationInputLock record to describe policy simulation inputs and expected digests. - Implemented validation logic for policy simulation inputs, including checks for digest drift and shadow mode requirements. test: Add unit tests for ReplayVerificationService and ReplayVerifier - Created ReplayVerificationServiceTests to validate the behavior of the ReplayVerificationService under various scenarios. - Developed ReplayVerifierTests to ensure the correctness of the ReplayVerifier logic. test: Implement PolicySimulationInputLockValidatorTests - Added tests for PolicySimulationInputLockValidator to verify the validation logic against expected inputs and conditions. chore: Add cosign key example and signing scripts - Included a placeholder cosign key example for development purposes. - Added a script for signing Signals artifacts using cosign with support for both v2 and v3. chore: Create script for uploading evidence to the evidence locker - Developed a script to upload evidence to the evidence locker, ensuring required environment variables are set.
This commit is contained in:
@@ -125,6 +125,16 @@ def check_content_hashes(manifest: dict, tar_path: pathlib.Path):
|
||||
raise SystemExit(f"index digest mismatch {name}: {digest}")
|
||||
|
||||
|
||||
def read_tar_entry(tar_path: pathlib.Path, name: str) -> bytes:
|
||||
with tarfile.open(tar_path, "r:gz") as tf:
|
||||
try:
|
||||
info = tf.getmember(name)
|
||||
except KeyError:
|
||||
info = tf.getmember(f"./{name}")
|
||||
data = tf.extractfile(info).read()
|
||||
return data
|
||||
|
||||
|
||||
def load_pubkey(path: pathlib.Path) -> Ed25519PublicKey:
|
||||
if not CRYPTO_AVAILABLE:
|
||||
raise SystemExit("cryptography is required for DSSE verification; install before using --pubkey")
|
||||
@@ -170,6 +180,16 @@ def check_bundle_meta(meta_path: pathlib.Path, manifest_path: pathlib.Path, tar_
|
||||
|
||||
expect("manifest", manifest_path)
|
||||
expect("tarball", tar_path)
|
||||
# DSSE sidecars are optional but if present, validate hashes
|
||||
dsse_manifest = artifacts.get("manifest_dsse")
|
||||
if dsse_manifest and dsse_manifest.get("path"):
|
||||
expect("manifest_dsse", meta_path.parent / dsse_manifest["path"])
|
||||
dsse_bundle = artifacts.get("bundle_dsse")
|
||||
if dsse_bundle and dsse_bundle.get("path"):
|
||||
expect("bundle_dsse", meta_path.parent / dsse_bundle["path"])
|
||||
dsse_anchor = artifacts.get("time_anchor_dsse")
|
||||
if dsse_anchor and dsse_anchor.get("path"):
|
||||
expect("time_anchor_dsse", meta_path.parent / dsse_anchor["path"])
|
||||
for extra in ["time_anchor", "transport_plan", "rekor_policy", "mirror_policy", "offline_policy", "artifact_hashes"]:
|
||||
rec = artifacts.get(extra)
|
||||
if not rec:
|
||||
@@ -177,6 +197,13 @@ def check_bundle_meta(meta_path: pathlib.Path, manifest_path: pathlib.Path, tar_
|
||||
if not rec.get("path"):
|
||||
raise SystemExit(f"bundle meta missing path for {extra}")
|
||||
|
||||
time_anchor_dsse = artifacts.get("time_anchor_dsse")
|
||||
if time_anchor_dsse:
|
||||
if not time_anchor_dsse.get("path"):
|
||||
raise SystemExit("bundle meta missing path for time_anchor_dsse")
|
||||
if not (meta_path.parent / time_anchor_dsse["path"]).exists():
|
||||
raise SystemExit("time_anchor_dsse referenced but file missing")
|
||||
|
||||
for group, expected_count in [("ok", 10), ("rk", 10), ("ms", 10)]:
|
||||
if len(meta.get("gaps", {}).get(group, [])) != expected_count:
|
||||
raise SystemExit(f"bundle meta gaps.{group} expected {expected_count} entries")
|
||||
@@ -215,6 +242,8 @@ def main():
|
||||
bundle_meta = args.bundle_meta
|
||||
bundle_dsse = bundle_meta.with_suffix(".dsse.json") if bundle_meta else None
|
||||
manifest_dsse = manifest_path.with_suffix(".dsse.json")
|
||||
time_anchor_dsse = None
|
||||
time_anchor_path = tar_path.parent / "stage-v1" / "layers" / "time-anchor.json"
|
||||
|
||||
man_expected = load_sha256_sidecar(manifest_path)
|
||||
tar_expected = load_sha256_sidecar(tar_path)
|
||||
@@ -236,6 +265,13 @@ def main():
|
||||
if sha256_file(bundle_meta) != meta_expected:
|
||||
raise SystemExit("bundle meta sha256 mismatch")
|
||||
check_bundle_meta(bundle_meta, manifest_path, tar_path, args.tenant, args.environment)
|
||||
meta = json.loads(bundle_meta.read_text())
|
||||
ta_entry = meta.get("artifacts", {}).get("time_anchor_dsse")
|
||||
if ta_entry and ta_entry.get("path"):
|
||||
ta_path = bundle_meta.parent / ta_entry["path"]
|
||||
if sha256_file(ta_path) != ta_entry.get("sha256"):
|
||||
raise SystemExit("time_anchor_dsse sha256 mismatch")
|
||||
time_anchor_dsse = ta_path
|
||||
|
||||
if args.pubkey:
|
||||
pubkey = args.pubkey
|
||||
@@ -243,6 +279,12 @@ def main():
|
||||
verify_dsse(manifest_dsse, pubkey, manifest_path, "application/vnd.stellaops.mirror.manifest+json")
|
||||
if bundle_dsse and bundle_dsse.exists():
|
||||
verify_dsse(bundle_dsse, pubkey, bundle_meta, "application/vnd.stellaops.mirror.bundle+json")
|
||||
if time_anchor_dsse and time_anchor_dsse.exists() and time_anchor_path.exists():
|
||||
anchor_bytes = read_tar_entry(tar_path, "layers/time-anchor.json")
|
||||
tmp_anchor = tar_path.parent / "time-anchor.verify.json"
|
||||
tmp_anchor.write_bytes(anchor_bytes)
|
||||
verify_dsse(time_anchor_dsse, pubkey, tmp_anchor, "application/vnd.stellaops.time-anchor+json")
|
||||
tmp_anchor.unlink(missing_ok=True)
|
||||
|
||||
print("OK: mirror-thin bundle verified")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user