Skip to content

fix(scripts): read compose's guards from the parsed YAML, not the text (#107) - #289

Merged
Gerrrt merged 2 commits into
mainfrom
gerrrt/compose-guards-107
Sep 4, 2026
Merged

Gerrrt merged 2 commits into
mainfrom
gerrrt/compose-guards-107

Conversation

@Gerrrt

@Gerrrt Gerrrt commented Sep 4, 2026 •

Copy link
Copy Markdown
Owner

Closes #107.

${VAR:?message} in compose.yaml is the declaration that a service cannot start without VAR, and two scripts derive what a stack requires from it: seed-validation-env.sh must satisfy every guard to get docker compose config past them, and render-config.sh must ask SOPS for every guarded secret. Both grepped the raw file, which reads comments as well as YAML — so a comment that mentioned the guard syntax became a guard, and validation demanded a value for a variable that does not exist:

compose.yaml guards VAR, which the validation .env does not set.

That was hit while writing #62, and the fix then was to reword the comment. Documentation should not have to avoid describing the thing it documents.

What changed

  • The renderer-token comment from Screenshot capture, and three faults it uncovered #62 now names its guard. 5625c52 described the mechanism as "the required-variable guard below" — a paraphrase written three days after the raw grep landed. There is no earlier text to restore; the rewording happened before the comment was ever committed.
  • The convention is now documented

Gerrrt and others added 2 commits September 4, 2026 22:09
#107)

`${VAR:?message}` in compose.yaml is the declaration that a service cannot
start without VAR, so two scripts derive what a stack requires from it:
seed-validation-env.sh must satisfy every guard to get `docker compose config`
past them, and render-config.sh must ask SOPS for every guarded secret. Both
grepped the raw file, which reads comments as well as YAML — so a comment that
*mentioned* the guard syntax became a guard, and validation demanded a value
for a variable that does not exist:

    compose.yaml guards VAR, which the validation .env does not set.

That was hit while writing #62, and the fix then was to reword the comment,
which is the wrong way round: documentation should not have to avoid describing
the thing it documents.

Read the parsed document instead, where a comment cannot appear. `docker
compose config` is not the authority to ask — it resolves the guards rather
than reporting them, and it is the thing being satisfied — so this walks every
scalar of the PyYAML parse, which check_compose_health.py already depends on.

One script, not two copies of the fix. render-config.sh's comment already
described its derivation as "the same one seed-validation-env.sh uses"; now it
literally is, in scripts/compose-guards.sh, so the two cannot drift and the
comment bug is not left standing in the caller the issue did not name — where
it is worse, because there it sends a render to SOPS for a key no stack has.

PyYAML is asked for and worked around if absent, rather than required: renders
happen on deploy hosts, and making one depend on a Python library to read a
list of variable names is a worse trade than the fallback, which strips what
YAML would treat as a comment and greps what is left. That is right about the
case this exists for and can only ever miss a guard hidden behind a `#` inside
a quoted string — the old failure mode, not a new false demand.

Both callers read the list through command substitution, because a process
substitution's exit status is not the loop's: a failure in the helper would
otherwise arrive as an empty guard list, and read as "this stack requires
nothing".

The guard convention is now documented in the header of stacks/observability/
compose.yaml — the documentation the old grep forbade, and a live regression
test for this fix: it names `${VAR:?message}`, so a return to grepping the raw
file fails `make validate` with the exact error from the issue.

Verified: guards for both stacks unchanged (parsed and fallback paths agree
with the old grep on both files), a guard added to a compose.yaml is still
caught by name, `make validate` passes, and the old grep sees VAR in the new
comment while neither new path does.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
… talk around (#107)

`5625c52` (#62) explains why GRAFANA_RENDERER_TOKEN is required rather than
optional, then describes the mechanism as "the required-variable guard below" —
a paraphrase, written three days after the raw-grep check landed in `595f0e2`
and made naming the syntax fatal. Writing what it means would have demanded a
throwaway value for a variable that does not exist before `make validate` would
pass. That is the rewording #107 was filed about, and the previous commit is
what removes the need for it.

There is no earlier text to restore: the rewording happened while the comment
was being written, so no commit ever carried the version this puts in its
place. Nothing else in either compose.yaml is talking around a guard — the
alertmanager note names `${RENDER_UID:-65534}`, and the `:-` form was never
matched by the grep.

Verified: the stack's guards are unchanged on both extraction paths, seed +
`docker compose config` pass, yamllint clean.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@Gerrrt
Gerrrt force-pushed the gerrrt/compose-guards-107 branch from 3bec684 to 4fe7ab8 Compare September 4, 2026 22:09
@Gerrrt
Gerrrt merged commit dd9ecb8 into main Sep 4, 2026
3 checks passed
@Gerrrt
Gerrrt deleted the gerrrt/compose-guards-107 branch September 4, 2026 22:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

seed-validation-env.sh greps comments, so documenting a compose guard breaks validation

1 participant