import base64 import json from pathlib import Path import pytest from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey from cryptography.hazmat.primitives.serialization import Encoding,PublicFormat from activity_core.release_runtime import Admission, CLUSTER_UID, DurableAudit, verify_runtime_identity def configuration(root): kube=root/'kubeconfig';kube.write_text('fixture private kube configuration');kube.chmod(0o600) git=root/'gitconfig';git.write_text('fixture private git configuration');git.chmod(0o600) trust={} for role in ('build','review','health','retention'): public=Ed25519PrivateKey.generate().public_key().public_bytes(Encoding.Raw,PublicFormat.Raw) trust[role]={'public_key':base64.b64encode(public).decode(),'principal':role,'roles':[role]} value={'schema_version':'activity-core-release-runtime/v1','enabled':True,'principal':'activity-core-release-broker', 'cluster_uid':CLUSTER_UID,'state_directory':str(root/'state'),'kubeconfig':str(kube),'git_config':str(git),'receipt_trust':trust} path=root/'runtime.json';path.write_text(json.dumps(value));path.chmod(0o600) return path,value def test_operator_private_config_drift_disable_and_custody_replacement_refused(tmp_path): path,value=configuration(tmp_path);admission=Admission(path);admission.require() assert admission.environment()['GIT_CONFIG_NOSYSTEM']=='1' value['enabled']=False;path.write_text(json.dumps(value)) with pytest.raises(ValueError,match='disabled'):admission.require() value['enabled']=True;value['principal']='borrowed-admin';path.write_text(json.dumps(value)) with pytest.raises(ValueError):admission.require() value['principal']='activity-core-release-broker';path.write_text(json.dumps(value)) Path(value['kubeconfig']).write_text('replaced fixture custody') with pytest.raises(ValueError,match='custody'):admission.require() @pytest.mark.parametrize('delta',[{'enabled':False},{'principal':'operator'},{'cluster_uid':'other'}, {'schema_version':'other'},{'untrusted_transport_factory':'arbitrary-import'}]) def test_disabled_widened_configuration_cannot_construct_runtime(tmp_path,delta): path,value=configuration(tmp_path);path.write_text(json.dumps(value|delta)) with pytest.raises(ValueError):Admission(path) def test_public_permissions_symlink_or_incomplete_role_registry_refused(tmp_path): path,value=configuration(tmp_path);path.chmod(0o644) with pytest.raises(ValueError,match='private'):Admission(path) path.chmod(0o600);alias=tmp_path/'symlink.json';alias.symlink_to(path) with pytest.raises(ValueError,match='private'):Admission(alias) del value['receipt_trust']['health'];path.write_text(json.dumps(value)) with pytest.raises(ValueError,match='independent'):Admission(path) def identity_runner(*,admin=False,extra_access=False,wrong_cluster=False): calls=[] def run(argv,**kwargs): calls.append(argv) if 'namespace' in argv:return json.dumps({'metadata':{'uid':'wrong' if wrong_cluster else CLUSTER_UID}}) if 'whoami' in argv:return json.dumps({'status':{'userInfo':{'username':'root' if admin else 'system:serviceaccount:activity-core:activity-core-release-broker','groups':['system:masters'] if admin else ['system:serviceaccounts']}}}) assert '--raw=/apis/authorization.k8s.io/v1/selfsubjectaccessreviews' in argv attrs=json.loads(kwargs['input'])['spec']['resourceAttributes'] allowed=attrs['resource']=='applications' and attrs.get('name') in {'activity-core','railiance-apps-root'} if extra_access and attrs['resource']=='secrets':allowed=True return json.dumps({'status':{'allowed':allowed}}) return run,calls def test_actual_subject_scope_and_denial_checks_are_required_before_dispatch(): run,calls=identity_runner();result=verify_runtime_identity(run) assert result=={'principal_verified':True,'allowed_checks':4,'denied_checks':7} assert len(calls)==13 for kwargs in [{'admin':True},{'extra_access':True},{'wrong_cluster':True}]: run,calls=identity_runner(**kwargs) with pytest.raises(ValueError):verify_runtime_identity(run) if kwargs.get('wrong_cluster'):assert len(calls)==1 def test_audit_sink_durably_deduplicates_and_refuses_collision_or_private_fields(tmp_path): sink=DurableAudit(tmp_path/'audit.sqlite') event={'event_id':'release:id:1','event_type':'release_transition','release_id':'id','application':'activity-core', 'phase':'complete','observed_at':'2026-10-11T20:00:00Z','candidate':'a'*40,'rollback':'b'*40} sink(event);DurableAudit(tmp_path/'audit.sqlite')(event) with sink.connect() as db:assert db.execute('SELECT count(*) FROM events').fetchone()[0]==1 with pytest.raises(ValueError,match='conflict'):sink(event|{'phase':'failed'}) with pytest.raises(ValueError):sink(event|{'credential':'secret fixture canary'})