Skip to content

feat(find): implement -exec command {} ;#133

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

feat(find): implement -exec command {} ;#133
matt-dz merged 3 commits intomainfrom
matt-dz/implement-find-exec

Conversation

@matt-dz
Copy link
Copy Markdown
Collaborator

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

Summary

Implements find -exec CMD [ARG]... \; — runs a command once per matched file, replacing {} with the full relative path. This complements the existing -execdir predicate (which runs in the file's parent directory with ./basename).

  • \; mode only+ (batch) mode is deferred and rejected with a clear error message
  • AllowedCommands enforced at both parse-time validation AND evaluation-time (defense-in-depth)
  • Same sandbox — sub-commands run through RunCommand with the same AllowedPaths restrictions
  • No shell re-parsing{} replacement via strings.ReplaceAll produces discrete Go string arguments
  • Parser refactored-exec and -execdir now share a parseExecLikePredicate helper, eliminating code duplication

-exec vs -execdir

Aspect -exec (new) -execdir (existing)
Working directory Find's original CWD File's parent directory
{} replacement Full path (dir/sub/file.txt) ./basename (./file.txt)
./ prefix No (matches GNU find) Yes (prevents dash-injection)
TOCTOU risk Higher (full path traversal) Lower (local basename)

Security model

The sandbox enforces AllowedPaths on all sub-command file operations, so even if a path is replaced with a symlink between stat and exec, the sub-command cannot escape the sandbox. The help text documents that -execdir is recommended over -exec for TOCTOU-sensitive and dash-injection-safe use cases.

Changes

File What
builtins/find/expr.go exprExec kind, shared parseExecLikePredicate helper, removed -exec from blocked list
builtins/find/eval.go evalExec() — uses printPath for {}, execWorkDir for RunCommand dir
builtins/find/find.go Threads execWorkDir into evalContext, renamed collectExecCmds to cover both, updated help/docs
builtins/find/expr_test.go 8 parser tests for -exec
builtins/find/builtin_find_pentest_test.go 15 security tests (CWE-78, CWE-88, CWE-284, CWE-426)
tests/scenarios/cmd/find/exec/ 23 scenario tests
SHELL_FEATURES.md Updated find entry

Test plan

  • gofmt -l . — clean
  • go build ./... — builds
  • GOOS=windows go build ./... — cross-compiles
  • go test ./builtins/find/ -v -count=1 — all pass (including 15 new pentest + 8 parser tests)
  • go test ./tests/ -run TestShellScenarios$ -count=1 -timeout 120s — all pass (23 new exec scenarios)
  • 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

Add -exec predicate to find, running commands in find's working
directory with the full relative path as the {} replacement. Unlike
-execdir (which uses ./basename in the file's parent directory),
-exec passes the complete path (e.g. dir/sub/file.txt) matching
GNU find behavior.

Key design decisions:
- \; mode only — + (batch) mode rejected with clear error
- AllowedCommands enforced at parse-time AND eval-time (defense-in-depth)
- Same sandbox — sub-commands run through RunCommand with AllowedPaths
- No shell re-parsing — {} replacement via strings.ReplaceAll
- No ./ prefix (unlike -execdir) — matches GNU find; -execdir
  recommended for TOCTOU-sensitive and dash-injection-safe use cases
- Parser refactored into shared parseExecLikePredicate helper

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

matt-dz commented Mar 19, 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: 90b46529f0

ℹ️ 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
GNU find applies {} substitution across the entire command vector
including the command name. Previously only execArgs were substituted
while execCmd was passed through unchanged. Now both evalExec and
evalExecDir substitute {} in the command name and validate the
resolved name against CommandAllowed. The post-parse eager check
skips commands containing {} since the substituted value depends
on each file.

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

matt-dz commented Mar 19, 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: error messages now use resolved cmd (post-{} substitution)
  instead of the raw template e.execCmd
- P2: extract shared evalExecLike helper — evalExec and evalExecDir
  are now thin wrappers that compute replacement and dir
- P3: TestFindExecFullPathReplacement reuses testExecFilename helper

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

matt-dz commented Mar 19, 2026

@codex conduct a comprehensive security and code review

@chatgpt-codex-connector
Copy link
Copy Markdown

Codex Review: Didn't find any major issues. You're on a roll.

ℹ️ 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 19, 2026 18:10
@matt-dz matt-dz added this pull request to the merge queue Mar 19, 2026
Merged via the queue into main with commit faf56ce Mar 19, 2026
31 of 32 checks passed
@matt-dz matt-dz deleted the matt-dz/implement-find-exec branch March 19, 2026 19:26
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