Skip to content

Commit c21eae1

Browse files
fix(merge-guard): close carrier-5 git commit -m over-blocks via shared value-strip (#1140) (#1176)
* 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/marketplace.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
"name": "PACT",
1313
"source": "./pact-plugin",
1414
"description": "Orchestration harness that turns Claude Code into a coordinated team of specialist AI agents",
15-
"version": "4.6.4",
15+
"version": "4.6.5",
1616
"author": {
1717
"name": "Synaptic-Labs-AI"
1818
},

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -605,7 +605,7 @@ When installed as a plugin, PACT lives in your plugin cache:
605605
│ └── cache/
606606
│ └── pact-plugin/
607607
│ └── PACT/
608-
│ └── 4.6.4/ # Plugin version
608+
│ └── 4.6.5/ # Plugin version
609609
│ ├── agents/
610610
│ ├── commands/
611611
│ ├── skills/

pact-plugin/.claude-plugin/plugin.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "PACT",
3-
"version": "4.6.4",
3+
"version": "4.6.5",
44
"description": "Orchestration harness that turns Claude Code into a coordinated team of specialist AI agents",
55
"author": {
66
"name": "Synaptic-Labs-AI",

pact-plugin/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# PACT — Orchestration Harness for Claude Code
22

3-
> **Version**: 4.6.4
3+
> **Version**: 4.6.5
44
55
Turn a single Claude Code session into a managed team of specialist AI agents that prepare, design, build, and test your code systematically.
66

0 commit comments

Comments
 (0)