Execpolicy rules cannot express stable shell-wrapped test command prefixes
Summary
Codex's current command approval rules are too brittle for common test-runner workflows because prefix_rule(...) cannot express a stable command family when Codex executes the command through a shell wrapper and the script contains an environment assignment.
This creates repeated approval prompts for commands that are logically the same operation, such as Playwright E2E test runs, but differ only by test file or flags.
Related issues:
- #17623: reusable approval scope is unclear and too brittle
- #29145: approval-rule persistence should support project-local scope instead of only global persistence
- #8778: "don't ask again" can be too narrow
- #24596: generated approval prefixes can be wrong for shell/piped commands
Reproducer
User has a rule such as:
prefix_rule(pattern=["/bin/zsh", "-lc", "NODE_ENV=test pnpm exec playwright test"], decision="allow")
Codex asks again for:
NODE_ENV=test pnpm exec playwright test tests/e2e/project.spec.ts --project=chromium
or:
NODE_ENV=test pnpm exec playwright test --project=chromium
The prompt may offer:
Yes, and don't ask again for commands that start with `NODE_ENV=test pnpm exec playwright test --project=chromium`
But this does not solve the workflow. The next run can insert a file path before --project, add a different flag, or otherwise produce a different shell string.
Why the current rule model fails here
prefix_rule matches argv elements, not a prefix inside the shell script string.
When the command is executed as something like:
["/bin/zsh", "-lc", "NODE_ENV=test pnpm exec playwright test tests/e2e/project.spec.ts --project=chromium"]
the third argv element must match as a whole. A rule ending in:
"NODE_ENV=test pnpm exec playwright test"
does not match the longer shell script argument.
Because the shell script contains an environment assignment (NODE_ENV=test), Codex does not split it into:
["pnpm", "exec", "playwright", "test", ...]
So a useful stable rule such as:
prefix_rule(pattern=["pnpm", "exec", "playwright", "test"], decision="allow")
does not help when Codex chooses the shell-wrapped form.
The only rule that works reliably is too broad:
prefix_rule(pattern=["/bin/zsh", "-lc"], decision="allow")
That effectively allows any shell command that goes through that wrapper, which is not a reasonable project-level permission for ordinary local development.
Expected behavior
Codex should provide a way to approve a stable command family for this kind of workflow without approving all shell invocations.
Possible product/API directions:
- Normalize env assignments before execpolicy matching.
- Treat
NODE_ENV=test pnpm exec playwright test ...as a command family equivalent toenv NODE_ENV=test pnpm exec playwright test ....
- Let rules match the parsed shell command prefix when a shell wrapper is present.
- For example, allow a rule that means: shell wrapper is
/bin/zsh -lc, and the shell script starts with the command tokensNODE_ENV=test pnpm exec playwright test.
- Add a rule primitive for shell-script prefixes or command-family matching.
- The current
prefix_rulename is misleading for shell wrappers because users reasonably expect the third shell argument to be prefix-matchable, but it is exact argv-element matching.
- Make "don't ask again" propose a useful generalized rule.
- For test runners, approving
NODE_ENV=test pnpm exec playwright test --project=chromiumis too specific. The reusable scope should be editable or selectable before saving.
- Support project-local approval persistence from the prompt.
- This is covered more directly by #29145. A Playwright command family is often safe in one repo and not safe globally across all repos.
Why this matters
For E2E test fixing, Codex may need to run many near-identical commands:
NODE_ENV=test pnpm exec playwright test --project=chromium
NODE_ENV=test pnpm exec playwright test tests/e2e/foo.spec.ts --project=chromium
NODE_ENV=test pnpm exec playwright test tests/e2e/bar.spec.ts --project=chromium
These are one workflow: run local Playwright tests. The current approval model turns them into repeated prompts unless the user grants a broad /bin/zsh -lc allow rule or disables approvals/sandboxing.
That pushes users toward either approval fatigue or overly broad permissions.
Comparison
Claude Code has project-local settings such as .claude/settings.json, which makes it easier to define per-project permissions and command behavior without granting global trust across unrelated repositories.
Codex already supports project-local .codex/rules/, but the interactive "don't ask again" flow does not make project-local scoping first-class, and the shell-wrapper matching behavior still makes useful per-project rules hard to write by hand.
Request
Please make command approvals usable for repeated local test-runner workflows without requiring broad shell-wrapper approval.
At minimum:
- document that
prefix_rulecannot prefix-match inside thebash/zsh -lcscript argument - make the TUI show the actual argv/rule that will be persisted
- allow the user to broaden/edit the saved approval scope at prompt time
- support project-local persistence as a first-class option
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