A template is the highest-leverage copy of anything. This one carried its
own inline build step, so every generated repo was born with a private
fork of the build logic -- which is how rootless buildah reached a dozen
repos before infra#241, and why the fix then had to be rediscovered here
weeks after the app repos were done.
The step now calls .gitea/build-image.sh, a byte-identical copy of
mathias/infra's ci-templates/build-image.sh. Generated repos inherit the
script and the call; adding the new repo to infra's adopters.txt puts it
under the drift gate.
Invoked as `bash .gitea/build-image.sh` rather than relying on the exec
bit: files written through the Gitea API land 0644, and a template whose
CI depends on a file mode is a trap for every repo generated from it.
Byte-identical copy of mathias/infra's ci-templates/build-image.sh. A
template that carries its own copy of the build LOGIC manufactures a new
copy of every bug in it -- which is exactly how rootless buildah reached
a dozen repos (infra#241). Now it manufactures a copy of one file that a
drift gate keeps current instead.
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.
env.IMAGE: __PROJECT_NAME__ is only substituted with a real, lowercase
project name when a repo is *generated* from this template. On the
template repo itself it's still the literal placeholder, which
buildah/Docker reject outright ("repository name must be lowercase") --
build (and therefore deploy) can never succeed here no matter what else
changes. Gate both on github.repository != this template's own path so
the template's CI reads green on what it actually validates: the check
job (lint/vet/test), the thing every generated repo inherits.
Template shipped with no go.sum and an unchecked resp.Body.Close(),
both failing `task check` (golangci-lint errcheck) on every push since
bootstrap -- every repo generated from this template inherited the same
red CI. go.sum generated via `go mod tidy`; Close() error explicitly
discarded (best-effort cleanup, nothing actionable to do with it).