Files
template-go-agent/.gitea/workflows/cd.yml
T
mathias c704fed563
CD / Lint / Test / Vet (push) Successful in 7s
CD / Build & Import (push) Skipped
CD / Deploy via GitOps (push) Skipped
ci: build with buildctl instead of buildah (infra#241)
Rootless buildah in gitea-runner's hardened securityContext (capabilities:
drop [ALL], allowPrivilegeEscalation: false) cannot remap the UID/GID range
newuidmap/newgidmap need on a fresh base-image pull, and the pod has no OCI
runtime at all. buildctl talks to the host's buildkitd over a socket, so the
privileged layer extraction happens on the host and the pod's securityContext
stops being in the picture. Same pattern as mathias/infra's segment-embedder.yml
and postgres18.yml.

A template is the highest-leverage place to fix this. Every repo generated from
here inherits its CI, so a buildah-based template does not just carry the bug —
it manufactures new instances of it. A fleet inventory for infra#241 found nine
repos still invoking buildah, and two of them are the templates.

Note the failure is latent, not immediate: warm base-image layers mask it, so a
generated repo builds fine until the first genuinely cold pull. That is exactly
the situation a NEW repo is in.

Verified by running the exact command against this repo's real build context:

    buildctl --addr unix:///run/buildkit/buildkitd.sock build \
      --frontend dockerfile.v0 --local context=. --local dockerfile=. \
      --output type=oci,dest=$TAR
    -> exporting manifest sha256:5a841529... DONE, 6.8MB OCI archive

That check matters here because this repo's own CI cannot validate the change:
the build job is deliberately skipped on the raw template (2ba2698), since
__PROJECT_NAME__ is not a legal image name. The next generated repo is the first
place it runs for real.

skopeo copy replaces `buildah push` — buildctl has no registry-push equivalent —
and runs twice to preserve the :sha and :latest tags the previous version pushed.
2026-08-21 18:29:55 +02:00

145 lines
5.5 KiB
YAML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
name: CD
"on":
push:
branches: [main]
tags: ["v*"]
pull_request:
branches: [main]
env:
IMAGE: __PROJECT_NAME__
jobs:
check:
name: Lint / Test / Vet
runs-on: self-hosted
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version-file: go.mod
cache: false
- name: Install toolchain
run: |
go version
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/HEAD/install.sh \
| sh -s -- -b "$(go env GOPATH)/bin" v2.11.4
- name: Run checks
run: task check
build:
name: Build & Import
needs: check
runs-on: self-hosted
# __PROJECT_NAME__/__MODULE_PATH__ are placeholders substituted only when
# a repo is generated from this template -- on the raw template repo
# itself they're still literal, and `IMAGE: __PROJECT_NAME__` contains
# uppercase letters, which buildah/Docker rejects outright ("repository
# name must be lowercase"). Build/deploy can never succeed here; skip
# them on this repo so its own CI reads green on what it can actually
# validate (the check job).
if: github.event_name != 'pull_request' && github.repository != 'mathias/template-go-agent'
outputs:
image-tag: ${{ steps.meta.outputs.sha-tag }}
steps:
- uses: actions/checkout@v4
- name: Derive image tags
id: meta
run: |
SHA=$(git rev-parse --short HEAD)
echo "sha-tag=${SHA}" >> "$GITHUB_OUTPUT"
# infra#241: buildctl, NOT buildah. Rootless buildah in gitea-runner's
# hardened securityContext (capabilities: drop [ALL],
# allowPrivilegeEscalation: false) cannot remap the UID/GID range
# newuidmap/newgidmap need on a fresh base-image pull, and it has no OCI
# runtime at all. buildctl talks to the host's buildkitd over a socket, so
# the privileged extraction happens in buildkitd on the host and never in
# this pod. Same pattern as mathias/infra's segment-embedder.yml.
#
# This matters MORE in a template than anywhere else: every repo generated
# from here inherits its CI, so a buildah-based template manufactures new
# instances of a bug that has already cost this estate several red builds.
- name: Build and push to local registry
run: |
set -e
BUILDKIT_HOST="unix:///run/buildkit/buildkitd.sock"
REGISTRY="localhost:5000"
REF="${REGISTRY}/${{ env.IMAGE }}:${{ steps.meta.outputs.sha-tag }}"
TAR_FILE="$(mktemp)"
trap 'rm -f "$TAR_FILE"' EXIT
buildctl --addr "$BUILDKIT_HOST" build \
--frontend dockerfile.v0 \
--local context=. \
--local dockerfile=. \
--opt label:org.opencontainers.image.revision="${{ github.sha }}" \
--output type=oci,dest="$TAR_FILE"
# buildctl has no registry-push equivalent to `buildah push`; skopeo
# copies the OCI archive up. Two copies because the buildah version
# tagged both :sha and :latest.
skopeo copy --dest-tls-verify=false \
oci-archive:"$TAR_FILE" docker://${REF}
skopeo copy --dest-tls-verify=false \
oci-archive:"$TAR_FILE" docker://${REGISTRY}/${{ env.IMAGE }}:latest
echo "✓ Image pushed to ${REF} and :latest"
deploy:
name: Deploy via GitOps
needs: build
runs-on: self-hosted
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
steps:
- name: Update image tag in infra repo
env:
IMAGE_TAG: ${{ needs.build.outputs.image-tag }}
DEPLOY_KEY: ${{ secrets.INFRA_DEPLOY_KEY }}
run: |
set -euo pipefail
mkdir -p ~/.ssh
echo "$DEPLOY_KEY" > ~/.ssh/id_infra
chmod 600 ~/.ssh/id_infra
ssh-keyscan -p 30022 10.0.1.20 >> ~/.ssh/known_hosts 2>/dev/null
export GIT_SSH_COMMAND="ssh -i ~/.ssh/id_infra -o IdentitiesOnly=yes"
rm -rf /tmp/infra
git clone -b main ssh://git@10.0.1.20:30022/mathias/infra.git /tmp/infra
cd /tmp/infra
DEPLOYMENT="k3s/apps/__PROJECT_NAME__/deployment.yaml"
sed -i "s|image: localhost:5000/__PROJECT_NAME__:.*|image: localhost:5000/__PROJECT_NAME__:${IMAGE_TAG}|" "$DEPLOYMENT"
grep -q "localhost:5000/__PROJECT_NAME__:${IMAGE_TAG}" "$DEPLOYMENT" \
|| { echo "✗ image tag patch failed"; exit 1; }
if git diff --quiet "$DEPLOYMENT"; then
echo "ℹ image tag unchanged — skipping push"
else
git -c user.name="__PROJECT_NAME__ CI" \
-c user.email="ci@__PROJECT_NAME__.local" \
commit -m "chore(deploy): __PROJECT_NAME__ → ${IMAGE_TAG}" "$DEPLOYMENT"
git push origin main
echo "✓ pushed to infra repo"
fi
shred -u ~/.ssh/id_infra
- name: Trigger Flux reconcile
run: |
kubectl -n flux-system annotate gitrepository flux-system \
reconcile.fluxcd.io/requestedAt="$(date +%s)" --overwrite
kubectl -n flux-system annotate kustomization apps \
reconcile.fluxcd.io/requestedAt="$(date +%s)" --overwrite
- name: Verify rollout
run: |
kubectl rollout status deployment/__PROJECT_NAME__ \
--namespace __PROJECT_NAME__ \
--timeout=120s \
|| {
kubectl get pods -n __PROJECT_NAME__ -o wide
kubectl get events -n __PROJECT_NAME__ --sort-by='.lastTimestamp' | tail -20
exit 1
}