Uh oh!
There was an error while loading. Please reload this page.
fix(installer): MySQL 8.4 gate must honor the chart digest, not just the tag (backend#2638) - #866
Conversation
…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>
# Conflicts: # scripts/manifest.sha256
saadqbal
left a comment
There was a problem hiding this comment.
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. 👍
Uh oh!
There was an error while loading. Please reload this page.
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_84concluded "MySQL 8.4 will run" whenevertag == "8.4" && digest == "". But its awk initialisesdigestto"", and the function is fed partial value views:_release_pins_mysql_84(adopt/reconcile) readshelm get valueswithout--all, which omits chart defaults.TRACEBLOC_VALUES_FILEpath can be a thin overlay carrying onlymysqlClient.tag.In both, the chart-default
images.mysqlClient.digest— the amd64-only 5.7 pin — is what actually renders, becausetracebloc.imagemakes 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:
mysql-clientimage…/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
sawdigestin 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 explicitdigest: "", 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 explicitdigest: ""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
tag 8.4with no digest line (thehelm get values/ partial-overlay shape) reads as NOT 8.4.tag: 8.4to include the explicitdigest: ""a real sticky/8.4 file always has.bats scripts/tests/install-client-helm.bats→ 239/239 pass.helm lint client/→ 0 charts failed;helm templaterenders both the digest-pinned default and the 8.4 opt-in correctly.scripts/manifest.sha256for the edited signed sub-script (gen-manifest.sh --checkclean).🤖 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_84treated a missingdigestline as empty, sotag: 8.4on partial value streams (e.g.helm get valueswithout--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 whentagis8.4anddigestappears on STDIN and is explicitly empty—the same shape the installer’s 8.4 heredoc writes. Callers are not switched tohelm 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.sha256is 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.