Commit Graph
10 Commits
Author SHA1 Message Date
mathiasandClaude Opus 5 b9bbbae3bb fix(ci): make the template guard survive its own substitution
CD / Detect unsubstituted template (pull_request) Successful in 1s
CD / Lint / Test / Vet (pull_request) Skipped
CD / Build & Import (pull_request) Skipped
CD / Deploy via GitOps (pull_request) Skipped
CD / Detect unsubstituted template (push) Successful in 1s
CD / Lint / Test / Vet (push) Skipped
CD / Build & Import (push) Skipped
CD / Deploy via GitOps (push) Skipped
Closes #9. Closes #10.

Every child repo born from this template has had fake-green CI: cd.yml's
guard grepped a literal placeholder, and both scaffolders substitute every
file in the tree -- including the guard. In a generated repo the check
became `grep -q 'git.d-ma.be/mathias/<name>' go.mod` against a go.mod whose
first line is `module git.d-ma.be/mathias/<name>`, so it matched forever,
check/build/deploy all skipped, and the run reported success having built
nothing. Confirmed in cad-atlas (#9) and openbanking-api (#10).

The second occurrence landed directly underneath a comment warning against
exactly this. That is the tell: an inline shell block in a workflow cannot
be tested, so a fix for it can only be reviewed by reading, and reading is
what missed it twice.

So the detection moves to scripts/is-template.sh and gets a test.

It greps the SHAPE of a placeholder rather than any literal token, which
also catches leftovers the scaffolders know nothing about, and a missing
target now exits non-zero instead of answering "false" -- failing open
there would skip CI on a repo that is not a template at all, which is the
same fake-green failure by another road.

scripts/tests/is-template_test.sh runs a scaffolder-style substitution over
a copy of the guard and asserts it still answers correctly. Both shipped
bugs fail that test.

The test assembles placeholder tokens at runtime rather than writing them
whole, for the same reason the guard does: a fixture containing a literal
token is substituted before the test runs, and the suite would then fail in
every generated repo while passing here. The first draft of the guard was
itself caught by this -- its explanatory comment named a token literally.

Verified by simulating a generated child (whole tree substituted):

    child  go.mod module git.d-ma.be/mathias/childproj
    guard  child    -> false   (CI runs)
    guard  template -> true    (template still skips its own build)
    suite  in child -> 8 passed, 0 failed
    suite  in template -> 8 passed, 0 failed

Wired into `task check`, so the guard that decides whether CI runs at all
in every child is covered by the same gate as the Go tests.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-17 16:29:29 +02:00
mathias 7c70489efe fix(context): sync to the estate canonical context-sync.sh (ADR-0019)
CD / Detect unsubstituted template (push) Successful in 0s
CD / Lint / Test / Vet (push) Skipped
CD / Build & Import (push) Skipped
CD / Deploy via GitOps (push) Skipped
Caught by the new estate-wide context-sync-drift gate (infra, ADR-0019).
This repo's copy had diverged from the canonical established in dma-cli/
infra -- synced to it, dead Cursor/Aider artifacts removed (2026-09-01
harness decision), Taskfile's drift assertion narrowed to match, adapters
regenerated against the current canonical AGENT.md.

Changed:
D  .aider.conf.yml
D  .aider.conventions.md
M  .context/system-prompt.txt
D  .cursorrules
M  AGENTS.md
M  Taskfile.yml
M  scripts/context-sync.sh

Refs: ADR-0019 (infra)
2026-09-05 08:33:36 +02:00
mathiasandClaude Opus 5 73c4f1c1de ci(deploy): refuse to patch a manifest with an empty IMAGE_TAG (infra#311)
CD / Detect unsubstituted template (push) Successful in 0s
CD / Lint / Test / Vet (push) Skipped
CD / Build & Import (push) Skipped
CD / Deploy via GitOps (push) Skipped
On 2026-08-25 a deploy job ran with an empty IMAGE_TAG, wrote
`image: localhost:5000/gitea-mcp:` into the infra repo and pushed it.
That is invalid YAML, so Flux failed the ENTIRE apps Kustomization --
every app stopped reconciling for about an hour, including three
unrelated deploys queued behind it.

This job's existing check could not catch it. It greps for
`image: <repo>:${IMAGE_TAG}` after the sed, and with IMAGE_TAG empty that
pattern matches the corrupted line itself, so the verification passes
because of the bug rather than despite it.

Asserting the input up front is the fix: an empty tag now fails the job
before anything is written, let alone committed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011PL5XcG68SvQqz3vGVbWbf
2026-08-25 17:25:24 +02:00
mathiasandClaude Opus 5 ba4adebd8d ci: re-sync build-image.sh — adds TARGET and BUILD_SECRETS (infra#309)
CD / Detect unsubstituted template (push) Successful in 1s
CD / Lint / Test / Vet (push) Skipped
CD / Build & Import (push) Skipped
CD / Deploy via GitOps (push) Skipped
Canonical gained two inputs so the repos still to migrate can adopt
without forking the script again: TARGET for multi-stage builds (cad,
agentsquad) and BUILD_SECRETS for buildkit secret mounts (agentsquad).

BUILD_SECRETS takes the SPEC only (`id=NAME,src=PATH`) -- the caller
writes the secret to PATH itself, so no secret value ever reaches this
script's argv or the CI log.

Unused here; this repo's copy just stays byte-identical, which is the
whole point. Written by `task ci:sync`, not by hand.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011PL5XcG68SvQqz3vGVbWbf
2026-08-25 11:27:06 +02:00
mathias 650644ebe3 ci(cd): call the shared build-image script instead of inlining it (infra#309)
CD / Detect unsubstituted template (push) Successful in 1s
CD / Lint / Test / Vet (push) Skipped
CD / Build & Import (push) Skipped
CD / Deploy via GitOps (push) Skipped
Same change as template-go-agent. A template that carries the build LOGIC
manufactures a private fork of it in every generated repo; one that
carries a CALL manufactures nothing. That distinction is what made
infra#241 a nine-repo sprint plus two rediscoveries in the templates.

Invoked as `bash .gitea/build-image.sh` -- files written through the
Gitea API land 0644, and CI that depends on a file mode is a trap for
every repo generated from here.
2026-08-25 08:53:23 +00:00
mathias ef4e47bf00 ci: carry the shared build-image script (infra#309)
CD / Detect unsubstituted template (push) Successful in 0s
CD / Lint / Test / Vet (push) Skipped
CD / Build & Import (push) Skipped
CD / Deploy via GitOps (push) Skipped
Byte-identical copy of mathias/infra's ci-templates/build-image.sh, so
repos generated from this template inherit a managed copy of one file
rather than a private fork of the build logic.
2026-08-25 08:52:53 +00:00
mathias bada904c8d ci: build with buildctl instead of buildah (infra#241)
CD / Detect unsubstituted template (push) Successful in 0s
CD / Lint / Test / Vet (push) Skipped
CD / Build & Import (push) Skipped
CD / Deploy via GitOps (push) Skipped
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.

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 merely carry the bug,
it manufactures new instances. The failure is latent — warm base-image layers
mask it — so a generated repo builds fine until its first genuinely cold pull,
which is precisely the situation a new repo is in.

Verification is PARTIAL here, and the limit is worth stating rather than
implying a green build. Running the exact command against this repo's real
context reaches step 8 and fails inside the Dockerfile:

    RUN templ generate && go build ... -o /out/app ./cmd/__PROJECT_NAME__
    error: failed to solve: ... exit code: 1

That failure is the template's own placeholder path, which cannot resolve on the
raw template — the same reason the guard job gates check/build/deploy off here
(is_template detects __MODULE_PATH__ in go.mod). What it does prove is that
buildctl resolved the frontend, the context and the Dockerfile and began
executing stages; every part of the buildctl integration worked, and only the
template's unsubstituted content did not.

template-go-agent's Dockerfile has no placeholder in its build path, so there the
same command produced a complete 6.8MB OCI archive. The first generated repo from
this template is where this one gets its end-to-end proof.

skopeo copy replaces `buildah push` — buildctl has no registry-push equivalent —
and runs twice to preserve the :sha and :latest tags.
2026-08-21 18:30:53 +02:00
mathiasandClaude Opus 4.8 8a22a28ab4 fix(template): parameterize scaffold with __PROJECT_NAME__/__MODULE_PATH__ (gitea-mcp#44)
CD / Lint / Test / Vet (push) Failing after 6s
CD / Build & Import (push) Has been skipped
CD / Deploy via GitOps (push) Has been skipped
template-go-web was seeded from the real `hostexecutor` project and never
parameterized: go.mod hardcoded `module gitea.d-ma.be/mathias/hostexecutor` and
`hostexecutor` appeared throughout (cmd dir, Dockerfile, Taskfile, CI, context
docs). create_project_from_template therefore substituted nothing and returned
a "no placeholders" partial_failure on the zero-config default path.

Replaced the full module path with __MODULE_PATH__ and the bare project name
with __PROJECT_NAME__ (incl. renaming cmd/hostexecutor → cmd/__PROJECT_NAME__),
matching the substitution the tool performs. Also drops the stale gitea.d-ma.be
host (the placeholder resolves to git.d-ma.be/<owner>/<name>).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-03 23:33:46 +02:00
mathias b2a87520b2 chore: drop environment: staging (no-op for solo homelab)
CD / Lint / Test / Vet (push) Failing after 3s
CD / Build & Import (push) Has been skipped
CD / Deploy via GitOps (push) Has been skipped
2026-05-05 08:51:20 +02:00
mathias a25120cd1d feat: initial template (Go + Templ + HTMX + CDN Tailwind)
CD / Lint / Test / Vet (push) Failing after 5s
CD / Build & Import (push) Has been skipped
CD / Deploy via GitOps (push) Has been skipped
2026-05-05 08:19:04 +02:00