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
585 lines
31 KiB
Python
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
|