Bind installed releases to signed artifact receipts

This commit is contained in:
2026-07-22 20:42:05 +02:00
parent 4dc0c8d013
commit 9c0650b2ed
13 changed files with 2179 additions and 52 deletions

View File

@@ -105,6 +105,31 @@ def parse_args(argv: list[str] | None = None) -> argparse.Namespace:
type=Path,
default=META_ROOT / "docs" / "installed-composition-evidence.schema.json",
)
parser.add_argument(
"--installer-receipt",
type=Path,
help="Signed installer receipt binding installed payloads to this catalog.",
)
parser.add_argument(
"--installer-receipt-schema",
type=Path,
default=META_ROOT / "docs" / "installer-receipt.schema.json",
)
parser.add_argument(
"--installer-authority-keyring",
type=Path,
help=(
"Independently provisioned, role-scoped trust root for installer "
"receipt signatures."
),
)
parser.add_argument(
"--installer-authority-keyring-schema",
type=Path,
default=META_ROOT
/ "docs"
/ "installer-receipt-authority-keyring.schema.json",
)
parser.add_argument(
"--boundary-evidence",
type=Path,
@@ -165,6 +190,18 @@ def main(argv: list[str] | None = None) -> int:
raise SystemExit(
"--boundary-evidence and --boundary-authority-keyring are required together"
)
if (args.installer_receipt is None) != (
args.installer_authority_keyring is None
):
raise SystemExit(
"--installer-receipt and --installer-authority-keyring are required together"
)
if args.installer_receipt is not None and (
args.installed_evidence is None and args.collect_installed_evidence is None
):
raise SystemExit(
"--installer-receipt requires --installed-evidence or --collect-installed-evidence"
)
if args.boundary_evidence is not None and (
args.installed_evidence is None and args.collect_installed_evidence is None
):
@@ -286,6 +323,32 @@ def main(argv: list[str] | None = None) -> int:
max_bytes=MAX_EVIDENCE_INPUT_BYTES,
)
installer_receipt = None
installer_receipt_schema = None
installer_authority_keyring = None
installer_authority_keyring_schema = None
if args.installer_receipt is not None:
installer_receipt = read_object(
args.installer_receipt,
label="installer receipt",
max_bytes=MAX_EVIDENCE_INPUT_BYTES,
)
installer_receipt_schema = read_object(
args.installer_receipt_schema,
label="installer receipt schema",
max_bytes=MAX_EVIDENCE_INPUT_BYTES,
)
installer_authority_keyring = read_object(
args.installer_authority_keyring,
label="installer authority keyring",
max_bytes=MAX_EVIDENCE_INPUT_BYTES,
)
installer_authority_keyring_schema = read_object(
args.installer_authority_keyring_schema,
label="installer authority keyring schema",
max_bytes=MAX_EVIDENCE_INPUT_BYTES,
)
verification_time = parse_datetime(args.verification_time)
report = review_capability_fit(
assessment=assessment,
@@ -298,6 +361,10 @@ def main(argv: list[str] | None = None) -> int:
else args.workspace_root.resolve(),
installed_evidence=installed_evidence,
installed_evidence_schema=installed_evidence_schema,
installer_receipt=installer_receipt,
installer_receipt_schema=installer_receipt_schema,
installer_authority_keyring=installer_authority_keyring,
installer_authority_keyring_schema=installer_authority_keyring_schema,
boundary_evidence=boundary_evidence,
boundary_evidence_schema=boundary_evidence_schema,
boundary_authority_keyring=boundary_authority_keyring,

View File

@@ -59,6 +59,10 @@ def review_capability_fit(
workspace_root: Path | None = None,
installed_evidence: dict[str, Any] | None = None,
installed_evidence_schema: dict[str, Any] | None = None,
installer_receipt: dict[str, Any] | None = None,
installer_receipt_schema: dict[str, Any] | None = None,
installer_authority_keyring: dict[str, Any] | None = None,
installer_authority_keyring_schema: dict[str, Any] | None = None,
boundary_evidence: dict[str, Any] | None = None,
boundary_evidence_schema: dict[str, Any] | None = None,
boundary_authority_keyring: dict[str, Any] | None = None,
@@ -377,6 +381,24 @@ def review_capability_fit(
verification_time=evidence_verification_time,
verification_mode=evidence_verification_mode,
catalog_trusted=catalog_dependency_trusted,
catalog_artifacts=(
catalog.get("release", {}).get("artifacts")
if isinstance(catalog.get("release"), dict)
and "artifacts" in catalog.get("release", {})
else None
),
catalog_sha256=canonical_hash(catalog),
catalog_channel=_text(catalog.get("channel")),
catalog_sequence=_integer(catalog.get("sequence")),
installer_receipt=installer_receipt,
installer_receipt_schema=installer_receipt_schema,
installer_authority_keyring=installer_authority_keyring,
installer_authority_keyring_schema=installer_authority_keyring_schema,
forbidden_installer_public_keys=public_key_material_from_keyrings(
published_keyring,
trusted_keyring,
boundary_authority_keyring or {},
),
)
findings.extend(
Finding(item.severity, item.code, item.message, item.assessment_ids)
@@ -398,6 +420,7 @@ def review_capability_fit(
forbidden_authority_public_keys=public_key_material_from_keyrings(
published_keyring,
trusted_keyring,
installer_authority_keyring or {},
),
)
findings.extend(
@@ -939,7 +962,7 @@ def build_report(
**boundary_scope,
}
return {
"report_version": "0.4.0",
"report_version": "0.5.0",
"status": status,
"assessment_id": assessment.get("assessment_id"),
"assessment_release": assessment.get("release", {}).get("ref")
@@ -977,7 +1000,11 @@ def render_review(report: dict[str, Any]) -> str:
(
"Scope: schema, signed release metadata, optional local tag provenance, "
+ (
"and locally observed installed-composition consistency evidence; release origin remains a separate proof boundary."
(
"and locally observed installed-composition evidence independently bound to signed release origin."
if release_origin_checked
else "and locally observed installed-composition consistency evidence; release origin remains a separate proof boundary."
)
if installed_checked
else (
"and supplied installed-composition evidence that did not establish local proof."

View File

@@ -25,6 +25,12 @@ from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PublicKey
from jsonschema import Draft202012Validator, FormatChecker
from jsonschema.exceptions import SchemaError
from govoplan_release.artifact_identity import (
INSTALLED_PAYLOAD_ALGORITHM,
WHEEL_PAYLOAD_ALGORITHM,
payload_identity_sha256,
)
MAX_GOVOPLAN_DISTRIBUTIONS = 256
MAX_DISTRIBUTION_FILES = 10_000
@@ -243,7 +249,7 @@ def collect_installed_composition(
sorted_issues.sort(key=lambda item: (item["package_name"], item["code"]))
return {
"$schema": "./installed-composition-evidence.schema.json",
"schema_version": "0.3.0",
"schema_version": "0.4.0",
"evidence_kind": "govoplan.installed-composition",
"assessment_id": _safe_opaque_id(
assessment.get("assessment_id"), fallback="invalid-assessment"
@@ -277,6 +283,15 @@ def review_installed_composition(
verification_time: datetime | None = None,
verification_mode: str = "current",
catalog_trusted: bool = False,
catalog_artifacts: object = None,
catalog_sha256: str | None = None,
catalog_channel: str | None = None,
catalog_sequence: int | None = None,
installer_receipt: dict[str, Any] | None = None,
installer_receipt_schema: dict[str, Any] | None = None,
installer_authority_keyring: dict[str, Any] | None = None,
installer_authority_keyring_schema: dict[str, Any] | None = None,
forbidden_installer_public_keys: frozenset[bytes] = frozenset(),
) -> InstalledEvidenceReview:
if evidence is None:
return InstalledEvidenceReview(
@@ -403,14 +418,6 @@ def review_installed_composition(
observation_trusted = True
elif effective_observation_mode == "imported_unsigned":
freshness = "unsigned_import"
findings.append(
EvidenceFinding(
"blocker",
"installed_evidence_unsigned_import",
"Imported unsigned installed evidence may be compared but cannot establish installed proof.",
("assessment.installed_composition",),
)
)
if effective_verification_mode == "invalid":
observation_trusted = False
if catalog_trusted is not True:
@@ -528,7 +535,7 @@ def review_installed_composition(
provenance_declared_match = 0
provenance_mutable = 0
provenance_unanchored = 0
artifact_valid = binding_valid and not duplicate_packages
payload_consistent = binding_valid and not duplicate_packages
for package_name, (component, catalog_entry) in sorted(expected_by_package.items()):
module_id = str(component["module_id"])
@@ -537,7 +544,7 @@ def review_installed_composition(
record_expected += 1
provenance_expected += 1
if package_name in duplicate_packages:
artifact_valid = False
payload_consistent = False
_record_change(
findings=findings,
changes=changes,
@@ -550,7 +557,7 @@ def review_installed_composition(
)
continue
if artifact is None:
artifact_valid = False
payload_consistent = False
_record_change(
findings=findings,
changes=changes,
@@ -567,7 +574,7 @@ def review_installed_composition(
package_version = str(artifact.get("package_version") or "")
catalog_version = str(catalog_entry.get("version") or "")
if package_version != expected_version or package_version != catalog_version:
artifact_valid = False
payload_consistent = False
_record_change(
findings=findings,
changes=changes,
@@ -606,7 +613,7 @@ def review_installed_composition(
and str(expected_manifest.get("manifest_version") or "") != expected_version
)
if manifest_mismatch:
artifact_valid = False
payload_consistent = False
_record_change(
findings=findings,
changes=changes,
@@ -619,7 +626,7 @@ def review_installed_composition(
)
unexpected_modules = sorted(set(module_rows) - {module_id})
if duplicate_module_ids or unexpected_modules:
artifact_valid = False
payload_consistent = False
_record_change(
findings=findings,
changes=changes,
@@ -647,7 +654,7 @@ def review_installed_composition(
if record_status == "verified" and record_semantics_valid:
record_verified += 1
else:
artifact_valid = False
payload_consistent = False
_record_change(
findings=findings,
changes=changes,
@@ -676,7 +683,6 @@ def review_installed_composition(
str(provenance.get("basis") or "") if isinstance(provenance, dict) else ""
)
if provenance_basis != "local-pep610-metadata":
artifact_valid = False
provenance_unanchored += 1
_record_change(
findings=findings,
@@ -703,7 +709,6 @@ def review_installed_composition(
if commit_matches and selected_matches:
provenance_declared_match += 1
else:
artifact_valid = False
_record_change(
findings=findings,
changes=changes,
@@ -716,7 +721,6 @@ def review_installed_composition(
)
elif provenance_kind in {"editable-vcs", "editable-local", "local-directory"}:
provenance_mutable += 1
artifact_valid = False
_record_change(
findings=findings,
changes=changes,
@@ -729,7 +733,6 @@ def review_installed_composition(
)
else:
provenance_unanchored += 1
artifact_valid = False
_record_change(
findings=findings,
changes=changes,
@@ -743,7 +746,7 @@ def review_installed_composition(
expected_packages = set(expected_by_package)
for package_name in sorted(set(artifacts_by_package) - expected_packages):
artifact_valid = False
payload_consistent = False
matching_module_id = next(
(
module_id
@@ -788,7 +791,7 @@ def review_installed_composition(
continue
package_name = str(issue.get("package_name") or "")
code = str(issue.get("code") or "")
artifact_valid = False
payload_consistent = False
findings.append(
EvidenceFinding(
"review",
@@ -801,18 +804,68 @@ def review_installed_composition(
exact_set = (
set(artifacts_by_package) == expected_packages and not duplicate_packages
)
installed_checked = observation_trusted
origin_scope, origin_findings = _review_installed_release_origin(
expected_by_package=expected_by_package,
installed_artifacts=artifacts_by_package,
installed_evidence=evidence,
installed_evidence_sha256=digest,
installed_composition_valid=(
binding_valid
and exact_set
and payload_consistent
and record_verified == record_expected
and record_expected > 0
),
observation_trusted=observation_trusted,
catalog_artifacts=catalog_artifacts,
catalog_sha256=catalog_sha256,
catalog_channel=catalog_channel,
catalog_sequence=catalog_sequence,
catalog_trusted=catalog_trusted,
receipt=installer_receipt,
receipt_schema=installer_receipt_schema,
authority_keyring=installer_authority_keyring,
authority_keyring_schema=installer_authority_keyring_schema,
verification_time=now,
forbidden_public_keys=forbidden_installer_public_keys,
)
findings.extend(origin_findings)
receipt_authenticated = (
origin_scope.get("valid") is True
and origin_scope.get("signed_installer_receipt_count") == record_expected
and record_expected > 0
)
effective_observation_trusted = observation_trusted or receipt_authenticated
if (
effective_observation_mode == "imported_unsigned"
and not receipt_authenticated
):
findings.append(
EvidenceFinding(
"blocker",
"installed_evidence_unsigned_import",
"Imported installed evidence requires a valid independent installer receipt before it can establish installed proof.",
("assessment.installed_composition",),
)
)
installed_checked = effective_observation_trusted
record_checked = (
observation_trusted and binding_valid and exact_set and record_expected > 0
effective_observation_trusted
and binding_valid
and exact_set
and record_expected > 0
)
provenance_checked = (
observation_trusted and binding_valid and exact_set and provenance_expected > 0
effective_observation_trusted
and binding_valid
and exact_set
and provenance_expected > 0
)
proof_scope = {
"installed_artifacts": {
"checked": installed_checked,
"valid": artifact_valid if installed_checked else None,
"comparison_valid": artifact_valid,
"valid": payload_consistent if installed_checked else None,
"comparison_valid": payload_consistent,
"evidence_sha256": digest,
"expected_distribution_count": len(expected_packages),
"observed_distribution_count": len(artifact_rows),
@@ -836,16 +889,7 @@ def review_installed_composition(
"expected_distribution_count": provenance_expected,
"release_origin_bound": False,
},
"installed_release_origin": {
"checked": False,
"valid": None,
"release_origin_bound": False,
"anchored_artifact_digest_count": 0,
"expected_distribution_count": provenance_expected,
"required_evidence": (
"An independently anchored artifact digest or signed installer receipt that binds each installed payload to the signed release catalog.",
),
},
"installed_release_origin": origin_scope,
"runtime_activation": {
"checked": False,
"valid": None,
@@ -861,6 +905,7 @@ def review_installed_composition(
"evaluated_at": _iso_datetime(now),
"verification_mode": effective_verification_mode,
"catalog_trusted": catalog_trusted is True,
"receipt_authenticated": receipt_authenticated,
"freshness_window_seconds": int(MAX_LOCAL_OBSERVATION_AGE.total_seconds()),
},
}
@@ -874,6 +919,489 @@ def review_installed_composition(
)
def _review_installed_release_origin(
*,
expected_by_package: Mapping[str, tuple[dict[str, Any], Mapping[str, Any]]],
installed_artifacts: Mapping[str, dict[str, Any]],
installed_evidence: dict[str, Any],
installed_evidence_sha256: str,
installed_composition_valid: bool,
observation_trusted: bool,
catalog_artifacts: object,
catalog_sha256: str | None,
catalog_channel: str | None,
catalog_sequence: int | None,
catalog_trusted: bool,
receipt: dict[str, Any] | None,
receipt_schema: dict[str, Any] | None,
authority_keyring: dict[str, Any] | None,
authority_keyring_schema: dict[str, Any] | None,
verification_time: datetime,
forbidden_public_keys: frozenset[bytes],
) -> tuple[dict[str, Any], tuple[EvidenceFinding, ...]]:
findings: list[EvidenceFinding] = []
expected_count = len(expected_by_package)
scope: dict[str, Any] = {
"checked": False,
"valid": None,
"release_origin_bound": False,
"anchored_artifact_digest_count": 0,
"signed_installer_receipt_count": 0,
"expected_distribution_count": expected_count,
"catalog_sha256": catalog_sha256,
"installer_receipt_sha256": None,
"required_evidence": (
"A signed catalog identity computed from each built immutable artifact, or a role-scoped installer receipt signed by an independently provisioned authority.",
),
}
manifest_supplied = catalog_artifacts is not None
receipt_supplied = receipt is not None
if not manifest_supplied and not receipt_supplied:
return scope, ()
scope["checked"] = True
scope["valid"] = False
if not installed_composition_valid or catalog_trusted is not True:
findings.append(
EvidenceFinding(
"blocker",
"installed_origin_dependency_untrusted",
"Installed release-origin proof requires a trusted catalog and valid fresh installed-composition evidence.",
("assessment.release", "assessment.installed_composition"),
)
)
return scope, tuple(findings)
catalog_by_package, catalog_findings = _catalog_artifact_identities(
catalog_artifacts
)
findings.extend(catalog_findings)
if catalog_findings:
return scope, tuple(findings)
direct_bound: set[str] = set()
receipt_required: set[str] = set()
for package_name, (component, catalog_entry) in sorted(expected_by_package.items()):
expected_version = str(catalog_entry.get("version") or "")
identity = catalog_by_package.get(package_name)
if identity is None or identity.get("package_version") != expected_version:
findings.append(
EvidenceFinding(
"review",
"installed_origin_catalog_artifact_missing",
f"The signed catalog has no built-artifact identity for {package_name!r} at the selected version.",
(f"composition.{component['module_id']}",),
)
)
continue
if identity.get("requires_installer_receipt") is True:
receipt_required.add(package_name)
continue
if not observation_trusted:
continue
installed = installed_artifacts.get(package_name)
record = installed.get("record_integrity") if isinstance(installed, dict) else None
observed = (
record.get("artifact_payload_identity") if isinstance(record, dict) else None
)
expected = identity.get("installed_payload")
if observed == expected:
direct_bound.add(package_name)
else:
findings.append(
EvidenceFinding(
"blocker",
"installed_origin_artifact_payload_mismatch",
f"Installed payload for {package_name!r} does not match the identity independently computed from the signed catalog artifact.",
(f"composition.{component['module_id']}",),
)
)
receipt_bound: set[str] = set()
if receipt_supplied:
receipt_bound, receipt_findings, receipt_digest = _verify_installer_receipt(
expected_by_package=expected_by_package,
installed_artifacts=installed_artifacts,
installed_evidence=installed_evidence,
installed_evidence_sha256=installed_evidence_sha256,
catalog_by_package=catalog_by_package,
catalog_sha256=catalog_sha256,
catalog_channel=catalog_channel,
catalog_sequence=catalog_sequence,
receipt=receipt,
receipt_schema=receipt_schema,
authority_keyring=authority_keyring,
authority_keyring_schema=authority_keyring_schema,
verification_time=verification_time,
forbidden_public_keys=forbidden_public_keys,
)
findings.extend(receipt_findings)
scope["installer_receipt_sha256"] = receipt_digest
elif receipt_required:
findings.append(
EvidenceFinding(
"review",
"installed_origin_receipt_required",
"At least one selected wheel produces installer-transformed files, so its signed installer receipt is required for complete origin proof.",
("assessment.installed_composition",),
)
)
bound = direct_bound | receipt_bound
scope["anchored_artifact_digest_count"] = len(direct_bound)
scope["signed_installer_receipt_count"] = len(receipt_bound)
valid = len(bound) == expected_count and not any(
finding.severity == "blocker" for finding in findings
)
scope["valid"] = valid
scope["release_origin_bound"] = valid
return scope, tuple(findings)
def _catalog_artifact_identities(
value: object,
) -> tuple[dict[str, dict[str, Any]], tuple[EvidenceFinding, ...]]:
if value is None:
return {}, ()
if not isinstance(value, list) or len(value) > MAX_GOVOPLAN_DISTRIBUTIONS:
return {}, (
EvidenceFinding(
"blocker",
"catalog_artifact_manifest_invalid",
"Signed catalog release artifacts must be a bounded list.",
("assessment.release",),
),
)
result: dict[str, dict[str, Any]] = {}
invalid = False
for item in value:
if not isinstance(item, dict) or set(item) != {
"artifact_kind",
"package_name",
"package_version",
"archive_sha256",
"archive_size",
"installed_payload",
"requires_installer_receipt",
}:
invalid = True
continue
package_name = item.get("package_name")
version = item.get("package_version")
archive_size = item.get("archive_size")
payload = item.get("installed_payload")
if (
item.get("artifact_kind") != "python-wheel"
or not isinstance(package_name, str)
or PACKAGE_PATTERN.fullmatch(package_name) is None
or not isinstance(version, str)
or VERSION_PATTERN.fullmatch(version) is None
or not isinstance(item.get("archive_sha256"), str)
or SHA256_PATTERN.fullmatch(str(item["archive_sha256"])) is None
or not isinstance(archive_size, int)
or isinstance(archive_size, bool)
or not 0 < archive_size <= MAX_HASHED_DISTRIBUTION_BYTES
or not isinstance(item.get("requires_installer_receipt"), bool)
or not _payload_identity_semantics_valid(
payload,
algorithm=WHEEL_PAYLOAD_ALGORITHM,
maximum_files=MAX_DISTRIBUTION_FILES,
)
or package_name in result
):
invalid = True
continue
result[package_name] = item
if invalid:
return {}, (
EvidenceFinding(
"blocker",
"catalog_artifact_manifest_invalid",
"Signed catalog release artifacts contain malformed or duplicate package identities.",
("assessment.release",),
),
)
return result, ()
def _verify_installer_receipt(
*,
expected_by_package: Mapping[str, tuple[dict[str, Any], Mapping[str, Any]]],
installed_artifacts: Mapping[str, dict[str, Any]],
installed_evidence: dict[str, Any],
installed_evidence_sha256: str,
catalog_by_package: Mapping[str, dict[str, Any]],
catalog_sha256: str | None,
catalog_channel: str | None,
catalog_sequence: int | None,
receipt: dict[str, Any],
receipt_schema: dict[str, Any] | None,
authority_keyring: dict[str, Any] | None,
authority_keyring_schema: dict[str, Any] | None,
verification_time: datetime,
forbidden_public_keys: frozenset[bytes],
) -> tuple[set[str], tuple[EvidenceFinding, ...], str]:
receipt_digest = canonical_sha256(receipt)
findings: list[EvidenceFinding] = []
if receipt_schema is None or authority_keyring_schema is None:
findings.append(
EvidenceFinding(
"blocker",
"installer_receipt_schema_missing",
"Installer receipt proof requires both bounded validation schemas.",
("assessment.installed_composition",),
)
)
return set(), tuple(findings), receipt_digest
receipt_errors = validate_payload(payload=receipt, schema=receipt_schema)
keyring_errors = (
validate_payload(payload=authority_keyring, schema=authority_keyring_schema)
if isinstance(authority_keyring, dict)
else ("$: an independently provisioned installer authority keyring is required",)
)
findings.extend(
EvidenceFinding(
"blocker",
"installer_receipt_schema",
message,
("assessment.installed_composition",),
)
for message in receipt_errors
)
findings.extend(
EvidenceFinding(
"blocker",
"installer_authority_keyring_schema",
message,
("assessment.installed_composition",),
)
for message in keyring_errors
)
if receipt_errors or keyring_errors or not isinstance(authority_keyring, dict):
return set(), tuple(findings), receipt_digest
expected_release = installed_evidence.get("assessment_release")
expected_assessment = installed_evidence.get("assessment_id")
catalog_binding = receipt.get("catalog")
binding_valid = True
if (
receipt.get("assessment_id") != expected_assessment
or receipt.get("assessment_release") != expected_release
or receipt.get("installed_evidence_sha256") != installed_evidence_sha256
):
binding_valid = False
findings.append(
EvidenceFinding(
"blocker",
"installer_receipt_evidence_mismatch",
"Installer receipt is not bound to the supplied assessment and installed-evidence digest.",
("assessment.installed_composition",),
)
)
if not isinstance(catalog_binding, dict) or (
catalog_binding.get("sha256") != catalog_sha256
or catalog_binding.get("channel") != catalog_channel
or catalog_binding.get("sequence") != catalog_sequence
):
binding_valid = False
findings.append(
EvidenceFinding(
"blocker",
"installer_receipt_catalog_mismatch",
"Installer receipt is not bound to the supplied signed catalog identity.",
("assessment.release", "assessment.installed_composition"),
)
)
issued_at = _datetime(receipt.get("issued_at"))
collected_at = _datetime(installed_evidence.get("collected_at"))
if (
issued_at is None
or collected_at is None
or issued_at < collected_at
or issued_at - collected_at > MAX_LOCAL_OBSERVATION_AGE
or issued_at > verification_time + MAX_LOCAL_OBSERVATION_FUTURE_SKEW
or verification_time - issued_at > MAX_LOCAL_OBSERVATION_AGE
):
binding_valid = False
findings.append(
EvidenceFinding(
"blocker",
"installer_receipt_time_invalid",
"Installer receipt issuance must follow the observation within five minutes and remain fresh at the selected verification time.",
("assessment.installed_composition",),
)
)
receipt_rows = [
item for item in receipt.get("artifacts", []) if isinstance(item, dict)
]
rows_by_package: dict[str, dict[str, Any]] = {}
duplicate_packages: set[str] = set()
for row in receipt_rows:
package_name = str(row.get("package_name") or "")
if package_name in rows_by_package:
duplicate_packages.add(package_name)
else:
rows_by_package[package_name] = row
expected_packages = set(expected_by_package)
if duplicate_packages or set(rows_by_package) != expected_packages:
binding_valid = False
findings.append(
EvidenceFinding(
"blocker",
"installer_receipt_artifact_set_mismatch",
"Installer receipt must bind exactly one row for every expected installed distribution.",
("assessment.installed_composition",),
)
)
bound: set[str] = set()
for package_name, (_, catalog_entry) in sorted(expected_by_package.items()):
row = rows_by_package.get(package_name)
installed = installed_artifacts.get(package_name)
record = installed.get("record_integrity") if isinstance(installed, dict) else None
observed_payload = (
record.get("installed_payload_identity") if isinstance(record, dict) else None
)
catalog_identity = catalog_by_package.get(package_name)
if (
row is None
or catalog_identity is None
or row.get("package_version") != catalog_entry.get("version")
or row.get("catalog_archive_sha256")
!= catalog_identity.get("archive_sha256")
or row.get("installed_payload") != observed_payload
):
binding_valid = False
findings.append(
EvidenceFinding(
"blocker",
"installer_receipt_artifact_mismatch",
f"Installer receipt does not bind the observed {package_name!r} payload to its signed catalog artifact.",
("assessment.installed_composition",),
)
)
else:
bound.add(package_name)
keys, key_findings = _installer_receipt_keys(
authority_keyring=authority_keyring,
issued_at=issued_at,
forbidden_public_keys=forbidden_public_keys,
)
findings.extend(key_findings)
signature_payload = dict(receipt)
signature_payload.pop("signatures", None)
signature_bytes = canonical_bytes(signature_payload)
signature_valid = False
seen_ids: set[str] = set()
duplicate_ids = False
for signature in receipt.get("signatures", []):
if not isinstance(signature, dict):
continue
key_id = str(signature.get("key_id") or "")
if key_id in seen_ids:
duplicate_ids = True
continue
seen_ids.add(key_id)
public_key = keys.get(key_id)
if public_key is None or signature.get("algorithm") != "ed25519":
continue
try:
encoded = base64.b64decode(str(signature.get("value") or ""), validate=True)
Ed25519PublicKey.from_public_bytes(public_key).verify(
encoded, signature_bytes
)
signature_valid = True
except (ValueError, InvalidSignature):
continue
if duplicate_ids or not signature_valid:
findings.append(
EvidenceFinding(
"blocker",
"installer_receipt_signature_untrusted",
"Installer receipt has no unique valid signature from an authorized independent installer key.",
("assessment.installed_composition",),
)
)
if not binding_valid or not signature_valid or key_findings:
return set(), tuple(findings), receipt_digest
return bound, tuple(findings), receipt_digest
def _installer_receipt_keys(
*,
authority_keyring: dict[str, Any],
issued_at: datetime | None,
forbidden_public_keys: frozenset[bytes],
) -> tuple[dict[str, bytes], tuple[EvidenceFinding, ...]]:
findings: list[EvidenceFinding] = []
result: dict[str, bytes] = {}
raw_keys = authority_keyring.get("keys")
if not isinstance(raw_keys, list) or issued_at is None:
return {}, (
EvidenceFinding(
"blocker",
"installer_authority_untrusted",
"Installer receipt authority keyring or issuance time is invalid.",
("assessment.installed_composition",),
),
)
seen_ids: set[str] = set()
seen_material: set[bytes] = set()
malformed = False
for item in raw_keys:
if not isinstance(item, dict):
malformed = True
continue
key_id = str(item.get("key_id") or "")
try:
public_key = base64.b64decode(str(item.get("public_key") or ""), validate=True)
Ed25519PublicKey.from_public_bytes(public_key)
except ValueError:
malformed = True
continue
not_before = _datetime(item.get("not_before"))
not_after = _datetime(item.get("not_after"))
interval_valid = not (
not_before is not None
and not_after is not None
and not_before >= not_after
)
if (
OPAQUE_ID_PATTERN.fullmatch(key_id) is None
or key_id in seen_ids
or public_key in seen_material
or public_key in forbidden_public_keys
or item.get("allowed_scopes") != ["installed_release_origin"]
or not interval_valid
):
malformed = True
continue
seen_ids.add(key_id)
seen_material.add(public_key)
status = item.get("status")
active_at_issue = (
(not_before is None or issued_at >= not_before)
and (not_after is None or issued_at < not_after)
)
historically_retired = status == "retired" and not_after is not None
if active_at_issue and (
status in {"active", "next"} or historically_retired
):
result[key_id] = public_key
if malformed or not result:
findings.append(
EvidenceFinding(
"blocker",
"installer_authority_untrusted",
"Installer authority keyring is malformed, reuses another trust-domain key, or has no role-scoped key valid at receipt issuance.",
("assessment.installed_composition",),
)
)
return {}, tuple(findings)
return result, ()
def review_boundary_evidence(
*,
assessment: dict[str, Any],
@@ -1606,13 +2134,17 @@ def _record_integrity(
"missing_file_count": 0,
"mismatched_file_count": 0,
}
identities = {
"artifact_payload_identity": None,
"installed_payload_identity": None,
}
try:
distribution_root = Path(distribution.locate_file("")).resolve()
installation_root = Path(sys.prefix).resolve()
except Exception:
return {"status": "unavailable", **counts}
return {"status": "unavailable", **counts, **identities}
if not _trusted_distribution_root(distribution_root):
return {"status": "unavailable", **counts}
return {"status": "unavailable", **counts, **identities}
entries, malformed_rows, record_status = _read_record_entries(
distribution=distribution,
distribution_root=distribution_root,
@@ -1620,13 +2152,13 @@ def _record_integrity(
)
if record_status == "limit-exceeded":
budget.remaining_files = 0
return {"status": "limit-exceeded", **counts}
return {"status": "limit-exceeded", **counts, **identities}
if record_status != "ok":
counts["unverifiable_file_count"] = malformed_rows
return {"status": "unavailable", **counts}
return {"status": "unavailable", **counts, **identities}
record_file_count = len(entries) + malformed_rows
if record_file_count == 0:
return {"status": "unavailable", **counts}
return {"status": "unavailable", **counts, **identities}
budget.remaining_files -= record_file_count
counts["unverifiable_file_count"] = malformed_rows
declared_scripts = _declared_distribution_scripts(distribution)
@@ -1666,6 +2198,8 @@ def _record_integrity(
}
total_hashed_bytes = 0
limit_exceeded = False
artifact_payload_rows: list[dict[str, object]] = []
installed_payload_rows: list[dict[str, object]] = []
for entry, resolved_path in resolved_entries:
if resolved_path is None:
counts["unverifiable_file_count"] += 1
@@ -1731,6 +2265,31 @@ def _record_integrity(
continue
if hmac.compare_digest(actual, expected):
counts["hashed_file_count"] += 1
installed_path = _installed_payload_path(
resolved_path,
distribution_root=distribution_root,
installation_root=installation_root,
declared_scripts=declared_scripts,
)
if installed_path is None:
counts["unverifiable_file_count"] += 1
continue
row = {
"path": installed_path,
"sha256": actual.hex(),
"size": file_stat.st_size,
}
installed_payload_rows.append(row)
artifact_path = _artifact_payload_path(
resolved_path,
distribution_root=distribution_root,
installation_root=installation_root,
declared_scripts=declared_scripts,
)
if artifact_path is not None and not _installer_generated_metadata(
resolved_path, distribution_root=distribution_root
):
artifact_payload_rows.append({**row, "path": artifact_path})
else:
counts["mismatched_file_count"] += 1
if limit_exceeded:
@@ -1743,7 +2302,85 @@ def _record_integrity(
status = "partial"
else:
status = "verified"
return {"status": status, **counts}
if status == "verified":
installed_identity = _payload_identity(
algorithm=INSTALLED_PAYLOAD_ALGORITHM,
rows=installed_payload_rows,
)
artifact_identity = _payload_identity(
algorithm=WHEEL_PAYLOAD_ALGORITHM,
rows=artifact_payload_rows,
)
if installed_identity is None or artifact_identity is None:
status = "partial"
counts["unverifiable_file_count"] += 1
else:
identities["installed_payload_identity"] = installed_identity
identities["artifact_payload_identity"] = artifact_identity
return {"status": status, **counts, **identities}
def _payload_identity(
*, algorithm: str, rows: list[dict[str, object]]
) -> dict[str, object] | None:
ordered = sorted(rows, key=lambda item: str(item["path"]))
paths = [str(item["path"]) for item in ordered]
if not ordered or len(set(paths)) != len(paths):
return None
return {
"algorithm": algorithm,
"sha256": payload_identity_sha256(algorithm=algorithm, rows=ordered),
"file_count": len(ordered),
}
def _installed_payload_path(
path: Path,
*,
distribution_root: Path,
installation_root: Path,
declared_scripts: frozenset[str],
) -> str | None:
if _is_relative_to(path, distribution_root):
return path.relative_to(distribution_root).as_posix()
for script_root in (
(installation_root / "bin").resolve(),
(installation_root / "Scripts").resolve(),
):
if path.parent == script_root and path.name in declared_scripts:
return f"@scripts/{path.name}"
if _is_relative_to(path, installation_root):
return f"@data/{path.relative_to(installation_root).as_posix()}"
return None
def _artifact_payload_path(
path: Path,
*,
distribution_root: Path,
installation_root: Path,
declared_scripts: frozenset[str],
) -> str | None:
installed = _installed_payload_path(
path,
distribution_root=distribution_root,
installation_root=installation_root,
declared_scripts=declared_scripts,
)
return None if installed is None or installed.startswith("@scripts/") else installed
def _installer_generated_metadata(
path: Path, *, distribution_root: Path
) -> bool:
if not _is_relative_to(path, distribution_root):
return False
relative = path.relative_to(distribution_root)
return (
len(relative.parts) >= 2
and relative.parent.name.endswith(".dist-info")
and relative.name in {"direct_url.json", "INSTALLER", "REQUESTED"}
)
def _resolve_record_path(
@@ -1867,12 +2504,25 @@ def _record_integrity_semantics_valid(record: Mapping[str, Any]) -> bool:
missing = counts["missing_file_count"]
mismatched = counts["mismatched_file_count"]
if status == "verified":
artifact_identity = record.get("artifact_payload_identity")
installed_identity = record.get("installed_payload_identity")
return (
hashed > 0
and counts["permitted_unhashed_file_count"] > 0
and unverifiable == 0
and missing == 0
and mismatched == 0
and _payload_identity_semantics_valid(
artifact_identity,
algorithm=WHEEL_PAYLOAD_ALGORITHM,
maximum_files=hashed,
)
and _payload_identity_semantics_valid(
installed_identity,
algorithm=INSTALLED_PAYLOAD_ALGORITHM,
maximum_files=hashed,
exact_files=hashed,
)
)
if status == "partial":
return hashed > 0 and unverifiable > 0 and missing == 0 and mismatched == 0
@@ -1885,6 +2535,31 @@ def _record_integrity_semantics_valid(record: Mapping[str, Any]) -> bool:
return False
def _payload_identity_semantics_valid(
value: object,
*,
algorithm: str,
maximum_files: int,
exact_files: int | None = None,
) -> bool:
if not isinstance(value, Mapping) or set(value) != {
"algorithm",
"sha256",
"file_count",
}:
return False
file_count = value.get("file_count")
return (
value.get("algorithm") == algorithm
and isinstance(value.get("sha256"), str)
and SHA256_PATTERN.fullmatch(str(value["sha256"])) is not None
and isinstance(file_count, int)
and not isinstance(file_count, bool)
and 0 < file_count <= maximum_files
and (exact_files is None or file_count == exact_files)
)
def _permitted_unhashed_record_path(
path: Path,
*,

View File

@@ -0,0 +1,204 @@
"""Issuance of role-scoped receipts from same-process installed observations."""
from __future__ import annotations
import base64
from datetime import UTC, datetime
from pathlib import Path
from typing import Any, Mapping
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
from .capability_fit import canonical_hash
from .evidence import (
MAX_LOCAL_OBSERVATION_AGE,
OPAQUE_ID_PATTERN,
_catalog_artifact_identities,
_record_integrity_semantics_valid,
canonical_bytes,
canonical_sha256,
normalize_package_name,
)
from govoplan_release.artifact_identity import inspect_python_wheel
def issue_installer_receipt(
*,
assessment: Mapping[str, Any],
catalog: Mapping[str, Any],
installed_evidence: dict[str, Any],
receipt_id: str,
key_id: str,
private_key: Ed25519PrivateKey,
consumed_artifacts: Mapping[str, Path | str] | None = None,
issued_at: datetime | None = None,
same_process_observation: bool = False,
) -> dict[str, Any]:
"""Sign a receipt only for a fresh observation collected by this process.
File-based evidence is intentionally not an admitted issuance input. The CLI
collector calls this function directly with its in-memory observation.
"""
if same_process_observation is not True:
raise ValueError("installer receipts require a same-process observation")
if OPAQUE_ID_PATTERN.fullmatch(receipt_id) is None:
raise ValueError("receipt ID must be a bounded opaque ID")
if OPAQUE_ID_PATTERN.fullmatch(key_id) is None:
raise ValueError("installer signing key ID must be a bounded opaque ID")
if not isinstance(consumed_artifacts, Mapping) or not consumed_artifacts:
raise ValueError("installer receipt issuance requires exact consumed wheels")
release = catalog.get("release")
raw_artifacts = release.get("artifacts") if isinstance(release, Mapping) else None
catalog_artifacts, artifact_findings = _catalog_artifact_identities(raw_artifacts)
if artifact_findings:
raise ValueError("signed catalog artifact manifest is invalid")
evidence_rows = installed_evidence.get("artifacts")
if not isinstance(evidence_rows, list) or not evidence_rows:
raise ValueError("installed evidence has no artifact observations")
expected_packages = _expected_packages(assessment=assessment, catalog=catalog)
receipt_rows: list[dict[str, Any]] = []
seen: set[str] = set()
for artifact in evidence_rows:
if not isinstance(artifact, dict):
raise ValueError("installed evidence contains a malformed artifact")
package_name = normalize_package_name(str(artifact.get("package_name") or ""))
package_version = str(artifact.get("package_version") or "")
if package_name in seen:
raise ValueError("installed evidence contains duplicate packages")
seen.add(package_name)
catalog_artifact = catalog_artifacts.get(package_name)
record = artifact.get("record_integrity")
installed_payload = (
record.get("installed_payload_identity")
if isinstance(record, Mapping)
else None
)
if (
catalog_artifact is None
or catalog_artifact.get("package_version") != package_version
or not isinstance(record, Mapping)
or record.get("status") != "verified"
or not _record_integrity_semantics_valid(record)
or not isinstance(installed_payload, Mapping)
):
raise ValueError(
"installed payload is not a verified match for a catalog artifact"
)
artifact_path = consumed_artifacts.get(package_name)
if artifact_path is None:
raise ValueError("every installed package requires its exact consumed wheel")
consumed = inspect_python_wheel(artifact_path)
if (
consumed.package_name != package_name
or consumed.package_version != package_version
or consumed.archive_sha256 != catalog_artifact.get("archive_sha256")
or consumed.catalog_payload().get("installed_payload")
!= catalog_artifact.get("installed_payload")
or record.get("artifact_payload_identity")
!= catalog_artifact.get("installed_payload")
):
raise ValueError(
"consumed wheel or observed wheel payload differs from the signed catalog identity"
)
receipt_rows.append(
{
"package_name": package_name,
"package_version": package_version,
"catalog_archive_sha256": catalog_artifact["archive_sha256"],
"installed_payload": dict(installed_payload),
}
)
if seen != expected_packages:
raise ValueError(
"installed evidence must contain exactly the enabled assessed catalog packages"
)
if set(consumed_artifacts) != expected_packages:
raise ValueError("consumed wheel set must exactly match enabled packages")
receipt_rows.sort(key=lambda item: (item["package_name"], item["package_version"]))
observed_at = issued_at or datetime.now(tz=UTC)
if observed_at.tzinfo is None:
raise ValueError("installer receipt issuance time must include a timezone")
collected_at = _datetime(installed_evidence.get("collected_at"))
if (
collected_at is None
or observed_at < collected_at
or observed_at - collected_at > MAX_LOCAL_OBSERVATION_AGE
):
raise ValueError(
"installer receipt issuance must follow live collection within five minutes"
)
assessment_release = assessment.get("release")
assessment_release_ref = (
assessment_release.get("ref")
if isinstance(assessment_release, Mapping)
else None
)
receipt: dict[str, Any] = {
"$schema": "./installer-receipt.schema.json",
"schema_version": "0.1.0",
"evidence_kind": "govoplan.installer-receipt",
"receipt_id": receipt_id,
"assessment_id": assessment.get("assessment_id"),
"assessment_release": assessment_release_ref,
"installed_evidence_sha256": canonical_sha256(installed_evidence),
"catalog": {
"channel": catalog.get("channel"),
"sequence": catalog.get("sequence"),
"sha256": canonical_hash(catalog),
},
"issued_at": observed_at.astimezone(UTC).isoformat().replace("+00:00", "Z"),
"artifacts": receipt_rows,
}
receipt["signatures"] = [
{
"algorithm": "ed25519",
"key_id": key_id,
"value": base64.b64encode(
private_key.sign(canonical_bytes(receipt))
).decode("ascii"),
}
]
return receipt
def _expected_packages(
*, assessment: Mapping[str, Any], catalog: Mapping[str, Any]
) -> set[str]:
entries: dict[str, Mapping[str, Any]] = {}
core = catalog.get("core_release")
if isinstance(core, Mapping):
entries["core"] = core
modules = catalog.get("modules")
if isinstance(modules, list):
for entry in modules:
if isinstance(entry, Mapping) and isinstance(entry.get("module_id"), str):
entries[str(entry["module_id"])] = entry
expected: set[str] = set()
composition = assessment.get("composition")
if not isinstance(composition, list):
raise ValueError("assessment composition is unavailable")
for component in composition:
if not isinstance(component, Mapping) or component.get("enabled") is not True:
continue
entry = entries.get(str(component.get("module_id") or ""))
package = entry.get("python_package") if isinstance(entry, Mapping) else None
if not isinstance(package, str):
raise ValueError("enabled assessment component has no catalog package")
normalized = normalize_package_name(package)
if normalized in expected:
raise ValueError("enabled assessment packages are ambiguous")
expected.add(normalized)
if not expected:
raise ValueError("assessment has no enabled catalog packages")
return expected
def _datetime(value: object) -> datetime | None:
if not isinstance(value, str):
return None
try:
parsed = datetime.fromisoformat(value.replace("Z", "+00:00"))
except ValueError:
return None
return parsed.astimezone(UTC) if parsed.tzinfo is not None else None

View File

@@ -0,0 +1,170 @@
#!/usr/bin/env python3
"""Collect live installed payloads and issue an independently signed receipt."""
from __future__ import annotations
import argparse
import json
from pathlib import Path
import sys
META_ROOT = Path(__file__).resolve().parents[2]
for tools_root in (META_ROOT / "tools" / "assessments", META_ROOT / "tools" / "release"):
if str(tools_root) not in sys.path:
sys.path.insert(0, str(tools_root))
from cryptography.hazmat.primitives import serialization # noqa: E402
from cryptography.hazmat.primitives.asymmetric.ed25519 import ( # noqa: E402
Ed25519PrivateKey,
)
from govoplan_assessment import collect_installed_composition # noqa: E402
from govoplan_assessment.atomic_io import ( # noqa: E402
AtomicJsonWriteError,
atomic_write_json,
)
from govoplan_assessment.capability_fit import ( # noqa: E402
canonical_hash,
review_capability_fit,
)
from govoplan_assessment.evidence import validate_payload # noqa: E402
from govoplan_assessment.installer_receipt import ( # noqa: E402
issue_installer_receipt,
)
MAX_INPUT_BYTES = 16 * 1024 * 1024
MAX_OUTPUT_BYTES = 4 * 1024 * 1024
def main(argv: list[str] | None = None) -> int:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--assessment", type=Path, required=True)
parser.add_argument("--assessment-schema", type=Path, default=META_ROOT / "docs" / "capability-fit.schema.json")
parser.add_argument("--catalog", type=Path, required=True)
parser.add_argument("--keyring", type=Path, required=True)
parser.add_argument("--trusted-keyring", type=Path, required=True)
parser.add_argument("--receipt-id", required=True)
parser.add_argument("--signing-key", required=True, metavar="KEY_ID=/PATH/PRIVATE.pem")
parser.add_argument(
"--python-artifact",
action="append",
default=[],
required=True,
metavar="PACKAGE=/PATH/TO/CONSUMED.whl",
help="Exact wheel consumed by this installer; repeat for every package.",
)
parser.add_argument("--evidence-output", type=Path, required=True)
parser.add_argument("--receipt-output", type=Path, required=True)
parser.add_argument("--installed-evidence-schema", type=Path, default=META_ROOT / "docs" / "installed-composition-evidence.schema.json")
parser.add_argument("--receipt-schema", type=Path, default=META_ROOT / "docs" / "installer-receipt.schema.json")
args = parser.parse_args(argv)
if args.evidence_output.resolve() == args.receipt_output.resolve():
parser.error("evidence and receipt output paths must differ")
assessment = read_object(args.assessment, label="assessment")
assessment_schema = read_object(args.assessment_schema, label="assessment schema")
catalog = read_object(args.catalog, label="catalog")
keyring = read_object(args.keyring, label="published keyring")
trusted_keyring = read_object(args.trusted_keyring, label="trusted keyring")
evidence_schema = read_object(args.installed_evidence_schema, label="installed evidence schema")
receipt_schema = read_object(args.receipt_schema, label="installer receipt schema")
release = catalog.get("release")
if not isinstance(release, dict) or release.get("keyring_sha256") != canonical_hash(keyring):
parser.error("catalog does not pin the supplied published keyring")
evidence = collect_installed_composition(assessment=assessment)
if validate_payload(payload=evidence, schema=evidence_schema):
parser.error("live installed observation does not satisfy its bounded schema")
report = review_capability_fit(
assessment=assessment,
schema=assessment_schema,
catalog=catalog,
published_keyring=keyring,
trusted_keyring=trusted_keyring,
workspace_root=None,
installed_evidence=evidence,
installed_evidence_schema=evidence_schema,
installed_evidence_mode="direct_local",
)
required_scopes = (
"catalog_signature_and_keyring",
"catalog_signature_and_trusted_keyring",
"published_keyring_hash",
"release_metadata",
"installed_artifacts",
"installed_record_integrity",
)
if any(report["proof_scope"].get(scope, {}).get("valid") is not True for scope in required_scopes):
parser.error("trusted catalog and live installed-composition checks must pass before receipt issuance")
key_id, private_key = read_signing_key(args.signing_key)
consumed_artifacts = parse_package_paths(tuple(args.python_artifact))
receipt = issue_installer_receipt(
assessment=assessment,
catalog=catalog,
installed_evidence=evidence,
receipt_id=args.receipt_id,
key_id=key_id,
private_key=private_key,
consumed_artifacts=consumed_artifacts,
same_process_observation=True,
)
if validate_payload(payload=receipt, schema=receipt_schema):
parser.error("issued installer receipt does not satisfy its bounded schema")
write_object(args.evidence_output, evidence, label="installed evidence")
write_object(args.receipt_output, receipt, label="installer receipt")
print(json.dumps({"receipt_id": args.receipt_id, "evidence_output": str(args.evidence_output), "receipt_output": str(args.receipt_output)}, sort_keys=True))
return 0
def read_object(path: Path, *, label: str) -> dict[str, object]:
try:
if path.stat().st_size > MAX_INPUT_BYTES:
raise ValueError("input exceeds size limit")
encoded = path.read_bytes()
payload = json.loads(encoded.decode("utf-8"))
except (OSError, UnicodeDecodeError, json.JSONDecodeError, ValueError) as exc:
raise SystemExit(f"Could not read {label}") from exc
if not isinstance(payload, dict):
raise SystemExit(f"{label.capitalize()} must be a JSON object")
return payload
def read_signing_key(value: str) -> tuple[str, Ed25519PrivateKey]:
key_id, separator, path_text = value.partition("=")
if not separator or not key_id or not path_text:
raise SystemExit("--signing-key must use KEY_ID=/path/to/private.pem")
try:
key = serialization.load_pem_private_key(Path(path_text).expanduser().read_bytes(), password=None)
except (OSError, ValueError) as exc:
raise SystemExit("Could not read installer signing key") from exc
if not isinstance(key, Ed25519PrivateKey):
raise SystemExit("Installer signing key must be Ed25519")
return key_id, key
def parse_package_paths(values: tuple[str, ...]) -> dict[str, Path]:
result: dict[str, Path] = {}
for value in values:
package, separator, path_text = value.partition("=")
package = package.strip()
path_text = path_text.strip()
if not separator or not package or not path_text or package in result:
raise SystemExit(
"--python-artifact must uniquely use PACKAGE=/path/to/consumed.whl"
)
result[package] = Path(path_text).expanduser()
return result
def write_object(path: Path, payload: dict[str, object], *, label: str) -> None:
try:
atomic_write_json(path, payload, max_bytes=MAX_OUTPUT_BYTES)
except AtomicJsonWriteError as exc:
raise SystemExit(f"Could not securely write {label}") from exc
if __name__ == "__main__":
raise SystemExit(main())