INFD-WP-0010-T02: owner-CI workflow for the full service image
All checks were successful
Build and Publish Service Image / build-and-push (push) Successful in 2m38s
All checks were successful
Build and Publish Service Image / build-and-push (push) Successful in 2m38s
.forgejo/workflows/service-image.yaml builds Containerfile from the pushed commit's tarball and pushes forgejo.coulomb.social/coulomb/informed-decision :main-<short sha>, then reports the immutable digest. Before pushing it checks the zlib floor, the runtime smoke (tools/zlib_overlay/check_runtime.py) and that the installed modules equal the commit's source. Containerfile builds the wheel in-image (hash-pinned setuptools in requirements-build.lock) and installs the zlib overlay's hash-pinned, Alpine-signed zlib-1.3.2-r1 package offline, failing below 1.3.2-r1, so the live image's zlib fix cannot regress. Overlay workflows are unchanged. Local build: 13/13 container checks, zlib 1.3.2-r1, source manifest match. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Assistant: claude-code Assistant-Model: opus Assistant-Process: 5502@bnt-lap001 Assistant-Session: 68b3b02f-5d0f-4e71-8421-796f62e50196
This commit is contained in:
parent
0ef57537ac
commit
c228583b60
9 changed files with 211 additions and 5 deletions
52
tests/test_service_image_build.py
Normal file
52
tests/test_service_image_build.py
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
"""Static checks for the owner-CI full service image (.forgejo/workflows/service-image.yaml).
|
||||
|
||||
The built image itself is checked in CI (zlib floor, runtime smoke, installed source manifest)
|
||||
and locally with tools/smoke_container.py; these tests keep the inputs consistent.
|
||||
"""
|
||||
import hashlib
|
||||
import json
|
||||
from pathlib import Path
|
||||
import re
|
||||
|
||||
import yaml
|
||||
|
||||
ROOT = Path(__file__).parents[1]
|
||||
ZLIB = ROOT / 'deploy' / 'zlib-overlay'
|
||||
|
||||
|
||||
def test_containerfile_installs_the_overlay_zlib_package_and_enforces_the_floor():
|
||||
text = (ROOT / 'Containerfile').read_text()
|
||||
pins = json.loads((ZLIB / 'pins.json').read_text())['files']
|
||||
for name in ('zlib-1.3.2-r1.apk', 'APKINDEX.tar.gz'):
|
||||
actual = hashlib.sha256((ZLIB / name).read_bytes()).hexdigest()
|
||||
assert actual == pins[name]
|
||||
assert f"echo '{actual} /tmp/infd-zlib/x86_64/{name}' | sha256sum -c -" in text
|
||||
assert '--no-network' in text and "apk info --exists 'zlib>=1.3.2-r1'" in text
|
||||
# Every stage uses the same pinned base; the wheel is built from source, not a workstation dist/.
|
||||
bases = re.findall(r'^FROM (\S+)', text, re.M)
|
||||
assert len(bases) == 3 and len(set(bases)) == 1 and '@sha256:' in bases[0]
|
||||
assert 'COPY dist/' not in text and 'COPY --from=wheel /dist/' in text
|
||||
|
||||
|
||||
def test_build_context_admits_exactly_the_inputs():
|
||||
ignore = (ROOT / '.dockerignore').read_text().split()
|
||||
assert ignore[0] == '**'
|
||||
for path in ('Containerfile', 'requirements.lock', 'requirements-build.lock', 'pyproject.toml',
|
||||
'informed_decision/**', 'deploy/zlib-overlay/zlib-1.3.2-r1.apk',
|
||||
'deploy/zlib-overlay/APKINDEX.tar.gz'):
|
||||
assert '!' + path in ignore
|
||||
build_lock = (ROOT / 'requirements-build.lock').read_text()
|
||||
assert re.search(r'^setuptools==[\d.]+ \\\n\s+--hash=sha256:[0-9a-f]{64}$', build_lock, re.M)
|
||||
|
||||
|
||||
def test_workflow_builds_from_the_pushed_commit_and_reports_the_digest():
|
||||
flow = yaml.safe_load((ROOT / '.forgejo' / 'workflows' / 'service-image.yaml').read_text())
|
||||
on = flow.get('on', flow.get(True))
|
||||
assert on['push']['branches'] == ['main']
|
||||
steps = flow['jobs']['build-and-push']['steps']
|
||||
script = steps[0]['run']
|
||||
assert 'archive/${REF}.tar.gz' in script and ':main-${SHORT}' in script
|
||||
assert script.index("zlib>=1.3.2-r1") < script.index('docker push')
|
||||
assert script.index('diff /tmp/source.txt /tmp/installed.txt') < script.index('docker push')
|
||||
assert steps[1]['name'] == 'Report immutable digest'
|
||||
assert flow['env']['IMAGE_NAME'] == 'coulomb/informed-decision'
|
||||
Loading…
Add table
Add a link
Reference in a new issue