activity-core/tests/test_release_runtime.py
tegwick 52dcc08f23
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 8s
Build and Publish Container Image / build-and-push (push) Successful in 1m39s
Implement bounded release runtime and durable native health sampler
Assistant: codex
Assistant-Model: gpt-6.1-sol
Assistant-Session: 01a126e1-76f8-7643-8cf3-e93336539ade
2026-10-11 23:26:03 +02:00

84 lines
4.9 KiB
Python

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'})