Uh oh!
There was an error while loading. Please reload this page.
fix(tests): preflight PyYAML in every yaml-parsing guard (backend#2686) - #880
Conversation
The chart guards check `command -v python3` and then `import yaml` inside a python heredoc. `command -v python3` proves the interpreter exists, not the PyYAML module: on a runner with python3 but no PyYAML the import dies as a bare ModuleNotFoundError traceback (in a .sh guard) or degrades to a silent skip (in a .bats one — indistinguishable from a pass in a required gate), where the sibling helm-unittest-error-assertions.sh already gives `[ERROR] PyYAML required`. Bugbot flagged one instance (the CronJob guard, backend#2686 / client#869). Fixing the class, not the instance: every scripts/tests guard that imports the yaml module now preflights it — the .sh guards with the interpreter-then-module try/except the siblings carry, chart-pull-secret.bats with a require_pymodule helper mirroring its require_tool (local skip / CI hard-fail), and the two image-refresh .bats with the same named refusal in their inline python. Adds scripts/tests/pyyaml-preflight.bats, which derives the guard list from the tree (no hardcoded names), fails closed on zero guards, and behaviourally proves a real guard refuses cleanly when PyYAML is absent. Records the recurring finding in .cursor/BUGBOT.md per CLAUDE.md. Closestracebloc/backend#2686 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Uh oh!
There was an error while loading. Please reload this page.
…end#2686) bats-hygiene.bats flags standalone [ ]/[[ ]] assertions that lack a `|| return 1` closer: bats only propagates the LAST command's status (and [[ ]] escapes errexit on bash 3.2), so a non-final failing assertion is silently advisory. Append the closer to every assertion in the new suite. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
aptracebloc
commented
Aug 27, 2026
bugbot run |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
saqlainsyed007
left a comment
There was a problem hiding this comment.
Reviewed at adde48b (high effort). The shipped fix is correct and I'd own it — the notes are all non-blocking robustness suggestions on the new enforcer, not the fix. Holding only on CI (still in progress; nothing failing).
What I verified on the fix: the PyYAML preflight is applied UNIFORMLY across all 14 yaml-importing guards — the .sh/heredoc guards try: import yaml / except ImportError: sys.exit("[ERROR] PyYAML required …") (with sys imported first and other imports preserved), the two image-refresh-*.bats do it in setup/setup_file, and chart-pull-secret.bats uses a require_pymodule helper mirroring the existing require_tool pattern. telemetry-token-agreement.sh's two heredocs both got it. Fail-closed is correct everywhere it matters: CI paths sys.exit/::error::+return 1; require_pymodule only skips on a local run (matching require_tool). The new pyyaml-preflight.bats class-enforcer greps the tree so a future unguarded guard reddens CI — exactly the class-fix #2686 wants.
Non-blocking notes on the enforcer (inline): (1) the enumerator regex \bimport\b[^\n]*\byaml\b misses the from yaml import … idiom, so such a future guard wouldn't be enumerated or checked (no current guard uses it); (2) preflight detection is a whole-file substring match, so the literal string PyYAML required in a comment/heredoc alone would satisfy it; (3) the enumerator counts pyyaml-preflight.bats itself (its own error text matches the import pattern and carries the signal), inflating the [OK] all N denominator by one; (4) the "PyYAML present" case re-runs the fullhelm-unittest-error-assertions.sh, coupling this suite to that sibling's unrelated hygiene. I withdrew a fifth note (the broad except ImportError) — your enforcer's own shadow-simulation test depends on that breadth, so it's correct as-is; resolved that thread.
None block. Get CI green and I'll reconcile the four enforcer notes (address or wave off — they're all optional hardening) and approve.
Uh oh!
There was an error while loading. Please reload this page.
saqlainsyed007
left a comment
There was a problem hiding this comment.
Re-reviewed at 05cbe77. Good hardening — and a real one, not cosmetic: bats runs @test bodies with set -e OFF, so the bare mid-test [[ … ]] assertions here were partially vacuous (an intermediate failure — a leaked Traceback/ModuleNotFoundError, or the wrong status — wouldn't fail the test, only the last command's status counted). Adding || return 1 to each assertion in all three tests makes every one of them able to redden. That closes a mutation-proofing gap in the enforcer's own tests.
This is independent of my four earlier notes on the enforcer's structure (the \bimport\b…\byaml\b regex missing from yaml import …; substring-based preflight detection; the enumerator counting pyyaml-preflight.bats itself in the denominator; the "PyYAML present" test re-running the full sibling). Those are all still open and all still optional — none block, and the shipped preflight across the 14 guards remains correct and uniform. Take or leave them.
Holding the approve only on CI (PENDING). Once it's green I'll reconcile the four notes (address or wave off) and approve.
…(backend#2686) Addresses review on client#880 (Saqlain): - Enumerate the `from yaml import ...` idiom too, not just `import ... yaml` — a guard written that way was silently skipped, contradicting the fails-closed claim. - Detect the preflight STRUCTURALLY (the import must sit in a `try:` whose `except` names ImportError/ModuleNotFoundError, or a shell-level require_pymodule/require_yaml_tooling gate), not by a whole-file substring — a stray "PyYAML required" in a comment no longer satisfies the rule. - Exclude the enforcer file itself from the denominator (it is not a guard-under-test); the count is now the real guards only. - The "PyYAML present" case now asserts only that the preflight does not fire, not the sibling guard's full repo-wide verdict, so an unrelated helm-unittest defect cannot misattribute a failure to this suite. Verified: the hardened detector flags an unguarded `from yaml import` and an unguarded `import yaml` whose file merely mentions "PyYAML required" in a comment, while passing every real guard. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
aptracebloc
commented
Aug 27, 2026
bugbot run |
Uh oh!
There was an error while loading. Please reload this page.
saqlainsyed007
left a comment
There was a problem hiding this comment.
Approving at a732ac4 — CI green, and you closed every one of my notes; thanks for the thorough rework.
The enforcer is now structural and complete, exactly as hoped: import_yaml matches the from yaml import … idiom as well as import … yaml (finding 1); the python-level preflight is verified STRUCTURALLY via guarded_by_try — the import must sit inside a try: whose except names ImportError/ModuleNotFoundError, so a stray "PyYAML required" in a comment no longer satisfies the rule (finding 2); and the enforcer skips itself via self_name so it no longer inflates the [OK] all N denominator (finding 3). all(guarded_by_try(...) for i in hits) means EVERY yaml import in a guard must be wrapped, and the || return 1 on the assertions (from the prior commit) keeps the enforcer's own tests non-vacuous. The shipped 14-guard preflight was already correct and uniform. Full rollup green, mergeable, all my threads resolved. LGTM.
…uristic (backend#2686) Bugbot on client#880: the previous enforcer could still fail open. Two gaps, both now closed: - The shell-gate acceptance and the try/except detection were whole-file/ windowed substring checks, so a `require_pymodule yaml` in a COMMENT, or a `try:` that closes before the import with an `except ImportError` within five lines, satisfied the rule without actually guarding the import. Now the check parses the embedded python with `ast` and confirms every yaml import (import/from, module `yaml`) sits lexically inside a `try` whose handler names ImportError/ModuleNotFoundError; the shell-level gate (require_pymodule/require_yaml_tooling/one-line probe) is matched on comment-stripped lines only; heredoc/`-c` openers quoted inside a comment no longer open a bogus block (the `<<TAG`-in-a-comment trap bats-hygiene itself handles); and a single-line inline `python3 -c 'import yaml...'` is enumerated via the extracted snippet. Unparseable yaml-bearing source fails closed. Verified against the tree (all 17 real guards pass) and crafted negatives: an unguarded import whose file only mentions "PyYAML required"/"require_pymodule yaml" in a comment, a `try:` closed before the import, a `from yaml import`, and an `except` that catches the wrong error are each flagged; a properly guarded file and a real shell-gated file pass. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
aptracebloc
commented
Aug 27, 2026
bugbot run |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
saqlainsyed007
left a comment
There was a problem hiding this comment.
My earlier approval was dismissed by the post-approval push, so I re-reviewed the delta a732ac48..0012ebec. It's a single commit touching only scripts/tests/pyyaml-preflight.bats, and it's a strict hardening of exactly the enforcer I approved — no regression.
It replaces the windowed-regex heuristic (guarded_by_try scanning ±5 lines) with an AST-based check: it extracts the embedded Python (heredocs + python3 -c '…') and confirms every yaml import — both import yaml and from yaml import — sits lexically inside a try whose handler names ImportError/ModuleNotFoundError, with shell-gate detection now matching on comment-stripped lines. The two behavioural tests are untouched from what I approved and every assertion still carries || return 1.
I re-verified empirically at head: green on the real tree (17 guards — 15 AST-guarded + 2 shell-gated), and mutation-proof — stripping a try/except, wrong except type, or a broken require_pymodule name each reddens the suite and names the offender; comment-only markers, a try: closed before the import, an unguarded from yaml import, and a heredoc-in-a-comment trap are all caught; zero guards and unparseable source both fail closed.
This strengthens the mutation-proofness the approval rested on. I'll re-approve as soon as CI is green — mutation-shard/Bugbot are still running on 0012ebec. Nothing outstanding on my side.
…L enforcer (backend#2686)
Two more Bugbot mediums on client#880, both fixed:
- Double-quoted `python3 -c "import yaml; …"` (single line) was neither
extracted nor gate-matched, so such a guard dropped out of the denominator
and the class check stayed green. Extraction now matches the SAME quote that
opened the -c string (either ' or "), and the one-line gate probe accepts
both quotes.
- `has_shell_gate` accepted the `require_yaml_tooling() {` DEFINITION as an
exemption, so copying the helper without calling it marked a file
preflighted. The gate now requires a CALL (`require_yaml_tooling` not
followed by `(`); `require_pymodule` was already safe via its `yaml` arg.
Also broadened heredoc-opener matching to quoted/double-quoted/bare spellings
so a future guard cannot slip through on the heredoc spelling.
Verified: the 17 real guards still pass; a double-quoted single-line import and
a define-but-never-call helper are each flagged; a file that actually CALLS the
helper passes; all earlier negatives still caught.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>aptracebloc
commented
Aug 27, 2026
bugbot run |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit f4141ae. Configure here.
saqlainsyed007
left a comment
There was a problem hiding this comment.
Approving at f4141ae5. CI is fully green, mergeable, Bugbot clear, and no threads are open.
The one commit since my last review (0012ebec..f4141ae5) is a strict tightening of the pyyaml-preflight.bats enumerator — it closes two more Bugbot mediums without weakening anything: the shell-gate probe now accepts both quote styles and require_yaml_tooling requires an actual call (a copied definition no longer counts as a gate via a (?![ \t]*\() lookahead); the python3 -c extractor now captures and closes on the matching quote so a double-quoted one-liner is enumerated instead of silently dropped; and the heredoc opener matches quoted/bare spellings.
I re-verified empirically at head: [OK] all 17 guards; removing a guard's preflight, using the wrong except type, or breaking a gate name each redden the suite and name the offender; zero yaml imports fails closed; and the two newly-covered holes (an unguarded double-quoted -c import, a define-but-never-call helper) are now flagged while their guarded/called forms pass. The enforcer I approved on remains AST-based and mutation-proof — this only makes it stricter. LGTM.
Uh oh!
There was an error while loading. Please reload this page.
What
The chart guards in
scripts/tests/checkcommand -v python3and thenimport yamlinside a python heredoc.command -v python3proves the interpreter exists, not the PyYAML module: on a runner with python3 but no PyYAML the import dies as a bareModuleNotFoundErrortraceback (in a.shguard) or degrades to a silent skip (in a.batsone — indistinguishable from a pass in a required gate), where the siblinghelm-unittest-error-assertions.shalready gives[ERROR] PyYAML required.Cursor Bugbot flagged one instance — the CronJob guard (
cronjob-failures-are-readable.sh), deferred as backend#2686 from the refused client#869 staging hop.Fix the class, not the instance
Every
scripts/testsguard that imports theyamlmodule now preflights it:.shguards get the interpreter-then-moduletry/except ImportError → sys.exit("[ERROR] PyYAML required …")the siblings already carry (preserving each heredoc's other imports).chart-pull-secret.batsgets arequire_pymodulehelper mirroring its existingrequire_tool(local skip / CI hard-fail via::error::).image-refresh-skip-streak.batsandimage-refresh-stale-pin.batsget the same named refusal in their inline python.Every python
import yamlin the repo lives underscripts/tests/, so this covers the whole class (14 guards; 4 siblings were already correct).Regression guard + test (missing-PyYAML case)
Adds
scripts/tests/pyyaml-preflight.bats(auto-discovered by the requiredUnit testsjob):no Traceback,no ModuleNotFoundError.Records the recurring finding (client#827/#830 → backend#2686) in
.cursor/BUGBOT.mdper CLAUDE.md.Verification
make drift: 10 edited.shguards render + parse green (happy path unchanged). The one local failure is pre-existing/environmental — local helm v4 defaultskubeVersionto 1.20.0 vs the chart's>=1.24.0-0; CI pins helm v3.15.4 and renders fine (the pristine develop guard fails identically locally)..shguards under a shadowed PyYAML: named[ERROR] PyYAML required, no traceback, noModuleNotFoundError..bats+ new.bats: 47/47 green on the happy path; missing-PyYAML gives a CI hard-fail (chart-pull-secret) / named refusal (image-refresh), local skip where appropriate.bash -nclean on all.sh; all.batsparse.Closes tracebloc/backend#2686
Note
Low Risk
Changes are limited to test scripts, bats helpers, and Bugbot guidance; production chart or installer behavior is unchanged, and CI gates become stricter rather than looser.
Overview
Chart test guards under
scripts/tests/only provedpython3exists, not that PyYAML is importable. On runners with the interpreter but no module, embeddedimport yamlfailed as aModuleNotFoundErrortraceback in shell guards or as a silent bats skip that looks like a green required gate.This PR applies the interpreter-then-module pattern everywhere that class appeared: ten
.shguards wrapimport yamlintry/except ImportErrorwith a named[ERROR] PyYAML required (pip install pyyaml)exit;chart-pull-secret.batsaddsrequire_pymodule(CI hard-fail / local skip, mirroringrequire_tool);image-refresh-skip-streak.batsandimage-refresh-stale-pin.batsget the same refusal in inline Python.scripts/tests/pyyaml-preflight.batsis new regression coverage: it derives the list of yaml-importing guards from the tree (fails closed if zero found), statically checks shell gates or guarded imports, and behaviorally asserts a real sibling (helm-unittest-error-assertions.sh) refuses cleanly under a shadowedyamlmodule..cursor/BUGBOT.mdrecords the recurring finding so new guards are flagged if they skip preflight.Reviewed by Cursor Bugbot for commit f4141ae. Bugbot is set up for automated code reviews on this repo. Configure here.