Skip to content

fix(parser): do not escape { } in quoted glob ranges — breaks ${VAR} expansion - #2064

Merged
chaliy merged 4 commits into
mainfrom
claude/kind-rubin-ky9xhx
Jun 13, 2026
Merged

chaliy merged 4 commits into
mainfrom
claude/kind-rubin-ky9xhx

Conversation

@chaliy

@chaliy chaliy commented Jun 13, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • escape_glob_metas_in_quoted_ranges ran at parse time on content that still contains un-expanded ${VAR} references. It was escaping {, }, @, !, +, (, ), | — characters that are part of parameter/command expansion syntax.
  • This produced e.g. $\{HARNESS_ROOT\} which the runtime variable expander does not recognise — so patterns like "${VAR}/plugins"/*/ produced an empty glob set.
  • The practical breakage: harness's _refresh_sources (in 30-walk-dirs) uses exactly this pattern. After commit 3f396f0, _HARNESS_SOURCES became empty → _find_command "agent" failed → CI broke with harness: no agent command found.
  • Fix: rewrite the function with a context-aware expansion stack. It tracks ${…} and $(…) constructs by pushing/popping a delimiter stack. Inside a construct, no character is escaped. In literal quoted text outside any construct, the full metacharacter set is escaped (\, *, ?, [, ], {, }, @, !, +, (, ), |) — so literal {a,b} in a quoted prefix stays escaped and won't brace-expand at runtime.
  • Also updated expand_glob in glob.rs to strip \ escapes from the directory portion of a glob path before VFS lookup (so \{a,b\} resolves to an actual {a,b} directory), while preserving the original relative path string in output.
  • Also fixed the Examples CI job: the live supabase.sh SSH step now probes supabase.sh:22 via nc first and emits a warning annotation instead of failing when the runner has no outbound SSH access. This was a pre-existing red gate on main unrelated to the parser change.

Test plan

  • New regression tests var_expansion_in_quoted_glob_prefix_not_corrupted and var_expansion_in_quoted_glob_prefix_with_star pass
  • literal_brace_expression_in_quoted_glob_prefix_stays_literal confirms literal {a,b} is not brace-expanded
  • subscript_var_expansion_in_quoted_glob_prefix_not_corrupted confirms ${arr[0]} subscript brackets are not corrupted
  • Existing quoted_glob_metacharacter_with_unquoted_suffix_stays_literal and quoted_brace_expression_with_unquoted_suffix_stays_literal still pass
  • All 6 tests in finding_mixed_quoted_word_quote_metadata module pass

… expansion

escape_glob_metas_in_quoted_ranges ran at parse time on content that
still contains un-expanded \${VAR} references.  It was escaping { and }
(and other non-glob-meta characters: @ ! + ( ) |) which are part of
parameter/command expansion syntax, producing e.g. \$\{HARNESS_ROOT\}
that the runtime variable expander did not recognise.

The practical effect: patterns like "\${VAR}/plugins"/*/ produced an
empty glob set because the variable was never expanded, so harness's
_refresh_sources found no plugin directories and could not locate the
"agent" command — reproducing "harness: no agent command found" in CI
after commit 3f396f0.

Fix: only escape the four POSIX glob metacharacters (* ? [ ]) and
backslash inside quoted ranges.  Brace-expansion characters and extglob
characters cannot be active inside a double-quoted context and must not
be escaped when they may be part of expansion syntax.

Adds two regression tests that were failing before the fix.
Copilot AI review requested due to automatic review settings June 13, 2026 09:38
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jun 13, 2026 •

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
bashkit 8b20aae Commit Preview URL

Branch Preview URL
Jun 13 2026, 04:33 PM

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR addresses a lexer behavior where quoted segments of “mixed quoted + unquoted glob” words were being pre-escaped in a way that corrupted ${...} / $(...) expansion syntax, breaking runtime expansion and causing glob prefixes like "${VAR}"/... to fail.

Changes:

  • Adjust escape_glob_metas_in_quoted_ranges to stop escaping non-POSIX glob metacharacters inside quoted ranges.
  • Add regression tests ensuring ${VAR} in a quoted glob prefix is preserved and expands correctly when followed by an unquoted glob suffix.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.

