Skip to content

fix: escape glob special chars in directory paths during stage copy#2804

Open
mdrach wants to merge 2 commits intosnowflakedb:mainfrom
mdrach:mdrach-SNOW-000-fix-get-put-path-bug
Open

fix: escape glob special chars in directory paths during stage copy#2804
mdrach wants to merge 2 commits intosnowflakedb:mainfrom
mdrach:mdrach-SNOW-000-fix-get-put-path-bug

Conversation

@mdrach
Copy link

@mdrach mdrach commented Mar 6, 2026

Directories with square brackets (e.g., [id], [slug]) failed during recursive stage copy with error 'File doesn't exist: [.../[id]/*]'.

The bug occurred because [id]/* was interpreted as a glob pattern matching 'i/' or 'd/' instead of the literal '[id]/*' directory.

Fix: Use glob.escape() before appending /* to directory paths. This only affects real directories (checked via .is_dir()), so user-provided glob patterns like 'src/[abc]' or '*.py' continue to work correctly.

Changes:

  • manager.py:406,369-372: Add glob.escape() when appending wildcards
  • test_stage.py: Add 4 tests for brackets and glob pattern preservation

Screenshot of symptom
Screenshot 2026-03-06 at 1 44 36 PM

Pre-review checklist

  • I've confirmed that instructions included in README.md are still correct after my changes in the codebase.
  • I've added or updated automated unit tests to verify correctness of my new code.
  • I've added or updated integration tests to verify correctness of my new code.
  • I've confirmed that my changes are working by executing CLI's commands manually on MacOS.
  • I've confirmed that my changes are working by executing CLI's commands manually on Windows.
  • I've confirmed that my changes are up-to-date with the target branch.
  • I've described my changes in the release notes.
  • I've described my changes in the section below.
  • I've described my changes in the documentation.

Changes description

Fixed bug that caused literal filepaths with special characters like [``] to be interpreted as globs.

@mdrach mdrach marked this pull request as ready for review March 6, 2026 21:58
@mdrach mdrach requested a review from a team as a code owner March 6, 2026 21:58
Directories with square brackets (e.g., [id], [slug]) failed during
recursive stage copy with error 'File doesn't exist: [.../[id]/*]'.

The bug occurred because [id]/* was interpreted as a glob pattern
matching 'i/*' or 'd/*' instead of the literal '[id]/*' directory.

Fix: Use glob.escape() before appending /* to directory paths. This
only affects real directories (checked via .is_dir()), so user-provided
glob patterns like 'src/[abc]' or '*.py' continue to work correctly.

Changes:
- manager.py:406,369-372: Add glob.escape() when appending wildcards
- test_stage.py: Add 4 tests for brackets and glob pattern preservation
@mdrach mdrach force-pushed the mdrach-SNOW-000-fix-get-put-path-bug branch from 39cd0dd to 538f42a Compare March 6, 2026 22:50
A path like '/tmp/campaigns/[id]/' would produce '/tmp/campaigns/[id]//*'
after escaping and appending '/*'. Strip trailing slashes first so the
result is always clean (e.g. '/tmp/campaigns/[[]id]/*').

Also removes test_stage_put_preserves_user_glob_patterns_with_brackets
which re-implemented the logic under test rather than calling StageManager,
and adds two new tests: trailing slash alone and trailing slash + brackets.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

call_args = mock_execute.call_args[0][0]
assert "//*" not in call_args, f"Double slash found in: {call_args}"
assert call_args.endswith(f"{tmp_dir}/* @stageName auto_compress=false parallel=4 overwrite=False")
Copy link
Contributor

Choose a reason for hiding this comment

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

The test assertion will fail if tmp_dir contains glob special characters (e.g., [, ], *, ?). The implementation on line 370 of manager.py applies glob.escape() to the path, but this assertion compares against the unescaped tmp_dir.

If TemporaryDirectory() creates a path like /tmp/pytest-[abc]/..., the actual call would contain file:///tmp/pytest-[[]abc]/.../* (escaped), but the assertion checks for /tmp/pytest-[abc]/* (unescaped), causing a test failure.

Fix:

expected_path = glob.escape(tmp_dir) + "/*"
assert call_args.endswith(f"{expected_path} @stageName auto_compress=false parallel=4 overwrite=False")

This matches the pattern used correctly in the other tests (lines 1589 and 1689).

Suggested change
assert call_args.endswith(f"{tmp_dir}/* @stageName auto_compress=false parallel=4 overwrite=False")
expected_path = glob.escape(tmp_dir) + "/*"
assert call_args.endswith(f"{expected_path} @stageName auto_compress=false parallel=4 overwrite=False")

Spotted by Graphite

Fix in Graphite


Is this helpful? React 👍 or 👎 to let us know.

@sfc-gh-jwilkowski
Copy link
Contributor

@mdrach looks like a duplicate of #2805 - can you close it?

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.

3 participants