714 lines
28 KiB
Python
714 lines
28 KiB
Python
from __future__ import annotations
|
|
|
|
import base64
|
|
import importlib.util
|
|
import json
|
|
import os
|
|
import re
|
|
import sys
|
|
from datetime import UTC, datetime, timedelta
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
from cryptography.hazmat.primitives import serialization
|
|
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
|
|
|
|
|
|
REPO_ROOT = Path(__file__).resolve().parents[2]
|
|
SCRIPT = REPO_ROOT / "yuqei-infra" / "scripts" / "rc06-release-trust-bootstrap.py"
|
|
EXISTING_BATCH_TEST = REPO_ROOT / "yuqei-infra" / "tests" / "test_rc06_publication_batch.py"
|
|
AUTHORITY_LAUNCHER = REPO_ROOT / "yuqei-infra" / "scripts" / "Launch-ReleaseAuthority.ps1"
|
|
|
|
|
|
def _load_script():
|
|
spec = importlib.util.spec_from_file_location("rc06_release_trust_bootstrap", SCRIPT)
|
|
assert spec is not None and spec.loader is not None
|
|
module = importlib.util.module_from_spec(spec)
|
|
sys.modules[spec.name] = module
|
|
spec.loader.exec_module(module)
|
|
return module
|
|
|
|
|
|
authority = _load_script()
|
|
|
|
|
|
def _load_existing_batch_test_module():
|
|
spec = importlib.util.spec_from_file_location(
|
|
"rc06_publication_batch_fixture_helpers",
|
|
EXISTING_BATCH_TEST,
|
|
)
|
|
assert spec is not None and spec.loader is not None
|
|
module = importlib.util.module_from_spec(spec)
|
|
sys.modules[spec.name] = module
|
|
spec.loader.exec_module(module)
|
|
return module
|
|
|
|
|
|
def _protect(raw: bytes, role: str) -> bytes:
|
|
return b"fixture-protected\0" + role.encode("ascii") + b"\0" + raw[::-1]
|
|
|
|
|
|
def _unprotect(raw: bytes, role: str) -> bytes:
|
|
prefix = b"fixture-protected\0" + role.encode("ascii") + b"\0"
|
|
if not raw.startswith(prefix):
|
|
raise ValueError("wrong fixture protection domain")
|
|
return raw[len(prefix) :][::-1]
|
|
|
|
|
|
def _reviewer_registration(path: Path, *, private_key: Ed25519PrivateKey | None = None) -> dict:
|
|
private_key = private_key or Ed25519PrivateKey.generate()
|
|
public_key = private_key.public_key()
|
|
public_raw = public_key.public_bytes(
|
|
serialization.Encoding.Raw,
|
|
serialization.PublicFormat.Raw,
|
|
)
|
|
public_pem = public_key.public_bytes(
|
|
serialization.Encoding.PEM,
|
|
serialization.PublicFormat.SubjectPublicKeyInfo,
|
|
)
|
|
fingerprint = authority.batch._sha256_bytes(public_raw)
|
|
registration = {
|
|
"schema_version": authority.REVIEWER_REGISTRATION_SCHEMA,
|
|
"key_id": f"chen-yuqi-rc06-{fingerprint[:16]}",
|
|
"algorithm": "Ed25519",
|
|
"reviewer": dict(authority.batch.SOLE_RELEASE_REVIEWER),
|
|
"created_at": "2026-09-27T00:00:00Z",
|
|
"public_key_pem": public_pem.decode("ascii"),
|
|
"public_key_raw_sha256": fingerprint,
|
|
"public_key_pem_sha256": authority.batch._sha256_bytes(public_pem),
|
|
}
|
|
path.write_bytes(authority._canonical(registration))
|
|
return registration
|
|
|
|
|
|
def _initialize(tmp_path: Path):
|
|
state = tmp_path / "authority-state"
|
|
result = authority.initialize_authority(
|
|
state,
|
|
protect=_protect,
|
|
unprotect=_unprotect,
|
|
created_at=datetime(2026, 9, 27, 1, 0, tzinfo=UTC),
|
|
)
|
|
return state, result, authority.load_authority(state, unprotect=_unprotect)
|
|
|
|
|
|
def _copy_pin_sources(tmp_path: Path) -> Path:
|
|
repo = tmp_path / "candidate"
|
|
paths = (
|
|
"yuqei-infra/scripts/build-rc06-publication-batch.py",
|
|
"yuqei-infra/deploy/plan-first-release-snapshot-restore.py",
|
|
"yuqei-infra/deploy/plan-rollback-rehearsal.py",
|
|
)
|
|
for relative in paths:
|
|
source = REPO_ROOT / relative
|
|
target = repo / relative
|
|
target.parent.mkdir(parents=True, exist_ok=True)
|
|
target.write_bytes(source.read_bytes())
|
|
return repo
|
|
|
|
|
|
def _formal_apply_materials(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> dict:
|
|
state, _result, keys = _initialize(tmp_path)
|
|
reviewer_private = Ed25519PrivateKey.generate()
|
|
reviewer_file = tmp_path / "reviewer-registration.json"
|
|
registration = _reviewer_registration(reviewer_file, private_key=reviewer_private)
|
|
helpers = _load_existing_batch_test_module()
|
|
inventory = helpers.batch.load_runtime_inventory(REPO_ROOT)
|
|
manifest = helpers._manifest(inventory, resolved=True)
|
|
manifest_raw = authority._canonical(manifest)
|
|
manifest_file = tmp_path / "rc06-publication-manifest.json"
|
|
manifest_file.write_bytes(manifest_raw)
|
|
manifest_sha = authority.batch._sha256_bytes(manifest_raw)
|
|
monkeypatch.setattr(
|
|
authority.batch,
|
|
"TRUSTED_APPROVAL_ROOT_PUBLIC_KEY_SHA256",
|
|
keys[authority.ROLE_RC06_ROOT].public_sha256,
|
|
)
|
|
monkeypatch.setattr(
|
|
authority.batch,
|
|
"TRUSTED_APPLY_SERVICE_PUBLIC_KEY_SHA256",
|
|
keys[authority.ROLE_APPLY_SERVICE].public_sha256,
|
|
)
|
|
monkeypatch.setattr(authority.batch, "FROZEN_APPROVAL_KEYRING_EPOCH", 1)
|
|
keyring_result = authority.build_rc06_candidate_keyring(
|
|
state,
|
|
reviewer_file,
|
|
manifest_file,
|
|
manifest_sha,
|
|
unprotect=_unprotect,
|
|
now=datetime(2026, 9, 27, 3, 0, tzinfo=UTC),
|
|
)
|
|
keyring_directory = Path(keyring_result["directory"])
|
|
keyring_file = keyring_directory / "rc06-approval-keyring.json"
|
|
keyring_raw = keyring_file.read_bytes()
|
|
keyring = json.loads(keyring_raw)
|
|
approved_at = datetime(2026, 9, 27, 3, 10, tzinfo=UTC)
|
|
expires_at = datetime(2026, 9, 27, 5, 0, tzinfo=UTC)
|
|
approval_payload = authority.batch.build_approval_payload(
|
|
manifest,
|
|
manifest_raw_sha256=manifest_sha,
|
|
key_id=registration["key_id"],
|
|
approval_keyring_epoch=1,
|
|
approval_keyring_payload_sha256=keyring["keyring_payload_sha256"],
|
|
approved_at=approved_at,
|
|
expires_at=expires_at,
|
|
)
|
|
approval_signature = reviewer_private.sign(
|
|
authority.batch.APPROVAL_SIGNATURE_DOMAIN + authority._canonical(approval_payload)
|
|
)
|
|
approval = {
|
|
"schema_version": authority.batch.APPROVAL_SCHEMA_VERSION,
|
|
"approval_id": (
|
|
"rc06-batch-approval-"
|
|
+ authority.batch._sha256_bytes(
|
|
authority._canonical(approval_payload) + approval_signature
|
|
)[:24]
|
|
),
|
|
"payload": approval_payload,
|
|
"signature": base64.b64encode(approval_signature).decode("ascii"),
|
|
}
|
|
approval_file = tmp_path / "rc06-batch-approval.json"
|
|
approval_raw = authority._canonical(approval)
|
|
approval_file.write_bytes(approval_raw)
|
|
item_results = [
|
|
{
|
|
"kind": "asset",
|
|
"item_id": item["template_id"],
|
|
"expected_content_sha256": item["content_sha256"],
|
|
"online_content_sha256": item["content_sha256"],
|
|
"status": "applied_and_verified",
|
|
}
|
|
for item in manifest["asset_batch"]["items"]
|
|
] + [
|
|
{
|
|
"kind": "prompt_module",
|
|
"item_id": item["key"],
|
|
"expected_content_sha256": item["content_sha256"],
|
|
"online_content_sha256": item["content_sha256"],
|
|
"status": "applied_and_verified",
|
|
}
|
|
for item in manifest["prompt_module_batch"]["items"]
|
|
]
|
|
item_results.sort(key=lambda item: (item["kind"], item["item_id"]))
|
|
apply_payload = {
|
|
"schema_version": authority.batch.APPLY_PAYLOAD_SCHEMA_VERSION,
|
|
"batch_manifest_payload_sha256": manifest["manifest_payload_sha256"],
|
|
"approval_receipt_sha256": authority.batch._sha256_bytes(approval_raw),
|
|
"environment_id": "isolated-uat-fixture",
|
|
"applied_at": "2026-09-27T04:00:00Z",
|
|
"generated_by": {"type": "system", "component": "rc06-publication-service"},
|
|
"item_results": item_results,
|
|
"write_count": 74,
|
|
"status": "applied_and_verified",
|
|
}
|
|
payloads_file = tmp_path / "apply-payloads.json"
|
|
payloads_raw = authority._canonical(apply_payload)
|
|
payloads_file.write_bytes(payloads_raw)
|
|
return {
|
|
"state": state,
|
|
"keys": keys,
|
|
"reviewer_private": reviewer_private,
|
|
"registration": registration,
|
|
"manifest": manifest,
|
|
"manifest_file": manifest_file,
|
|
"manifest_sha": manifest_sha,
|
|
"keyring": keyring,
|
|
"keyring_file": keyring_file,
|
|
"keyring_sha": authority.batch._sha256_bytes(keyring_raw),
|
|
"root_file": keyring_directory / "rc06-approval-root-public-key.raw",
|
|
"approval": approval,
|
|
"approval_file": approval_file,
|
|
"approval_sha": authority.batch._sha256_bytes(approval_raw),
|
|
"apply_payload": apply_payload,
|
|
"payloads_file": payloads_file,
|
|
"payloads_sha": authority.batch._sha256_bytes(payloads_raw),
|
|
}
|
|
|
|
|
|
def test_authority_initialization_creates_three_distinct_protected_keys_and_is_idempotent(
|
|
tmp_path: Path,
|
|
) -> None:
|
|
state, result, keys = _initialize(tmp_path)
|
|
|
|
assert result["status"] == "initialized_not_pinned_not_signed"
|
|
assert result["private_key_export_supported"] is False
|
|
assert set(keys) == set(authority.AUTHORITY_ROLES)
|
|
assert len({item.public_raw for item in keys.values()}) == 3
|
|
key_dir = state / authority.KEYS_DIRECTORY_NAME
|
|
assert set(child.name for child in key_dir.iterdir()) == (
|
|
authority._expected_authority_names() | {authority.signer.BUNDLE_COMPLETE_FILENAME}
|
|
)
|
|
for role, item in keys.items():
|
|
protected_raw = (key_dir / authority._private_filename(role)).read_bytes()
|
|
private_der = authority._private_der(item.private_key)
|
|
assert private_der not in protected_raw
|
|
assert b"BEGIN PRIVATE KEY" not in protected_raw
|
|
envelope = json.loads(protected_raw)
|
|
assert envelope["protection"] == authority.PROTECTION_NAME
|
|
assert base64.b64decode(envelope["ciphertext_base64"], validate=True) != private_der
|
|
|
|
repeated = authority.initialize_authority(
|
|
state,
|
|
protect=lambda _raw, _role: pytest.fail("idempotent initialization generated a new key"),
|
|
unprotect=_unprotect,
|
|
)
|
|
assert repeated["status"] == "already_initialized_and_verified"
|
|
assert repeated["roles"] == result["roles"]
|
|
|
|
|
|
def test_authority_rejects_partial_or_tampered_bundle(tmp_path: Path) -> None:
|
|
state, _result, _keys = _initialize(tmp_path)
|
|
key_dir = state / authority.KEYS_DIRECTORY_NAME
|
|
(key_dir / authority._public_filename(authority.ROLE_APPLY_SERVICE)).unlink()
|
|
|
|
with pytest.raises(authority.AuthorityError, match="incomplete"):
|
|
authority.initialize_authority(state, protect=_protect, unprotect=_unprotect)
|
|
|
|
|
|
def test_recovery_keyrings_share_only_the_recovery_root_and_verify_both_schemas(
|
|
tmp_path: Path,
|
|
) -> None:
|
|
state, _result, keys = _initialize(tmp_path)
|
|
reviewer_file = tmp_path / "reviewer-registration.json"
|
|
reviewer = _reviewer_registration(reviewer_file)
|
|
now = datetime(2026, 9, 27, 2, 0, tzinfo=UTC)
|
|
|
|
result = authority.build_recovery_keyrings(
|
|
state,
|
|
reviewer_file,
|
|
epoch=1,
|
|
unprotect=_unprotect,
|
|
now=now,
|
|
validity=timedelta(days=30),
|
|
)
|
|
|
|
assert result["status"] == "recovery_keyrings_created_not_pinned"
|
|
assert result["recovery_root_public_key_sha256"] == keys[
|
|
authority.ROLE_RECOVERY_ROOT
|
|
].public_sha256
|
|
assert result["first_release_keyring_payload_sha256"] != result[
|
|
"rollback_keyring_payload_sha256"
|
|
]
|
|
bundle = Path(result["directory"])
|
|
first_release = json.loads((bundle / "first-release-recovery-keyring.json").read_bytes())
|
|
rollback = json.loads((bundle / "rollback-rehearsal-keyring.json").read_bytes())
|
|
assert first_release["root_key_id"] == authority.FIRST_RELEASE_ROOT_KEY_ID
|
|
assert rollback["root_key_id"] == authority.ROLLBACK_ROOT_KEY_ID
|
|
assert "algorithm" not in first_release["keys"][0]
|
|
assert rollback["keys"][0]["algorithm"] == "ed25519"
|
|
assert first_release["keys"][0]["public_key_base64"] == rollback["keys"][0][
|
|
"public_key_base64"
|
|
]
|
|
assert reviewer["public_key_raw_sha256"] not in {
|
|
item.public_sha256 for item in keys.values()
|
|
}
|
|
|
|
repeated = authority.build_recovery_keyrings(
|
|
state,
|
|
reviewer_file,
|
|
epoch=1,
|
|
unprotect=_unprotect,
|
|
now=now + timedelta(hours=1),
|
|
)
|
|
assert repeated["status"] == "recovery_keyrings_already_created_and_verified_not_pinned"
|
|
assert repeated["first_release_keyring_payload_sha256"] == result[
|
|
"first_release_keyring_payload_sha256"
|
|
]
|
|
|
|
|
|
def test_recovery_keyrings_reject_reviewer_reuse_of_any_technical_key(tmp_path: Path) -> None:
|
|
state, _result, keys = _initialize(tmp_path)
|
|
technical_private = keys[authority.ROLE_APPLY_SERVICE].private_key
|
|
reviewer_file = tmp_path / "reviewer-registration.json"
|
|
_reviewer_registration(reviewer_file, private_key=technical_private)
|
|
|
|
with pytest.raises(authority.AuthorityError, match="must differ"):
|
|
authority.build_recovery_keyrings(
|
|
state,
|
|
reviewer_file,
|
|
epoch=1,
|
|
unprotect=_unprotect,
|
|
now=datetime(2026, 9, 27, 2, 0, tzinfo=UTC),
|
|
)
|
|
|
|
|
|
def test_pin_preview_and_apply_update_only_public_hashes_and_epoch_in_temp_sources(
|
|
tmp_path: Path,
|
|
) -> None:
|
|
state, _result, keys = _initialize(tmp_path)
|
|
reviewer_file = tmp_path / "reviewer-registration.json"
|
|
_reviewer_registration(reviewer_file)
|
|
recovery = authority.build_recovery_keyrings(
|
|
state,
|
|
reviewer_file,
|
|
epoch=1,
|
|
unprotect=_unprotect,
|
|
now=datetime(2026, 9, 27, 2, 0, tzinfo=UTC),
|
|
)
|
|
repo = _copy_pin_sources(tmp_path)
|
|
before = {
|
|
path.relative_to(repo): path.read_bytes()
|
|
for path in repo.rglob("*.py")
|
|
}
|
|
|
|
plan = authority.plan_pin_updates(
|
|
repo,
|
|
state,
|
|
Path(recovery["directory"]),
|
|
epoch=1,
|
|
unprotect=_unprotect,
|
|
)
|
|
preview = authority.pin_plan_summary(plan)
|
|
assert preview["status"] == "preview_only_not_applied"
|
|
assert all(path.read_bytes() == before[path.relative_to(repo)] for path in repo.rglob("*.py"))
|
|
assert all(len(str(value)) in {1, 64} for value in preview["values"].values())
|
|
|
|
applied = authority.apply_pin_plan(plan)
|
|
assert applied["status"] == "pins_applied_not_frozen_not_signed"
|
|
assert applied["changed_file_count"] == 3
|
|
rc06 = (repo / "yuqei-infra/scripts/build-rc06-publication-batch.py").read_text(
|
|
encoding="utf-8"
|
|
)
|
|
first = (repo / "yuqei-infra/deploy/plan-first-release-snapshot-restore.py").read_text(
|
|
encoding="utf-8"
|
|
)
|
|
rollback = (repo / "yuqei-infra/deploy/plan-rollback-rehearsal.py").read_text(
|
|
encoding="utf-8"
|
|
)
|
|
assert f'TRUSTED_APPROVAL_ROOT_PUBLIC_KEY_SHA256 = "{keys[authority.ROLE_RC06_ROOT].public_sha256}"' in rc06
|
|
assert f'TRUSTED_APPLY_SERVICE_PUBLIC_KEY_SHA256 = "{keys[authority.ROLE_APPLY_SERVICE].public_sha256}"' in rc06
|
|
assert "FROZEN_APPROVAL_KEYRING_EPOCH = 1" in rc06
|
|
for text in (first, rollback):
|
|
assert f'TRUSTED_ROOT_PUBLIC_KEY_SHA256 = "{keys[authority.ROLE_RECOVERY_ROOT].public_sha256}"' in text
|
|
assert re.search(r"(?m)^MIN_KEYRING_EPOCH: int \| None = 1$", text)
|
|
assert "PRIVATE KEY" not in text
|
|
|
|
repeated = authority.plan_pin_updates(
|
|
repo,
|
|
state,
|
|
Path(recovery["directory"]),
|
|
epoch=1,
|
|
unprotect=_unprotect,
|
|
)
|
|
assert all(change.original == change.proposed for change in repeated.changes)
|
|
assert authority.apply_pin_plan(repeated)["changed_file_count"] == 0
|
|
|
|
|
|
def test_pin_planner_refuses_unknown_existing_pin_without_overwriting(tmp_path: Path) -> None:
|
|
state, _result, _keys = _initialize(tmp_path)
|
|
reviewer_file = tmp_path / "reviewer-registration.json"
|
|
_reviewer_registration(reviewer_file)
|
|
recovery = authority.build_recovery_keyrings(
|
|
state,
|
|
reviewer_file,
|
|
epoch=1,
|
|
unprotect=_unprotect,
|
|
now=datetime(2026, 9, 27, 2, 0, tzinfo=UTC),
|
|
)
|
|
repo = _copy_pin_sources(tmp_path)
|
|
rc06 = repo / "yuqei-infra/scripts/build-rc06-publication-batch.py"
|
|
original = rc06.read_text(encoding="utf-8")
|
|
rc06.write_text(
|
|
original.replace(
|
|
'TRUSTED_APPROVAL_ROOT_PUBLIC_KEY_SHA256 = ""',
|
|
'TRUSTED_APPROVAL_ROOT_PUBLIC_KEY_SHA256 = "' + "f" * 64 + '"',
|
|
),
|
|
encoding="utf-8",
|
|
)
|
|
|
|
# A different already-provisioned pin cannot be replaced by a first-time
|
|
# provisioning run.
|
|
with pytest.raises(authority.AuthorityError, match="different epoch|unexpected existing value"):
|
|
authority.plan_pin_updates(
|
|
repo,
|
|
state,
|
|
Path(recovery["directory"]),
|
|
epoch=1,
|
|
unprotect=_unprotect,
|
|
)
|
|
|
|
|
|
def test_pin_apply_rolls_back_completed_files_when_later_replace_fails(
|
|
tmp_path: Path,
|
|
monkeypatch: pytest.MonkeyPatch,
|
|
) -> None:
|
|
state, _result, _keys = _initialize(tmp_path)
|
|
reviewer_file = tmp_path / "reviewer-registration.json"
|
|
_reviewer_registration(reviewer_file)
|
|
recovery = authority.build_recovery_keyrings(
|
|
state,
|
|
reviewer_file,
|
|
epoch=1,
|
|
unprotect=_unprotect,
|
|
now=datetime(2026, 9, 27, 2, 0, tzinfo=UTC),
|
|
)
|
|
repo = _copy_pin_sources(tmp_path)
|
|
plan = authority.plan_pin_updates(
|
|
repo,
|
|
state,
|
|
Path(recovery["directory"]),
|
|
epoch=1,
|
|
unprotect=_unprotect,
|
|
)
|
|
real_replace = authority._write_atomic_replacement
|
|
calls = 0
|
|
|
|
def fail_second(path: Path, raw: bytes) -> None:
|
|
nonlocal calls
|
|
calls += 1
|
|
if calls == 2:
|
|
raise OSError("fixture replacement failure")
|
|
real_replace(path, raw)
|
|
|
|
monkeypatch.setattr(authority, "_write_atomic_replacement", fail_second)
|
|
with pytest.raises(authority.AuthorityError, match="transaction failed"):
|
|
authority.apply_pin_plan(plan)
|
|
assert all(change.path.read_bytes() == change.original for change in plan.changes)
|
|
|
|
|
|
def test_rc06_candidate_keyring_requires_frozen_pin_and_binds_exact_manifest(
|
|
tmp_path: Path,
|
|
monkeypatch: pytest.MonkeyPatch,
|
|
) -> None:
|
|
state, _result, keys = _initialize(tmp_path)
|
|
reviewer_file = tmp_path / "reviewer-registration.json"
|
|
registration = _reviewer_registration(reviewer_file)
|
|
manifest_file = tmp_path / "manifest.json"
|
|
manifest_raw = authority._canonical({"fixture": "validated elsewhere in this unit test"})
|
|
manifest_file.write_bytes(manifest_raw)
|
|
manifest_sha = authority.batch._sha256_bytes(manifest_raw)
|
|
monkeypatch.setattr(authority.batch, "validate_manifest", lambda value: value)
|
|
|
|
with pytest.raises(authority.AuthorityError, match="frozen RC-06 root pin"):
|
|
authority.build_rc06_candidate_keyring(
|
|
state,
|
|
reviewer_file,
|
|
manifest_file,
|
|
manifest_sha,
|
|
unprotect=_unprotect,
|
|
now=datetime(2026, 9, 27, 3, 0, tzinfo=UTC),
|
|
)
|
|
|
|
monkeypatch.setattr(
|
|
authority.batch,
|
|
"TRUSTED_APPROVAL_ROOT_PUBLIC_KEY_SHA256",
|
|
keys[authority.ROLE_RC06_ROOT].public_sha256,
|
|
)
|
|
monkeypatch.setattr(authority.batch, "FROZEN_APPROVAL_KEYRING_EPOCH", 1)
|
|
result = authority.build_rc06_candidate_keyring(
|
|
state,
|
|
reviewer_file,
|
|
manifest_file,
|
|
manifest_sha,
|
|
unprotect=_unprotect,
|
|
now=datetime(2026, 9, 27, 3, 0, tzinfo=UTC),
|
|
)
|
|
assert result["status"] == "rc06_candidate_keyring_created_not_approved"
|
|
bundle = Path(result["directory"])
|
|
keyring = json.loads((bundle / "rc06-approval-keyring.json").read_bytes())
|
|
assert keyring["authorized_batch_manifest_raw_sha256"] == manifest_sha
|
|
assert keyring["epoch"] == 1
|
|
assert keyring["keys"][0]["key_id"] == registration["key_id"]
|
|
assert keyring["root_key_id"] == authority.batch.TRUSTED_APPROVAL_ROOT_KEY_ID
|
|
|
|
repeated = authority.build_rc06_candidate_keyring(
|
|
state,
|
|
reviewer_file,
|
|
manifest_file,
|
|
manifest_sha,
|
|
unprotect=_unprotect,
|
|
now=datetime(2026, 9, 27, 4, 0, tzinfo=UTC),
|
|
)
|
|
assert repeated["status"] == "rc06_candidate_keyring_already_created_and_verified_not_approved"
|
|
with pytest.raises(authority.AuthorityError, match="SHA-256 mismatch"):
|
|
authority.build_rc06_candidate_keyring(
|
|
state,
|
|
reviewer_file,
|
|
manifest_file,
|
|
"f" * 64,
|
|
unprotect=_unprotect,
|
|
now=datetime(2026, 9, 27, 4, 0, tzinfo=UTC),
|
|
)
|
|
|
|
|
|
def test_apply_private_key_provision_command_fails_closed_without_export(
|
|
tmp_path: Path,
|
|
monkeypatch: pytest.MonkeyPatch,
|
|
capsys: pytest.CaptureFixture[str],
|
|
) -> None:
|
|
monkeypatch.setattr(authority, "_assert_runtime", lambda: None)
|
|
result = authority.main(
|
|
[
|
|
"provision-apply-private-key",
|
|
"--state-directory",
|
|
os.fspath(tmp_path / "authority-state"),
|
|
]
|
|
)
|
|
captured = capsys.readouterr()
|
|
assert result == 2
|
|
assert "not implemented" in captured.err
|
|
assert '"private_material_exported":false' in captured.err
|
|
assert list(tmp_path.iterdir()) == []
|
|
|
|
|
|
def test_apply_payload_signing_is_bound_verified_atomic_and_idempotent(
|
|
tmp_path: Path,
|
|
monkeypatch: pytest.MonkeyPatch,
|
|
) -> None:
|
|
materials = _formal_apply_materials(tmp_path, monkeypatch)
|
|
output = tmp_path / "signed-apply-receipts"
|
|
result = authority.sign_apply_payloads(
|
|
materials["state"],
|
|
manifest_file=materials["manifest_file"],
|
|
manifest_sha256=materials["manifest_sha"],
|
|
approval_file=materials["approval_file"],
|
|
approval_sha256=materials["approval_sha"],
|
|
approval_keyring_file=materials["keyring_file"],
|
|
approval_keyring_sha256=materials["keyring_sha"],
|
|
approval_root_public_key_file=materials["root_file"],
|
|
payloads_file=materials["payloads_file"],
|
|
payloads_sha256=materials["payloads_sha"],
|
|
output_directory=output,
|
|
unprotect=_unprotect,
|
|
)
|
|
assert result["status"] == "apply_receipts_signed_and_verified_not_published"
|
|
assert result["receipt_count"] == 1
|
|
assert result["business_api_calls"] == 0
|
|
assert result["private_keys_in_bundle"] is False
|
|
receipt = json.loads((output / "apply-receipt-001.json").read_bytes())
|
|
assert authority.batch.validate_apply_receipt(
|
|
materials["manifest"],
|
|
materials["manifest_sha"],
|
|
materials["approval"],
|
|
materials["keyring"],
|
|
materials["keys"][authority.ROLE_RC06_ROOT].public_key,
|
|
materials["keys"][authority.ROLE_APPLY_SERVICE].public_key,
|
|
materials["approval_sha"],
|
|
receipt,
|
|
) == receipt
|
|
repeated = authority.sign_apply_payloads(
|
|
materials["state"],
|
|
manifest_file=materials["manifest_file"],
|
|
manifest_sha256=materials["manifest_sha"],
|
|
approval_file=materials["approval_file"],
|
|
approval_sha256=materials["approval_sha"],
|
|
approval_keyring_file=materials["keyring_file"],
|
|
approval_keyring_sha256=materials["keyring_sha"],
|
|
approval_root_public_key_file=materials["root_file"],
|
|
payloads_file=materials["payloads_file"],
|
|
payloads_sha256=materials["payloads_sha"],
|
|
output_directory=output,
|
|
unprotect=_unprotect,
|
|
)
|
|
assert repeated["status"] == "apply_receipts_already_signed_and_verified_not_published"
|
|
assert repeated["receipts"] == result["receipts"]
|
|
|
|
|
|
def test_apply_payload_signing_rejects_tamper_cross_approval_and_partial_bundle(
|
|
tmp_path: Path,
|
|
monkeypatch: pytest.MonkeyPatch,
|
|
) -> None:
|
|
materials = _formal_apply_materials(tmp_path, monkeypatch)
|
|
|
|
tampered = dict(materials["apply_payload"])
|
|
tampered["batch_manifest_payload_sha256"] = "f" * 64
|
|
tampered_file = tmp_path / "tampered-payload.json"
|
|
tampered_raw = authority._canonical(tampered)
|
|
tampered_file.write_bytes(tampered_raw)
|
|
tampered_output = tmp_path / "tampered-output"
|
|
with pytest.raises(authority.AuthorityError, match="not bound to this batch"):
|
|
authority.sign_apply_payloads(
|
|
materials["state"],
|
|
manifest_file=materials["manifest_file"],
|
|
manifest_sha256=materials["manifest_sha"],
|
|
approval_file=materials["approval_file"],
|
|
approval_sha256=materials["approval_sha"],
|
|
approval_keyring_file=materials["keyring_file"],
|
|
approval_keyring_sha256=materials["keyring_sha"],
|
|
approval_root_public_key_file=materials["root_file"],
|
|
payloads_file=tampered_file,
|
|
payloads_sha256=authority.batch._sha256_bytes(tampered_raw),
|
|
output_directory=tampered_output,
|
|
unprotect=_unprotect,
|
|
)
|
|
assert not tampered_output.exists()
|
|
|
|
second_payload = dict(materials["approval"]["payload"])
|
|
second_payload["approved_at"] = "2026-09-27T03:15:00Z"
|
|
second_signature = materials["reviewer_private"].sign(
|
|
authority.batch.APPROVAL_SIGNATURE_DOMAIN + authority._canonical(second_payload)
|
|
)
|
|
second_approval = {
|
|
"schema_version": authority.batch.APPROVAL_SCHEMA_VERSION,
|
|
"approval_id": (
|
|
"rc06-batch-approval-"
|
|
+ authority.batch._sha256_bytes(
|
|
authority._canonical(second_payload) + second_signature
|
|
)[:24]
|
|
),
|
|
"payload": second_payload,
|
|
"signature": base64.b64encode(second_signature).decode("ascii"),
|
|
}
|
|
second_approval_file = tmp_path / "second-approval.json"
|
|
second_approval_raw = authority._canonical(second_approval)
|
|
second_approval_file.write_bytes(second_approval_raw)
|
|
with pytest.raises(authority.AuthorityError, match="not bound to the approval receipt"):
|
|
authority.sign_apply_payloads(
|
|
materials["state"],
|
|
manifest_file=materials["manifest_file"],
|
|
manifest_sha256=materials["manifest_sha"],
|
|
approval_file=second_approval_file,
|
|
approval_sha256=authority.batch._sha256_bytes(second_approval_raw),
|
|
approval_keyring_file=materials["keyring_file"],
|
|
approval_keyring_sha256=materials["keyring_sha"],
|
|
approval_root_public_key_file=materials["root_file"],
|
|
payloads_file=materials["payloads_file"],
|
|
payloads_sha256=materials["payloads_sha"],
|
|
output_directory=tmp_path / "cross-approval-output",
|
|
unprotect=_unprotect,
|
|
)
|
|
|
|
partial = dict(materials["apply_payload"])
|
|
partial["item_results"] = partial["item_results"][:-1]
|
|
payload_list = [materials["apply_payload"], partial]
|
|
payload_list_file = tmp_path / "payload-list.json"
|
|
payload_list_raw = authority._canonical(payload_list)
|
|
payload_list_file.write_bytes(payload_list_raw)
|
|
partial_output = tmp_path / "partial-output"
|
|
with pytest.raises(authority.AuthorityError, match="74-item online evidence drift"):
|
|
authority.sign_apply_payloads(
|
|
materials["state"],
|
|
manifest_file=materials["manifest_file"],
|
|
manifest_sha256=materials["manifest_sha"],
|
|
approval_file=materials["approval_file"],
|
|
approval_sha256=materials["approval_sha"],
|
|
approval_keyring_file=materials["keyring_file"],
|
|
approval_keyring_sha256=materials["keyring_sha"],
|
|
approval_root_public_key_file=materials["root_file"],
|
|
payloads_file=payload_list_file,
|
|
payloads_sha256=authority.batch._sha256_bytes(payload_list_raw),
|
|
output_directory=partial_output,
|
|
unprotect=_unprotect,
|
|
)
|
|
assert not partial_output.exists()
|
|
|
|
|
|
def test_authority_launcher_uses_authority_script_and_forwards_non_secret_arguments() -> None:
|
|
text = AUTHORITY_LAUNCHER.read_text(encoding="utf-8-sig")
|
|
assert '"rc06-release-trust-bootstrap.py"' in text
|
|
assert "ValueFromRemainingArguments = $true" in text
|
|
assert "$authorityScript $Command @CommandArguments" in text
|
|
assert "rc06-single-reviewer-signing.py" not in text
|
|
assert "password" not in text.casefold()
|
|
assert "passphrase" not in text.casefold()
|
|
|
|
|
|
@pytest.mark.skipif(os.name != "nt", reason="Windows CurrentUser DPAPI is platform-specific")
|
|
def test_windows_current_user_dpapi_round_trip_has_role_entropy() -> None:
|
|
raw = b"not-a-real-private-key-fixture"
|
|
protected = authority._protect_current_user(raw, authority.ROLE_RC06_ROOT)
|
|
assert protected != raw
|
|
assert authority._unprotect_current_user(protected, authority.ROLE_RC06_ROOT) == raw
|
|
with pytest.raises(authority.AuthorityError):
|
|
authority._unprotect_current_user(protected, authority.ROLE_APPLY_SERVICE)
|