Skip to content

feat(find): implement -execdir command {} ;#125

Merged
matt-dz merged 15 commits intomainfrom
matt-dz/implement-find-exec
Mar 19, 2026
Merged

feat(find): implement -execdir command {} ;#125
matt-dz merged 15 commits intomainfrom
matt-dz/implement-find-exec

Conversation

@matt-dz
Copy link
Copy Markdown
Collaborator

@matt-dz matt-dz commented Mar 18, 2026

Summary

Implements find -execdir CMD [ARG]... \; — the safer alternative to -exec that runs commands in each matched file's parent directory, passing ./basename as the argument.

  • \; mode only+ (batch) mode is deferred and rejected with a clear error message
  • -exec stays blocked-execdir is strictly safer (no TOCTOU on the path, no path traversal in arguments); -exec can be unblocked as a follow-up
  • AllowedCommands enforced — checked at both parse-time validation AND evaluation-time (defense-in-depth)
  • Same sandbox — sub-commands run through the interpreter with the same AllowedPaths restrictions
  • No shell re-parsing{} replacement produces discrete Go string arguments; metacharacters in filenames are inert bytes, never re-parsed as shell commands
  • ./ prefix — prevents argument injection via dash-prefixed filenames (e.g. file named -rf becomes ./-rf)

Changes

File What
builtins/builtins.go Added WorkDir and RunCommand to CallContext
interp/runner_exec.go Populated RunCommand — executes builtins through sandbox with custom working directory
builtins/find/expr.go Parser: exprExecDir kind, parseExecDirPredicate(), removed -execdir from blocked list
builtins/find/eval.go evalExecDir(){}./basename replacement, double-checks CommandAllowed
builtins/find/find.go Walk integration: execDirParent computation, post-parse command validation, help/doc updates
allowedsymbols/symbols_builtins.go Added strings.Contains, filepath.{Dir,IsAbs,Join} to find's allowed symbols
SHELL_FEATURES.md Updated find entry

Tests

  • 21 scenario tests (tests/scenarios/cmd/find/execdir/) — basic usage, action suppression, predicate interactions (AND/OR/NOT/quit/prune), error cases
  • 14 pentest tests (builtin_find_pentest_test.go) — CWE-78 command injection via filenames (8 variants), CWE-88 argument injection, CWE-426 PATH injection, CWE-284 access control, GTFOBins validation
  • 7 parser tests — added to expr_test.go

Test plan

  • gofmt -l . — clean
  • go build ./... — builds
  • GOOS=windows go build ./... — cross-compiles
  • go test ./builtins/find/ -v -count=1 — all pass
  • go test ./allowedsymbols/ -v -count=1 — all pass
  • go test ./tests/ -run TestShellScenarios$ -count=1 -timeout 120s — all pass
  • go test ./... -count=1 -timeout 120s — all pass
  • RSHELL_BASH_TEST=1 go test ./tests/ -run TestShellScenariosAgainstBash -timeout 120s — requires Docker

🤖 Generated with Claude Code

@matt-dz
Copy link
Copy Markdown
Collaborator Author

matt-dz commented Mar 18, 2026

@codex conduct a comprehensive security and code review

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 734d67b7d5

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread builtins/find/find.go Outdated
Comment thread builtins/find/expr.go Outdated
@matt-dz
Copy link
Copy Markdown
Collaborator Author

matt-dz commented Mar 18, 2026

@codex conduct a comprehensive security and code review

matt-dz and others added 3 commits March 18, 2026 15:10
Add -execdir predicate to find, allowing execution of allowed builtin
commands in each matched file's parent directory with ./basename as
the argument. This is the safer alternative to -exec (no TOCTOU on the
path, no path traversal in arguments) and -exec remains blocked.

Key design decisions:
- \; mode only — + (batch) mode rejected with clear error
- AllowedCommands enforced at parse-time AND eval-time (defense-in-depth)
- Sub-commands run through the interpreter with the same sandbox/AllowedPaths
- No shell re-parsing — {} replacement produces discrete Go string args
- ./basename prefix prevents argument injection via dash-prefixed filenames

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
filepath.Join cleans its result, so Join(cwd, ".") = cwd and
Dir(cwd) points one level above the search root. Replace with
joinPath (simple concatenation) so "." is preserved as the last
component and filepath.Dir correctly strips it.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
In find syntax, '+' is only a batch-mode terminator when it
immediately follows '{}'. Previously the parser rejected any '+'
token, blocking valid commands like -execdir echo + {} \;. Now '+'
is only rejected in the {} + position.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@matt-dz matt-dz force-pushed the matt-dz/implement-find-exec branch from 3c20b8a to 6a80911 Compare March 18, 2026 19:10
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3c20b8ad59

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread interp/runner_exec.go Outdated
Comment thread builtins/find/find.go Outdated
matt-dz and others added 3 commits March 18, 2026 15:21
…exts

The child CallContext built by RunCommand was missing RunCommand and
WorkDir, so builtins invoked via -execdir that themselves need
sub-command execution (e.g. nested find) would fail with "command
execution not available". Extract RunCommand into a named variable
so the child can reference it recursively.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
filepath.Dir("/cwd/dir/") returns "/cwd/dir" (the directory itself),
not "/cwd" (its parent). Trim trailing slashes before taking Dir so
-execdir runs in the correct parent directory for paths like "dir/".

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Take main's emoji-annotated comment style and add our -execdir
symbols (path/filepath.Dir, path/filepath.IsAbs, strings.Contains)
to both the find per-command list and the global allowed list.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@matt-dz
Copy link
Copy Markdown
Collaborator Author

