Skip to content

fix(codexcli): restore sandbox baseline fields lost on permissions round-trip - #1801

Merged
dyoshikawa merged 5 commits into
dyoshikawa:mainfrom
saitota:i1733
Jun 10, 2026
Merged

fix(codexcli): restore sandbox baseline fields lost on permissions round-trip#1801
dyoshikawa merged 5 commits into
dyoshikawa:mainfrom
saitota:i1733

Conversation

@saitota

@saitota saitota commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

Fix #1733 — Codex CLI permission profiles lose sandbox baseline fields on round-trip.

Background

Codex CLI v0.131.0 renamed :project_roots:workspace_roots and removed legacy parsing (#22624). v0.133.0 added extends inheritance resolution (#22270) and made deny the canonical filesystem value (#23493). v0.134.0 removed legacy profile v1 resolution entirely (#24051, #24055).

After these changes, a functional Codex profile requires:

  • extends = ":workspace" — inherits workspace-write baseline protections; without it, writes inside workspace roots are not covered (Codex permissions docs)
  • network.enabled = true — defaults to false; network.domains entries are silently ignored unless this is set (Codex permissions docs)
  • filesystem.":workspace_roots"."." = "write" — scopes filesystem write rules to workspace roots

Rulesync modelled network as domains only and had no concept of extends or network.enabled, so these fields were lost on every import/generate cycle regardless of the source tool.

Changes

  • Emit extends = ":workspace" when any edit/write rule is present
  • Emit network.enabled = true alongside network.domains when any webfetch rule is present
  • Import network.enabled = true (no domains) as webfetch: { "*": "allow" }
  • Preserve description, network.mode, network.unix_sockets from existing config on regeneration

The converter infers these values from existing rule semantics rather than extending permissions.json with Codex-specific fields. This keeps the schema tool-agnostic and guarantees idempotency: any round-trip (Claude Code → Rulesync → Codex, Cursor → Rulesync → Codex, etc.) produces the same result.

saitota added 5 commits June 10, 2026 01:19
network.enabled, network.mode, network.unix_sockets, extends, and
description are not representable in Rulesync's canonical permissions
model, but were silently dropped on every regeneration.

Now toCodexProfile() reads these fields and mergeWithExistingProfile()
carries them forward so that an existing .codex/config.toml is not
mutated beyond the managed filesystem/network.domains surface.
…s in docs

- Add structural TOML parse assertion to verify preserved fields land in
  the correct table hierarchy (addresses reviewer suggestion)
- Clarify in docs that filesystem and network.domains are always
  overwritten by Rulesync (canonical source), contrasting with the
  passthrough fields
…ebfetch rules

Round-trip idempotency fix:
- emit extends = ":workspace" when any edit/write rule is present so
  Codex workspace-write baseline protections are always inherited
- emit network.enabled = true alongside network.domains when any
  webfetch rule is present so domain rules actually take effect
- import network.enabled=true without domains as webfetch: { "*": "allow" }
  so Codex-only configs round-trip correctly through Rulesync

Previously, a Codex config.toml containing these sandbox-level fields
would lose them after import + generate through any other tool (Claude
Code, Cursor, etc.) because Rulesync only modelled network as domains
and had no concept of extends or network.enabled.
…tion

Address reviewer findings:
- extends emitted only when actual write-access rules exist (deny-only
  or empty edit/write no longer triggers workspace baseline)
- network.enabled=false suppresses domain import (avoids disabled→enabled
  upgrade on next generate)
- unknown domain values no longer fall back to wildcard allow
- domainsHadUnknown internal flag prevents wildcard inflation after
  unrecognized entries are stripped
- warn when extends is replaced, unix_sockets preserved, or unknown
  domain entries are skipped
- remove non-null assertion on domains; strip internal flag before
  TOML serialization
- add tests covering deny-only edge cases and each new guard
@dyoshikawa
dyoshikawa merged commit 0971b81 into dyoshikawa:main Jun 10, 2026
5 checks passed
@dyoshikawa

Copy link
Copy Markdown
Owner

@saitota Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Codex CLI permissions export can lose network and filesystem sandbox baselines

2 participants