Images: --provenance=false on buildx pushes; workflow passes the token via env, registry in one place, git version sort, temp builder config; build-images.sh shares the Gradle lock check

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TQd3pEP9UeN2uifbHknQ7B
This commit is contained in:
2026-10-18 22:11:07 +02:00
parent b647faf715
commit e70fe0d9fe
2 changed files with 49 additions and 28 deletions
+38 -23
View File
@@ -10,16 +10,20 @@
# write:repository for the tag push) of the user that pushes (owner step, infra/README.md).
#
# RISK: the runner is a Raspberry Pi 3 with 1 GB RAM and the server image compiles about 232 Rust crates
# (aws-lc-sys's C code included). The build passes CARGO_BUILD_JOBS=1 to keep memory down; server/Dockerfile must
# declare `ARG CARGO_BUILD_JOBS` in its build stage for it to take effect (contract request in the M2c-pi report;
# until then buildx warns that the argument is unused and cargo uses every core). The Dockerfile already keeps
# the cargo registry and the target directory in BuildKit cache mounts, which persist in the reused builder
# `local-http-builder`, so later builds are incremental. First-build duration on the Pi: unknown.
# (aws-lc-sys's C code included). The build passes CARGO_BUILD_JOBS=1 to keep memory down; server/Dockerfile
# honours it (`ARG CARGO_BUILD_JOBS`, SPEC §10.3). The Dockerfile keeps the cargo registry and the target directory
# in BuildKit cache mounts, which persist in the reused builder `local-http-builder`, so later builds are
# incremental. First-build duration on the Pi: unknown.
# The builder's buildkitd.toml is read only when the builder is created; after changing it, remove the builder on
# the runner once (docker buildx rm local-http-builder), which also drops its cache.
# Fallback: infra/build-images.sh on the Mac.
name: Build Kvitt images
env:
MAJOR: 1
MINOR: 0
REGISTRY_HOST: gitea.lan
# ${KVITT_REGISTRY} of SPEC §10.3 (D-104).
REGISTRY: gitea.lan/jacobh2
defaults:
run:
@@ -41,17 +45,22 @@ jobs:
- name: Install Git and Docker CLI
run: apk add --no-cache git docker-cli docker-cli-buildx
- name: Log in to Gitea Container Registry
run: echo "${{ secrets.kvitt_cicd }}" | docker login gitea.lan -u ${{ github.actor }} --password-stdin
# The token reaches the shell as an environment variable, never as text inside the script.
env:
REGISTRY_TOKEN: ${{ secrets.kvitt_cicd }}
REGISTRY_USER: ${{ github.actor }}
run: printf '%s' "$REGISTRY_TOKEN" | docker login "$REGISTRY_HOST" -u "$REGISTRY_USER" --password-stdin
- name: Create Custom Buildx Builder for HTTP
run: |
# 1. Write a configuration rule forcing plain HTTP for the local registry
echo '[registry."gitea.lan"]' > buildkitd.toml
echo ' http = true' >> buildkitd.toml
# 2. Create the builder once and reuse it, so its BuildKit cache (cargo registry, target) survives runs
# Create the builder once and reuse it, so its BuildKit cache (cargo registry, target) survives runs.
if docker buildx inspect local-http-builder >/dev/null 2>&1; then
docker buildx use local-http-builder
else
docker buildx create --use --name local-http-builder --config buildkitd.toml
# A configuration rule forcing plain HTTP for the local registry.
cfg=$(mktemp)
printf '[registry."%s"]\n http = true\n' "$REGISTRY_HOST" > "$cfg"
docker buildx create --use --name local-http-builder --config "$cfg"
rm -f "$cfg"
fi
- name: Checkout
uses: actions/checkout@v4
@@ -61,30 +70,35 @@ jobs:
fetch-depth: 0
- name: Determine Version
run: |
LATEST_TAG=$(git tag -l "v${{ env.MAJOR }}.${{ env.MINOR }}.*" | sort -V | tail -n 1)
# git's own version sort: busybox sort on the Alpine runner may lack -V.
LATEST_TAG=$(git tag -l "v$MAJOR.$MINOR.*" --sort=-v:refname | head -n 1)
if [ -z "$LATEST_TAG" ]; then
VERSION="v${{ env.MAJOR }}.${{ env.MINOR }}.0"
VERSION="v$MAJOR.$MINOR.0"
else
# Strip the 'v' and get the patch version
PATCH=$(echo "$LATEST_TAG" | sed 's/v//' | cut -d'.' -f3)
NEW_PATCH=$((PATCH + 1))
VERSION="v${{ env.MAJOR }}.${{ env.MINOR }}.$NEW_PATCH"
# The patch number is the part after the last dot.
VERSION="v$MAJOR.$MINOR.$((${LATEST_TAG##*.} + 1))"
fi
echo "Version: $VERSION"
echo "VERSION=$VERSION" >> "$GITHUB_ENV"
# --provenance=false on every build: one plain linux/arm64 manifest per tag, as Podman and infra/build-images.sh
# push. Without it buildx pushes an index with an attestation entry (platform unknown/unknown), which the Gitea
# package page lists as an extra platform; nothing here reads attestations.
- name: Build cert-sync image
run: |
docker buildx build \
--platform linux/arm64 \
-t gitea.lan/jacobh2/kvitt-cert-sync:${{ env.VERSION }} \
-t gitea.lan/jacobh2/kvitt-cert-sync:latest \
--provenance=false \
-t "$REGISTRY/kvitt-cert-sync:$VERSION" \
-t "$REGISTRY/kvitt-cert-sync:latest" \
./infra/cert-sync \
--push
- name: Build backup image
run: |
docker buildx build \
--platform linux/arm64 \
-t gitea.lan/jacobh2/kvitt-backup:${{ env.VERSION }} \
-t gitea.lan/jacobh2/kvitt-backup:latest \
--provenance=false \
-t "$REGISTRY/kvitt-backup:$VERSION" \
-t "$REGISTRY/kvitt-backup:latest" \
./infra/backup \
--push
- name: Build server image
@@ -92,10 +106,11 @@ jobs:
# Context server/: server/Dockerfile copies the Cargo workspace from its own directory.
docker buildx build \
--platform linux/arm64 \
--provenance=false \
--build-arg CARGO_BUILD_JOBS=1 \
-f ./server/Dockerfile \
-t gitea.lan/jacobh2/kvitt-server:${{ env.VERSION }} \
-t gitea.lan/jacobh2/kvitt-server:latest \
-t "$REGISTRY/kvitt-server:$VERSION" \
-t "$REGISTRY/kvitt-server:latest" \
./server \
--push
- name: Tag and Push Version