mirror of
https://github.com/norandom/OpenUltraSAST.git
synced 2026-11-13 01:48:17 +00:00
feat(access-control-prover): record authority review ceremony
This commit is contained in:
@@ -0,0 +1,212 @@
|
||||
"""Approved repo-local identities for installed entry-fact authority."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
from dataclasses import replace
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
from test_fact_authority import _case
|
||||
|
||||
from openultrasast.core import canonical, provenance
|
||||
from openultrasast.core.factpack import (
|
||||
derive_review_evidence_digest,
|
||||
derive_review_independence_policy_digest,
|
||||
)
|
||||
from openultrasast.mapping.authority_ceremony import (
|
||||
APPROVED_IDENTITY_MANIFESTS,
|
||||
INSTALLED_ARTIFACT_STORE_IDENTITY,
|
||||
AuthorityCeremonyError,
|
||||
InstalledAuthorityCeremony,
|
||||
decode_identity_manifest_bytes,
|
||||
identity_manifest_bytes,
|
||||
load_installed_authority_ceremony,
|
||||
validate_authority_ceremony_bindings,
|
||||
)
|
||||
from openultrasast.mapping.fact_authority import EntryFactAuthorityBundle
|
||||
from openultrasast.mapping.installed_fact_authority import decode_bootstrap_bytes
|
||||
|
||||
_ENTRIES = Path(__file__).parents[1] / "src" / "openultrasast" / "ruleset" / "entries"
|
||||
|
||||
|
||||
def _canonical_json(value: object) -> bytes:
|
||||
return json.dumps(value, ensure_ascii=False, sort_keys=True, separators=(",", ":")).encode()
|
||||
|
||||
|
||||
def _bound_bundle(ceremony: InstalledAuthorityCeremony) -> EntryFactAuthorityBundle:
|
||||
bundle = _case().bundle
|
||||
producer = ceremony.producer.identity_digest
|
||||
reviewer = ceremony.reviewer.identity_digest
|
||||
custodian = ceremony.custodian.identity_digest
|
||||
packs = []
|
||||
for pack in bundle.packs:
|
||||
evidence = tuple(
|
||||
replace(
|
||||
item,
|
||||
producer_identity=producer,
|
||||
reviewer_identity=reviewer,
|
||||
independence=replace(
|
||||
item.independence,
|
||||
producer_identity=producer,
|
||||
reviewer_identity=reviewer,
|
||||
),
|
||||
)
|
||||
for item in pack.review_evidence
|
||||
)
|
||||
packs.append(
|
||||
replace(
|
||||
pack,
|
||||
review_identity=reviewer,
|
||||
review_evidence=evidence,
|
||||
review_evidence_digest=derive_review_evidence_digest(evidence),
|
||||
)
|
||||
)
|
||||
custody = provenance.PopulationCustodyPolicy(
|
||||
(custodian,),
|
||||
provenance.derive_population_custody_policy_digest((custodian,)),
|
||||
)
|
||||
stores = ceremony.bootstrap.trusted_store_identities
|
||||
policy = replace(
|
||||
bundle.review_policy,
|
||||
reviewed_reviewer_digests=(reviewer,),
|
||||
trusted_store_identities=stores,
|
||||
)
|
||||
policy = replace(
|
||||
policy,
|
||||
policy_digest=derive_review_independence_policy_digest(
|
||||
policy.reviewed_reviewer_digests,
|
||||
policy.forbidden_identity_pairs,
|
||||
policy.trusted_store_identities,
|
||||
policy.maximum_evidence_bytes,
|
||||
),
|
||||
)
|
||||
packs = [replace(pack, review_policy_digest=policy.policy_digest) for pack in packs]
|
||||
return replace(
|
||||
bundle,
|
||||
packs=tuple(packs),
|
||||
custody_policy=custody,
|
||||
review_policy=policy,
|
||||
authority_review=replace(
|
||||
bundle.authority_review,
|
||||
producer_identity=producer,
|
||||
reviewer_identity=reviewer,
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
def test_installed_ceremony_loads_canonical_nonempty_records() -> None:
|
||||
paths = (
|
||||
_ENTRIES / "identities" / "generator.json",
|
||||
_ENTRIES / "identities" / "maintainer-reviewer.json",
|
||||
_ENTRIES / "identities" / "custodian.json",
|
||||
_ENTRIES / "bootstrap.json",
|
||||
)
|
||||
assert all(path.stat().st_size > 0 for path in paths)
|
||||
|
||||
ceremony = load_installed_authority_ceremony(_ENTRIES)
|
||||
|
||||
assert (ceremony.producer, ceremony.reviewer, ceremony.custodian) == APPROVED_IDENTITY_MANIFESTS
|
||||
assert ceremony.bootstrap == decode_bootstrap_bytes((_ENTRIES / "bootstrap.json").read_bytes())
|
||||
assert ceremony.bootstrap.reviewed_bundle_reviewer_digests == (ceremony.reviewer.identity_digest,)
|
||||
assert ceremony.bootstrap.trusted_store_identities == (INSTALLED_ARTIFACT_STORE_IDENTITY,)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("mutation", ("unknown", "missing", "whitespace"))
|
||||
def test_identity_decoder_rejects_open_or_noncanonical_records(mutation: str) -> None:
|
||||
raw = json.loads(identity_manifest_bytes(APPROVED_IDENTITY_MANIFESTS[0]))
|
||||
if mutation == "unknown":
|
||||
raw["extra"] = "not-approved"
|
||||
content = _canonical_json(raw)
|
||||
elif mutation == "missing":
|
||||
del raw["approval_basis"]
|
||||
content = _canonical_json(raw)
|
||||
else:
|
||||
content = json.dumps(raw, indent=2).encode()
|
||||
|
||||
with pytest.raises(AuthorityCeremonyError):
|
||||
decode_identity_manifest_bytes(content)
|
||||
|
||||
|
||||
def test_identity_decoder_rejects_changed_schema_field() -> None:
|
||||
raw = json.loads(identity_manifest_bytes(APPROVED_IDENTITY_MANIFESTS[0]))
|
||||
raw["schema_version"] = "openultrasast.access-control.authority-identity.changed"
|
||||
|
||||
with pytest.raises(AuthorityCeremonyError):
|
||||
decode_identity_manifest_bytes(_canonical_json(raw))
|
||||
|
||||
|
||||
def test_synthetic_authority_and_pack_identities_bind_to_ceremony() -> None:
|
||||
ceremony = load_installed_authority_ceremony(_ENTRIES)
|
||||
|
||||
validate_authority_ceremony_bindings(ceremony, _bound_bundle(ceremony))
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("part", "field"),
|
||||
(
|
||||
("producer", "name"),
|
||||
("producer", "role"),
|
||||
("producer", "approval_basis"),
|
||||
("reviewer", "name"),
|
||||
("reviewer", "role"),
|
||||
("reviewer", "approval_basis"),
|
||||
("custodian", "name"),
|
||||
("custodian", "role"),
|
||||
("custodian", "approval_basis"),
|
||||
),
|
||||
)
|
||||
def test_changed_identity_field_changes_digest_and_invalidates_binding(part: str, field: str) -> None:
|
||||
ceremony = load_installed_authority_ceremony(_ENTRIES)
|
||||
bundle = _bound_bundle(ceremony)
|
||||
manifest = getattr(ceremony, part)
|
||||
changed = replace(manifest, **{field: f"changed-{getattr(manifest, field)}"})
|
||||
decoded = decode_identity_manifest_bytes(identity_manifest_bytes(changed))
|
||||
changed_ceremony = replace(ceremony, **{part: decoded})
|
||||
|
||||
assert decoded.identity_digest != manifest.identity_digest
|
||||
with pytest.raises(AuthorityCeremonyError, match="identity binding"):
|
||||
validate_authority_ceremony_bindings(changed_ceremony, bundle)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"binding",
|
||||
(
|
||||
"bootstrap",
|
||||
"bootstrap-store",
|
||||
"review-policy-reviewer",
|
||||
"review-policy-store",
|
||||
"custody",
|
||||
"authority-producer",
|
||||
"authority-reviewer",
|
||||
"pack-producer",
|
||||
"pack-reviewer",
|
||||
),
|
||||
)
|
||||
def test_every_ceremony_binding_is_required(binding: str) -> None:
|
||||
ceremony = load_installed_authority_ceremony(_ENTRIES)
|
||||
bundle = _bound_bundle(ceremony)
|
||||
other = canonical.content_digest(f"other-{binding}")
|
||||
if binding == "bootstrap":
|
||||
changed = replace(ceremony.bootstrap, reviewed_bundle_reviewer_digests=(other,))
|
||||
ceremony = replace(ceremony, bootstrap=changed)
|
||||
elif binding == "bootstrap-store":
|
||||
changed = replace(ceremony.bootstrap, trusted_store_identities=("other-store",))
|
||||
ceremony = replace(ceremony, bootstrap=changed)
|
||||
elif binding == "review-policy-reviewer":
|
||||
bundle = replace(bundle, review_policy=replace(bundle.review_policy, reviewed_reviewer_digests=(other,)))
|
||||
elif binding == "review-policy-store":
|
||||
bundle = replace(bundle, review_policy=replace(bundle.review_policy, trusted_store_identities=("other-store",)))
|
||||
elif binding == "custody":
|
||||
bundle = replace(bundle, custody_policy=replace(bundle.custody_policy, reviewed_custodian_digests=(other,)))
|
||||
elif binding.startswith("authority-"):
|
||||
field = binding.removeprefix("authority-") + "_identity"
|
||||
bundle = replace(bundle, authority_review=replace(bundle.authority_review, **{field: other}))
|
||||
else:
|
||||
field = binding.removeprefix("pack-") + "_identity"
|
||||
pack = bundle.packs[0]
|
||||
evidence = replace(pack.review_evidence[0], **{field: other})
|
||||
bundle = replace(bundle, packs=(replace(pack, review_evidence=(evidence,)), *bundle.packs[1:]))
|
||||
|
||||
with pytest.raises(AuthorityCeremonyError, match="identity binding"):
|
||||
validate_authority_ceremony_bindings(ceremony, bundle)
|
||||
Reference in New Issue
Block a user