Prepare scoped GitOps adoption and tested immutable image releases
All checks were successful
CI Smoke / host-smoke (push) Successful in 1s
CI Smoke / container-smoke (push) Successful in 7s
Build and Publish Container Image / build-and-push (push) Successful in 2m18s

Assistant: codex
Assistant-Model: gpt-6-astra
Assistant-Session: 01a0e241-8285-7a63-8c0c-51c9cb824dc3
This commit is contained in:
tegwick 2026-09-27 13:50:16 +02:00
parent 5d5ee84d70
commit c12a8fbcfb
12 changed files with 2585 additions and 731 deletions

View file

@ -0,0 +1,64 @@
"""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)