Skip to content

fix(guard): read quoted wrapper values and long-option prefixes in the hard rules (#464) - #467

Merged
CryptoJones merged 2 commits into
mainfrom
fix/464-quoted-values-and-long-prefixes
Oct 3, 2026
Merged

CryptoJones merged 2 commits into
mainfrom
fix/464-quoted-values-and-long-prefixes

Conversation

@CryptoJones

Copy link
Copy Markdown
Owner

Summary

Two wrapper-argument shapes kept sudo out of command position for the hard rules (#464).

  • Unique-prefix long options. env --chd /x sudo id and stdbuf --out L sudo id were allowed. A long value-taking wrapper switch now matches by any prefix that no other value-taking switch of that wrapper shares, as GNU getopt_long reads it. This applies in policy._wrapper_pattern (new _long_prefixes), in guard._switch_width (reusing _long_option from fix(guard): more write tools for the repo-work classifier (#450) #456) and in _env_chdir_value. An ambiguous prefix stays a plain flag. env --chd sudo echo hi is no longer a false positive.
  • Quoted values. On main, env -iC "/a b" sudo id and xargs -0I '{} x' sudo id were denied only by accident, through the walk's opaque-site fallback. The regex itself took a value as \S+, and _program_stages split " " in two and landed on " as the program. Now:
    • A wrapper switch, its value and a VAR=value assignment are read as shell words. A word is made of pieces: a quoted run, a backslash escape or a plain character. Each kind of piece starts with a different character, so a word matches only one way and cannot backtrack.
    • timeout "5" is accepted as a duration.
    • The stage parser keeps a quoted run as one word, so it agrees with the hard rules.
  • Cost bound. _cmd_position_cost now bounds a chain through a quoted or escaped link word by the end of its line, because no word piece crosses a newline. It does the same for an assignment after a separator inside a word.

Stays out of decide, the deadline and the fact-lookup layer (#466).

Test evidence

  • New shapes are in CLUSTERED_WRAPPER_HARD_COMMANDS, so the guard hard rules: bundled wrapper option clusters (env -iC dir sudo …) are not read getopt-style #451 parity test covers them. 21 of the new cases fail on main and pass here.
  • New test_command_position_reads_a_quoted_wrapper_value_as_one_word checks the rule regex directly, not the fallback.
  • Other new tests:
    • _switch_width prefix widths.
    • The ambiguous prefix stays a flag.
    • _env_chdir_value reads --chd.
    • Two benign cases: env --chd sudo echo hi and env -C "sudo x" echo hi.
  • test_wrapper_runs_cannot_backtrack_the_hard_rules gained six runs: 'env -iC "/a b" ' * 400, "xargs -0I '{} x' " * 400, 'env -C "-a -b" ' * 400, "env --chd /x " * 400, 'X="a b" ' * 400 and 'timeout "5" ' * 400.
  • Gates:
  • Scratch probes:
    • perf446.py: at most 0.02 s.
    • probe459.py: at most 0.02 s, and the budget verdict is unchanged.
    • probe453.py: same results as main, including the existing source <(grep -v sudo .env) FP.
    • probe465.py: same results, with the cubic case at most 0.02 s.
    • Adversarial unbalanced-quote and escape runs (5,000 words): each at most 0.07 s.

Closes #464

Proudly Made in Nebraska. Go Big Red! 🌽 https://xkcd.com/2347/

🤖 Generated with Claude Code

https://claude.ai/code/session_011Zj1PCfsSSJgzLxi32jvde

…e hard rules (#464)

`env --chd /x sudo id` and `stdbuf --out L sudo id` were allowed: the
command-position regex and guard._switch_width treated any long option
they did not know exactly as a flag, so its value was read as the program.
`env -iC "/a b" sudo id` was denied only through the walk's opaque-site
fallback; the regex took a value as \S+ and the stage parser split the
quoted value in two.

- policy: a wrapper switch, its value and a VAR=value assignment are read
  as shell words made of pieces (quoted run, escape, plain char) that each
  start with a different character, so a word still matches one way only.
  timeout's duration may be quoted.
- policy/guard: a long value-taking switch matches by unique prefix among
  the wrapper's value-taking switches, in the regex, _switch_width and env
  --chdir tracking; an ambiguous prefix stays a flag.
- guard: the stage parser keeps a quoted run as one word.
- policy: _cmd_position_cost bounds a chain through a quoted or escaped
  word by the end of its line.
- tests: new shapes join the clusters table (and so the parity test), the
  backtracking bound test, and unit tests for prefixes and the regex.
- chore(release): 10.2.27

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011Zj1PCfsSSJgzLxi32jvde
@coderabbitai

coderabbitai Bot commented Oct 3, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

🧰 Additional context used
📚 Code guidelines (2)
BACKLOG.md — configured
CONTRIBUTING.md — configured

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: ASSERTIVE
  • Plan: Advanced
  • Run ID: de7c0549-9ba6-4ad0-8f6e-a4cf580b2e41
📥 Commits

Reviewing files that changed from the base of the PR and between 9047f2e and 6995e63.

⛔ Files ignored due to path filters (1)
  • uv.lock is excluded by !**/*.lock
📒 Files selected for processing (7)
  • BACKLOG.md
  • CHANGELOG.md
  • pyproject.toml
  • src/omind/__init__.py
  • src/omind/guard.py
  • src/omind/policy.py
  • tests/test_guard.py

Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.

📜 Recent review details
⏰ Context from checks skipped due to timeout. (20)
  • GitHub Check: test (windows-latest, 3.10)
  • GitHub Check: test (ubuntu-latest, 3.11)
  • GitHub Check: test (windows-latest, 3.14)
  • GitHub Check: test (macos-latest, 3.14)
  • GitHub Check: Upgrade from latest (macos-latest)
  • GitHub Check: test (ubuntu-latest, 3.14)
  • GitHub Check: test (ubuntu-latest, 3.10)
  • GitHub Check: test (ubuntu-latest, 3.12)
  • GitHub Check: test (ubuntu-latest, 3.13)
  • GitHub Check: Upgrade from v9.4.0 (ubuntu-latest)
  • GitHub Check: test (macos-latest, 3.10)
  • GitHub Check: Wheel build + install smoke test (macos-latest)
  • GitHub Check: Upgrade from latest (ubuntu-latest)
  • GitHub Check: Upgrade from v9.4.0 (macos-latest)
  • GitHub Check: Upgrade from latest (windows-latest)
  • GitHub Check: Upgrade from v9.4.0 (windows-latest)
  • GitHub Check: Secret scan (gitleaks, full history)
  • GitHub Check: Wheel build + install smoke test (ubuntu-latest)
  • GitHub Check: MCP conformance (live stdio)
  • GitHub Check: Analyze (python)
🧰 Additional context used
📓 Path-based instructions (2)
Source excerpt: This file and the GitHub **[Issues tab](https://github.com/CryptoJones/omind/issues)** are two views of the same list and must stay in sync.

📄 CodeRabbit inference engine (BACKLOG.md)

Files:

  • BACKLOG.md
Source excerpt: The version is declared in three places that must stay in lockstep — `pyproject.toml`, `src/omind/__init__.py`, and `uv.lock` — and a test asserts `__version__` matches `pyproject.toml`, so a release can't leave one behind.

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Files:

  • src/omind/__init__.py
  • pyproject.toml
  • CHANGELOG.md
🪛 ast-grep (0.45.3)
src/omind/guard.py

[warning] 3364-3364: XPath query is request-/variable-derived; use parameterized XPath to prevent injection.
Context: _STAGE_WORD_RE.findall(text)
Note: [CWE-643] Improper Neutralization of Data within XPath Expressions ('XPath Injection').

(xpath-injection-python)

tests/test_guard.py

[warning] 4595-4595: XPath query is request-/variable-derived; use parameterized XPath to prevent injection.
Context: guard._STAGE_WORD_RE.findall(text)
Note: [CWE-643] Improper Neutralization of Data within XPath Expressions ('XPath Injection').

(xpath-injection-python)


[warning] 4596-4596: Regex pattern passed to re is built from a non-literal (variable, call, concatenation, or f-string) value. If that value is attacker-controlled it can introduce a malicious pattern with catastrophic backtracking (ReDoS). Use a hardcoded literal pattern, or validate/escape untrusted input with re.escape() and bound the regex complexity before compiling.
Context: re.fullmatch(policy._WORD, word)
Note: [CWE-1333] Inefficient Regular Expression Complexity.

(redos-non-literal-regex-python)

src/omind/policy.py

[warning] 151-151: Regex pattern passed to re is built from a non-literal (variable, call, concatenation, or f-string) value. If that value is attacker-controlled it can introduce a malicious pattern with catastrophic backtracking (ReDoS). Use a hardcoded literal pattern, or validate/escape untrusted input with re.escape() and bound the regex complexity before compiling.
Context: re.compile(_WORD_PIECE + r"""|["'\]""")
Note: [CWE-1333] Inefficient Regular Expression Complexity.

(redos-non-literal-regex-python)


[warning] 152-152: Regex pattern passed to re is built from a non-literal (variable, call, concatenation, or f-string) value. If that value is attacker-controlled it can introduce a malicious pattern with catastrophic backtracking (ReDoS). Use a hardcoded literal pattern, or validate/escape untrusted input with re.escape() and bound the regex complexity before compiling.
Context: re.compile("(?:" + _WORD_PIECE + r"""|["'\])+""")
Note: [CWE-1333] Inefficient Regular Expression Complexity.

(redos-non-literal-regex-python)

🪛 markdownlint-cli2 (0.23.2)
CHANGELOG.md

[warning] 12-12: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 45-45: Spaces inside code span elements

(MD038, no-space-in-code)

🔇 Additional comments (6)
tests/test_guard.py (1)

4629-4634: LGTM!

BACKLOG.md (1)

82-90: LGTM!

CHANGELOG.md (1)

10-57: LGTM!

pyproject.toml (1)

3-3: LGTM!

src/omind/__init__.py (1)

5-5: LGTM!

src/omind/guard.py (1)

1803-1811: LGTM!

Also applies to: 3274-3293, 3314-3318, 3365-3365


📝 Summary

Summary by CodeRabbit

  • Bug Fixes
    • Improved command-line wrapper parsing so quoted or escaped values containing spaces are handled as a single value.
    • Corrected handling of unambiguous shortened long options and value-taking switches, while ambiguous prefixes remain flags.
    • Expanded recognition of wrapper options and improved parsing of quoted timeout durations and command assignments.
    • Improved search-cost estimates for commands containing quoted words, separators, or unmatched quotes.
  • Chores
    • Updated the project version to 10.2.27.

Walkthrough

Wrapper parsing now handles quoted and escaped values, unique-prefix long options, and additional value-taking switches. Guard stage parsing and command-position search-cost estimates use shared shell-word parsing. Regression tests and the 10.2.27 release records cover these changes.

Changes

Wrapper parsing

Layer / File(s) Summary
Shared shell-word and wrapper-option matching
src/omind/policy.py, tests/test_guard.py, BACKLOG.md, CHANGELOG.md, pyproject.toml, src/omind/__init__.py
Wrapper patterns and assignment matching use shared shell-word parsing. Wrapper definitions add value-taking options and long forms. Tests cover quoted and escaped values, and release records set the project version to 10.2.27.
Guard switch and stage parsing
src/omind/guard.py, tests/test_guard.py
Guard switch-width and env chdir parsing recognize unambiguous long-option prefixes. Stage parsing uses the shared shell-word tokenizer. Tests cover prefix handling and quoted wrapper values.
Quote-aware search-cost bounds
src/omind/policy.py, tests/test_guard.py
Command-position cost estimates account for quoted words, quoted separators, and unmatched quotes. Tests cover quoted command inputs and wrapper runs.

Priority: ➖ Normal

Estimated code review effort: 3 (Moderate) | ~25 minutes

Change: Bug fix

Merge Risk: ⚪ Minimal · up to 6995e

The reported regex concern does not affect current callers, and release versions are in sync. No actionable merge-blocking risk remains after normal checks.

Security Architecture Review

Security architecture risk: 🔵 Low · up to 6995e

The change improves consistency of shell-command checks. No newly introduced bypass was established, but unsupported shell syntax and incomplete runtime validation limit confidence.

Retained concerns
No architecture-level concerns identified.

Security review details

Security Blast Radius

  • inferred — The affected security surface is command text evaluated by guard rules, including commands behind wrappers and bodies run through local shells. The inspected change does not establish broader execution authority; deployment-specific privileges and tenant exposure were not supplied.

Trust Boundaries and Controls

  • observed — Wrapper values remain distinct from executable command words. Ambiguous configured long-option prefixes do not consume the following word, optional-value xargs switches are excluded from the separate-value table, and hard-rule evaluation retains additional word and quoted-code subjects.

Resilience and Maintainability Implications

  • observed — The shared word definition explicitly excludes joining backslash-newline continuations. A strict expected-failure test documents a missed wrapped command for that syntax and says it was also missed on main. This is a documented existing limitation, not evidence that the PR introduced or worsened a bypass; its effective baseline exposure was not independently verified.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: handling quoted wrapper values and long-option prefixes in the hard rules.
Description check ✅ Passed The description explains the wrapper parsing changes, their objectives, and reported test coverage. It is directly related to the changeset.
Linked Issues check ✅ Passed [#464] The PR summary reports shell-word parsing for quoted and escaped wrapper values, unique-prefix matching for value-taking long options, and matching behavior in the hard-rule regex and `guard._s…
Out of Scope Changes check ✅ Passed The implementation, option-table updates, regression tests, and documentation changes support or document the wrapper parsing changes in [#464]. The version updates accompany the changelog entry. The …
Docstring Coverage ✅ Passed Docstring coverage is 82.14% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 28 functions across 4 files. (3 skipped: 3 …
✨ Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@CryptoJones

Copy link
Copy Markdown
Owner Author

EM review: changes requested (Flatline Roundtable: HAL9000, Cortana, TheDixieFlatline)

The two shapes the issue names are fixed. I verified each finding below with guard._hard_policy_verdict on 56816a3 and on main (9047f2e).

Must fix

  1. Regression: escaped quotes now hide a whole stage (HAL9000).

    • env -u \" bash -c 'sudo id' x "y" is denied on main and allowed on this PR.
    • Cause: _STAGE_WORD_RE (guard.py:~3318) has no \\. piece, so \" opens a quoted run that swallows bash -c ….
    • Fix: build _STAGE_WORD_RE from the same word-piece definition as policy._WORD, so the two parsers share one definition of a shell word.
    • Tests: a parity test for \", a\ b and the quoted forms, run through both parsers.
  2. Parser parity on escaped blanks (Cortana, Dixie, HAL9000). _program_stages("env -C a\ b sudo id") lands on program b, while the regex treats a\ b as one value. Item 1's shared definition fixes this too. Add it to the parity list and correct the CHANGELOG claim.

  3. New false positive: a benign one-liner trips the budget (Cortana).

    • ('A="x" true; ' * 700) + 'echo sudo' is now denied with "command too large/complex to judge". On main it is allowed.
    • Cause: stretching a quoted link's reach to end-of-line over-counts.
    • Fix: make the bound tight again, e.g. compute spans with the shared word regex as Dixie suggests, so quoted words are already whole and the line_end estimate can go.
    • Also: keep the "only overestimates" promise for timeout -s K "5" (Cortana, HAL9000: a quoted duration after a switch value).
    • Tests: add quoted shapes to test_command_position_cost_bounds_the_chain_shapes, including this benign one staying under budget.
  4. Long-option twins missing from STAGE_WRAPPERS (HAL9000, Cortana). These all still hide sudo (verified):

    • timeout --kill-after 5 10 sudo id, timeout --signal KILL 5 sudo id
    • xargs --max-args 1 sudo id, plus --arg-file, --delimiter, --max-lines, --max-procs, --replace / -I, --eof
    • nice --adjustment 5 sudo id
    • ionice --class 3 sudo id, plus --classdata, --pid
    • time --output f sudo id, plus --format

    The issue's acceptance ("long wrapper options match by unique prefix") needs the table to list each value-taking long option. Add the GNU long twins for every wrapper in the table, with deny cases.

Should fix

  • Quoted env -C value used as a raw path (Dixie). _env_chdir_value hands "/a b" with its quotes to _chdir, so cwd tracking becomes a relative dir literally named "/a b". Unquote it with shell semantics before _chdir, and test that env -C "/a b" git … resolves to /a b.
  • command -"v" sudo false positive (HAL9000). The quoted-run alternative bypasses the vV exclusion. Make the lookup-wrapper switch exclude it.
  • Line continuation env -C a\<newline>b sudo id (Dixie). Already missed on main. Handle it if the shared word definition makes it cheap (\\\n is a continuation in code context). Otherwise add it to guard hard rules: quoted wrapper switch values and unique-prefix long options hide sudo #464's out-of-scope list in the CHANGELOG with a pinned test.

Dismissed

  • Prefix ambiguity among flag options (HAL9000): a truly ambiguous prefix makes the command error, and this is a documented approximation.
  • Nested quotes inside $(…) (HAL9000): plausible only, untraced.

Version: at push time, set the version one patch above origin/main. #466 is merging as 10.2.27, so this becomes 10.2.28.

Proudly Made in Nebraska. Go Big Red! 🌽 https://xkcd.com/2347/

#464 review)

- Stage parser, hard-rule regex and _cmd_position_cost use one word
  definition (policy.SHELL_WORD_RE), so an escaped quote no longer hides a
  bash -c stage and an escaped blank lands both parsers on the same program.
- _cmd_position_cost reads whole quoted words: the benign quoted one-liner is
  judged again, and a quoted duration after a switch value is a link.
- Long twins for timeout, nice, ionice, time, xargs and sudo value switches.
- command -\v is a lookup; a quoted lookup switch stays judged (fail closed).
- Line continuation inside a wrapper value pinned out of scope (xfail strict).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011Zj1PCfsSSJgzLxi32jvde
@CryptoJones

Copy link
Copy Markdown
Owner Author

EM review: response (commit 6995e63)

The branch sits on current origin/main (10.2.26), and the version is 10.2.27, as the EM asked after #466 went back into a fix round.

Must fix

  1. Escaped quote hides a stage: fixed.

    • policy.SHELL_WORD_RE (policy.py:153) is now the single definition of a shell word. It is built from _WORD_PIECE (_word_piece, policy.py:132), the same pieces _WORD uses, plus a fallback for a quote or backslash with no partner.
    • guard._STAGE_WORD_RE is now just that regex (guard.py:3318), so \" is an escape piece and opens no quoted run.
    • env -u \" bash -c 'sudo id' x "y" lands on bash and is denied.
    • Tests:
      • test_an_escaped_quote_hides_no_stage
      • test_stage_words_are_the_hard_rules_words: word lists for \", a\ b, "/a b" and "d\"e", each a _WORD match.
      • Parity rows added to CLUSTERED_WRAPPER_HARD_COMMANDS, run through both parsers by test_stage_parser_agrees_with_hard_rules_on_wrapper_clusters: env -u \" sudo id, env -C a\ b sudo id, env -C '/a b' sudo id and env -u \" -C "/a b" sudo id.
  2. Escaped-blank parity: fixed by the same change. _program_stages("env -C a\ b sudo id") now lands on id (sudo's program), as the regex does. The case is in the parity list, and the CHANGELOG claim is corrected.

  3. Benign one-liner trips the budget: fixed.

    • _cmd_position_cost (policy.py:278) now takes its words from SHELL_WORD_RE, so A="x" is one whole word. The line_end reach for quoted links and assignments is gone.
    • Only two shapes still use an end-of-line bound: a separator inside a quoted run ("$(a;b)", where a start after it can pair the quotes differently) and an unpartnered quote.
    • ('A="x" true; ' * 700) + 'echo sudo' costs 20,313 and is allowed again.
    • "Only overestimates": a word that starts with a quote and follows a joined link counts as a link, so timeout -s K "5" chains are counted in full.
    • Tests:
      • Quoted shapes (benign under 4×len, chains over budget) and a timeout -s K "5" duration chain added to test_command_position_cost_bounds_the_chain_shapes.
      • New test_a_benign_quoted_one_liner_stays_under_the_budget.
  4. Long twins: added (policy.py:92-115). New entries per wrapper:

    • timeout: --signal, --kill-after
    • nice: --adjustment
    • ionice: --class, --classdata, --pid, --pgid, --uid
    • time: --format, --output
    • xargs: --max-args, --max-procs, --max-chars, --delimiter, --arg-file, --process-slot-var
    • sudo: --user, --group, --close-from, --host, --prompt, --other-user, --role, --type, --chdir

    Deny rows are in CLUSTERED_WRAPPER_HARD_COMMANDS, which runs through both the hard-rule and parity tests. Benign rows are in test_wrapper_clusters_leave_benign_commands_alone: timeout --signal sudo 5 echo hi and xargs --max-args sudo echo hi.

    Disagreement, with evidence: I did not add --replace, --eof or --max-lines. In GNU xargs these are --replace[=R], --eof[=E] and --max-lines[=N]: an OPTIONAL value that can only be attached with =. The word after them is the command. Listing them as value-taking would turn xargs --replace sudo id into a miss. test_optional_value_long_switches_take_no_next_word pins all three as denied. -I, -E and -L stay in the table as short switches that take a value.

Should fix

  • Quoted env -C value: not reproducible; test added.
    • _env_chdir reads its prefix through _shell_tokens, which unquotes with shell rules before _env_chdir_value sees a word.
    • _env_chdir('env -C "/a b" git status', Path("/x")) returns /a b, both on 56816a3 and on main.
    • test_env_chdir_resolves_a_quoted_directory pins -C "…", -iC '…' and --chd="…". The probe's last line now passes a cwd and asserts /a b.
  • command -"v" sudo: partly done, and the rest is a disagreement.
    • _word_piece("vV") now excludes v/V both bare and escaped (policy.py:195), so command -\v sudo and -\V are lookups. Tested in the benign list; both were denied on 56816a3.
    • I kept the quoted run as a switch piece on purpose. The search reads shell_code_text, which blanks "v" and "p" to the same " ". Excluding quoted runs would allow command -"p" sudo id, which runs sudo and is denied on main.
    • command -"v" sudo id was already denied on main, so this is not a regression from this PR.
    • test_quoted_lookup_switch_fails_closed pins both as denied.
  • Line continuation: out of scope. Joining \<newline> in a word piece breaks the "no piece crosses a newline" rule that the cost bound depends on. It is listed under guard hard rules: quoted wrapper switch values and unique-prefix long options hide sudo #464's out-of-scope note in the CHANGELOG and pinned by test_line_continuation_inside_a_wrapper_value_is_out_of_scope (xfail(strict=True)).

Verification

  • Probe: probe467.py prints ok on every row, including the benign budget row. The line-continuation row stays MISS (out of scope), and chdir quoted: /a b passes its assertion.
  • Before/after probes: probe_rules, probe_classify, probe446, 447, 453, 456, 457, 461 and 465 give the same output once temp paths are normalised.
  • Timings: perf446 and probe459 all run in ≤0.02 s.
  • Adversarial shapes: unclosed quotes, runs of \", random strings of quotes, backslashes and separators (60k chars), and timeout -s K "5" chains all judge in ≤0.09 s.
  • Gates:
    • ruff check .: clean
    • mypy src (strict): clean
    • pytest -q: 3810 passed, 12 skipped, 1 xfailed
    • pytest --cov tests/test_guard.py: 1682 passed, 1 xfailed
    • My lines pass ruff format --check.
  • New tests vs the previous head: 44 of them fail on 56816a3.

Proudly Made in Nebraska. Go Big Red! 🌽 https://xkcd.com/2347/

@CryptoJones

Copy link
Copy Markdown
Owner Author

EM merge (#464). Reviewed by the Flatline Roundtable (HAL9000, Cortana, TheDixieFlatline), with one fix round.

Verified on the final head (6995e63):

  • Quoted wrapper values (env -iC "/a b", xargs -0I '{} x') and unique-prefix long options (env --chd, stdbuf --out) are denied.
  • The GNU long twins for timeout, nice, ionice, time, xargs and sudo (--kill-after, --signal, --max-args, --adjustment, --class, …) are denied.
  • The regression the panel found, env -u \" bash -c 'sudo id' …, is denied again. Both parsers now share one shell-word definition (policy.SHELL_WORD_RE).
  • The benign quoted one-liner stays under the budget.
  • A quoted env -C path resolves to /a b.
  • Every earlier probe suite is unchanged, and the guard: _shell_walk / _program_stages scale superlinearly (x=1; repeats quadratic; bash -c body n^1.5) #445 timings hold.

EM accepted two reasoned dissents from the fixer:

  • xargs --replace, --eof and --max-lines take an optional, =-attached value. They are deliberately not listed, because listing them would let the next word escape judgement.
  • Quoted lookup switches (command -"v") stay denied, because command -"p" sudo id really runs sudo.

Out of scope: the line continuation env -C a\<newline>b, pinned with a strict xfail.

All 23 CI jobs are green. Releasing as 10.2.27.

Proudly Made in Nebraska. Go Big Red! 🌽 https://xkcd.com/2347/

@CryptoJones
CryptoJones merged commit 13854e9 into main Oct 3, 2026
23 checks passed
@CryptoJones
CryptoJones deleted the fix/464-quoted-values-and-long-prefixes branch October 3, 2026 01:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

guard hard rules: quoted wrapper switch values and unique-prefix long options hide sudo

1 participant