diff --git a/scripts/release_candidate_driver.py b/scripts/release_candidate_driver.py index 8787ec2f2..cee1c64a2 100644 --- a/scripts/release_candidate_driver.py +++ b/scripts/release_candidate_driver.py @@ -88,7 +88,11 @@ from scripts.release_install_smoke import ( ) from scripts.release_ledger import ( LedgerError, + RetainedLedgerSchema, + current_retained_ledger_schema, read_retained_ledger, + resolve_retained_ledger_schema, + retained_ledger_schema_declares_nvattest, validate_native_members_against_release_dir, write_ledger, ) @@ -158,6 +162,8 @@ SPEAKERS_ANALYZE_WORKSPACE_PACKAGE = "solstone-core-speakers-analyze" RESERVED_CANDIDATE_DIRNAME = "release-candidate" RELEASE_CANDIDATE_DISCARD_RETAINED_ENV = "RELEASE_CANDIDATE_DISCARD_RETAINED" RELEASE_CANDIDATE_DISCARD_PUBLISHED_TAG_ENV = "RELEASE_CANDIDATE_DISCARD_PUBLISHED_TAG" +RETAINED_CANDIDATE_VALID_HEADING = "retained-candidate-valid" +RETAINED_PRE_NVATTEST_CANDIDATE_VALID_HEADING = "retained-pre-nvattest-candidate-valid" DistPreflightOperation = Literal["cleanup", "inventory"] DistState = Literal["missing", "directory", "unsafe"] @@ -2571,11 +2577,39 @@ def _nvattest_ledger_payload( } +def _schema_absent_nvattest_failure(version: int) -> Failure: + return _failure( + "retained ledger schema does not declare nvattest", + expected="schema with nvattest binding", + actual=f"schema_version {version}", + repair="bash scripts/release.sh --recover", + ) + + +def _resolve_driver_retained_ledger_schema( + ledger: Mapping[str, Any], +) -> tuple[int, RetainedLedgerSchema]: + try: + return resolve_retained_ledger_schema(ledger) + except LedgerError as exc: + raise DriverError(exc.failures) from None + + +def _require_nvattest_schema( + ledger: Mapping[str, Any], +) -> tuple[int, RetainedLedgerSchema]: + version, schema = _resolve_driver_retained_ledger_schema(ledger) + if not retained_ledger_schema_declares_nvattest(schema): + raise DriverError([_schema_absent_nvattest_failure(version)]) + return version, schema + + def _retained_support_binding_failures( *, evidence_dir: Path, ledger: Mapping[str, Any], ) -> list[Failure]: + _require_nvattest_schema(ledger) failures: list[Failure] = [] nvattest = ledger.get("nvattest") if not isinstance(nvattest, Mapping): @@ -2637,6 +2671,7 @@ def _retained_authority_binding( release_dir: Path, ledger: Mapping[str, Any], ) -> tuple[bytes | None, list[Failure]]: + _require_nvattest_schema(ledger) names, name_failures = _ledger_candidate_file_names(ledger) if name_failures: return None, name_failures @@ -2698,6 +2733,7 @@ def _validate_retained_nvattest_binding( release_dir: Path, version: str, ) -> dict[str, str]: + _require_nvattest_schema(ledger) failures: list[Failure] = [] nvattest = ledger.get("nvattest") if not isinstance(nvattest, Mapping): @@ -3262,19 +3298,34 @@ def _validate_publication_prerequisite_record( return validate_core_unsupported_tombstone_record(payload, version=version) +def _required_evidence_entries(schema: RetainedLedgerSchema) -> set[str]: + entries = {"ledger.json", "proofs"} + if retained_ledger_schema_declares_nvattest(schema): + entries.update(("nvattest", "support")) + return entries + + +def _evidence_inventory_text(entries: set[str]) -> str: + return ", ".join(sorted(entries)) + + def _validate_evidence_inventory( evidence_dir: Path, *, + schema_version: int, + schema: RetainedLedgerSchema, publication_prerequisite_version: str | None = None, ) -> list[Failure]: failures: list[Failure] = [] + required_entries = _required_evidence_entries(schema) + expected_inventory = _evidence_inventory_text(required_entries) try: evidence_entry = evidence_dir.lstat() except FileNotFoundError: return [ _failure( "release evidence directory is missing", - expected="ledger.json, proofs, nvattest, and support", + expected=expected_inventory, actual="missing", repair="bash scripts/release.sh --recover", ) @@ -3289,9 +3340,7 @@ def _validate_evidence_inventory( ) ] entries = {path.name: path for path in evidence_dir.iterdir()} - required_entries = {"ledger.json", "proofs", "nvattest", "support"} accepted_entries = set(required_entries) - expected_inventory = "ledger.json, nvattest, proofs, support" if publication_prerequisite_version is not None: accepted_entries.add(CORE_UNSUPPORTED_TOMBSTONE_RECORD) expected_inventory = ( @@ -3302,7 +3351,7 @@ def _validate_evidence_inventory( failures.append( _failure( "release evidence inventory is not exact", - expected=expected_inventory, + expected=f"schema_version {schema_version}: {expected_inventory}", actual=", ".join(sorted(entries)) or "", repair="bash scripts/release.sh --recover", ) @@ -3814,11 +3863,16 @@ def _pair_promote_payload_and_evidence( promoted_payload = False promoted_evidence = False try: + current_schema_version, current_schema = current_retained_ledger_schema() failures = [ *_validate_flat_payload_inventory( payload_staging, include_models=include_models ), - *_validate_evidence_inventory(evidence_staging), + *_validate_evidence_inventory( + evidence_staging, + schema_version=current_schema_version, + schema=current_schema, + ), ] for final_path, label in ( (ready_path, "final payload"), @@ -3933,19 +3987,33 @@ def _report( validate_current_release_metadata: bool = True, allow_publication_prerequisite: bool = False, ) -> CandidateReport: + ledger_path = evidence_dir / "ledger.json" + try: + ledger = read_retained_ledger(ledger_path) + except OSError as exc: + raise DriverError( + [ + _failure( + "retained ledger could not be read", + expected="readable retained ledger.json", + actual=type(exc).__name__, + repair="bash scripts/release.sh --recover", + ) + ] + ) from None + except LedgerError as exc: + raise DriverError(exc.failures) from None + schema_version, schema = _resolve_driver_retained_ledger_schema(ledger) inventory_failures = _validate_evidence_inventory( evidence_dir, + schema_version=schema_version, + schema=schema, publication_prerequisite_version=( version if allow_publication_prerequisite else None ), ) if inventory_failures: raise DriverError(inventory_failures) - ledger_path = evidence_dir / "ledger.json" - try: - ledger = read_retained_ledger(ledger_path) - except LedgerError as exc: - raise DriverError(exc.failures) from None models = ledger.get("models") include_models = isinstance(models, Mapping) and models.get("decision") == "include" if validate_current_release_metadata: @@ -3997,14 +4065,17 @@ def _report( release_dir=release_dir, version=version, ) - nvattest_hashes = _validate_retained_nvattest_binding( - evidence_dir=evidence_dir, - ledger=ledger, - digest=digest, - ledger_sha256=ledger_sha256, - release_dir=release_dir, - version=version, - ) + if retained_ledger_schema_declares_nvattest(schema): + nvattest_hashes = _validate_retained_nvattest_binding( + evidence_dir=evidence_dir, + ledger=ledger, + digest=digest, + ledger_sha256=ledger_sha256, + release_dir=release_dir, + version=version, + ) + else: + nvattest_hashes = {} return CandidateReport( heading=heading, version=version, @@ -4037,7 +4108,13 @@ def _payload_report_inventory(release_dir: Path) -> list[dict[str, Any]]: ] -def _evidence_report_inventory(evidence_dir: Path) -> list[dict[str, Any]]: +def _evidence_report_inventory( + evidence_dir: Path, + *, + schema_version: int, + schema: RetainedLedgerSchema, +) -> list[dict[str, Any]]: + _ = schema_version entries = [ _inventory_entry(evidence_dir / "ledger.json", name="ledger.json"), ] @@ -4046,6 +4123,8 @@ def _evidence_report_inventory(evidence_dir: Path) -> list[dict[str, Any]]: _inventory_entry(path, name=f"proofs/{path.name}") for path in sorted(proofs_dir.iterdir(), key=lambda item: item.name) ) + if not retained_ledger_schema_declares_nvattest(schema): + return sorted(entries, key=lambda item: item["name"]) nvattest_dir = evidence_dir / "nvattest" entries.extend( _inventory_entry(path, name=f"nvattest/{path.name}") @@ -4067,7 +4146,15 @@ def _proof_report_inventory(evidence_dir: Path) -> dict[str, dict[str, Any]]: } -def _nvattest_report_inventory(evidence_dir: Path) -> dict[str, dict[str, Any]]: +def _nvattest_report_inventory( + evidence_dir: Path, + *, + schema_version: int, + schema: RetainedLedgerSchema, +) -> dict[str, dict[str, Any]]: + _ = schema_version + if not retained_ledger_schema_declares_nvattest(schema): + return {} nvattest_dir = evidence_dir / "nvattest" return { target: _inventory_entry(nvattest_dir / f"{target}.json", name=f"{target}.json") @@ -4075,7 +4162,15 @@ def _nvattest_report_inventory(evidence_dir: Path) -> dict[str, dict[str, Any]]: } -def _support_report_inventory(evidence_dir: Path) -> list[dict[str, Any]]: +def _support_report_inventory( + evidence_dir: Path, + *, + schema_version: int, + schema: RetainedLedgerSchema, +) -> list[dict[str, Any]]: + _ = schema_version + if not retained_ledger_schema_declares_nvattest(schema): + return [] support_dir = evidence_dir / "support" return [ _inventory_entry(path, name=path.name) @@ -4095,11 +4190,17 @@ def _publication_prerequisite_report_inventory( def format_report(report: CandidateReport) -> str: + try: + ledger = read_retained_ledger(report.evidence_dir / "ledger.json") + except LedgerError as exc: + raise DriverError(exc.failures) from None + schema_version, schema = _resolve_driver_retained_ledger_schema(ledger) payload = { "schema_version": 1, "kind": "solstone-release-candidate-report", "verdict": report.heading, "publication_authorization": "local candidate evidence only; not publication authorization", + "retained_ledger_schema_version": schema_version, "version": report.version, "release_dir": CANDIDATE, "evidence_dir": "EVIDENCE", @@ -4108,10 +4209,12 @@ def format_report(report: CandidateReport) -> str: "ledger_sha256": report.ledger_sha256, "bundle_digest": report.bundle_digest, "payload_inventory": _payload_report_inventory(report.release_dir), - "evidence_inventory": _evidence_report_inventory(report.evidence_dir), + "evidence_inventory": _evidence_report_inventory( + report.evidence_dir, + schema_version=schema_version, + schema=schema, + ), "proof_inventory": _proof_report_inventory(report.evidence_dir), - "nvattest_inventory": _nvattest_report_inventory(report.evidence_dir), - "support_inventory": _support_report_inventory(report.evidence_dir), "proof_sha256": { target: report.proof_sha256[target] for target in sorted(report.proof_sha256) @@ -4124,6 +4227,17 @@ def format_report(report: CandidateReport) -> str: _publication_prerequisite_report_inventory(report.evidence_dir) ), } + if retained_ledger_schema_declares_nvattest(schema): + payload["nvattest_inventory"] = _nvattest_report_inventory( + report.evidence_dir, + schema_version=schema_version, + schema=schema, + ) + payload["support_inventory"] = _support_report_inventory( + report.evidence_dir, + schema_version=schema_version, + schema=schema, + ) return canonical_json_bytes(payload).decode("utf-8") @@ -4509,6 +4623,7 @@ def run_recover( ) from None except LedgerError as exc: raise DriverError(exc.failures) from None + schema_version, schema = _resolve_driver_retained_ledger_schema(ledger) selector_failures: list[Failure] = [] if ledger.get("version") != version: selector_failures.append( @@ -4530,8 +4645,13 @@ def run_recover( ) if selector_failures: raise DriverError(selector_failures) + heading = ( + RETAINED_CANDIDATE_VALID_HEADING + if retained_ledger_schema_declares_nvattest(schema) + else RETAINED_PRE_NVATTEST_CANDIDATE_VALID_HEADING + ) return _report( - heading="retained-candidate-valid", + heading=heading, root=root, version=version, source_commit=source_commit, diff --git a/scripts/release_ledger.py b/scripts/release_ledger.py index b4f6adfec..c7cb04232 100644 --- a/scripts/release_ledger.py +++ b/scripts/release_ledger.py @@ -36,19 +36,56 @@ from scripts.release_nvattest_support import validate_support_declarations from scripts.release_public_evidence import validate_public_evidence_tree RELEASE_EVIDENCE_CONTRACT_DOC = "docs/release-evidence-contract.md" -CURRENT_LEDGER_SCHEMA_VERSION = 1 +CURRENT_LEDGER_SCHEMA_VERSION = 2 @dataclass(frozen=True) class RetainedLedgerSchema: top_level_keys: frozenset[str] models_keys: frozenset[str] - nvattest_keys: frozenset[str] + nvattest_keys: frozenset[str] | None policy_run_keys: frozenset[str] LEDGER_SCHEMA_REGISTRY: dict[int, RetainedLedgerSchema] = { 1: RetainedLedgerSchema( + top_level_keys=frozenset( + ( + "schema_version", + "kind", + "product", + "version", + "source_commit", + "candidate", + "models", + "core_lock_sha256", + "rust_targets", + "tool_evidence", + "native_members", + "dependency_policy", + "policy_run", + "native_summary", + "proofs", + "redaction", + ) + ), + models_keys=frozenset(("decision", "package_version")), + nvattest_keys=None, + policy_run_keys=frozenset( + ( + "advisory_source_id", + "db_snapshot_basename", + "db_commit", + "db_archive_sha256", + "advisory_count", + "advisory_acquired_at", + "db_commit_timestamp", + "policy_checked_at", + "result", + ) + ), + ), + 2: RetainedLedgerSchema( top_level_keys=frozenset( ( "schema_version", @@ -87,7 +124,7 @@ LEDGER_SCHEMA_REGISTRY: dict[int, RetainedLedgerSchema] = { "result", ) ), - ) + ), } RETAINED_LEDGER_CONSUMER_TOP_LEVEL_KEYS = frozenset( ("candidate", "core_lock_sha256", "models") @@ -121,6 +158,16 @@ def _current_writer_schema() -> RetainedLedgerSchema: return _registered_ledger_schema(CURRENT_LEDGER_SCHEMA_VERSION) +def current_retained_ledger_schema() -> tuple[int, RetainedLedgerSchema]: + return CURRENT_LEDGER_SCHEMA_VERSION, _current_writer_schema() + + +def retained_ledger_schema_declares_nvattest( + schema: RetainedLedgerSchema, +) -> bool: + return "nvattest" in schema.top_level_keys + + def _resolve_retained_ledger_schema( payload: Mapping[str, Any], ) -> tuple[int | None, RetainedLedgerSchema | None, list[Failure]]: @@ -208,6 +255,17 @@ def _resolve_retained_ledger_schema( return version, schema, [] +def resolve_retained_ledger_schema( + payload: Mapping[str, Any], +) -> tuple[int, RetainedLedgerSchema]: + version, schema, failures = _resolve_retained_ledger_schema(payload) + if failures: + raise LedgerError(failures) + if version is None or schema is None: + raise AssertionError("retained ledger schema resolution returned no schema") + return version, schema + + def _candidate_files(release_dir: Path) -> list[dict[str, Any]]: files: list[dict[str, Any]] = [] for path in sorted( @@ -474,6 +532,17 @@ def validate_nvattest_payload( ) -> list[Failure]: failures: list[Failure] = [] resolved_schema = schema or _current_writer_schema() + if not retained_ledger_schema_declares_nvattest(resolved_schema): + if value is None: + return [] + return [ + _failure( + "retained ledger schema does not declare nvattest", + expected="schema with no nvattest binding", + actual="nvattest present", + repair="python3 scripts/check_rust_release_manifest.py", + ) + ] if not isinstance(value, Mapping): return [ _failure( @@ -483,6 +552,8 @@ def validate_nvattest_payload( repair="python3 scripts/check_rust_release_manifest.py", ) ] + if resolved_schema.nvattest_keys is None: + raise AssertionError("nvattest schema has no declared key set") if set(value) != resolved_schema.nvattest_keys: failures.append( _failure( diff --git a/tests/fixtures/release_evidence/canonical-ledger-v1.json b/tests/fixtures/release_evidence/canonical-ledger-v2.json similarity index 99% rename from tests/fixtures/release_evidence/canonical-ledger-v1.json rename to tests/fixtures/release_evidence/canonical-ledger-v2.json index 65ddff4c2..bb25ceb69 100644 --- a/tests/fixtures/release_evidence/canonical-ledger-v1.json +++ b/tests/fixtures/release_evidence/canonical-ledger-v2.json @@ -1 +1 @@ -{"candidate":{"candidate_digest":"dda18a0e21ae47c53b4309434cbc02ae8bf764fa83a6defbb719431242722aa7","file_count":0,"files":[],"manifest_file_count":0,"package_file_count":0,"path":"dist/release-candidate/1.2.3"},"core_lock_sha256":"dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd","dependency_policy":"allow-empty","kind":"solstone-release-ledger","models":{"decision":"exclude","package_version":"1.0.0"},"native_members":{"linux-aarch64-musl":{"solstone-core":{"bytes":1,"path":"retained/linux-aarch64-musl/solstone-core","sha256":"bf3e3948e53173f3a185538d8e24a4d190c3f8c40e6cba0d9613ae6ee01704b9"}},"linux-x86_64-musl":{"solstone-core":{"bytes":1,"path":"retained/linux-x86_64-musl/solstone-core","sha256":"de312e130e0a3c556e7e2ce94b08e776362f766562b80c8a5fde455b704e9785"}},"macos-arm64":{"parakeet-helper":{"bytes":1,"path":"retained/macos-arm64/parakeet-helper","sha256":"0416a562f93aec529b96673433c05bbb7118cb90ba2acba0559a43bf604584db"},"solstone-core":{"bytes":1,"path":"retained/macos-arm64/solstone-core","sha256":"b9bde111845c5e27c78bd8240a8ffc984e811514b6608a3e433eafa4c4e3027f"}}},"native_summary":{},"nvattest":{"authority":{"schema_version":1,"targets":{"linux-aarch64":{"artifact":{"name":"libnvat-linux-aarch64-1.2.2-sol.2-archive.tar.xz","sha256":"7a13a15192f5005a700dbe154da28cbc2a2b5f3f387113c8cd89a36083a2bd80","size_bytes":7423268,"url":"https://updates.solstone.app/providers/nvattest/libnvat-linux-aarch64-1.2.2-sol.2-archive.tar.xz"},"companion_manifest":{"name":"libnvat-linux-aarch64-1.2.2-sol.2-archive.manifest.json","sha256":"0d46ffdf21a9c5a61370fbf77aed0c275dae93f3609511f4573515a7260ddc39","url":"https://updates.solstone.app/providers/nvattest/libnvat-linux-aarch64-1.2.2-sol.2-archive.manifest.json"},"inventory":[{"executable":true,"kind":"regular","relpath":"bin/nvattest","symlink_target":null},{"executable":false,"kind":"regular","relpath":"lib/libnvat.so.1.2.2","symlink_target":null},{"executable":false,"kind":"symlink","relpath":"lib/libnvat.so.1","symlink_target":"libnvat.so.1.2.2"},{"executable":false,"kind":"symlink","relpath":"lib/libnvat.so","symlink_target":"libnvat.so.1"},{"executable":false,"kind":"regular","relpath":"LICENSE","symlink_target":null},{"executable":false,"kind":"regular","relpath":"share/ca/ca-bundle.pem","symlink_target":null},{"executable":false,"kind":"regular","relpath":"share/THIRD_PARTY_NOTICES.md","symlink_target":null}],"source":{"fork_commit":"1c95b1f5ae72b5f4282f7b6b96722f7c8d69f744","upstream_base":"73c032ebff680ca6d2ba06f4006b511491b71ce9","url_prefix":"https://updates.solstone.app/providers/nvattest/","version":"1.2.2-sol.2"}},"linux-x86_64":{"artifact":{"name":"libnvat-linux-x86_64-1.2.2-sol.2-archive.tar.xz","sha256":"3e2d207a3bb6eab9c47fc9cf65d7990f0d11541ff8691dce18e786e2ce9b26c7","size_bytes":7655628,"url":"https://updates.solstone.app/providers/nvattest/libnvat-linux-x86_64-1.2.2-sol.2-archive.tar.xz"},"companion_manifest":{"name":"libnvat-linux-x86_64-1.2.2-sol.2-archive.manifest.json","sha256":"a013d18a74d89f3ee99a0a3648c582df08446a30f5b8f5bbb48929a08fad4a8f","url":"https://updates.solstone.app/providers/nvattest/libnvat-linux-x86_64-1.2.2-sol.2-archive.manifest.json"},"inventory":[{"executable":true,"kind":"regular","relpath":"bin/nvattest","symlink_target":null},{"executable":false,"kind":"regular","relpath":"lib/libnvat.so.1.2.2","symlink_target":null},{"executable":false,"kind":"symlink","relpath":"lib/libnvat.so.1","symlink_target":"libnvat.so.1.2.2"},{"executable":false,"kind":"symlink","relpath":"lib/libnvat.so","symlink_target":"libnvat.so.1"},{"executable":false,"kind":"regular","relpath":"LICENSE","symlink_target":null},{"executable":false,"kind":"regular","relpath":"share/ca/ca-bundle.pem","symlink_target":null},{"executable":false,"kind":"regular","relpath":"share/THIRD_PARTY_NOTICES.md","symlink_target":null}],"source":{"fork_commit":"1c95b1f5ae72b5f4282f7b6b96722f7c8d69f744","upstream_base":"73c032ebff680ca6d2ba06f4006b511491b71ce9","url_prefix":"https://updates.solstone.app/providers/nvattest/","version":"1.2.2-sol.2"}},"macos-arm64":{"artifact":{"name":"libnvat-macos-arm64-1.2.2-sol.2-archive.tar.xz","sha256":"f2b01f60ee52f9c38c9e5e0f3cea6e8078a1efa165fad1f5c59994563120e365","size_bytes":5848264,"url":"https://updates.solstone.app/providers/nvattest/libnvat-macos-arm64-1.2.2-sol.2-archive.tar.xz"},"companion_manifest":{"name":"libnvat-macos-arm64-1.2.2-sol.2-archive.manifest.json","sha256":"dca5342f87bba1244f8ee78848207410ae5ee8976df42fe10d804f1c99167094","url":"https://updates.solstone.app/providers/nvattest/libnvat-macos-arm64-1.2.2-sol.2-archive.manifest.json"},"inventory":[{"executable":true,"kind":"regular","relpath":"bin/nvattest","symlink_target":null},{"executable":false,"kind":"regular","relpath":"lib/libnvat.1.2.2.dylib","symlink_target":null},{"executable":false,"kind":"symlink","relpath":"lib/libnvat.1.dylib","symlink_target":"libnvat.1.2.2.dylib"},{"executable":false,"kind":"symlink","relpath":"lib/libnvat.dylib","symlink_target":"libnvat.1.dylib"},{"executable":false,"kind":"regular","relpath":"LICENSE","symlink_target":null},{"executable":false,"kind":"regular","relpath":"share/ca/ca-bundle.pem","symlink_target":null},{"executable":false,"kind":"regular","relpath":"share/THIRD_PARTY_NOTICES.md","symlink_target":null}],"source":{"fork_commit":"1c95b1f5ae72b5f4282f7b6b96722f7c8d69f744","upstream_base":"73c032ebff680ca6d2ba06f4006b511491b71ce9","url_prefix":"https://updates.solstone.app/providers/nvattest/","version":"1.2.2-sol.2"}}}},"authority_sha256":"1ab5173e69a11bf6a3d0e9abe27954608a34a70f09c2b940d842a761a764e766","challenge":"2dd00bd77e0222ced882665481a9c1d9f907309d16e05ed007a1ea63928477a9","support_distributions":[{"bytes":5,"filename":"anyio-0.0.1-py3-none-any.whl","name":"anyio","sha256":"d07ebf7465b4aa3ee99060bc5b1347bd3a913a761c1534fdba3b8f844fd80a68","version":"0.0.1"},{"bytes":7,"filename":"certifi-0.0.2-py3-none-any.whl","name":"certifi","sha256":"78ae46fa5d1c2657327d889cd418990b92a9aa17b75f90197bf0aaff6d336c26","version":"0.0.2"},{"bytes":3,"filename":"h11-0.0.3-py3-none-any.whl","name":"h11","sha256":"973b98d4ef3aac8c991d5d027837c3c6767ec05ebe20e5c49c03d8dde588de88","version":"0.0.3"},{"bytes":8,"filename":"httpcore-0.0.4-py3-none-any.whl","name":"httpcore","sha256":"682c636f44bfc33ca376792c4acb9246df32daaf83d29a1704f1a066a14517bb","version":"0.0.4"},{"bytes":5,"filename":"httpx-0.0.5-py3-none-any.whl","name":"httpx","sha256":"44c3f6f83c39094fec0db8b7f158d0a8fad3418e77f5f739b103e1ac73eee5d8","version":"0.0.5"},{"bytes":4,"filename":"idna-0.0.6-py3-none-any.whl","name":"idna","sha256":"de30d2f3e9e48193e55188b7fece1776250f00f27d96c279c7e6afbf35b461e1","version":"0.0.6"},{"bytes":7,"filename":"sniffio-0.0.7-py3-none-any.whl","name":"sniffio","sha256":"2fec9baed119969292cf56bb1944072f0a857abcfa0dbd8ffb5ca008a750e17a","version":"0.0.7"},{"bytes":17,"filename":"typing_extensions-0.0.8-py3-none-any.whl","name":"typing-extensions","sha256":"c46d4553c50cd8e4ec8727d4a7de0334894f1b44776821716d4e5bc7a10eeecc","version":"0.0.8"}]},"policy_run":{"advisory_acquired_at":"2026-07-20T11:00:00Z","advisory_count":1,"advisory_source_id":"internal","db_archive_sha256":"cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc","db_commit":"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb","db_commit_timestamp":"2026-07-19T12:00:00Z","db_snapshot_basename":"advisory-db-fixture00000000","policy_checked_at":"2026-07-20T12:00:00Z","result":"pass"},"product":"solstone","proofs":{"expected_targets":["linux-x86_64-musl","linux-aarch64-musl","macos-arm64"]},"redaction":{"validator":"recursive-key-value-public-evidence"},"rust_targets":[],"schema_version":1,"source_commit":"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","tool_evidence":{"linux-aarch64-musl":{"cargo":"cargo 1.97.1 (c980f4866 2026-06-30)","cargo-deny":"cargo-deny 0.20.2","maturin":"maturin 1.14.1","python":"3.14.3","rustc":"rustc 1.97.1 (8bab26f4f 2026-07-14)","uv":"uv 0.11.4 (x86_64-unknown-linux-gnu)","zig":"zig 0.16.0"},"linux-x86_64-musl":{"cargo":"cargo 1.97.1 (c980f4866 2026-06-30)","cargo-deny":"cargo-deny 0.20.2","maturin":"maturin 1.14.1","python":"3.14.3","rustc":"rustc 1.97.1 (8bab26f4f 2026-07-14)","uv":"uv 0.11.4 (x86_64-unknown-linux-gnu)","zig":"zig 0.16.0"},"macos-arm64":{"cargo":"cargo 1.97.1 (c980f4866 2026-06-30)","cargo-deny":"cargo-deny 0.20.2","codesign":"codesign pinned-path verified","maturin":"maturin 1.14.1","notarytool":"1.1.2 (41)","python":"3.14.6","rustc":"rustc 1.97.1 (8bab26f4f 2026-07-14)","signing_mode":"signed-verified","swift":"swift-driver version: 1.148.6 Apple Swift version 6.3.3 (swiftlang-6.3.3.1.3 clang-2100.1.1.101)","uv":"uv 0.11.4 (Homebrew 2026-04-08 aarch64-apple-darwin)","xcode":"xcode 26.6 build 17F113"},"source":{"cargo":"cargo 1.97.1 (c980f4866 2026-06-30)","cargo-deny":"cargo-deny 0.20.2","maturin":"maturin 1.14.1","python":"3.14.3","rustc":"rustc 1.97.1 (8bab26f4f 2026-07-14)","uv":"uv 0.11.4 (x86_64-unknown-linux-gnu)"}},"version":"1.2.3"} +{"candidate":{"candidate_digest":"dda18a0e21ae47c53b4309434cbc02ae8bf764fa83a6defbb719431242722aa7","file_count":0,"files":[],"manifest_file_count":0,"package_file_count":0,"path":"dist/release-candidate/1.2.3"},"core_lock_sha256":"dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd","dependency_policy":"allow-empty","kind":"solstone-release-ledger","models":{"decision":"exclude","package_version":"1.0.0"},"native_members":{"linux-aarch64-musl":{"solstone-core":{"bytes":1,"path":"retained/linux-aarch64-musl/solstone-core","sha256":"bf3e3948e53173f3a185538d8e24a4d190c3f8c40e6cba0d9613ae6ee01704b9"}},"linux-x86_64-musl":{"solstone-core":{"bytes":1,"path":"retained/linux-x86_64-musl/solstone-core","sha256":"de312e130e0a3c556e7e2ce94b08e776362f766562b80c8a5fde455b704e9785"}},"macos-arm64":{"parakeet-helper":{"bytes":1,"path":"retained/macos-arm64/parakeet-helper","sha256":"0416a562f93aec529b96673433c05bbb7118cb90ba2acba0559a43bf604584db"},"solstone-core":{"bytes":1,"path":"retained/macos-arm64/solstone-core","sha256":"b9bde111845c5e27c78bd8240a8ffc984e811514b6608a3e433eafa4c4e3027f"}}},"native_summary":{},"nvattest":{"authority":{"schema_version":1,"targets":{"linux-aarch64":{"artifact":{"name":"libnvat-linux-aarch64-1.2.2-sol.2-archive.tar.xz","sha256":"7a13a15192f5005a700dbe154da28cbc2a2b5f3f387113c8cd89a36083a2bd80","size_bytes":7423268,"url":"https://updates.solstone.app/providers/nvattest/libnvat-linux-aarch64-1.2.2-sol.2-archive.tar.xz"},"companion_manifest":{"name":"libnvat-linux-aarch64-1.2.2-sol.2-archive.manifest.json","sha256":"0d46ffdf21a9c5a61370fbf77aed0c275dae93f3609511f4573515a7260ddc39","url":"https://updates.solstone.app/providers/nvattest/libnvat-linux-aarch64-1.2.2-sol.2-archive.manifest.json"},"inventory":[{"executable":true,"kind":"regular","relpath":"bin/nvattest","symlink_target":null},{"executable":false,"kind":"regular","relpath":"lib/libnvat.so.1.2.2","symlink_target":null},{"executable":false,"kind":"symlink","relpath":"lib/libnvat.so.1","symlink_target":"libnvat.so.1.2.2"},{"executable":false,"kind":"symlink","relpath":"lib/libnvat.so","symlink_target":"libnvat.so.1"},{"executable":false,"kind":"regular","relpath":"LICENSE","symlink_target":null},{"executable":false,"kind":"regular","relpath":"share/ca/ca-bundle.pem","symlink_target":null},{"executable":false,"kind":"regular","relpath":"share/THIRD_PARTY_NOTICES.md","symlink_target":null}],"source":{"fork_commit":"1c95b1f5ae72b5f4282f7b6b96722f7c8d69f744","upstream_base":"73c032ebff680ca6d2ba06f4006b511491b71ce9","url_prefix":"https://updates.solstone.app/providers/nvattest/","version":"1.2.2-sol.2"}},"linux-x86_64":{"artifact":{"name":"libnvat-linux-x86_64-1.2.2-sol.2-archive.tar.xz","sha256":"3e2d207a3bb6eab9c47fc9cf65d7990f0d11541ff8691dce18e786e2ce9b26c7","size_bytes":7655628,"url":"https://updates.solstone.app/providers/nvattest/libnvat-linux-x86_64-1.2.2-sol.2-archive.tar.xz"},"companion_manifest":{"name":"libnvat-linux-x86_64-1.2.2-sol.2-archive.manifest.json","sha256":"a013d18a74d89f3ee99a0a3648c582df08446a30f5b8f5bbb48929a08fad4a8f","url":"https://updates.solstone.app/providers/nvattest/libnvat-linux-x86_64-1.2.2-sol.2-archive.manifest.json"},"inventory":[{"executable":true,"kind":"regular","relpath":"bin/nvattest","symlink_target":null},{"executable":false,"kind":"regular","relpath":"lib/libnvat.so.1.2.2","symlink_target":null},{"executable":false,"kind":"symlink","relpath":"lib/libnvat.so.1","symlink_target":"libnvat.so.1.2.2"},{"executable":false,"kind":"symlink","relpath":"lib/libnvat.so","symlink_target":"libnvat.so.1"},{"executable":false,"kind":"regular","relpath":"LICENSE","symlink_target":null},{"executable":false,"kind":"regular","relpath":"share/ca/ca-bundle.pem","symlink_target":null},{"executable":false,"kind":"regular","relpath":"share/THIRD_PARTY_NOTICES.md","symlink_target":null}],"source":{"fork_commit":"1c95b1f5ae72b5f4282f7b6b96722f7c8d69f744","upstream_base":"73c032ebff680ca6d2ba06f4006b511491b71ce9","url_prefix":"https://updates.solstone.app/providers/nvattest/","version":"1.2.2-sol.2"}},"macos-arm64":{"artifact":{"name":"libnvat-macos-arm64-1.2.2-sol.2-archive.tar.xz","sha256":"f2b01f60ee52f9c38c9e5e0f3cea6e8078a1efa165fad1f5c59994563120e365","size_bytes":5848264,"url":"https://updates.solstone.app/providers/nvattest/libnvat-macos-arm64-1.2.2-sol.2-archive.tar.xz"},"companion_manifest":{"name":"libnvat-macos-arm64-1.2.2-sol.2-archive.manifest.json","sha256":"dca5342f87bba1244f8ee78848207410ae5ee8976df42fe10d804f1c99167094","url":"https://updates.solstone.app/providers/nvattest/libnvat-macos-arm64-1.2.2-sol.2-archive.manifest.json"},"inventory":[{"executable":true,"kind":"regular","relpath":"bin/nvattest","symlink_target":null},{"executable":false,"kind":"regular","relpath":"lib/libnvat.1.2.2.dylib","symlink_target":null},{"executable":false,"kind":"symlink","relpath":"lib/libnvat.1.dylib","symlink_target":"libnvat.1.2.2.dylib"},{"executable":false,"kind":"symlink","relpath":"lib/libnvat.dylib","symlink_target":"libnvat.1.dylib"},{"executable":false,"kind":"regular","relpath":"LICENSE","symlink_target":null},{"executable":false,"kind":"regular","relpath":"share/ca/ca-bundle.pem","symlink_target":null},{"executable":false,"kind":"regular","relpath":"share/THIRD_PARTY_NOTICES.md","symlink_target":null}],"source":{"fork_commit":"1c95b1f5ae72b5f4282f7b6b96722f7c8d69f744","upstream_base":"73c032ebff680ca6d2ba06f4006b511491b71ce9","url_prefix":"https://updates.solstone.app/providers/nvattest/","version":"1.2.2-sol.2"}}}},"authority_sha256":"1ab5173e69a11bf6a3d0e9abe27954608a34a70f09c2b940d842a761a764e766","challenge":"2dd00bd77e0222ced882665481a9c1d9f907309d16e05ed007a1ea63928477a9","support_distributions":[{"bytes":5,"filename":"anyio-0.0.1-py3-none-any.whl","name":"anyio","sha256":"d07ebf7465b4aa3ee99060bc5b1347bd3a913a761c1534fdba3b8f844fd80a68","version":"0.0.1"},{"bytes":7,"filename":"certifi-0.0.2-py3-none-any.whl","name":"certifi","sha256":"78ae46fa5d1c2657327d889cd418990b92a9aa17b75f90197bf0aaff6d336c26","version":"0.0.2"},{"bytes":3,"filename":"h11-0.0.3-py3-none-any.whl","name":"h11","sha256":"973b98d4ef3aac8c991d5d027837c3c6767ec05ebe20e5c49c03d8dde588de88","version":"0.0.3"},{"bytes":8,"filename":"httpcore-0.0.4-py3-none-any.whl","name":"httpcore","sha256":"682c636f44bfc33ca376792c4acb9246df32daaf83d29a1704f1a066a14517bb","version":"0.0.4"},{"bytes":5,"filename":"httpx-0.0.5-py3-none-any.whl","name":"httpx","sha256":"44c3f6f83c39094fec0db8b7f158d0a8fad3418e77f5f739b103e1ac73eee5d8","version":"0.0.5"},{"bytes":4,"filename":"idna-0.0.6-py3-none-any.whl","name":"idna","sha256":"de30d2f3e9e48193e55188b7fece1776250f00f27d96c279c7e6afbf35b461e1","version":"0.0.6"},{"bytes":7,"filename":"sniffio-0.0.7-py3-none-any.whl","name":"sniffio","sha256":"2fec9baed119969292cf56bb1944072f0a857abcfa0dbd8ffb5ca008a750e17a","version":"0.0.7"},{"bytes":17,"filename":"typing_extensions-0.0.8-py3-none-any.whl","name":"typing-extensions","sha256":"c46d4553c50cd8e4ec8727d4a7de0334894f1b44776821716d4e5bc7a10eeecc","version":"0.0.8"}]},"policy_run":{"advisory_acquired_at":"2026-07-20T11:00:00Z","advisory_count":1,"advisory_source_id":"internal","db_archive_sha256":"cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc","db_commit":"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb","db_commit_timestamp":"2026-07-19T12:00:00Z","db_snapshot_basename":"advisory-db-fixture00000000","policy_checked_at":"2026-07-20T12:00:00Z","result":"pass"},"product":"solstone","proofs":{"expected_targets":["linux-x86_64-musl","linux-aarch64-musl","macos-arm64"]},"redaction":{"validator":"recursive-key-value-public-evidence"},"rust_targets":[],"schema_version":2,"source_commit":"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","tool_evidence":{"linux-aarch64-musl":{"cargo":"cargo 1.97.1 (c980f4866 2026-06-30)","cargo-deny":"cargo-deny 0.20.2","maturin":"maturin 1.14.1","python":"3.14.3","rustc":"rustc 1.97.1 (8bab26f4f 2026-07-14)","uv":"uv 0.11.4 (x86_64-unknown-linux-gnu)","zig":"zig 0.16.0"},"linux-x86_64-musl":{"cargo":"cargo 1.97.1 (c980f4866 2026-06-30)","cargo-deny":"cargo-deny 0.20.2","maturin":"maturin 1.14.1","python":"3.14.3","rustc":"rustc 1.97.1 (8bab26f4f 2026-07-14)","uv":"uv 0.11.4 (x86_64-unknown-linux-gnu)","zig":"zig 0.16.0"},"macos-arm64":{"cargo":"cargo 1.97.1 (c980f4866 2026-06-30)","cargo-deny":"cargo-deny 0.20.2","codesign":"codesign pinned-path verified","maturin":"maturin 1.14.1","notarytool":"1.1.2 (41)","python":"3.14.6","rustc":"rustc 1.97.1 (8bab26f4f 2026-07-14)","signing_mode":"signed-verified","swift":"swift-driver version: 1.148.6 Apple Swift version 6.3.3 (swiftlang-6.3.3.1.3 clang-2100.1.1.101)","uv":"uv 0.11.4 (Homebrew 2026-04-08 aarch64-apple-darwin)","xcode":"xcode 26.6 build 17F113"},"source":{"cargo":"cargo 1.97.1 (c980f4866 2026-06-30)","cargo-deny":"cargo-deny 0.20.2","maturin":"maturin 1.14.1","python":"3.14.3","rustc":"rustc 1.97.1 (8bab26f4f 2026-07-14)","uv":"uv 0.11.4 (x86_64-unknown-linux-gnu)"}},"version":"1.2.3"}