Commit c21eae1
authored
* fix(merge-guard): close carrier-5 git commit -m over-blocks via shared value-strip (#1140)
Migrate the carrier-5 git commit -m/--message message-value strip from two -m-only inline re.sub arms to the shared span-bounded quote-balanced machinery (_strip_flag_values/_VALUE_TOKEN/_keep_carrier_value), a verb-only clone of carrier-7d.
Closes five faithful-commit over-blocks that a message mentioning a destructive op previously tripped: multi -m, ANSI-C $'...', adjacent-concat, --message single, and git -C <path> commit.
The global-flag prefix uses a non-gobbling [^;&|\n\s] word class (not a \S+ gobbler): it tolerates global flags like -C <path> while remaining unable to cross an unquoted separator, so an executing tail after the message stays leg-local and caught. A gobbling prefix would merge an intermediate leg into the stripped span and open a leg-merge under-block.
* test(merge-guard): certify carrier-5 git commit -m over-block closure + under-block retention (#1140)
Add test_merge_guard_1140_carrier5_cert.py (35 tests): the design §5 certification matrix codified as permanent bidirectional regression tests against the real is_dangerous_command.
Non-vacuity is in-test and permanent via a baked pre-fix classifier (git show f6e3639, the fix's parent) — every over-block-closure row asserts base=True AND head=False, every under-block-retention row asserts base=True AND head=True; crash-atomic (no working-tree mutation). The gobbling-mutant negative control proves the non-gobbling word class is load-bearing (swapping it flips u8 to an under-block), and a source drift-detector guards against a future de-brittling edit.
* chore(release): bump plugin version to 4.6.5 (#1140)
* fix(merge-guard): make the shared verb-message span bash-faithful — close escaped-quote/ANSI-C leg-merge under-block (#1140)
The prior carrier-5 migration used a naive single-quote body arm that was not bash-faithful: the escaped-single-quote idiom 'don'\''t' (don't/it's/can't) and ANSI-C $'...' plant a literal quote that desynced regex quote-pairing, so a later quote from a trailing quoted leg paired across an unquoted separator and the executing destructive tail was swallowed into STRIPPED — a security under-block (found by independent adversarial review, base=True/HEAD=False).
FIX-R makes the shared span bash-faithful with one regex arm per bash quoting mechanism (backslash-escape, ANSI-C, double/locale quote, single quote, plain, bare dollar), extracted to a single shared _VERB_MSG_BODY constant replacing 7 former inline copies, plus a faithful _VALUE_TOKEN. Separators are excluded from every arm so the span stops at the first real unquoted separator by construction (leg-locality over bash's finite quoting grammar).
Closes the under-block for git commit AND git tag and the gh carriers (which shared the vulnerable span). Certified bidirectionally against the real classifier: opens zero over-blocks (several pre-existing over-blocks closed as a bonus), executing tails stay caught, and the multi-arm body is empirically linear (no ReDoS).
* fix(merge-guard): close bundled/attached -m over-block — widen value-strip anchor (#1140)
A faithful git commit/tag with a bundled short-flag (-am/-sam/-Sam) or attached (-m"..."/-m'...') message whose text merely mentions destructive-sounding prose was over-blocked, because the value-strip anchor ((?:-m|--message)\s+) required a standalone -m plus whitespace and so left the message unstripped — a cardinal-sin over-block (review findings #3/#5).
Widen the anchor to ((?:--message|-[a-ln-zA-Z]*m)\s*) at both the commit and tag carriers. The character class excludes only lowercase m, so -[a-ln-zA-Z]*m consumes the bundled cluster and stops at the message flag with no backtracking: unbounded (closes even an absurd -aaaa...aam cluster), complete, and linear by construction. \s* (was \s+) admits the attached forms while still matching the spaced forms.
Certified bidirectionally against the real classifier on top of the bash-faithful body: closes every over-block for commit AND tag with zero residual, opens no under-block (executing tails stay leg-local and caught, incl. value-flag clusters -Cm/-Fm), preserves --message= (handled by carrier-4), and is empirically ReDoS-linear. Anchor-only; the shared body/_VALUE_TOKEN and all other carriers are untouched.
* test(merge-guard): expand carrier-5 cert for FIX-R + C4 remediation (three-baseline non-vacuity) (#1140)
Expand test_merge_guard_1140_carrier5_cert.py (35 -> 88 tests) to certify the FINAL remediated state (FIX-R b641872 + C4 f7f370a) after the independent review found a blocking under-block in the first fix.
Three baked pre-state classifiers (git show f6e3639 + 2d7fcd0 + b641872) provide the sharpest per-fix non-vacuity: C4 over-block closures isolate on b641872=True->HEAD=False; the FIX-R commit under-block on the three-point base=True/firstfix=False/HEAD=True; the FIX-R tag under-block on the pre-existing base=False. Crash-atomic, git-history-guarded.
Over-block certified first and most thoroughly (bundled -am/-sam/-Sam + attached -m-quote + the absurd -a*Nm cluster -> False, commit AND tag; --message= non-regression; plain -m/--message stay False). Under-block retention pinned across the esc-idiom/ANSI-C + executing tail + trailing-quoted-leg cross-product (the load-bearing trigger the original matrix never combined) for commit and tag and all three separators, plus the A3 value-flag clusters. Adds a C4 anchor char-class drift-detector and ReDoS linear-scaling pins for the body and the anchor cluster. Full suite: 11095 passed, 0 failed, 0 errors.
* fix(merge-guard): span-scope the substitution preserve to close benign-sub over-blocks (#1140)
Replace preserve-on-any-substitution with a quote-context-faithful span scanner: preserve only genuine command-substitution/backtick spans (they execute, so stay caught) and strip the surrounding inert literal. Closes over-blocks where a benign substitution or a double-quoted literal apostrophe coexists with danger-looking prose. Because the replacer is shared, the same latent over-block closes uniformly across the gh and git prose carriers. The fail-safe preserves the whole value for exotic spans (no under-block opens); malicious substitutions and executing tails stay caught. Linear-time by construction.
* fix(merge-guard): widen the message anchors to close abbreviated --message over-blocks (#1140)
Accept unambiguous abbreviations of --message (--m through --messag) in the commit and tag message-value anchors, so a faithful commit or tag whose message contains danger-looking prose is no longer over-blocked. The two anchors are deliberately different: commit accepts any --m prefix (its sole --m option is --message); tag is bounded to --mes because tag also has the value-taking --merged/--no-merged options (which diverge at char 3). Short-arm handling is unchanged; executing tails stay caught.
* fix(merge-guard): add message-value carriers for sibling git verbs to close their over-blocks (#1140)
Strip the message value for git merge, git stash push/store/save, and git notes add/append the same way as commit and tag, so a faithful use of those verbs whose message contains danger-looking prose is no longer over-blocked. cherry-pick and revert are excluded because their -m is a mainline parent-number, not a message. Each carrier is leg-local, so an executing tail after an unquoted separator stays caught, and a message command-substitution still executes and stays caught.
* test(merge-guard): certify the fold-all-4 over-block closures + realign the anchor drift-detector (#1140)
Expand the carrier-5 cert from 88 to 178 tests, codifying the fold-all-4 over-block closures bidirectionally against the real classifier. Add a pre-fold baked baseline (the fold parent commit) so each closure is proven to flip from blocked at pre-fold to allowed at HEAD (non-vacuous), with true-positives and executing-tail under-blocks caught at both baselines, and the fail-safe residual pinned as an explicit no-regression row. Realign the anchor drift-detector to assert the load-bearing m-excluding short-arm class (its long arm changed legitimately) while keeping the two ReDoS negative assertions verbatim. Full suite green.
* fix(merge-guard): span-scope carrier-4 var-assignment strip to close equals-form over-blocks (#1140)
Route carrier-4 double-quoted variable-assignment values through the span-scoped substitution preserve (the same scanner the message carriers use), so an attached-equals flag or general NAME=value carrying a benign command-substitution beside danger-looking prose is no longer over-blocked (commit --message=, gh --title=/--notes=, merge/stash/notes --message=, general FOO=). Expanded variables preserve the whole value (a bare expansion executes it), and git -c section.key= config values are excluded via a dotted-key guard so the config-injection surface (#11) stays at exact status quo. Single-quoted assignments are unaffected. No new under-block; true-positive substitutions and executing tails stay caught.
* test(merge-guard): certify the carrier-4 equals-form over-block closures (#1140)
Expand the cert to 219 tests, codifying the equals-form / variable-assignment over-block closures bidirectionally against the real classifier with an immediate-pre-fix baked baseline proving each closure flips from blocked to allowed (non-vacuous). Covers the equivalence axis (a literal gets the same disposition with or without a benign command-substitution), true-positive retention, executing-tail under-blocks, the dotted-key config-guard status-quo pins, and single-quoted controls. Full suite green.
* fix(merge-guard): span-scope the last 4 prose carriers to close the coarse-substitution over-block class (#1140)
Route the echo/printf, here-string, HTTP-body -d/--data, and gh-api -q/--jq carriers through the span-scoped substitution preserve (the same scanner the message and variable carriers use), so a benign command-substitution beside danger-looking prose in those carriers is no longer over-blocked. Emits the scanner native double-quoted output, keeping each preserved span in the same executing context as before so a real substitution stays caught; each carrier existing guards and no-substitution output are unchanged; single-quoted carriers are unaffected. This closes the coarse-preserve-on-substitution over-block class across all six affected carriers.
* test(merge-guard): certify the last-4-carrier coarse-substitution closures + pin the anchor-coverage boundary (#1140)
Expand the cert to 265 tests, codifying the echo/printf, here-string, HTTP-body -d, and gh-api --jq closures bidirectionally with an immediate-pre-fix baked baseline (each flips from blocked to allowed, non-vacuous), plus per-carrier true-positive retention under the native double-quoted output (a real substitution stays caught identically to base), equivalence controls, and a boundary pin recording the pre-existing echo/printf multi-arg anchor gap as out-of-scope. Full suite green.
* fix(merge-guard): strip every positional echo/printf argument to close the multi-arg over-block (#1140)
Replace the echo/printf carrier first-argument-only strip with a span-plus-loop that strips every quoted positional argument, so danger-looking prose in a second or later echo/printf argument is no longer over-blocked. Both quoted forms are covered; the span stops at the first unquoted separator so an executing tail stays caught, and the loop stays inside the pipe-to-shell/process-substitution guard so a piped echo still executes and stays caught. This is a bounded carve-out for echo/printf (which never execute their arguments); the broader positional over-block surface in commands that DO execute arguments is out of scope.
* test(merge-guard): certify the echo/printf multi-arg closures + record the deferred anchor-coverage boundary (#1140)
Expand the cert to 297 tests, codifying the echo/printf multi-argument closures bidirectionally with an immediate-pre-fix baked baseline (each 2nd+ argument case flips from blocked to allowed, non-vacuous; a single-argument backtick case already closed earlier is reclassified out). Cover both quoted forms and mixed orders, retain every under-block guard (piped-to-shell, process substitution, executing tails, and a real substitution in any argument stay caught), and pin a representative set of still-deferred positional over-blocks in other commands as the recorded boundary of the separate anchor-coverage class. Full suite green.
1 parent f6e3639 commit c21eae1
6 files changed
Lines changed: 1959 additions & 79 deletions
File tree
- .claude-plugin
- pact-plugin
- .claude-plugin
- tests
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
12 | 12 | | |
13 | 13 | | |
14 | 14 | | |
15 | | - | |
| 15 | + | |
16 | 16 | | |
17 | 17 | | |
18 | 18 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
605 | 605 | | |
606 | 606 | | |
607 | 607 | | |
608 | | - | |
| 608 | + | |
609 | 609 | | |
610 | 610 | | |
611 | 611 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
3 | | - | |
| 3 | + | |
4 | 4 | | |
5 | 5 | | |
6 | 6 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
3 | | - | |
| 3 | + | |
4 | 4 | | |
5 | 5 | | |
6 | 6 | | |
| |||
0 commit comments