Conversation
Full access passed only approval_policy="never" to codex-acp. With an API
key, NBI's isolated CODEX_HOME has no config, so Codex used its default
read-only sandbox, and under "never" nothing can be approved past it. Every
edit was refused ("patch rejected: writing is blocked by read-only
sandbox") while the ACP tab promised edits and shell commands without
asking.
Pin sandbox_mode="workspace-write" alongside the approval policy when full
access is on. That sandbox allows writes to the workspace and temp
directories and keeps network access off by default, which matches what the
setting promises without widening to danger-full-access. The default
posture is unchanged.
Update the admin guide, the README policy row, and the ACP tab copy to
describe the new behavior.
The first pass described the sandbox too absolutely and left the policy path to the launch command untested. - State Codex's trust rule correctly, and scope the pins' precedence to user and project config, since managed config outranks them. - Document what full access cannot do (network access and writes outside the workspace fail without prompting), how the pin narrows a broader sandbox_mode under ChatGPT auth, command allow rules that bypass the sandbox, the risk of a workspace root that contains ~/.jupyter/nbi, and platforms where the sandbox cannot be enforced. - Add launch tests that a force-off policy keeps a stored full_access off, that force-on turns it on, and that an NBI_ACP_AGENT_COMMAND override keeps the pins. Removing apply_acp_policies from the settings read path previously left the whole suite passing.
Codex starts NBI's MCP server outside its sandbox with the workspace as its working directory, and NBI launched it with `python -m`, which puts that directory first on sys.path. Now that full access can write the workspace without asking, a notebook_intelligence package planted there would run in place of the server, with network access. Launch the server by absolute file path instead. It imports only the standard library, so this works on every supported Python. Tighten the docs as well: files written in the workspace can later run outside the sandbox, so full access amounts to letting the agent run code as the Jupyter server's account; managed Codex config differs by platform, and on Windows the managed_config.toml read from CODEX_HOME is writable by that account; and a replacement NBI_ACP_AGENT_COMMAND must pass NBI's -c options through. Adds a test that spawns the server from a workspace containing a planted package, and a test that a missing full_access setting launches with the default posture.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
With ACP full access on and an API key configured, Codex could not edit any file. NBI passed only
-c approval_policy="never". NBI's isolatedCODEX_HOMEhas no config, so Codex used its default read-only sandbox, and undernevernothing can be approved past it. Every edit failed withpatch rejected: writing is blocked by read-only sandbox; rejected by user approval settings, while the ACP tab says full access "lets it run tools (edits, shell) without asking." In practice, turning on full access made the agent less capable than the default mode.Solution
The pin. When full access is on,
codex_approval_argsnow also passes-c sandbox_mode="workspace-write". That sandbox allows writes to the workspace (the Jupyter server's root directory) and temp directories, and keeps outbound network access off unless Codex's own config enables it. It matches what the setting promises.danger-full-accesswould also have removed the network and filesystem boundary that no administrator opted into by enabling full access. The default posture (approval_policy="untrusted", no sandbox pin) is unchanged. The pin is applied in the same place as the approval policy, so it follows the existing policy clamp and theNBI_ACP_AGENT_COMMANDpath.A shadowing fix made necessary by the pin. Codex starts NBI's MCP server outside its sandbox, with the workspace as its working directory, and NBI launched it with
python -m notebook_intelligence.acp_mcp_server.-mputs the working directory first onsys.path, so now that full access can write the workspace without asking, anotebook_intelligencepackage planted there would run in place of the server. I reproduced that from a directory containing a planted package. The server is now launched by absolute file path. It imports only the standard library, so this works on every supported Python, including 3.10, where-Pis unavailable.Docs. The admin guide, the README policy row, the ACP tab copy, and the
acp_full_access_policytraitlet help now describe the sandbox precisely:NBI_ACP_AGENT_COMMANDmust pass NBI's-coptions through.Testing
Automated
TestApprovalArgs: the full-access pins, exact list.TestFullAccessLaunch, through the real launch path:full_accesssetting launches with the default posture.force-offpolicy keeps a storedfull_access: trueoff. This goes through the realNBIConfig.force-onturns full access on.NBI_ACP_AGENT_COMMANDoverride keeps the pins.TestNbiMcpServerLaunch: the server launches by absolute path, and a spawn test runs the real launch command from a workspace containing a plantednotebook_intelligencepackage and checks that the genuine server answersinitialize.danger-full-access, or dropping the pin on the override path each fails the relevant tests.apply_acp_policiesfrom the settings read path now fails the clamp tests. Previously the whole suite still passed.-mlaunch fails both server-launch tests.pytest tests/ --ignore=tests/test_claude_client.py: 1760 passed.jlpm tsc --noEmit, stylelint, prettier, and eslint are clean.jlpm jest: 423 passed.Live, against a JupyterLab running this branch (
codex-acp0.16.0, Codex 0.137.0, API-key auth,NBI_ACP_FULL_ACCESS_POLICY=force-on):-c approval_policy="never"; the transcript showed aread-onlysandbox; the edit was rejected and the file was unchanged.-c approval_policy="never" -c sandbox_mode="workspace-write", and the transcript showsworkspace-write.python .../notebook_intelligence/acp_mcp_server.py.Behavior change
user-choicewith the toggle on, orforce-on) will now see the agent write to the workspace without asking. That is what the setting has always described, but it did not happen with API-key auth before.sandbox_modein the user's~/.codex(for exampledanger-full-access) is narrowed toworkspace-writewhile full access is on, so commands that need the network fail without prompting.No CHANGELOG entry:
mainhas no 5.4.1 section yet, and I did not want to decide that header in this PR. Happy to add one wherever you prefer.Risks / follow-ups
.venv, IPython startup scripts, or Claude project hooks (and NBI's own config when the root is a home directory), can run later outside the sandbox. This is documented here. A guard for roots that contain~/.jupyteris a product decision I left open.approvals_reviewer. With ChatGPT auth, the user's Codex config decides both in the default mode. That is unchanged by this PR but worth a look.workspace-writeas read-only. The Windows behavior and themanaged_config.tomlprecedence come from reading the Codex source, not from a test run.codex_approval_argsnow returns the sandbox pin too, so a rename may be worth it._NbiAcpClient.read_text_fileandwrite_text_filehave no workspace containment.codex-acp0.16.0 does not call them, so this is separate and pre-existing, and I plan to raise it on its own.No issue was filed for this. The reproduction is in the Summary and Testing sections.