Assistant: codex Assistant-Model: gpt-6-astra Assistant-Session: 01a0e241-8285-7a63-8c0c-51c9cb824dc3
87 lines
4.6 KiB
Python
87 lines
4.6 KiB
Python
"""Adoption and routine-promotion boundaries are checked without cluster access."""
|
|
import importlib.util
|
|
from pathlib import Path
|
|
import copy
|
|
import pytest
|
|
import yaml
|
|
ROOT=Path(__file__).resolve().parents[1]
|
|
def load(name):
|
|
spec=importlib.util.spec_from_file_location(name,ROOT/'scripts'/f'{name}.py')
|
|
mod=importlib.util.module_from_spec(spec);spec.loader.exec_module(mod);return mod
|
|
|
|
def test_render_exact_reviewed_set_and_no_jobs_or_secrets():
|
|
render=load('render_gitops')
|
|
assert render.render()==(ROOT/'k8s/gitops/runtime.yaml').read_text()
|
|
docs=list(yaml.safe_load_all(render.render()))
|
|
assert len(docs)==9
|
|
assert {d['kind'] for d in docs}=={'Deployment','ConfigMap','Service'}
|
|
assert all(d['metadata']['namespace']=='activity-core' for d in docs)
|
|
worker=next(d for d in docs if d['metadata']['name']=='actcore-worker')
|
|
mounts=worker['spec']['template']['spec']['containers'][0]['volumeMounts']
|
|
assert any(m.get('subPath')=='entrypoint' and m['name']=='backup-verified' for m in mounts)
|
|
|
|
|
|
def test_image_workflow_publishes_commit_tag_and_digest():
|
|
text=(ROOT/'.forgejo/workflows/image.yaml').read_text()
|
|
assert ':latest' not in text and ':git-${REF}' in text
|
|
assert '${REF}.tar.gz' in text and '--target test' in text
|
|
assert 'RepoDigests' in text
|
|
|
|
|
|
def test_build_inputs_are_pinned():
|
|
text=(ROOT/'Dockerfile').read_text()
|
|
assert text.count('python:3.12-slim@sha256:')==2
|
|
assert 'uv==0.5.9' in text and '--frozen' in text
|
|
|
|
|
|
def promotion():
|
|
from datetime import datetime,timezone
|
|
before=list(yaml.safe_load_all((ROOT/'k8s/gitops/runtime.yaml').read_text()))
|
|
after=copy.deepcopy(before)
|
|
worker=next(d for d in after if d['metadata']['name']=='actcore-worker')
|
|
container=worker['spec']['template']['spec']['containers'][0]
|
|
container.update(image='forgejo.coulomb.social/coulomb/activity-core@sha256:'+'a'*64,imagePullPolicy='IfNotPresent')
|
|
evidence=dict(schema_version=1,identity_admitted=True,authority='ACTIVITY-WP-0041-image-only-v1',checks='pass',review_result='pass',reviewer='independent-ci',producer='build-ci',candidate_commit='a'*40,rollback_commit='b'*40,healthy_since='2026-09-26T00:00:00Z',observed_at='2026-09-27T01:00:00Z',argo_synced=True,argo_healthy=True)
|
|
return before,after,evidence,datetime(2026,9,27,1,tzinfo=timezone.utc)
|
|
|
|
def test_admits_only_digest_release_after_soak():
|
|
assert load('check_gitops_promotion').validate(*promotion())['deployments']==['actcore-worker']
|
|
|
|
@pytest.mark.parametrize('key,value',[('identity_admitted',False),('checks','fail'),('reviewer','build-ci'),('healthy_since','2026-09-27T00:00:00Z'),('observed_at','2026-09-26T01:00:00Z'),('argo_healthy',False),('rollback_commit','not-a-sha')])
|
|
def test_refuses_missing_release_guards(key,value):
|
|
before,after,evidence,now=promotion();evidence[key]=value
|
|
with pytest.raises(ValueError):load('check_gitops_promotion').validate(before,after,evidence,now)
|
|
|
|
@pytest.mark.parametrize('change',['command','resources','tag','inventory'])
|
|
def test_refuses_authority_expansion(change):
|
|
before,after,evidence,now=promotion()
|
|
worker=next(d for d in after if d['metadata']['name']=='actcore-worker')
|
|
c=worker['spec']['template']['spec']['containers'][0]
|
|
if change=='command':c['command']=['sh']
|
|
elif change=='resources':c['resources']={'requests':{'cpu':'2'}}
|
|
elif change=='tag':c['image']='forgejo.coulomb.social/coulomb/activity-core:latest'
|
|
else:after.pop()
|
|
with pytest.raises(ValueError):load('check_gitops_promotion').validate(before,after,evidence,now)
|
|
|
|
|
|
def test_frontend_projection_checks_content_and_pin(tmp_path):
|
|
renderer=load('render_gitops')
|
|
cm=next(d for d in yaml.safe_load_all(renderer.render()) if d['metadata']['name']=='actcore-external-activity-definitions')
|
|
for name,body in cm['data'].items():
|
|
if name.startswith('frontend-patterns-'): (tmp_path/name).write_text(body)
|
|
renderer.verify_frontend(tmp_path)
|
|
(tmp_path/'frontend-patterns-daily.md').write_text('tampered')
|
|
with pytest.raises(ValueError): renderer.verify_frontend(tmp_path)
|
|
|
|
|
|
def test_retention_projection_is_pinned_and_mounted(tmp_path):
|
|
renderer=load('render_gitops')
|
|
docs=list(yaml.safe_load_all(renderer.render()))
|
|
cm=next(d for d in docs if d['metadata']['name']=='actcore-ops-service-inventory')
|
|
source=tmp_path/'prune.py';source.write_text(cm['data']['forgejo_package_prune.py'])
|
|
renderer.verify_platform(source)
|
|
worker=next(d for d in docs if d['metadata']['name']=='actcore-worker')
|
|
mounts=worker['spec']['template']['spec']['containers'][0]['volumeMounts']
|
|
assert any(m.get('subPath')=='forgejo_package_prune.py' and m['readOnly'] is True for m in mounts)
|
|
source.write_text('tampered')
|
|
with pytest.raises(ValueError):renderer.verify_platform(source)
|