Skip to content

fix(installer): MySQL 8.4 gate must honor the chart digest, not just the tag (backend#2638) - #866

Merged
aptracebloc merged 2 commits into
developfrom
fix/2638-mysql-84-pin-honors-digest
Aug 27, 2026
Merged

fix(installer): MySQL 8.4 gate must honor the chart digest, not just the tag (backend#2638)#866
aptracebloc merged 2 commits into
developfrom
fix/2638-mysql-84-pin-honors-digest

Conversation

@aptracebloc

@aptraceblocaptracebloc commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Closes tracebloc/backend#2638

What

Fixes the Bugbot High finding that blocked the client#838 staging→main promotion (filed as backend#2638): "MySQL 8.4 pin ignores chart digest." Fixed forward on develop.

The bug

The engine gate _values_pin_mysql_84 concluded "MySQL 8.4 will run" whenever tag == "8.4" && digest == "". But its awk initialises digest to "", and the function is fed partial value views:

  • _release_pins_mysql_84 (adopt/reconcile) reads helm get valueswithout --all, which omits chart defaults.
  • the dev-mode TRACEBLOC_VALUES_FILE path can be a thin overlay carrying only mysqlClient.tag.

In both, the chart-default images.mysqlClient.digest — the amd64-only 5.7 pin — is what actually renders, because tracebloc.image makes a set digest win over the tag. Yet the digest line is nowhere on STDIN, so the absent digest was read as an empty one → a false "8.4" verdict → the 5.7 arch gate was skipped → the amd64-only image CrashLooped on arm64 (adopt / dev-mode).

Confirmed against the real chart:

valuesrendered mysql-client image
default…/mysql-client@sha256:f546e47f… (digest wins → 5.7-amd64)
tag: 8.4+ digest: ""…/mysql-client:8.4 (genuine opt-in)
tag: 8.4, digest untouched…/mysql-client@sha256:f546e47f… (still 5.7-amd64)

The third row is the finding: a tag-only flip does not run 8.4.

The fix

Require the digest key to appear and be empty before concluding 8.4: track sawdigest in the reader so an absent digest is "not provably cleared" → not 8.4 → the 5.7 arch gate runs (fail closed). One reader change fixes all three callers uniformly. The installer's 8.4 heredoc always writes an explicit digest: "", so no genuine opt-in regresses (verified end-to-end by the adopt/dev-mode/sticky bats tests).

Deliberately not switched to helm get values --all: default-coalescing can re-default an operator's explicit digest: "" back to the chart's 5.7 pin, which would false-refuse a real 8.4 reconcile. Reading only supplied values and demanding an explicit empty digest is the fail-closed direction that costs nothing real.

Tests / verification

  • Added a regression test: tag 8.4 with no digest line (the helm get values / partial-overlay shape) reads as NOT 8.4.
  • Updated three fixtures that carried a bare tag: 8.4 to include the explicit digest: "" a real sticky/8.4 file always has.
  • bats scripts/tests/install-client-helm.bats239/239 pass.
  • helm lint client/ → 0 charts failed; helm template renders both the digest-pinned default and the 8.4 opt-in correctly.
  • Regenerated scripts/manifest.sha256 for the edited signed sub-script (gen-manifest.sh --check clean).

🤖 Generated with Claude Code


Note

Medium Risk
Changes install-time MySQL engine detection on adopt/reconcile and dev-mode paths; fail-closed behavior may refuse or gate more arm64 cases, but genuine 8.4 opt-ins with explicit digest: "" should not regress.

Overview
Fixes a fail-open MySQL engine gate: _values_pin_mysql_84 treated a missingdigest line as empty, so tag: 8.4 on partial value streams (e.g. helm get values without --all, or a thin dev overlay) was read as a real 8.4 opt-in. The chart still renders the default digest-pinned 5.7 image, so the 5.7 arch gate was skipped and arm64 hosts could CrashLoop on the amd64-only image.

The reader now tracks sawdigest: 8.4 is recognized only when tag is 8.4anddigest appears on STDIN and is explicitly empty—the same shape the installer’s 8.4 heredoc writes. Callers are not switched to helm get values --all (that could false-refuse genuine 8.4 reconciles by re-coalescing chart defaults).

Tests add a regression for tag-only partial YAML; existing sticky/8.4 fixtures include digest: "". scripts/manifest.sha256 is updated for the signed sub-script.

Reviewed by Cursor Bugbot for commit 1a847d0. Bugbot is set up for automated code reviews on this repo. Configure here.

…the tag (backend#2638)
_values_pin_mysql_84 reported an 8.4 pin whenever tag=="8.4" && digest=="",
but it initialises digest to "" and is fed PARTIAL values — _release_pins_mysql_84
reads `helm get values` WITHOUT --all (chart defaults omitted) and a dev-mode
overlay can carry only mysqlClient.tag. In both, the chart-default digest (the
amd64-only 5.7 pin) is what actually renders — tracebloc.image makes the digest
win over the tag — yet its line is nowhere on STDIN. Treating that missing line
as an empty digest skipped the 5.7 arch gate and CrashLooped the amd64-only
image on arm64 (adopt / dev-mode).
Require the digest key to APPEAR and be empty (sawdigest) before concluding 8.4;
an absent digest is "not provably cleared" -> not 8.4 -> the 5.7 arch gate runs
(fail closed). The installer's 8.4 heredoc always writes an explicit `digest: ""`,
so no genuine opt-in regresses. Deliberately not switched to `helm get values
--all`: coalescing can re-default an operator's explicit `digest: ""` back to the
chart pin, which would false-refuse a real 8.4 reconcile.
Regen scripts/manifest.sha256 for the edited signed sub-script.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@aptraceblocaptracebloc self-assigned this Aug 27, 2026
# Conflicts:
#	scripts/manifest.sha256

@saadqbalsaadqbal left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I reviewed the awk this fixes, on #833, and missed exactly this. I checked that it dropped comment and blank lines so a decoy # tag: "8.4" couldn't match, and that tag == "8.4" was exact. What I never asked was what an absent digest line meant — and the function's own comment told me it didn't matter: "the digest is empty/absent", treating them as one case. I read that as a specification and moved on. It was the bug, written down, in the place a reviewer is most likely to trust.

Which makes the new comment's first line the right correction: AN ABSENT DIGEST IS NOT AN EMPTY ONE.

The mechanism is worth stating plainly because it's subtle in the right way: the reader is fed partial views — _release_pins_mysql_84 reads helm get values without --all, and a dev-mode overlay may carry only mysqlClient.tag — so the chart-default digest is still what renders (tracebloc.image makes a set digest beat the tag) while being nowhere on STDIN. digest == "" on an awk variable initialised to "" therefore reported a real 8.4 pin, skipped the 5.7 arch gate, and CrashLooped an amd64-only image on arm64. The three-row table is the proof, and the third row — tag: 8.4 with the digest untouched still rendering 5.7-amd64 — is the whole finding.

Verified the fix rather than taking it. flush() now requires sawdigest && digest == "", and sawdigest is reset to 0 on both block-entry paths (line 1538 entering from outside, line 1545 entering a new mysqlClient: block while already inside one), with sawdigest = 1 set whenever the key appears "empty or not". So no leak across blocks, which is the one bug this shape of fix invites.

Declining helm get values --all is the right call and the reasoning is the good kind: coalescing can re-default an operator's explicit digest: "" back to the chart's 5.7 pin, which would false-refuse a genuine 8.4 reconcile. So both error directions were weighed, and the chosen one fails closed at no real cost because our own heredoc always writes the explicit empty digest. Fixing it in the reader rather than the three callers is also right — one change, uniform behaviour.

Green, no threads. 👍

@aptracebloc
aptracebloc merged commit 76f4690 into developAug 27, 2026
49 checks passed
@aptracebloc
aptracebloc deleted the fix/2638-mysql-84-pin-honors-digest branch August 27, 2026 09:41
Sign up for freeto 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.

3 participants

@aptracebloc@saadqbal@LukasWodka