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
98
.forgejo/workflows/service-image.yaml
Normal file
98
.forgejo/workflows/service-image.yaml
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
name: Build and Publish Service Image
|
||||
|
||||
# Full informed-decision service image (INFD-WP-0010-T02 release path). Modelled on the fleet's
|
||||
# canonical image-publish pattern (activity-core, access-engine, state-hub memo-dispatch): CI
|
||||
# builds from a tarball of the pushed commit, never from a workstation working tree, so the
|
||||
# artifact's provenance is a forge revision. The wheel is built inside the image from source.
|
||||
#
|
||||
# zlib: the Containerfile installs the same hash-pinned, Alpine-signed zlib-1.3.2-r1 package the
|
||||
# zlib overlay uses (deploy/zlib-overlay), offline, and fails the build unless zlib >= 1.3.2-r1.
|
||||
# This job re-checks that in the built image before anything is pushed.
|
||||
#
|
||||
# The purpose-overlay and zlib-overlay workflows are separate and unchanged. Publication is not
|
||||
# deployment: pins move by digest in deploy/lifecycle/ under the founder-run release runbook.
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- ".forgejo/workflows/service-image.yaml"
|
||||
- "Containerfile"
|
||||
- ".dockerignore"
|
||||
- "requirements.lock"
|
||||
- "requirements-build.lock"
|
||||
- "pyproject.toml"
|
||||
- "informed_decision/**"
|
||||
- "deploy/zlib-overlay/zlib-1.3.2-r1.apk"
|
||||
- "deploy/zlib-overlay/APKINDEX.tar.gz"
|
||||
- "tools/service_image/**"
|
||||
- "tools/zlib_overlay/check_runtime.py"
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
group: informed-decision-service-image
|
||||
cancel-in-progress: false
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
env:
|
||||
REGISTRY: forgejo.coulomb.social
|
||||
IMAGE_NAME: coulomb/informed-decision
|
||||
DOCKER_HOST: tcp://127.0.0.1:2375
|
||||
|
||||
jobs:
|
||||
build-and-push:
|
||||
runs-on: container-build
|
||||
steps:
|
||||
- name: Build, check and push image
|
||||
env:
|
||||
REGISTRY_USER: ${{ secrets.REGISTRY_USER }}
|
||||
REGISTRY_TOKEN: ${{ secrets.REGISTRY_TOKEN }}
|
||||
run: |
|
||||
set -eu
|
||||
REF="${GITHUB_SHA:?full source revision required}"
|
||||
echo "${REF}" | grep -Eq '^[0-9a-f]{40}$'
|
||||
test "${GITHUB_REPOSITORY}" = "coulomb/informed-decision"
|
||||
if [ -z "${REGISTRY_USER:-}" ] || [ -z "${REGISTRY_TOKEN:-}" ]; then
|
||||
echo "Admitted repository registry publication capability is unavailable; no borrowed credential is permitted." >&2
|
||||
exit 2
|
||||
fi
|
||||
SHORT="$(printf '%s' "${REF}" | cut -c1-7)"
|
||||
mkdir -p buildctx "${HOME}/bin"
|
||||
wget -qO /tmp/repo.tar.gz \
|
||||
"https://forgejo.coulomb.social/${GITHUB_REPOSITORY}/archive/${REF}.tar.gz"
|
||||
tar xzf /tmp/repo.tar.gz -C buildctx --strip-components=1
|
||||
wget -qO- https://download.docker.com/linux/static/stable/x86_64/docker-27.3.1.tgz \
|
||||
| tar xz --strip-components=1 -C "${HOME}/bin" docker/docker
|
||||
export PATH="${HOME}/bin:${PATH}"
|
||||
echo "${REGISTRY_TOKEN}" | docker login "${REGISTRY}" -u "${REGISTRY_USER}" --password-stdin
|
||||
IMAGE="${REGISTRY}/${IMAGE_NAME}:main-${SHORT}"
|
||||
docker build --label "org.opencontainers.image.revision=${REF}" \
|
||||
-f buildctx/Containerfile -t "${IMAGE}" buildctx
|
||||
# Checks before publication: zlib floor, runtime compression/crypto smoke, exact source.
|
||||
docker run --rm --network none --read-only --entrypoint sh "${IMAGE}" \
|
||||
-c "apk info --exists 'zlib>=1.3.2-r1' >/dev/null"
|
||||
docker run --rm -i --network none --read-only --entrypoint python "${IMAGE}" - \
|
||||
< buildctx/tools/zlib_overlay/check_runtime.py > /tmp/runtime.json
|
||||
grep -q '"zlib_runtime_version": "1.3.2' /tmp/runtime.json
|
||||
grep -q '"uid": 10001' /tmp/runtime.json
|
||||
docker run --rm -i --network none --read-only --entrypoint python "${IMAGE}" - \
|
||||
< buildctx/tools/service_image/installed_manifest.py > /tmp/installed.txt
|
||||
(cd buildctx/informed_decision && find . -name '*.py' -not -path '*/__pycache__/*' \
|
||||
| LC_ALL=C sort | xargs sha256sum) > /tmp/source.txt
|
||||
diff /tmp/source.txt /tmp/installed.txt
|
||||
docker push "${IMAGE}"
|
||||
echo "pushed ${IMAGE} from ${REF}"
|
||||
|
||||
- name: Report immutable digest
|
||||
run: |
|
||||
set -eu
|
||||
export PATH="${HOME}/bin:${PATH}"
|
||||
SHORT="$(printf '%s' "${GITHUB_SHA}" | cut -c1-7)"
|
||||
IMAGE="${REGISTRY}/${IMAGE_NAME}:main-${SHORT}"
|
||||
# Deployments pin by digest, never by tag -- print it for the release step.
|
||||
docker inspect --format='{{index .RepoDigests 0}}' "${IMAGE}"
|
||||
echo "source_revision=${GITHUB_SHA}"
|
||||
echo "candidate_only=true; the founder-run release runbook pins this digest"
|
||||
Loading…
Add table
Add a link
Reference in a new issue