File Description
crates/bashkit/src/parser/lexer.rs Updates quoted-range escaping logic for QuotedGlobWord tokenization.
crates/bashkit/tests/integration/blackbox_security_tests.rs Adds regression tests for variable expansion in quoted prefixes used with unquoted glob suffixes.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread crates/bashkit/src/parser/lexer.rs Outdated
Comment on lines 1483 to 1491
// Only escape the four POSIX glob metacharacters (* ? [ ]) and
// backslash. Characters like { } ( ) @ ! + | may appear as part of
// ${ } or $( ) expansion syntax in the content string (which is
// stored pre-expansion at parse time) and must not be escaped here,
// or the runtime variable/command expansion that runs before glob
// expansion will silently fail (e.g. $\{VAR\} is not recognised as
// a variable reference, so the glob never sees the real path).
if in_quoted && matches!(ch, '\\' | '*' | '?' | '[' | ']') {
result.push('\\');
Comment on lines +1449 to +1451
.exec(
r#"MYDIR=/tmp/tqg2; dirs=(); for d in "${MYDIR}"/*/; do dirs+=("${d%/}"); done; echo "${dirs[*]}""#,
)
Comment on lines +1436 to +1440
assert_eq!(
result.stdout.trim(),
"/tmp/tqg/sub",
"${{VAR}} in quoted glob prefix was not expanded (braces escaped by escape_glob_metas_in_quoted_ranges)"
);
Comment on lines +1455 to +1458
assert!(
stdout.contains("/tmp/tqg2/a") && stdout.contains("/tmp/tqg2/b"),
"glob '\"${{VAR}}\"/*/` did not expand correctly, got: {stdout}"
);
escape_glob_metas_in_quoted_ranges now tracks ${ } and $( ) expansion
constructs while scanning the quoted content, suppressing metacharacter
escaping inside them and re-enabling it for literal text outside them.

This fixes three things:
- ${VAR} in a quoted glob prefix no longer has { } corrupted to $\{VAR\}
- ${arr[0]} subscript brackets are no longer escaped inside ${}
- literal {a,b} in a quoted segment is still escaped (preventing
  incorrect brace-expansion at runtime) via the full metacharacter set

Also fix expand_glob to strip backslash-escapes from the directory
component before VFS lookup, so paths like /prefix/\{a,b\}/pattern
correctly resolve to the literal directory named {a,b}.

Add tests:
- literal_brace_expression_in_quoted_glob_prefix_stays_literal
- subscript_var_expansion_in_quoted_glob_prefix_not_corrupted
Fix Copilot review nits: assertion messages used wrong variable name $VAR

chaliy commented Jun 13, 2026

Copy link
Copy Markdown
Contributor Author

Addressed all four Copilot review comments in commit 7d3ceaa:

Substantive fix (lexer.rs:1491): Replaced the naïve "remove {} from escape set" approach with a context-aware scanner. escape_glob_metas_in_quoted_ranges now tracks ${…} and $(…) expansion constructs using a stack, suppressing metacharacter escaping while inside them. Outside any expansion construct (literal text in the quoted range), the full metacharacter set is escaped — including {, }, (, ), etc. — preventing incorrect brace/extglob expansion at runtime.

${arr[0]} fix: The context-aware scanner also suppresses [/] escaping inside ${…}, so subscript references like ${arr[0]} are no longer corrupted.

glob.rs path unescape: expand_glob now strips \-escapes from the directory component before VFS lookup (\{a,b\} → {a,b}), so paths with escaped braces resolve to the literal directory on the filesystem.

Two new regression tests:

  • literal_brace_expression_in_quoted_glob_prefix_stays_literal — verifies "{a,b}"/*/ matches the literal directory {a,b} and doesn't brace-expand
  • subscript_var_expansion_in_quoted_glob_prefix_not_corrupted — verifies "${dirs[0]}"/sub expands the array subscript correctly

Test nits (blackbox_security_tests.rs:1440, 1458): Updated assertion messages to reference ${{MYDIR}} instead of ${{VAR}}.


Generated by Claude Code

chaliy added 2 commits June 13, 2026 16:29
nc probes supabase.sh:22 before running the example and test suite.
Emits a warning annotation instead of failing when the runner has no
outbound SSH access, keeping the step a no-op rather than a red gate.
…star

The raw string ended with echo "${dirs[*]}"" (two closing quotes).
Switch to r##"..."## delimiter so the extra " is absorbed by the
terminator, leaving the bash command with the correct single closing quote.
@chaliy
chaliy merged commit 00b19ab into main Jun 13, 2026
36 checks passed
@chaliy
chaliy deleted the claude/kind-rubin-ky9xhx branch June 13, 2026 16:42
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.

2 participants