dd07ca4395
Build Kvitt images / build (push) Failing after 55s
Prints the lengths of secrets.kvitt_cicd, secrets.KVITT_CICD, the control secrets.babymonitor_cicd, secrets.GITEA_TOKEN and github.token, plus the repository, owner, actor, event, ref and server URL, before the registry login. Values are never printed. Remove once the empty-secret cause is known. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TQd3pEP9UeN2uifbHknQ7B
138 lines
7.0 KiB
YAML
138 lines
7.0 KiB
YAML
# Kvitt image build on Gitea Actions (SPEC §10.3, D-104). NOT YET RUN (written 2026-10-18 from the owner's working
|
|
# example workflow and the Gitea Actions documentation; the first run is an owner step, infra/README.md).
|
|
#
|
|
# Runner: act_runner with the label `host` on the owner's Raspberry Pi (Alpine-based host, docker builds on the
|
|
# Pi itself). Pushes two linux/arm64 images to the Gitea container registry of the same instance (gitea.lan,
|
|
# plain HTTP), each tagged with the version vMAJOR.MINOR.PATCH and `latest`, then pushes the git tag of that version.
|
|
# On the Kvitt Pi: /opt/kvitt/deploy.sh <version>.
|
|
#
|
|
# Secret: `kvitt_cicd`, a repository secret holding a Gitea access token with scope write:package of the user that
|
|
# pushes (owner step, infra/README.md). It is used only for `docker login`; the git tag push at the end goes through
|
|
# the credentials actions/checkout stored (the job's own token), not this secret, so it needs no write:repository.
|
|
#
|
|
# 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
|
|
# 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:
|
|
shell: sh
|
|
|
|
on:
|
|
push:
|
|
paths:
|
|
- "server/**"
|
|
- "infra/backup/**"
|
|
- ".gitea/workflows/**"
|
|
workflow_dispatch: {}
|
|
|
|
jobs:
|
|
build:
|
|
runs-on: host
|
|
steps:
|
|
- name: Install Git and Docker CLI
|
|
run: apk add --no-cache git docker-cli docker-cli-buildx
|
|
# TEMPORARY (D-120 follow-up): remove this step once the cause of the empty `kvitt_cicd` secret is known.
|
|
# Prints only lengths (0 = absent or empty) and non-secret context values, never a secret value.
|
|
# Gitea stores secret names upper-cased and the expression lookup is case-insensitive; the upper-case line
|
|
# tests that on this runner. babymonitor_cicd is the owner's known-working user-level secret (control).
|
|
# GITEA_TOKEN and github.token are the job's automatic token.
|
|
- name: Diagnose secrets (temporary, D-120 follow-up)
|
|
run: |
|
|
A='${{ secrets.kvitt_cicd }}'; printf 'secrets.kvitt_cicd length: %s\n' "${#A}"
|
|
A='${{ secrets.KVITT_CICD }}'; printf 'secrets.KVITT_CICD length: %s\n' "${#A}"
|
|
A='${{ secrets.babymonitor_cicd }}'; printf 'secrets.babymonitor_cicd length: %s\n' "${#A}"
|
|
A='${{ secrets.GITEA_TOKEN }}'; printf 'secrets.GITEA_TOKEN length: %s\n' "${#A}"
|
|
A='${{ github.token }}'; printf 'github.token length: %s\n' "${#A}"
|
|
unset A
|
|
printf 'github.repository: %s\n' '${{ github.repository }}'
|
|
printf 'github.repository_owner: %s\n' '${{ github.repository_owner }}'
|
|
printf 'github.actor: %s\n' '${{ github.actor }}'
|
|
printf 'github.event_name: %s\n' '${{ github.event_name }}'
|
|
printf 'github.ref: %s\n' '${{ github.ref }}'
|
|
printf 'github.server_url: %s\n' '${{ github.server_url }}'
|
|
- name: Log in to Gitea Container Registry
|
|
# The owner's proven form: the secret interpolated into the run line (act_runner masks it in the log).
|
|
# The env-based form (env: REGISTRY_TOKEN: ${{ secrets.kvitt_cicd }}) came through empty on act_runner 0.6.1.
|
|
run: printf '%s' "${{ secrets.kvitt_cicd }}" | docker login "$REGISTRY_HOST" -u "${{ github.actor }}" --password-stdin
|
|
- name: Create Custom Buildx Builder for HTTP
|
|
run: |
|
|
# 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
|
|
# 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
|
|
with:
|
|
# Tells the action to use the local 'git' binary installed above
|
|
set-safe-directory: 'true'
|
|
fetch-depth: 0
|
|
- name: Determine Version
|
|
run: |
|
|
# 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$MAJOR.$MINOR.0"
|
|
else
|
|
# 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 backup image
|
|
run: |
|
|
docker buildx build \
|
|
--platform linux/arm64 \
|
|
--provenance=false \
|
|
-t "$REGISTRY/kvitt-backup:$VERSION" \
|
|
-t "$REGISTRY/kvitt-backup:latest" \
|
|
--metadata-file /tmp/kvitt-backup.metadata.json \
|
|
./infra/backup \
|
|
--push
|
|
- name: Build server image
|
|
run: |
|
|
# 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 "$REGISTRY/kvitt-server:$VERSION" \
|
|
-t "$REGISTRY/kvitt-server:latest" \
|
|
--metadata-file /tmp/kvitt-server.metadata.json \
|
|
./server \
|
|
--push
|
|
- name: Print image digests
|
|
# The digests deploy.sh prints and records on the Kvitt Pi (/opt/kvitt/deployed-digests, D-117) must match.
|
|
run: |
|
|
for name in backup server; do
|
|
digest=$(sed -n 's/.*"containerimage.digest": *"\([^"]*\)".*/\1/p' "/tmp/kvitt-$name.metadata.json")
|
|
echo "$REGISTRY/kvitt-$name:$VERSION ${digest:-unknown}"
|
|
rm -f "/tmp/kvitt-$name.metadata.json"
|
|
done
|
|
- name: Tag and Push Version
|
|
run: |
|
|
git tag "$VERSION"
|
|
git push origin "$VERSION"
|