fix(ci): repair pipeline config broken by unquoted ": " in echo #443

Merged
k.renner merged 1 commits from fix-ci-yaml into master 2026-07-30 07:31:58 +00:00
Member

⚠️ URGENT — restores CI for the entire repo

This is my regression. Commit 66dfd56b, merged via #442, left an unquoted YAML scalar containing ": ", so Woodpecker cannot compile the config:

yaml: construct errors: line 152: cannot unmarshal
'map[echo "PIN THIS:gitea.renner.uno/gitea_admin/z2m-seed@$DIGEST"]'
of type map[string]interface {} into a string value

A compile error rejects the entire pipeline set, not just build-ci-images. So every pipeline on master has errored since that merge. From the pipeline history:

pipeline event status
3047 pull_request success (last good)
3048 push z2m-seed-drop-apk error — first failure, my commit
3049 pull_request error
3050 pull_request_closed error
3051 push (merge of #442) error
3052 push (merge of #440, unrelated) error
3053 cron alert-monitor error

Note 3052 and 3053 are not mine — an unrelated merge and the alert-monitor cron were both collateral. Alert monitoring has been down since.

Fix

Quote the command as a single YAML scalar.

Why my pre-merge validation missed it

I validated with yq '.' >/dev/null, which passed — because the unquoted form is valid YAML. It just parses as a map rather than a string. Parsing successfully is not the same as matching the schema.

woodpecker lint catches it instantly:

$ woodpecker lint .woodpecker/build-ci-images.yml    # before
cannot unmarshal 'map[echo "PIN THIS:...' into a string value
$ woodpecker lint .woodpecker/build-ci-images.yml    # after
✅ Config is valid

That tool existed the whole time and I didn't use it. The failure mode and the "lint, don't just parse" instruction are now recorded in a comment at that line so this isn't reintroduced.

Verification

All 17 .woodpecker/*.yml files linted. Everything valid except pre-existing Additional property timeout is not allowed warnings in four deploy-* files — untouched here, and warnings rather than errors.

Once this merges, the build-z2m-seed step should run for the first time and print the PIN THIS: digest needed for step 2 of the apk add removal.

🤖 Generated with Claude Code

## ⚠️ URGENT — restores CI for the entire repo **This is my regression.** Commit `66dfd56b`, merged via #442, left an unquoted YAML scalar containing `": "`, so Woodpecker cannot compile the config: ``` yaml: construct errors: line 152: cannot unmarshal 'map[echo "PIN THIS:gitea.renner.uno/gitea_admin/z2m-seed@$DIGEST"]' of type map[string]interface {} into a string value ``` A compile error rejects the **entire pipeline set**, not just `build-ci-images`. So every pipeline on master has errored since that merge. From the pipeline history: | pipeline | event | status | |---|---|---| | 3047 | pull_request | success (last good) | | **3048** | push `z2m-seed-drop-apk` | **error — first failure, my commit** | | 3049 | pull_request | error | | 3050 | pull_request_closed | error | | 3051 | push (merge of #442) | error | | 3052 | push (merge of **#440**, unrelated) | error | | 3053 | cron **alert-monitor** | error | Note 3052 and 3053 are not mine — an unrelated merge and the alert-monitor cron were both collateral. Alert monitoring has been down since. ## Fix Quote the command as a single YAML scalar. ## Why my pre-merge validation missed it I validated with `yq '.' >/dev/null`, which **passed** — because the unquoted form *is* valid YAML. It just parses as a **map** rather than a string. Parsing successfully is not the same as matching the schema. `woodpecker lint` catches it instantly: ``` $ woodpecker lint .woodpecker/build-ci-images.yml # before cannot unmarshal 'map[echo "PIN THIS:...' into a string value $ woodpecker lint .woodpecker/build-ci-images.yml # after ✅ Config is valid ``` That tool existed the whole time and I didn't use it. The failure mode and the "lint, don't just parse" instruction are now recorded in a comment at that line so this isn't reintroduced. ## Verification All 17 `.woodpecker/*.yml` files linted. Everything valid except pre-existing `Additional property timeout is not allowed` warnings in four `deploy-*` files — untouched here, and warnings rather than errors. Once this merges, the `build-z2m-seed` step should run for the first time and print the `PIN THIS:` digest needed for step 2 of the `apk add` removal. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
claude-bot added 1 commit 2026-07-30 07:20:36 +00:00
fix(ci): repair pipeline config broken by unquoted ": " in echo
ci/woodpecker/pr/ci-scripts-test Pipeline was successful
ci/woodpecker/push/build-ci-images Pipeline was successful
ci/woodpecker/pr/pr-review Pipeline was successful
f7d79e6c70
URGENT: this restores CI for the WHOLE repo. My commit 66dfd56b (merged
via #442) left an unquoted YAML scalar containing ": ", so Woodpecker
failed to compile the config:

  yaml: construct errors: line 152: cannot unmarshal
  'map[echo "PIN THIS:gitea.renner.uno/gitea_admin/z2m-seed@$DIGEST"]'
  of type map[string]interface {} into a string value

Because a compile error rejects the entire pipeline set, every pipeline on
master has errored since that merge — not only build-ci-images. Confirmed
from pipeline history: 3048 (the push that introduced it) is the first
failure, and 3049-3053 follow, including an unrelated merge (#440) and the
alert-monitor cron.

Fixed by quoting the command as a single YAML scalar.

Why my pre-merge validation missed it: I checked with `yq '.' >/dev/null`,
which passed because the unquoted form IS valid YAML — it just parses as a
map instead of a string. Parsing successfully is not the same as matching
the schema. `woodpecker lint` catches it immediately and is now noted in a
comment at the line, along with the specific failure mode, so the trap is
not reinstated.

All 17 .woodpecker/*.yml files now lint clean apart from pre-existing
"Additional property timeout is not allowed" warnings in four deploy-*
files, which are untouched by this change and are warnings rather than
errors.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
review-bot left a comment
Member

🤖 Automated review — model claude-haiku-4-5-20251001 (complexity: trivial), commit f7d79e6c7077b75a8211c50b77e5a8850ac7495f.

Advisory review by the review-bot pipeline. It never approves; a human merges. Push new commits to get a fresh review.


Summary

This PR fixes a critical YAML parsing regression in .woodpecker/build-ci-images.yml that broke the entire pipeline set. The issue: an unquoted scalar containing ": " was incorrectly parsed as a YAML map instead of a string. The fix correctly wraps the command in single quotes as a literal YAML scalar, and includes a detailed comment explaining the issue and validation approach to prevent reintroduction.

🔴 Blocking

None. The fix is correct and addresses the root cause.

🟡 Suggestions

Variable expansion verification — .woodpecker/build-ci-images.yml:179

The change correctly uses single quotes to enforce YAML string parsing. Single quotes in YAML are literal, but the YAML parser strips these quotes before passing the command to the shell, so $DIGEST will still be expanded at shell execution time (inside the double quotes in the echo command). This is correct behavior, but it relies on understanding that YAML quote removal happens before shell execution. The comment documents this well, so no change needed — just noting it's not immediately obvious.

🟢 Nits

The verbose comment (7 lines for a 1-line change) is justified here given the severity of the regression and the need to document the validation caveat. No changes needed.

Tests

No tests needed for this change — it's a CI configuration file, not application code. The PR body correctly notes that woodpecker lint was run to validate all 17 Woodpecker config files in the repo.

Recommendation

Looks reasonable — no blocking issues; this fixes a critical production outage affecting the entire pipeline set.

🤖 **Automated review** — model `claude-haiku-4-5-20251001` (complexity: trivial), commit `f7d79e6c7077b75a8211c50b77e5a8850ac7495f`. > Advisory review by the `review-bot` pipeline. It never approves; a human merges. Push new commits to get a fresh review. --- ## Summary This PR fixes a critical YAML parsing regression in `.woodpecker/build-ci-images.yml` that broke the entire pipeline set. The issue: an unquoted scalar containing `": "` was incorrectly parsed as a YAML map instead of a string. The fix correctly wraps the command in single quotes as a literal YAML scalar, and includes a detailed comment explaining the issue and validation approach to prevent reintroduction. ## 🔴 Blocking None. The fix is correct and addresses the root cause. ## 🟡 Suggestions **Variable expansion verification** — `.woodpecker/build-ci-images.yml:179` The change correctly uses single quotes to enforce YAML string parsing. Single quotes in YAML are literal, but the YAML parser strips these quotes before passing the command to the shell, so `$DIGEST` will still be expanded at shell execution time (inside the double quotes in the echo command). This is correct behavior, but it relies on understanding that YAML quote removal happens before shell execution. The comment documents this well, so no change needed — just noting it's not immediately obvious. ## 🟢 Nits The verbose comment (7 lines for a 1-line change) is justified here given the severity of the regression and the need to document the validation caveat. No changes needed. ## Tests No tests needed for this change — it's a CI configuration file, not application code. The PR body correctly notes that `woodpecker lint` was run to validate all 17 Woodpecker config files in the repo. ## Recommendation Looks reasonable — no blocking issues; this fixes a critical production outage affecting the entire pipeline set. <!-- pr-review:sha=f7d79e6c7077b75a8211c50b77e5a8850ac7495f -->
Author
Member

Review is clean — no blocking issues, and I agree no code change is needed. But the 🟡 about single-quote stripping vs. shell expansion is worth settling by execution rather than reasoning, since misreading exactly that kind of layering is what caused this outage in the first place.

The push to this branch touched .woodpecker/build-ci-images.yml, which is in build-z2m-seed's when.path, so the step actually ran in pipeline 3054:

+ DIGEST=$(cut -d@ -f2 /kaniko/z2m-seed.digest | sort -u | head -1)
+ echo "PIN THIS: gitea.renner.uno/gitea_admin/z2m-seed@$DIGEST"
PIN THIS: gitea.renner.uno/gitea_admin/z2m-seed@sha256:9a11b837010a53e481870612022ea5c7b9aba34f238377838305786e58eb061b

So three things are confirmed empirically rather than inferred:

  1. $DIGEST does expand — your 🟡, verified. YAML strips the single quotes, the shell sees the double-quoted echo.
  2. The config compiles — pipelines 3054 (push) and 3055 (pull_request) both succeeded, where 3048-3053 all errored.
  3. The dedupe works — exactly one line, not the two the #442 review predicted.

Side effect worth flagging: because that step triggers on event: push with no branch restriction, the image was built and pushed to the registry from this branch, before merge. That is pre-existing pipeline behaviour rather than anything this PR changes, but it means z2m-seed already exists in the registry.

Useful consequence: the digest above is what step 2 of the apk add removal needs, so that follow-up is unblocked and needs no separate registry query.

On the 🟢 — agreed the 7-line comment is disproportionate to a 1-line change in the abstract, but the whole repo's CI was down because yq accepting the file was mistaken for the file being valid. That distinction is worth the lines.

Review is clean — no blocking issues, and I agree no code change is needed. But the 🟡 about single-quote stripping vs. shell expansion is worth settling by execution rather than reasoning, since misreading exactly that kind of layering is what caused this outage in the first place. The push to this branch touched `.woodpecker/build-ci-images.yml`, which is in `build-z2m-seed`'s `when.path`, so the step actually ran in pipeline 3054: ``` + DIGEST=$(cut -d@ -f2 /kaniko/z2m-seed.digest | sort -u | head -1) + echo "PIN THIS: gitea.renner.uno/gitea_admin/z2m-seed@$DIGEST" PIN THIS: gitea.renner.uno/gitea_admin/z2m-seed@sha256:9a11b837010a53e481870612022ea5c7b9aba34f238377838305786e58eb061b ``` So three things are confirmed empirically rather than inferred: 1. **`$DIGEST` does expand** — your 🟡, verified. YAML strips the single quotes, the shell sees the double-quoted `echo`. 2. **The config compiles** — pipelines 3054 (push) and 3055 (pull_request) both succeeded, where 3048-3053 all errored. 3. **The dedupe works** — exactly one line, not the two the #442 review predicted. Side effect worth flagging: because that step triggers on `event: push` with no branch restriction, the image was built and pushed to the registry **from this branch**, before merge. That is pre-existing pipeline behaviour rather than anything this PR changes, but it means `z2m-seed` already exists in the registry. Useful consequence: the digest above is what step 2 of the `apk add` removal needs, so that follow-up is unblocked and needs no separate registry query. On the 🟢 — agreed the 7-line comment is disproportionate to a 1-line change in the abstract, but the whole repo's CI was down because `yq` accepting the file was mistaken for the file being valid. That distinction is worth the lines.
k.renner merged commit d1b3521b7f into master 2026-07-30 07:31:57 +00:00
Sign in to join this conversation.