Files
aios/tests/test_c5_completion_renewal.py
T
AIOS Governed Continuation 540e28a724
autonomy-smoke-tests Exact governed tree; evidence 7dbba7ff168e72af
autonomy-unit-tests Exact governed tree; evidence 7dbba7ff168e72af
campaign-approval-gate Exact governed tree; evidence 7dbba7ff168e72af
git-diff-check Exact governed tree; evidence 7dbba7ff168e72af
py-compile Exact governed tree; evidence 7dbba7ff168e72af
reconciliation-contract Exact governed tree; evidence 7dbba7ff168e72af
release-state-machine Exact governed tree; evidence 7dbba7ff168e72af
secret-scan Exact governed tree; evidence 7029b3eafb209066
signer-validator-contract Exact governed tree; evidence 7dbba7ff168e72af
Publish exact C5 issuer V3 bootstrap source
2026-10-01 23:09:33 +08:00

585 lines
31 KiB
Python

import base64
import copy
import os
from pathlib import Path
from datetime import datetime, timezone
import pytest
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
from cryptography.hazmat.primitives.serialization import Encoding, PublicFormat
import c5_completion_renewal as renewal
def test_registered_bindings_require_digest_and_install_no_live_defaults(monkeypatch):
root = Path.cwd() / 'registered'
value = {
'schema': 'aios.c5.completion-bindings.v1',
'authority_root': str(root / 'c5'),
'state_root': str(root / 'state'),
'owner_key_id': 'SHA256:' + base64.b64encode(b'k' * 32).decode(),
'predecessor_fingerprint': '1' * 64,
'saga_head': '2' * 64,
'historical_root': str(root / 'history'),
'controller_workspace': str(root / 'workspace'),
'authoritative_git_dir': str(root / 'repo.git'),
'runtime_registry_root': str(root / 'registry'),
'runtime_baseline_path': str(root / 'baseline.json'),
'trusted_release_policy_path': str(root / 'policy.json'),
'trusted_release_policy_sha256': '3' * 64,
}
raw = renewal.canonical(value)
monkeypatch.setattr(renewal, '_safe_parents', lambda _path: None)
monkeypatch.setattr(renewal, 'secure_bytes', lambda _path, owner_uid=0: raw)
monkeypatch.setattr(renewal, '_BINDINGS_DIGEST', None)
result = renewal.configure_registered_bindings(
root / 'c5' / 'completion-bindings.json', renewal.digest(raw),
)
assert result == value
assert renewal.AUTHORITY_ROOT == root / 'c5'
assert renewal.STATE_ROOT == root / 'state'
with pytest.raises(renewal.RenewalRejected, match='DIGEST_MISMATCH'):
renewal.configure_registered_bindings(
root / 'c5' / 'completion-bindings.json', 'f' * 64,
)
def signed(payload, key):
raw = renewal.canonical(payload)
return {**payload, 'fingerprint': renewal.digest(raw),
'signature': base64.b64encode(key.sign(raw)).decode()}
@pytest.fixture
def materials(monkeypatch):
key = Ed25519PrivateKey.generate()
public = key.public_key().public_bytes(Encoding.Raw, PublicFormat.Raw)
payload = {'candidate_id': renewal.CID, 'source_commit': renewal.SOURCE,
'tree_oid': renewal.TREE, 'artifact_sha256': renewal.ARTIFACT,
'release_plan_sha256': renewal.PLAN, 'capabilities': renewal.CAPABILITIES,
'issued_at': '2026-10-01T07:47:47Z', 'not_before': '2026-10-01T07:47:47Z',
'expires_at': '2026-10-01T08:47:47Z', 'nonce': 'historical', 'key_id': 'fixture',
'owner_identity': 'fixture-owner', 'trust_domain': 'fixture-domain',
'owner_approval_record_oid': 'a'*40}
old = signed(payload, key)
monkeypatch.setattr(renewal, 'OLD_FP', old['fingerprint'])
successor = {**payload, 'issued_at': '2026-10-01T08:50:00Z',
'not_before': '2026-10-01T08:50:00Z', 'expires_at': '2026-10-01T09:00:00Z', 'nonce': 'fresh'}
return key, public, old, signed(successor, key), renewal.timestamp('2026-10-01T08:51:00Z')
def test_valid_chain_and_append_preserve_original(tmp_path, materials):
key, public, old, new, now = materials
historical = renewal.canonical(old)
path = tmp_path / 'original.json';path.write_bytes(historical)
receipt = renewal.publish_successor(tmp_path, old, new, public, now=now,
registration_digest='1'*64, predecessor_bytes=historical)
assert path.read_bytes() == historical
assert receipt['runtime_effects_allowed'] is False
assert receipt['completion_only'] is True
assert renewal.publish_successor(tmp_path, old, new, public, now=now,
registration_digest='1'*64, predecessor_bytes=historical) == receipt
@pytest.mark.parametrize('field,value', [
('candidate_id','other'), ('source_commit','f'*40), ('tree_oid','f'*40),
('artifact_sha256','f'*64), ('release_plan_sha256','f'*64), ('key_id','other'),
('capabilities',['tag_publish']), ('nonce','historical'),
('expires_at','2026-10-01T08:51:00Z'), ('expires_at','2026-10-01T09:50:00Z'),
('issued_at','2026-10-01T08:52:00Z'), ('not_before','2026-10-01T08:52:00Z'),
])
def test_signed_drift_or_stale_rejected(materials, field, value):
key, public, old, new, now = materials
payload = {k:v for k,v in new.items() if k not in {'fingerprint','signature'}}
payload[field] = value
with pytest.raises(renewal.RenewalRejected):
renewal.validate_successor(old, signed(payload,key), public, now=now)
def test_live_predecessor_cannot_be_superseded(materials):
key, public, old, new, now = materials
with pytest.raises(renewal.RenewalRejected, match='PREDECESSOR_NOT_EXPIRED'):
renewal.validate_successor(old, new, public, now=renewal.timestamp('2026-10-01T08:47:00Z'))
def test_tampered_signature_and_unexpected_field_rejected(materials):
key, public, old, new, now = materials
altered = copy.deepcopy(new);altered['source_commit'] = 'f'*40
with pytest.raises(renewal.RenewalRejected, match='DIGEST_INVALID'):
renewal.validate_successor(old, altered, public, now=now)
altered = {k:v for k,v in new.items() if k not in {'fingerprint','signature'}}
altered['new_authority'] = True
with pytest.raises(renewal.RenewalRejected, match='BINDING_DRIFT'):
renewal.validate_successor(old, signed(altered,key), public, now=now)
def test_conflicting_receipt_is_not_replaced(tmp_path, materials):
_, public, old, new, now = materials
receipt = tmp_path/(new['fingerprint']+'.receipt.json')
receipt.write_bytes(b'old audit');receipt.chmod(0o600)
with pytest.raises(renewal.RenewalRejected, match='APPEND_ONLY_RECORD_CONFLICT'):
renewal.publish_successor(tmp_path, old, new, public, now=now,
registration_digest='1'*64, predecessor_bytes=renewal.canonical(old))
assert receipt.read_bytes() == b'old audit'
def test_symlink_and_world_writable_directory_rejected(tmp_path, materials):
_, public, old, new, now = materials
original = tmp_path/'preserved';original.write_bytes(b'unchanged');original.chmod(0o600)
alias = tmp_path/(new['fingerprint']+'.approval.json');alias.symlink_to(original)
with pytest.raises(OSError):
renewal.publish_successor(tmp_path, old, new, public, now=now,
registration_digest='1'*64, predecessor_bytes=renewal.canonical(old))
assert original.read_bytes() == b'unchanged'
alias.unlink();tmp_path.chmod(0o777)
with pytest.raises(renewal.RenewalRejected, match='UNSAFE_APPEND_DIRECTORY'):
renewal.publish_successor(tmp_path, old, new, public, now=now,
registration_digest='1'*64, predecessor_bytes=renewal.canonical(old))
def test_predecessor_raw_bytes_must_match_signed_parent(tmp_path, materials):
_, public, old, new, now = materials
with pytest.raises(renewal.RenewalRejected, match='PREDECESSOR_BYTES_DRIFT'):
renewal.publish_successor(tmp_path, old, new, public, now=now,
registration_digest='1'*64, predecessor_bytes=b'{}')
assert list(tmp_path.iterdir()) == []
@pytest.fixture
def store_fixture(tmp_path, materials, monkeypatch):
key, public, old, new, now = materials
new_payload = {k:v for k,v in new.items() if k not in {'fingerprint','signature'}}
new_payload['nonce'] = 'a'*64
new = signed(new_payload,key)
class Frozen(datetime):
@classmethod
def now(cls, tz=None):
return datetime.fromtimestamp(now, timezone.utc)
monkeypatch.setattr(renewal,'datetime',Frozen)
class Approval:
def __init__(self,value):self.value=value;self.fingerprint=value['fingerprint']
def to_dict(self):return self.value
@classmethod
def from_dict(cls,value):return cls(value)
class Original:
def __init__(self,root):self.root=root
def load(self,candidate_id):return Approval(old)
def save(self,candidate_id,approval):
assert approval.fingerprint == old['fingerprint']
return self.root/(candidate_id+'.json'),False
origin=tmp_path/'original';origin.mkdir(mode=0o700)
raw=renewal.canonical(old)
(origin/(renewal.CID+'.json')).write_bytes(raw)
(origin/(renewal.CID+'.json')).chmod(0o600)
directory=tmp_path/'renewals';directory.mkdir(mode=0o700)
policy={'candidate_id':renewal.CID,'predecessor_fingerprint':old['fingerprint'],
'approval_nonce':'a'*64,'payload_sha256':'1'*64,
'predecessor_uid':os.geteuid(),'predecessor_sha256':renewal.digest(raw)}
store=renewal.CompletionApprovalStore(Original(origin),directory,public,lambda:policy,Approval)
return store,Approval(new),Approval(old),policy
def test_explicit_store_activation_and_replay(store_fixture):
store,new,old,policy=store_fixture
original=(store.original.root/(renewal.CID+'.json')).read_bytes()
assert store.load(renewal.CID).fingerprint==old.fingerprint
path,created=store.save(renewal.CID,new)
assert created and path.is_file()
assert store.load(renewal.CID).fingerprint==new.fingerprint
assert store.save(renewal.CID,new)[1] is False
assert (store.original.root/(renewal.CID+'.json')).read_bytes()==original
def test_store_rejects_wrong_registered_nonce(store_fixture):
store,new,old,policy=store_fixture
policy['approval_nonce']='b'*64
with pytest.raises(renewal.RenewalRejected,match='REGISTERED_NONCE_MISMATCH'):
store.save(renewal.CID,new)
assert list(store.directory.iterdir())==[]
def test_store_detects_parent_file_change(store_fixture):
store,new,old,policy=store_fixture
path=store.original.root/(renewal.CID+'.json')
path.write_bytes(renewal.canonical({**old.to_dict(),'nonce':'altered'}))
with pytest.raises(renewal.RenewalRejected,match='PREDECESSOR_FILE_DRIFT'):
store.save(renewal.CID,new)
def test_partial_append_is_not_active(store_fixture):
store,new,old,policy=store_fixture
renewal.append_file(store.directory/(new.fingerprint+'.approval.json'),renewal.canonical(new.to_dict()))
assert store.load(renewal.CID).fingerprint==old.fingerprint
def test_active_receipt_tamper_fails_closed(store_fixture):
store,new,old,policy=store_fixture
path,_=store.save(renewal.CID,new)
receipt=__import__('json').loads(path.read_bytes());receipt['runtime_effects_allowed']=True
path.write_bytes(renewal.canonical(receipt))
with pytest.raises(renewal.RenewalRejected,match='SUCCESSOR_ACTIVATION_DRIFT'):
store.load(renewal.CID)
@pytest.fixture
def signer_fixture(tmp_path, materials, monkeypatch):
key,public,old,new,now=materials
class Frozen(datetime):
@classmethod
def now(cls,tz=None):return datetime.fromtimestamp(now,timezone.utc)
monkeypatch.setattr(renewal,'datetime',Frozen)
snapshot=tmp_path/'parent.json';snapshot.write_bytes(renewal.canonical(old));snapshot.chmod(0o600)
policy={'candidate_id':renewal.CID,'predecessor_fingerprint':old['fingerprint'],
'issued_at':now-30,'expires_at':now+900,'gate_observed_at':now-1,
'predecessor_snapshot':str(snapshot),'predecessor_sha256':renewal.digest(snapshot.read_bytes()),
'approval_nonce':'b'*64,'payload_sha256':'1'*64}
class SigningKey:
count=0
def public_key(self):return key.public_key()
def sign(self,raw):self.count+=1;return key.sign(raw)
class Signer(renewal.CompletionSignerMixin):pass
signer=Signer();signer.private_key=SigningKey();signer.authorization_oid='a'*40
signer.policy=type('Policy',(),{'key_id':'fixture','owner_identity':'fixture-owner','trust_domain':'fixture-domain'})()
signer.state_root=tmp_path;(tmp_path/'completion-renewals').mkdir(mode=0o700)
signer.completion_authority=lambda:policy
request={'schema':'aios.exact-release-signer.request.v1','operation':'renew_exact_completion_approval',
'candidate_id':renewal.CID,'predecessor_fingerprint':old['fingerprint']}
return signer,policy,request,old
def test_purpose_signer_signs_once_and_replays(signer_fixture):
signer,policy,request,old=signer_fixture
result=signer.sign_exact_completion_successor(request)
assert result['status']=='SIGNED' and result['completion_only']
assert signer.private_key.count==1
assert result['approval']['nonce']==policy['approval_nonce']
assert signer.sign_exact_completion_successor(request)['status']=='SIGNED_IDEMPOTENT'
assert signer.private_key.count==1
@pytest.mark.parametrize('change',[{'candidate_id':'other'},{'extra':'arbitrary'},{'operation':'sign_anything'}])
def test_purpose_signer_rejects_arbitrary_request_before_sign(signer_fixture,change):
signer,policy,request,old=signer_fixture
with pytest.raises(renewal.RenewalRejected,match='EXACT_SIGNER_RENEWAL_REQUEST_REQUIRED'):
signer.sign_exact_completion_successor({**request,**change})
assert signer.private_key.count==0
@pytest.mark.parametrize('field,value',[('gate_observed_at',0),('expires_at',0),('predecessor_sha256','f'*64),('approval_nonce','historical')])
def test_purpose_signer_rejects_stale_gate_and_preimage_before_sign(signer_fixture,field,value):
signer,policy,request,old=signer_fixture;policy[field]=value
with pytest.raises(renewal.RenewalRejected):signer.sign_exact_completion_successor(request)
assert signer.private_key.count==0
@pytest.fixture
def registered_authority(tmp_path, monkeypatch):
import sys
import types
root = tmp_path / 'registered'; root.mkdir(mode=0o700)
monkeypatch.setattr(renewal, 'AUTHORITY_ROOT', root)
monkeypatch.setattr(renewal, '__file__', str(root / 'c5_completion_renewal.py'))
# pytest scratch parents are not production paths; preserve the real file
# checks but substitute this ancestry fixture only in the isolated test.
monkeypatch.setattr(renewal, '_safe_parents', lambda path: None)
monkeypatch.setattr(renewal.time, 'time', lambda: 1100)
verifier = types.SimpleNamespace(verify=lambda **kw: kw['signature'] == 'fixture-valid')
monkeypatch.setitem(sys.modules, 'c5_staging_installation', types.SimpleNamespace(
RegistryOwnerVerifier=lambda *a, **kw: verifier))
files = {
'c5_completion_renewal.py': b'fixture registered authority module',
'c5_release_execution_host.py': b'fixture typed host',
'silent_release_hardening.py': b'fixture typed API',
'c5_completion_signer.py': b'fixture exact signer wrapper',
'c5_completion_api.py': b'fixture typed composition',
'c5_completion_phase.py': b'fixture fixed completion phase',
'approval-public-keyring.json': b'fixture public keyring',
'original_api.py': b'fixture preserved original API',
'predecessor-approval.json': b'fixture historical bytes',
'historical-production-proof.json': renewal.canonical({
'candidate_id': renewal.CID, 'approval_fingerprint': renewal.OLD_FP,
'release_plan_sha256': renewal.PLAN, 'status': 'COMPLETED',
'public_business_verified': True, 'real_c4_rollback_verified': True, 'c5_restore_verified': True}),
'current-gate.json': renewal.canonical({
'candidate_id': renewal.CID, 'source_commit': renewal.SOURCE,
'artifact_sha256': renewal.ARTIFACT, 'release_plan_sha256': renewal.PLAN,
'saga_revision': 15, 'saga_head': renewal.SAGA_HEAD, 'local_tag_oid': renewal.TAG_OID,
'remote_tag_oid': None, 'runtime_verified': True, 'business_verified': True,
'global_writes_enabled': False, 'observed_at': 1000}),
}
for name in renewal.PHASE_DEPENDENCIES: files[name] = b'fixture signed dependency'
files['source-material.json'] = renewal.canonical({
'status': 'MATERIALIZED', 'task_status': 'SUCCEEDED', 'remote_verified': True,
'source_commit': '1'*40, 'source_tree': '2'*40,
'file_sha256': {n: renewal.digest(files[n]) for n in renewal.RENEWAL_SOURCE_FILES}})
for name, raw in files.items():
(root/name).write_bytes(raw); (root/name).chmod(0o600)
payload = {'schema': 'aios.c5.registered-completion-authority.v1', 'host': 'cn-network-mkt',
'repository': 'aios/aios', 'candidate_id': renewal.CID, 'source_commit': renewal.SOURCE,
'tree_oid': renewal.TREE, 'artifact_sha256': renewal.ARTIFACT, 'release_plan_sha256': renewal.PLAN,
'state_root': str(renewal.STATE_ROOT), 'predecessor_fingerprint': renewal.OLD_FP,
'predecessor_sha256': renewal.digest(files['predecessor-approval.json']), 'predecessor_uid': 1000,
'predecessor_snapshot': str(root/'predecessor-approval.json'), 'approval_nonce': '3'*64,
'issued_at': 1000, 'expires_at': 1600, 'owner_key_id': renewal.OWNER_KEY,
'owner_namespace': 'aios-owner-approval-v1',
'allowed_effects': ['approval_successor_append','baseline_finalize','registry_finalize','tag_publish'],
'runtime_effects_allowed': False,
'files': [{'path': str(root/n), 'sha256': renewal.digest(raw), 'uid': 0} for n, raw in files.items()],
'gate_path': str(root/'current-gate.json'), 'gate_observed_at': 1000,
'governed_source_commit': '1'*40, 'governed_source_tree': '2'*40}
def seal(signature='fixture-valid'):
(root/'contract.json').write_bytes(renewal.canonical({'payload': payload, 'signature': signature}))
(root/'registration.json').write_bytes(renewal.canonical({
'schema': 'aios.c5.completion-registration.v1', 'status': 'REGISTERED',
'payload_sha256': renewal.digest(renewal.canonical(payload)), 'approval_nonce': payload['approval_nonce']}))
(root/'contract.json').chmod(0o600); (root/'registration.json').chmod(0o600)
seal()
return root, payload, seal, renewal.RegisteredCompletionAuthority()
def completion_gate():
gate = {'saga_revision': 20, 'observed_at': 1000, 'completion_journal_suffix': []}
previous = renewal.SAGA_HEAD
pairs = [
('owner_registered_completion_successor_tag_reconciliation', 'TAG_PENDING'),
('release_reconciliation_required', 'RECONCILIATION_REQUIRED'),
('owner_registered_tag_capability_successor_verified', 'TAG_VERIFIED'),
('baseline_registry_finalization_pending', 'BASELINE_REGISTRY_PENDING'),
('release_reconciliation_required', 'RECONCILIATION_REQUIRED'),
]
for revision, (name, state) in enumerate(pairs, 16):
event = {'schema_version': 1, 'sequence': revision + 1, 'previous_hash': previous,
'payload': {'candidate_id': renewal.CID, 'release_plan_id': 'pending-' + renewal.CID,
'revision': revision, 'state': state, 'event': name,
'timestamp': '1970-01-01T00:10:00Z', 'details': {}}}
event['event_hash'] = renewal.digest(renewal.canonical({
key: event[key] for key in ('sequence', 'previous_hash', 'payload')}))
gate['completion_journal_suffix'].append(event)
previous = event['event_hash']
gate['saga_head'] = previous
return gate
def test_registered_authority_accepts_authenticated_post_tag_lineage(registered_authority):
import json
root, payload, seal, authority = registered_authority
path = root / 'current-gate.json'
gate = json.loads(path.read_bytes())
gate.update(completion_gate())
path.write_bytes(renewal.canonical(gate))
next(item for item in payload['files'] if item['path'] == str(path))['sha256'] = renewal.digest(path.read_bytes())
seal()
assert authority()['payload_sha256'] == renewal.digest(renewal.canonical(payload))
@pytest.mark.parametrize('fault', [
'head', 'origin', 'gap', 'truncated', 'revision_bool', 'sequence_bool', 'candidate',
'plan', 'payload_hash', 'runtime_event', 'state', 'future', 'observation_bool', 'observation_nan',
])
def test_completion_lineage_rejects_corruption_or_noncompletion_effect(fault):
gate = completion_gate()
first = gate['completion_journal_suffix'][0]
if fault == 'head': gate['saga_head'] = '0' * 64
elif fault == 'origin': first['previous_hash'] = '0' * 64
elif fault == 'gap': first['sequence'] = 18
elif fault == 'truncated': gate['completion_journal_suffix'].pop()
elif fault == 'revision_bool': gate['saga_revision'] = True
elif fault == 'sequence_bool': first['sequence'] = True
elif fault == 'candidate': first['payload']['candidate_id'] = 'other'
elif fault == 'plan': first['payload']['details']['release_plan_sha256'] = '0' * 64
elif fault == 'payload_hash': first['payload']['details']['tampered'] = True
elif fault == 'runtime_event': first['payload']['event'] = 'runtime_switch_pending'
elif fault == 'state': first['payload']['state'] = 'SWITCH_PENDING'
elif fault == 'future': first['payload']['timestamp'] = '2026-10-01T12:00:00Z'
elif fault == 'observation_bool': gate['observed_at'] = True
elif fault == 'observation_nan': gate['observed_at'] = float('nan')
with pytest.raises(renewal.RenewalRejected): renewal.validate_completion_lineage(gate)
def test_registered_authority_validates_closure_and_denies_runtime(registered_authority):
root, payload, _, authority = registered_authority
assert authority()['payload_sha256'] == renewal.digest(renewal.canonical(payload))
authority.validate_host(state_root=renewal.STATE_ROOT, candidate_id=renewal.CID,
source_commit=renewal.SOURCE, tree_oid=renewal.TREE, artifact_sha256=renewal.ARTIFACT,
release_plan_sha256=renewal.PLAN)
with pytest.raises(renewal.RenewalRejected, match='RUNTIME_EFFECT_FORBIDDEN'):
authority.deny_runtime_effect()
@pytest.mark.parametrize('field,value', [
('candidate_id', 'other'), ('artifact_sha256','f'*64), ('release_plan_sha256','f'*64),
('state_root','/tmp/second-plane'), ('runtime_effects_allowed',True),
('owner_key_id','other-key'), ('owner_namespace','other-namespace'),
('expires_at',1100), ('issued_at',1101), ('expires_at',3000),
('approval_nonce','bad'), ('predecessor_uid',1), ('gate_observed_at',939),
('governed_source_commit','bad')])
def test_registered_authority_signed_drift_rejected(registered_authority, field, value):
_, payload, seal, authority = registered_authority
payload[field] = value; seal()
with pytest.raises(renewal.RenewalRejected): authority()
def test_registered_authority_rejects_signature_registration_and_rollback(registered_authority):
root, _, seal, authority = registered_authority
seal('invalid')
with pytest.raises(renewal.RenewalRejected, match='SIGNATURE_REJECTED'): authority()
seal(); (root/'registration.json').write_bytes(b'{}')
with pytest.raises(renewal.RenewalRejected, match='REGISTRATION_REQUIRED'): authority()
seal(); (root/'rollback.json').write_bytes(b'{}')
with pytest.raises(renewal.RenewalRejected, match='ROLLED_BACK'): authority()
def test_registered_authority_rejects_code_drift_and_symlink(registered_authority):
root, _, _, authority = registered_authority
path = root/'c5_completion_renewal.py'; original = path.read_bytes()
path.write_bytes(b'altered')
with pytest.raises(renewal.RenewalRejected, match='BYTES_DRIFT'): authority()
path.unlink(); target=root/'target'; target.write_bytes(original); path.symlink_to(target)
with pytest.raises(OSError): authority()
@pytest.mark.parametrize('file,field,value', [
('source-material.json','task_status','FAILED'),
('source-material.json','remote_verified',False),
('historical-production-proof.json','real_c4_rollback_verified',False),
('historical-production-proof.json','approval_fingerprint','f'*64),
('current-gate.json','business_verified',False),
('current-gate.json','saga_revision',14),
('current-gate.json','remote_tag_oid','f'*40)])
def test_registered_authority_rejects_signed_false_evidence(registered_authority, file, field, value):
import json
root, payload, seal, authority=registered_authority
path=root/file; data=json.loads(path.read_bytes()); data[field]=value
raw=renewal.canonical(data); path.write_bytes(raw)
for pin in payload['files']:
if pin['path']==str(path): pin['sha256']=renewal.digest(raw)
seal()
with pytest.raises(renewal.RenewalRejected): authority()
def test_registered_store_cannot_select_another_plane(tmp_path):
from types import SimpleNamespace
with pytest.raises(renewal.RenewalRejected, match='SAME_APPROVAL_PLANE_REQUIRED'):
renewal.RegisteredCompletionApprovalStore(SimpleNamespace(root=tmp_path), b'', object)
def test_completion_runtime_guard_uses_execute_contract(registered_authority):
_, _, _, authority = registered_authority
with pytest.raises(renewal.RenewalRejected, match='RUNTIME_EFFECT_FORBIDDEN'):
renewal.CompletionRuntimeGuard(authority).execute(candidate=object(), plan=object())
with pytest.raises(renewal.RenewalRejected, match='AUTHORITY_REQUIRED'):
renewal.CompletionRuntimeGuard(lambda: {})
def test_typed_host_rejects_callback_before_approval_load(tmp_path, monkeypatch):
import c5_release_execution_host as host
from types import SimpleNamespace
monkeypatch.setenv('AIOS_GITOPS_WRITES_ENABLED','false')
config=SimpleNamespace(verify_files=lambda **kw: None, state_root=tmp_path)
with pytest.raises(host.C5ExecutionHostBlocked, match='REGISTERED_COMPLETION_DEPENDENCY_REQUIRED'):
host.build_execution_host(config, completion_approvals=lambda: {})
def test_api_rejects_untyped_completion_store(tmp_path):
from silent_release_hardening import SilentReleaseActionService, CapabilityAuthorizationError
with pytest.raises(CapabilityAuthorizationError, match='completion approval dependency'):
SilentReleaseActionService(tmp_path, completion_approvals=object())
def test_signer_wrapper_preserves_existing_dispatch():
from types import SimpleNamespace
from c5_completion_signer import signer_class
class Original:
def handle(self, request): return {'original_operation': request['operation']}
signer=signer_class(SimpleNamespace(ExactReleaseSigner=Original))()
assert signer.handle({'operation':'status'}) == {'original_operation':'status'}
with pytest.raises(renewal.RenewalRejected, match='EXACT_SIGNER_RENEWAL_REQUEST_REQUIRED'):
signer.handle({'operation':'renew_exact_completion_approval', 'arbitrary':True})
@pytest.fixture
def real_api_roundtrip(tmp_path, monkeypatch):
import dataclasses
from datetime import timedelta
from test_c5_release_execution_host import _plan, _approval
import c5_exact_deployment_adapter as exact
import silent_release_hardening as core
from silent_release_controller import ReleaseCandidate, ReleaseCandidateStore
private = Ed25519PrivateKey.generate()
public = private.public_key().public_bytes(Encoding.Raw, PublicFormat.Raw)
policy_sha = '1'*64
plan = _plan(renewal.SOURCE, renewal.TREE, renewal.ARTIFACT,
tmp_path/'repo.git', policy_sha, exact.C4_ROLLBACK_TARGET)
monkeypatch.setattr(renewal,'PLAN',plan.sha256)
candidate=ReleaseCandidate(candidate_id=renewal.CID, source_commit=renewal.SOURCE,
tree_oid=renewal.TREE, artifact_sha256=renewal.ARTIFACT,
manifest_sha256=plan.deployment.manifest_sha256)
now=datetime.now(timezone.utc)
def sign(approval):
return dataclasses.replace(approval,signature=base64.b64encode(
private.sign(approval.canonical_bytes())).decode())
old=sign(dataclasses.replace(_approval(candidate,plan,private),
capabilities=tuple(renewal.CAPABILITIES),
issued_at=(now-timedelta(minutes=70)).isoformat(),
not_before=(now-timedelta(minutes=70)).isoformat(),
expires_at=(now-timedelta(minutes=10)).isoformat()))
new=sign(dataclasses.replace(old,issued_at=(now-timedelta(seconds=5)).isoformat(),
not_before=(now-timedelta(seconds=5)).isoformat(),
expires_at=(now+timedelta(seconds=595)).isoformat(),nonce='f'*64))
monkeypatch.setattr(renewal,'OLD_FP',old.fingerprint)
monkeypatch.setattr(renewal,'STATE_ROOT',tmp_path)
original=core.SignedApprovalStore(tmp_path/'approvals')
original.save(renewal.CID,old)
raw=(original.root/(renewal.CID+'.json')).read_bytes()
policy={'candidate_id':renewal.CID,'predecessor_fingerprint':old.fingerprint,
'approval_nonce':'f'*64,'payload_sha256':'1'*64,'predecessor_uid':os.geteuid(),
'predecessor_sha256':renewal.digest(raw)}
class FixtureAuthority:
state_root = tmp_path
def __call__(self):return policy
monkeypatch.setattr(renewal,'RegisteredCompletionAuthority',FixtureAuthority)
directory=original.root/'c5-completion-successors';directory.mkdir(mode=0o700)
store=renewal.RegisteredCompletionApprovalStore(original,public,core.SignedReleasePlanApproval)
ReleaseCandidateStore(tmp_path/'candidates').save(candidate)
core.ReleasePlanStore(tmp_path/'release-plans').save(renewal.CID,plan)
sagas=core.ReleaseSagaStore(tmp_path/'sagas')
saga=sagas.create(renewal.CID,old.release_plan_id)
sagas.compare_and_set(renewal.CID,expected_revision=saga.revision,
expected_states={core.SagaState.PREPARING},target=core.SagaState.RECONCILIATION_REQUIRED,
event='isolated_existing_partial_tag')
verifier=core.SignedApprovalVerifier(core.ApprovalKeyRing({'c5-owner-key-001':public}),
core.ApprovalRevocationStore(tmp_path/'revocations'))
service=core.SilentReleaseActionService(tmp_path,approval_verifier=verifier,
policy_sha256=policy_sha,completion_approvals=store)
return service,store,old,new,raw,private
def test_actual_api_verifier_append_successor_roundtrip(real_api_roundtrip):
service,store,old,new,raw,_=real_api_roundtrip
response=service.submit_owner_approval(new.to_dict())
assert response['status']=='VERIFIED_AND_STORED'
assert response['saga_state']=='RECONCILIATION_REQUIRED'
assert response['side_effects_executed'] is False
assert response['shadow_mode'] is True
assert store.load(renewal.CID).fingerprint==new.fingerprint
assert service.submit_owner_approval(new.to_dict())['status']=='IDEMPOTENT'
assert (store.original.root/(renewal.CID+'.json')).read_bytes()==raw
@pytest.mark.parametrize('failure',['expired','tampered','wrong_binding','revoked'])
def test_actual_api_verifier_rejects_before_successor_append(real_api_roundtrip,failure):
import dataclasses
import silent_release_hardening as core
service,store,old,new,raw,key=real_api_roundtrip
value=new.to_dict()
if failure=='expired':value=old.to_dict()
if failure=='tampered':value['signature']=base64.b64encode(b'0'*64).decode()
if failure=='wrong_binding':
bad=dataclasses.replace(new,artifact_sha256='0'*64)
bad=dataclasses.replace(bad,signature=base64.b64encode(key.sign(bad.canonical_bytes())).decode())
value=bad.to_dict()
if failure=='revoked':service.approval_verifier.keyring.revoke(new.key_id)
with pytest.raises(core.CapabilityAuthorizationError):service.submit_owner_approval(value)
assert list(store.directory.iterdir())==[]
assert (store.original.root/(renewal.CID+'.json')).read_bytes()==raw