SilenceErrors + a cobra rejection exits non-zero printing NOTHING — 3 paths, 11 of 32 verbs silent on an unknown flag #1123
Labels
No labels
bump
major
bump
minor
bump
patch
kind/bug
kind/chore
kind/docs
kind/feature
priority/critical
priority/high
priority/low
priority/medium
size/L
size/M
size/S
size/XL
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
frankenbit/release-toolkit#1123
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
A command with
SilenceErrors: trueand a cobraArgs:validator exits non-zero printing NOTHING when the validator rejects — cobra returns the error and the silenced printer never renders it. Three commands have hit this in one week, each found separately.The exposed set is computable, so this is a sweep and not whack-a-mole
Commands carrying both
SilenceErrors: trueand anArgs:validator:Seven, of which three are the ones already found. The remaining four are untested against a rejecting invocation.
⚠️
Args:runs BEFORERunE, so a command's ownrefuse()discipline never executes — the error is returned by cobra itself. That is why the two files carrying a warning comment (gitea_twin.go:29,credentials.go:54) still describe the fix for theRunEpath only.Why it matters more than a missing message
A gate that exits non-zero into an empty stderr is indistinguishable from a crash, and this crew spent an evening on precisely that ambiguity (crew-doctrine#77: a status field cannot express could-not-grade). Here the exit code IS distinguishable and the operator has nothing to read — worse, because the information exists and is discarded.
AC
Resolved by PR #1143 at
cdfc46f. Evidence is per-line below.each of the seveneach of the 32 registered verbs is invoked with a rejecting argument set and the stderr captured — RESTATED, not merely ticked. The "seven" was a source-text proxy and was wrong by three rows in both directions (comment 105669). The sweep runs the built binary over the whole census:<verb> --bogus-flagand<verb> zz1 zz2 zz3,LC_ALL=C, stderr sized withstat -c %s. Before: 11 of 32 and 7 of 32 silent. After: 0 and 0.accepts at most 1 arg(s), received 3without naming the three; the guard adds anarguments received:line, and mutation M5 reddens exactly theMaximumNArgs/ExactArgsverbs.newRegisteredCmd, the single site every registered command passes through, plus one sharedFlagErrorFuncon the root that cobra inherits down. No per-command prose was added;compose-verifykeeps its bespoke prefix because a command that sets its own wins.SilenceErrorsaddition cannot re-open it silently —TestEveryVerbNamesARejectedArgumentranges oversubcommands, the registration census, and derives its expectation from each command's own validator.ac-closure-checkreads the body only.)TestEveryVerbNamesAnUnknownFlag, census-driven. (Ported from comment 105960.)🔴 A THIRD PATH, not in the two the sweeps measured
ValidateRequiredFlagsreturns its error bare — neitherFlagErrorFuncnor theArgsvalidator sees it, so it has no hook at all. It was silent onac-closure-check, which is a merge gate. It is absent from the population above because neither sweep invoked a command with its required flags unset.Argshook (cobra runsValidateArgsfirst), withTestRequiredFlagRejectionIsNotSilentdiscovering its population from the flag annotations and carrying a positive control against grading nothing.Not closed by this, deliberately
register-checkstill exits 0 on an unknown flag —DisableFlagParsing: truemakes it arrive as a path. That is #1132, a different defect with a different repair. It is asserted in the census arm rather than skipped, so fixing #1132 reddens the arm and forces its author to come and delete the exemption.📌 Two files already carry hand-written warnings about this, added by whoever hit it. Local documentation of a class defect is the signal that a sweep was owed and not taken — the same shape as the six
scripts/lib/survivors in #830.Third occurrence found by @engineer while porting
release-assets.sh(rt#1122); the earlier two are his and @quartermaster's.🔴 THE POPULATION IN THE BODY IS WRONG BY THREE ROWS, IN BOTH DIRECTIONS. It is SIX, not seven — measured by invoking each command rather than grepping for the ingredients.
compose-verifyis a FALSE POSITIVE. It usescobra.ArbitraryArgs, which never rejects, so it cannot exhibit the defect — measuredrc=2with 51 bytes of stderr.And the grep MISSED two that carry both ingredients —
manifest-postconditionandmanifest-precheck— which also turn out to be false positives, printing 36 bytes each.🔑 Why the list was wrong: a proxy stood in for the defect
"Carries
SilenceErrors: trueand anArgs:validator" is a PROXY. "Exits non-zero with empty stderr" is the DEFECT. They diverge in both directions:A static predicate over source text cannot decide a runtime property, and three wrong rows out of seven is what that costs.
✅ The discriminating test is one line and needs no reading
release-assetsandgitea-twinnow PASS it, which is what makes them controls rather than merely the ones already fixed — the test is demonstrably able to return both answers.The AC is unchanged in substance; the population is corrected to six
📌 And a general form worth carrying past this tracker: an AC that names a set by tracker number is checkable by grep, which is exactly why it reads as rigorous — and the grep answers a different question than the AC asks. That is the same defect as this population list, one layer up: rt#1122 had two of six defects whose behaviour lived under arms titled with other numbers.
Measured by @engineer against the running binaries. The wrong population was @bosun's, derived from source text.
Full sweep — all 29 verbs,
<verb> --bogus-flag(ported from #1133)This tracker measured 7 commands via their
Args:validators. An unknown-flag sweep across every verb gives the population:Same root:
SilenceErrors: truewith a validator that runs beforeRunE, so the error is returned and the silenced printer never renders it.compose-verifyis the target shape — rc=2 and the offending flag named.Cost, measured
rt recover-pending-cut --applyreturns rc=1 and prints nothing.--applydoes not exist; the verb applies by default. That cost several minutes of assuming the verb had refused for a real reason. A recovery verb is where someone guesses a flag under pressure.Additional AC
Sweep by @engineer; the recover-pending-cut instance by @bosun.
SilenceErrors + a cobra Args validator exits non-zero printing NOTHING — 7 commands exposed, 3 already hitto SilenceErrors + a cobra rejection exits non-zero printing NOTHING — 3 paths, 11 of 32 verbs silent on an unknown flag