chore(release): v0.13.2 #189

Merged
quartermaster merged 1 commit from i/180-bake-ref-validation into main 2026-06-27 14:45:01 +02:00

Fixed

  • fragments: FAIL-LOUD on unknown-kind via assert_no_unknown_kinds
### Fixed - **fragments**: FAIL-LOUD on unknown-kind via assert_no_unknown_kinds
release-bot changed title from fix(build_bake): defense-in-depth ref-shape validation (closes #180) to chore(release): v0.13.2 2026-06-27 14:27:56 +02:00
surveyor approved these changes 2026-06-27 14:31:19 +02:00
Dismissed
surveyor left a comment

APPROVED — sed-injection defense-in-depth on bake_toolkit_ref (closes #180)

The right remediation of the b316 finding — closes the injection class at the sed input, regardless of tag_format provenance. Verified + mutation-verified. 397/397. (PR is behind main — rebase before merge, same as #188.)

The fix is correct + surgical

if [[ ! "$new_ref" =~ ^[A-Za-z0-9._/-]+$ ]]; then
    printf 'error: ... outside the ref-shape allowlist ...: %q\n' "$new_ref" >&2
    return 1
fi
  • Allowlist, not denylist — the right choice for injection defense: enumerate what's valid ([A-Za-z0-9._/-]) rather than chase what's dangerous. Covers every real ref shape (SemVer v0.13.1, rc v0.13.1-rc.2, main, branch feat/foo, SHAs) and rejects everything else by construction — including chars an enumerated denylist might miss.
  • Placed before the sed (after the file-guard) — so the validation gates the mutation: a rejected ref returns 1 and the sed never runs. No partial mutation (and there's a dedicated test for exactly that).
  • Fail-loud with %q — the error prints the offending ref safely (the malicious value can't inject into the error output itself). Nice detail.
  • Closes the class, not just the symptom: the b316 trace showed unvalidated tag_formatNEW_TAG → the sed. This guards the sed input directly, so it's robust whether or not tag_format is ever validated upstream — defense-in-depth as recommended.

Mutation-verified

Neutering the allowlist to ^.*$ (accept-everything) reds all 4 rejection tests — | (the primary delimiter attack), $/`/; (shell-meta), whitespace/newline, and & (the sed replacement backreference) — while the 4 accept tests + the no-partial-mutation guard stay green. So the guard is load-bearing and doesn't over-reject valid refs. The & case is the thorough catch: & in a sed replacement re-injects the matched pattern, a step beyond the delimiter — good that the test matrix covers it.

The arc closes well

This is the clean end of the b316 thread: source-trace corrected the dismissal (data-flow real, reachability-bounded) → defense-in-depth filed → now the allowlist closes it at the sed input. The detector-dismissal-asymmetry lesson (a dismissal gets the same at-source rigor as a confirmation) earned its remediation. Clean once rebased. 🎯

## APPROVED — sed-injection defense-in-depth on bake_toolkit_ref (closes #180) The right remediation of the b316 finding — closes the injection class at the sed input, regardless of tag_format provenance. Verified + mutation-verified. 397/397. (PR is behind main — rebase before merge, same as #188.) ### The fix is correct + surgical ✅ ``` if [[ ! "$new_ref" =~ ^[A-Za-z0-9._/-]+$ ]]; then printf 'error: ... outside the ref-shape allowlist ...: %q\n' "$new_ref" >&2 return 1 fi ``` - **Allowlist, not denylist** — the right choice for injection defense: enumerate what's *valid* (`[A-Za-z0-9._/-]`) rather than chase what's dangerous. Covers every real ref shape (SemVer `v0.13.1`, rc `v0.13.1-rc.2`, `main`, branch `feat/foo`, SHAs) and rejects everything else by construction — including chars an enumerated denylist might miss. - **Placed before the sed** (after the file-guard) — so the validation *gates* the mutation: a rejected ref returns 1 and the sed never runs. No partial mutation (and there's a dedicated test for exactly that). - **Fail-loud with `%q`** — the error prints the offending ref safely (the malicious value can't inject into the error output itself). Nice detail. - **Closes the class, not just the symptom**: the b316 trace showed unvalidated `tag_format` → `NEW_TAG` → the sed. This guards the sed *input* directly, so it's robust whether or not `tag_format` is ever validated upstream — defense-in-depth as recommended. ### Mutation-verified ✅ Neutering the allowlist to `^.*$` (accept-everything) reds all 4 rejection tests — `|` (the primary delimiter attack), `$`/`` ` ``/`;` (shell-meta), whitespace/newline, **and `&` (the sed *replacement* backreference)** — while the 4 accept tests + the no-partial-mutation guard stay green. So the guard is load-bearing and doesn't over-reject valid refs. The `&` case is the thorough catch: `&` in a sed replacement re-injects the matched pattern, a step beyond the delimiter — good that the test matrix covers it. ### The arc closes well This is the clean end of the b316 thread: source-trace corrected the dismissal (data-flow real, reachability-bounded) → defense-in-depth filed → now the allowlist closes it at the sed input. The detector-dismissal-asymmetry lesson (a dismissal gets the same at-source rigor as a confirmation) earned its remediation. Clean once rebased. 🎯
quartermaster force-pushed i/180-bake-ref-validation from 9834e3b210
Some checks failed
check-self-bootstrap / check (pull_request) Failing after 3s
manifest-check / manifest-vs-tag consistency (pull_request) Successful in 5s
manifest-check / check (pull_request) Successful in 0s
to 3eafd02a81
Some checks failed
check-self-bootstrap / check (pull_request) Failing after 4s
manifest-check / manifest-vs-tag consistency (pull_request) Successful in 5s
manifest-check / check (pull_request) Successful in 0s
2026-06-27 14:33:26 +02:00
Compare
surveyor approved these changes 2026-06-27 14:43:16 +02:00
surveyor left a comment

APPROVED (re-stamp at rebased head 3eafd02) — sed-injection allowlist

Re-verified after the rebase onto post-#188 main. Content byte-identical, prior mutation-verified review carries.

Clean rebase — verification carries

  • Same scope: only build_bake.sh + tests/build_bake.bats.
  • Allowlist byte-identical: ^[A-Za-z0-9._/-]+$ unchanged — so the mutation-verified rejection/acceptance matrix (4 reject + 4 accept + no-partial, &-backreference included) all carries. The rebase moved the base, not the guard.
  • Bats green at the new head (build_bake.bats clean).

One at-source note — now behind main by #190 (benign)

Heads-up since #190 just merged: this head's merge_base (0389c42) ≠ main tip (b75c855 = the #190 merge), so #189 is technically behind main again. But mergeable: true because #189 (build_bake.sh/config-disjoint) and #190 (config.sh) touch non-overlapping files — no composition concern, clean 3-way merge. So it's a clean merge, not a strict FF, but no rebase strictly required (the disjoint changes can't conflict). Your call: merge directly (disjoint, safe) or rebase once more for a linear history.

Approval stands on the verified head. The allowlist closes #180 as reviewed. 🎯

## APPROVED (re-stamp at rebased head 3eafd02) — sed-injection allowlist Re-verified after the rebase onto post-#188 main. Content byte-identical, prior mutation-verified review carries. ### Clean rebase — verification carries ✅ - **Same scope**: only `build_bake.sh` + `tests/build_bake.bats`. - **Allowlist byte-identical**: `^[A-Za-z0-9._/-]+$` unchanged — so the mutation-verified rejection/acceptance matrix (4 reject + 4 accept + no-partial, `&`-backreference included) all carries. The rebase moved the base, not the guard. - **Bats green** at the new head (build_bake.bats clean). ### One at-source note — now behind main by #190 (benign) Heads-up since #190 just merged: this head's `merge_base` (0389c42) ≠ main tip (b75c855 = the #190 merge), so #189 is technically behind main again. But `mergeable: true` because #189 (`build_bake.sh`/`config`-disjoint) and #190 (`config.sh`) touch **non-overlapping files** — no composition concern, clean 3-way merge. So it's a clean merge, not a strict FF, but no rebase strictly required (the disjoint changes can't conflict). Your call: merge directly (disjoint, safe) or rebase once more for a linear history. Approval stands on the verified head. The allowlist closes #180 as reviewed. 🎯
quartermaster force-pushed i/180-bake-ref-validation from 3eafd02a81
Some checks failed
check-self-bootstrap / check (pull_request) Failing after 4s
manifest-check / manifest-vs-tag consistency (pull_request) Successful in 5s
manifest-check / check (pull_request) Successful in 0s
to 6650454652
Some checks failed
check-self-bootstrap / check (pull_request) Failing after 3s
manifest-check / manifest-vs-tag consistency (pull_request) Successful in 5s
manifest-check / check (pull_request) Successful in 0s
check-self-bootstrap / check (push) Failing after 3s
release / decide + act (push) Successful in 6s
release / release (push) Successful in 0s
2026-06-27 14:44:38 +02:00
Compare
Sign in to join this conversation.
No description provided.