Execpolicy rules cannot express stable shell-wrapped test command prefixes

Open 💬 1 comment Opened Jul 1, 2026 by vladkens

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:

  1. Normalize env assignments before execpolicy matching.
  • Treat NODE_ENV=test pnpm exec playwright test ... as a command family equivalent to env NODE_ENV=test pnpm exec playwright test ....
  1. 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 tokens NODE_ENV=test pnpm exec playwright test.
  1. Add a rule primitive for shell-script prefixes or command-family matching.
  • The current prefix_rule name is misleading for shell wrappers because users reasonably expect the third shell argument to be prefix-matchable, but it is exact argv-element matching.
  1. Make "don't ask again" propose a useful generalized rule.
  • For test runners, approving NODE_ENV=test pnpm exec playwright test --project=chromium is too specific. The reusable scope should be editable or selectable before saving.
  1. 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_rule cannot prefix-match inside the bash/zsh -lc script 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

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