Commit Graph

31 Commits

  • fix(core) exec_policy parsing fixes (#11951)
    ## Summary
    Fixes a few things in our exec_policy handling of prefix_rules:
    1. Correctly match redirects specifically for exec_policy parsing. i.e.
    if you have `prefix_rule(["echo"], decision="allow")` then `echo hello >
    output.txt` should match - this should fix #10321
    2. If there already exists any rule that would match our prefix rule
    (not just a prompt), then drop it, since it won't do anything.
    
    
    ## Testing
    - [x] Updated unit tests, added approvals ScenarioSpecs
  • chore(core) rm Feature::RequestRule (#11866)
    ## Summary
    This feature is now reasonably stable, let's remove it so we can
    simplify our upcoming iterations here.
    
    ## Testing 
    - [x] Existing tests pass
  • Report syntax errors in rules file (#11686)
    Currently, if there are syntax errors detected in the starlark rules
    file, the entire policy is silently ignored by the CLI. The app server
    correctly emits a message that can be displayed in a GUI.
    
    This PR changes the CLI (both the TUI and non-interactive exec) to fail
    when the rules file can't be parsed. It then prints out an error message
    and exits with a non-zero exit code. This is consistent with the
    handling of errors in the config file.
    
    This addresses #11603
  • chore(core) Restrict model-suggested rules (#11671)
    ## Summary
    If the model suggests a bad rule, don't show it to the user. This does
    not impact the parsing of existing rules, just the ones we show.
    
    ## Testing
    - [x] Added unit tests
    - [x] Ran locally
  • Remove git commands from dangerous command checks (#11510)
    ### Motivation
    
    - Git subcommand matching was being classified as "dangerous" and caused
    benign developer workflows (for example `git push --force-with-lease`)
    to be blocked by the preflight policy.
    - The change aligns behavior with the intent to reserve the dangerous
    checklist for truly destructive shell ops (e.g. `rm -rf`) and avoid
    surprising developer-facing blocks.
    
    ### Description
    
    - Remove git-specific subcommand checks from
    `is_dangerous_to_call_with_exec` in
    `codex-rs/shell-command/src/command_safety/is_dangerous_command.rs`,
    leaving only explicit `rm` and `sudo` passthrough checks.
    - Deleted the git-specific helper logic that classified `reset`,
    `branch`-delete, `push` (force/delete/refspec) and `clean --force` as
    dangerous.
    - Updated unit tests in the same file to assert that various `git
    reset`/`git branch`/`git push`/`git clean` variants are no longer
    classified as dangerous.
    - Kept `find_git_subcommand` (used by safe-command classification)
    intact so safe/unsafe parsing elsewhere remains functional.
    
    ### Testing
    
    - Ran formatter with `just fmt` successfully.  
    - Ran unit tests with `cargo test -p codex-shell-command` and all tests
    passed (`144 passed; 0 failed`).
    
    ------
    [Codex
    Task](https://chatgpt.com/codex/tasks/task_i_698d19dedb4883299c3ceb5bbc6a0dcf)
  • feat: make sandbox read access configurable with ReadOnlyAccess (#11387)
    `SandboxPolicy::ReadOnly` previously implied broad read access and could
    not express a narrower read surface.
    This change introduces an explicit read-access model so we can support
    user-configurable read restrictions in follow-up work, while preserving
    current behavior today.
    
    It also ensures unsupported backends fail closed for restricted-read
    policies instead of silently granting broader access than intended.
    
    ## What
    
    - Added `ReadOnlyAccess` in protocol with:
      - `Restricted { include_platform_defaults, readable_roots }`
      - `FullAccess`
    - Updated `SandboxPolicy` to carry read-access configuration:
      - `ReadOnly { access: ReadOnlyAccess }`
      - `WorkspaceWrite { ..., read_only_access: ReadOnlyAccess }`
    - Preserved existing behavior by defaulting current construction paths
    to `ReadOnlyAccess::FullAccess`.
    - Threaded the new fields through sandbox policy consumers and call
    sites across `core`, `tui`, `linux-sandbox`, `windows-sandbox`, and
    related tests.
    - Updated Seatbelt policy generation to honor restricted read roots by
    emitting scoped read rules when full read access is not granted.
    - Added fail-closed behavior on Linux and Windows backends when
    restricted read access is requested but not yet implemented there
    (`UnsupportedOperation`).
    - Regenerated app-server protocol schema and TypeScript artifacts,
    including `ReadOnlyAccess`.
    
    ## Compatibility / rollout
    
    - Runtime behavior remains unchanged by default (`FullAccess`).
    - API/schema changes are in place so future config wiring can enable
    restricted read access without another policy-shape migration.
  • fix(exec-policy) No empty command lists (#11397)
    ## Summary
    This should rarely, if ever, happen in practice. But regardless, we
    should never provide an empty list of `commands` to ExecPolicy. This PR
    is almost entirely adding test around these cases.
    
    ## Testing
    - [x] Adds a bunch of unit tests for this
  • fix(core): canonicalize wrapper approvals and support heredoc prefix … (#10941)
    ## Summary
    - Reduced repeated approvals for equivalent wrapper commands and fixed
    execpolicy matching for heredoc-style shell invocations, with minimal
    behavior change and fail-closed defaults.
    
    ## Fixes
    1. Canonicalized approval matching for wrappers so equivalent commands
    map to the same approval intent.
    2. Added heredoc-aware prefix extraction for execpolicy so commands like
    `python3 <<'PY' ... PY` match rules such as `prefix_rule(["python3"],
    ...)`.
    3. Kept fallback behavior conservative: if parsing is ambiguous,
    existing prompt behavior is preserved.
    
    ## Edge Cases Covered
    - Wrapper path/name differences: `/bin/bash` vs `bash`, `/bin/zsh` vs
    `zsh`.
    - Shell modes: `-c` and `-lc`.
    - Heredoc forms: quoted delimiter (`<<'PY'`) and unquoted delimiter (`<<
    PY`).
    - Multi-command heredoc scripts are rejected by the fallback
    - Non-heredoc redirections (`>`, etc.) are not treated as heredoc prefix
    matches.
    - Complex scripts still fall back to prior behavior rather than
    expanding permissions.
    
    ---------
    
    Co-authored-by: Dylan Hurd <dylan.hurd@openai.com>
  • Removed "exec_policy" feature flag (#10851)
    This is no longer needed because it's on by default
  • fix: unsafe auto-approval of git commands (#10258)
    fixes https://github.com/openai/codex/issues/10160 and some more.
    
    ## Description
    
    Hardens Git command safety to prevent approval bypasses for destructive
    or write-capable invocations (branch delete, risky push forms,
    output/config-override flags), so these commands no longer auto-run as
    “safe.”
    
    - `git branch -d` variants (especially in worktrees / with global
    options like -C / -c)
    - `git show|diff|log --output` ... style file-write flags
    - risky Git config override flags (-c, --config-env) that can trigger
    external execution
    - dangerous push forms that weren’t fully caught (`--force*`,
    `--delete`, `+refspec`, `:refspec`)
    - grouped short-flag delete forms (e.g. stacked branch flags containing
    `d/D`)
    
    will fast follow with a common git policy to bring windows to parity.
    
    ---------
    
    Co-authored-by: Eric Traut <etraut@openai.com>
  • Load exec policy rules from requirements (#10190)
    `requirements.toml` should be able to specify rules which always run. 
    
    My intention here was that these rules could only ever be restrictive,
    which means the decision can be "prompt" or "forbidden" but never
    "allow". A requirement of "you must always allow this command" didn't
    make sense to me, but happy to be gaveled otherwise.
    
    Rules already applies the most restrictive decision, so we can safely
    merge these with rules found in other config folders.
  • feat(core) RequestRule (#9489)
    ## Summary
    Instead of trying to derive the prefix_rule for a command mechanically,
    let's let the model decide for us.
    
    ## Testing
    - [x] tested locally
  • Print warning if we skip config loading (#9611)
    https://github.com/openai/codex/pull/9533 silently ignored config if
    untrusted. Instead, we still load it but disable it. Maybe we shouldn't
    try to parse it either...
    
    <img width="939" height="515" alt="Screenshot 2026-01-21 at 14 56 38"
    src="https://github.com/user-attachments/assets/e753cc22-dd99-4242-8ffe-7589e85bef66"
    />
  • Improve handling of config and rules errors for app server clients (#9182)
    When an invalid config.toml key or value is detected, the CLI currently
    just quits. This leaves the VSCE in a dead state.
    
    This PR changes the behavior to not quit and bubble up the config error
    to users to make it actionable. It also surfaces errors related to
    "rules" parsing.
    
    This allows us to surface these errors to users in the VSCE, like this:
    
    <img width="342" height="129" alt="Screenshot 2026-01-13 at 4 29 22 PM"
    src="https://github.com/user-attachments/assets/a79ffbe7-7604-400c-a304-c5165b6eebc4"
    />
    
    <img width="346" height="244" alt="Screenshot 2026-01-13 at 4 45 06 PM"
    src="https://github.com/user-attachments/assets/de874f7c-16a2-4a95-8c6d-15f10482e67b"
    />
  • Feat: appServer.requirementList for requirement.toml (#8800)
    ### Summary
    We are exposing requirements via `requirement/list` method from
    app-server so that we can conditionally disable the agent mode dropdown
    selection in VSCE and correctly setting the default value.
    
    ### Sample output
    #### `etc/codex/requirements.toml`
    <img width="497" height="49" alt="Screenshot 2026-01-06 at 11 32 06 PM"
    src="https://github.com/user-attachments/assets/fbd9402e-515f-4b9e-a158-2abb23e866a0"
    />
    
    #### App server response
    <img width="1107" height="79" alt="Screenshot 2026-01-06 at 11 30 18 PM"
    src="https://github.com/user-attachments/assets/c0d669cd-54ef-4789-a26c-adb2c41950af"
    />
  • feat: add justification arg to prefix_rule() in *.rules (#8751)
    Adds an optional `justification` parameter to the `prefix_rule()`
    execpolicy DSL so policy authors can attach human-readable rationale to
    a rule. That justification is propagated through parsing/matching and
    can be surfaced to the model (or approval UI) when a command is blocked
    or requires approval.
    
    When a command is rejected (or gated behind approval) due to policy, a
    generic message makes it hard for the model/user to understand what went
    wrong and what to do instead. Allowing policy authors to supply a short
    justification improves debuggability and helps guide the model toward
    compliant alternatives.
    
    Example:
    
    ```python
    prefix_rule(
        pattern = ["git", "push"],
        decision = "forbidden",
        justification = "pushing is blocked in this repo",
    )
    ```
    
    If Codex tried to run `git push origin main`, now the failure would
    include:
    
    ```
    `git push origin main` rejected: pushing is blocked in this repo
    ```
    
    whereas previously, all it was told was:
    
    ```
    execpolicy forbids this command
    ```
  • feat: load ExecPolicyManager from ConfigLayerStack (#8453)
    https://github.com/openai/codex/pull/8354 added support for in-repo
    `.config/` files, so this PR updates the logic for loading `*.rules`
    files to load `*.rules` files from all relevant layers. The main change
    to the business logic is `load_exec_policy()` in
    `codex-rs/core/src/exec_policy.rs`.
    
    Note this adds a `config_folder()` method to `ConfigLayerSource` that
    returns `Option<AbsolutePathBuf>` so that it is straightforward to
    iterate over the sources and get the associated config folder, if any.
  • Add ExecPolicyManager (#8349)
    Move exec policy management into services to keep turn context
    immutable.
  • fix: policy/*.codexpolicy -> rules/*.rules (#7888)
    We decided that `*.rules` is a more fitting (and concise) file extension
    than `*.codexpolicy`, so we are changing the file extension for the
    "execpolicy" effort. We are also changing the subfolder of `$CODEX_HOME`
    from `policy` to `rules` to match.
    
    This PR updates the in-repo docs and we will update the public docs once
    the next CLI release goes out.
    
    Locally, I created `~/.codex/rules/default.rules` with the following
    contents:
    
    ```
    prefix_rule(pattern=["gh", "pr", "view"])
    ```
    
    And then I asked Codex to run:
    
    ```
    gh pr view 7888 --json title,body,comments
    ```
    
    and it was able to!
  • proposing execpolicy amendment when prompting due to sandbox denial (#7653)
    Currently, we only show the “don’t ask again for commands that start
    with…” option when a command is immediately flagged as needing approval.
    However, there is another case where we ask for approval: When a command
    is initially auto-approved to run within sandbox, but it fails to run
    inside sandbox, we would like to attempt to retry running outside of
    sandbox. This will require a prompt to the user.
    
    This PR addresses this latter case
  • chore: refactor to move Arc<RwLock> concern outside exec_policy_for (#7615)
    The caller should decide whether wrapping the policy in `Arc<RwLock>` is
    necessary. This should make https://github.com/openai/codex/pull/7609 a
    bit smoother.
    
    - `exec_policy_for()` -> `load_exec_policy_for_features()`
    - introduce `load_exec_policy()` that does not take `Features` as an arg
    - both return `Result<Policy, ExecPolicyError>` instead of
    Result<Arc<RwLock<Policy>>, ExecPolicyError>`
    
    This simplifies the tests as they have no need for `Arc<RwLock>`.
  • Refactor execpolicy fallback evaluation (#7544)
    ## Refactor of the `execpolicy` crate
    
    To illustrate why we need this refactor, consider an agent attempting to
    run `apple | rm -rf ./`. Suppose `apple` is allowed by `execpolicy`.
    Before this PR, `execpolicy` would consider `apple` and `pear` and only
    render one rule match: `Allow`. We would skip any heuristics checks on
    `rm -rf ./` and immediately approve `apple | rm -rf ./` to run.
    
    To fix this, we now thread a `fallback` evaluation function into
    `execpolicy` that runs when no `execpolicy` rules match a given command.
    In our example, we would run `fallback` on `rm -rf ./` and prevent
    `apple | rm -rf ./` from being run without approval.
  • whitelist command prefix integration in core and tui (#7033)
    this PR enables TUI to approve commands and add their prefixes to an
    allowlist:
    <img width="708" height="605" alt="Screenshot 2025-11-21 at 4 18 07 PM"
    src="https://github.com/user-attachments/assets/56a19893-4553-4770-a881-becf79eeda32"
    />
    
    note: we only show the option to whitelist the command when 
    1) command is not multi-part (e.g `git add -A && git commit -m 'hello
    world'`)
    2) command is not already matched by an existing rule
  • chore: make create_approval_requirement_for_command an async fn (#7501)
    I think this might help with https://github.com/openai/codex/pull/7033
    because `create_approval_requirement_for_command()` will soon need
    access to `Session.state`, which is a `tokio::sync::Mutex` that needs to
    be accessed via `async`.
  • bypass sandbox for policy approved commands (#7110)
    allowing cmds greenlit by execpolicy to bypass sandbox + minor refactor
    for a world where we have execpolicy rules with specific sandbox
    requirements
  • execpolicycheck command in codex cli (#7012)
    adding execpolicycheck tool onto codex cli
    
    this is useful for validating policies (can be multiple) against
    commands.
    
    it will also surface errors in policy syntax:
    <img width="1150" height="281" alt="Screenshot 2025-11-19 at 12 46
    21 PM"
    src="https://github.com/user-attachments/assets/8f99b403-564c-4172-acc9-6574a8d13dc3"
    />
    
    this PR also changes output format when there's no match in the CLI.
    instead of returning the raw string `noMatch`, we return
    `{"noMatch":{}}`
    
    this PR is a rewrite of: https://github.com/openai/codex/pull/6932 (due
    to the numerous merge conflicts present in the original PR)
    
    ---------
    
    Co-authored-by: Michael Bolin <mbolin@openai.com>
  • execpolicy2 core integration (#6641)
    This PR threads execpolicy2 into codex-core.
    
    activated via feature flag: exec_policy (on by default)
    
    reads and parses all .codexpolicy files in `codex_home/codex`
    
    refactored tool runtime API to integrate execpolicy logic
    
    ---------
    
    Co-authored-by: Michael Bolin <mbolin@openai.com>