matt-dz commented Mar 18, 2026

@codex conduct a comprehensive security and code review

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 342c0e407e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread builtins/find/eval.go Outdated
baseName("/") returns "/", so "./" + "/" produced ".//". Special-case
the root entry to pass "/" directly, matching GNU find behavior.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@matt-dz
Copy link
Copy Markdown
Collaborator Author

matt-dz commented Mar 18, 2026

@codex conduct a comprehensive security and code review

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b9343bd191

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread builtins/find/find.go Outdated
The trailing-slash trim converted C:/ to C:, making filepath.Dir
return the drive-relative C:. instead of the drive root. Skip the
trim when the slash immediately follows a colon (drive separator).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@matt-dz
Copy link
Copy Markdown
Collaborator Author

matt-dz commented Mar 18, 2026

@codex conduct a comprehensive security and code review

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: fb857ae78f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread builtins/find/eval.go
Comment thread builtins/find/expr.go Outdated
matt-dz and others added 2 commits March 18, 2026 16:22
baseName strips trailing slashes, so dir/ became ./dir instead of
./dir/. Re-append the slash when the original relPath ends with /,
matching GNU find and preserving slash-sensitive sub-command semantics.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Remove the parser gate that rejected arguments containing {} unless
they were exactly {}. Now {}.bak, prefix-{}-suffix, etc. are accepted
and replaced via strings.ReplaceAll, matching GNU find behavior.
This is safe because arguments are discrete Go strings — no shell
re-parsing occurs.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@matt-dz
Copy link
Copy Markdown
Collaborator Author

matt-dz commented Mar 18, 2026

@codex conduct a comprehensive security and code review

@chatgpt-codex-connector
Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Breezy!

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

- P1: rename shadowed fn → cmdFn inside runCmd closure to avoid
  masking the outer builtins.Lookup result (variable shadowing)
- P2: remove redundant strings.Contains guard before ReplaceAll;
  drop strings.Contains from find's allowed symbols
- P3: use accumulator pattern in collectExecDirCmds to avoid
  intermediate slice allocations from append-spread

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@matt-dz
Copy link
Copy Markdown
Collaborator Author

matt-dz commented Mar 18, 2026

@codex conduct a comprehensive security and code review

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6b9dd6d4d0

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread builtins/find/find.go Outdated
The trailing-slash guard matched any path ending in :/ (e.g.
/tmp/d:/), not just Windows drive roots like C:/. Tighten to
len == 3 && [1] == ':' so only X:/ is preserved. Extract the
trim+Dir logic into execDirParentDir for direct unit testing.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@matt-dz
Copy link
Copy Markdown
Collaborator Author

matt-dz commented Mar 18, 2026

@codex conduct a comprehensive security and code review

@chatgpt-codex-connector
Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Another round soon, please!

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@matt-dz matt-dz marked this pull request as ready for review March 18, 2026 21:13
matt-dz and others added 2 commits March 18, 2026 17:15
filepath.Dir returns backslashes on Windows. Apply filepath.ToSlash
to the result before comparing against forward-slash expectations,
matching the shell's path normalization convention.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@matt-dz matt-dz enabled auto-merge March 19, 2026 14:31
@matt-dz matt-dz added this pull request to the merge queue Mar 19, 2026
Merged via the queue into main with commit 1e94be5 Mar 19, 2026
31 checks passed
@matt-dz matt-dz deleted the matt-dz/implement-find-exec branch March 19, 2026 16:54
gh-worker-dd-mergequeue-cf854d Bot pushed a commit to DataDog/datadog-agent that referenced this pull request Mar 30, 2026
### What does this PR do?

See changes:
- https://github.com/DataDog/rshell/releases/tag/v0.0.7
- https://github.com/DataDog/rshell/releases/tag/v0.0.8


Besides the minor fixes to improve security and memory usage, we have those changes to rshell commands:
- feat(find): implement -execdir command {} ; by @matt-dz in DataDog/rshell#125
- feat(find): implement -exec command {} ; by @matt-dz in DataDog/rshell#133
- feat(ip): add ip route show/get builtin (Linux only) by @AlexandreYang in DataDog/rshell#135

### Testing

✅ Tested e2e with local agent

### Describe how you validated your changes

Test rshell works e2e

### Additional Notes


Co-authored-by: alexandre.yang <alexandre.yang@datadoghq.com>
AlexandreYang added a commit to DataDog/datadog-agent that referenced this pull request Mar 30, 2026
See changes:
- https://github.com/DataDog/rshell/releases/tag/v0.0.7
- https://github.com/DataDog/rshell/releases/tag/v0.0.8

Besides the minor fixes to improve security and memory usage, we have those changes to rshell commands:
- feat(find): implement -execdir command {} ; by @matt-dz in DataDog/rshell#125
- feat(find): implement -exec command {} ; by @matt-dz in DataDog/rshell#133
- feat(ip): add ip route show/get builtin (Linux only) by @AlexandreYang in DataDog/rshell#135

✅ Tested e2e with local agent

Test rshell works e2e

Co-authored-by: alexandre.yang <alexandre.yang@datadoghq.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants