fix(codex): trust bottle workspace on launch

This commit is contained in:
2026-06-01 17:13:48 -04:00
committed by didericis
parent ac1aa197d4
commit 8e6583fcb7
4 changed files with 162 additions and 17 deletions
@@ -15,7 +15,11 @@ from bot_bottle.manifest import Manifest
from bot_bottle.pipelock import PipelockProxyPlan
def _plan(*, codex_auth_file: Path | None = None) -> DockerBottlePlan:
def _plan(
*,
codex_auth_file: Path | None = None,
agent_provider_template: str = "codex",
) -> DockerBottlePlan:
manifest = Manifest.from_json_obj({
"bottles": {"dev": {"agent_provider": {"template": "codex"}}},
"agents": {"demo": {"skills": [], "prompt": "", "bottle": "dev"}},
@@ -58,18 +62,46 @@ def _plan(*, codex_auth_file: Path | None = None) -> DockerBottlePlan:
supervise_plan=None,
use_runsc=False,
agent_command="codex",
agent_provider_template="codex",
agent_provider_template=agent_provider_template,
codex_auth_file=codex_auth_file,
)
class TestProvisionProviderAuth(unittest.TestCase):
def test_noop_without_codex_auth_file(self):
def test_noop_for_non_codex_provider(self):
with patch.object(_provider_auth.subprocess, "run") as run:
_provider_auth.provision_provider_auth(
_plan(agent_provider_template="claude"), "bot-bottle-demo-abc12",
)
self.assertEqual(0, run.call_count)
def test_codex_provider_trusts_workspace_without_auth_file(self):
with patch.object(_provider_auth.subprocess, "run") as run:
_provider_auth.provision_provider_auth(
_plan(), "bot-bottle-demo-abc12",
)
self.assertEqual(0, run.call_count)
argvs = [call.args[0] for call in run.call_args_list]
self.assertIn(
["docker", "exec", "-u", "0", "bot-bottle-demo-abc12",
"mkdir", "-p", "/home/node/.codex"],
argvs,
)
trust_config = next(
a for a in argvs
if a[:6] == ["docker", "exec", "-u", "0", "bot-bottle-demo-abc12", "sh"]
)
self.assertIn('[projects."/home/node/workspace"]', trust_config[-1])
self.assertIn('trust_level = "trusted"', trust_config[-1])
self.assertIn(
["docker", "exec", "-u", "0", "bot-bottle-demo-abc12",
"chown", "node:node", "/home/node/.codex/config.toml"],
argvs,
)
self.assertIn(
["docker", "exec", "-u", "0", "bot-bottle-demo-abc12",
"chmod", "600", "/home/node/.codex/config.toml"],
argvs,
)
def test_copies_dummy_auth_json_to_codex_home(self):
with patch.object(_provider_auth.subprocess, "run") as run:
@@ -83,6 +115,16 @@ class TestProvisionProviderAuth(unittest.TestCase):
"mkdir", "-p", "/home/node/.codex"],
argvs,
)
self.assertIn(
["docker", "exec", "-u", "0", "bot-bottle-demo-abc12",
"chown", "node:node", "/home/node/.codex"],
argvs,
)
self.assertIn(
["docker", "exec", "-u", "0", "bot-bottle-demo-abc12",
"chmod", "700", "/home/node/.codex"],
argvs,
)
self.assertIn(
["docker", "cp", "/tmp/codex-auth.json",
"bot-bottle-demo-abc12:/home/node/.codex/auth.json"],
+36 -2
View File
@@ -57,6 +57,7 @@ def _plan(
agent_git_gate_host: str = "127.0.0.1:55555",
agent_supervise_url: str = "http://127.0.0.1:55556/",
codex_auth_file: Path | None = None,
agent_provider_template: str = "claude",
guest_env: dict[str, str] | None = None,
) -> SmolmachinesBottlePlan:
bottle_json: dict = {}
@@ -133,6 +134,7 @@ def _plan(
agent_git_gate_host=agent_git_gate_host,
agent_supervise_url=agent_supervise_url,
codex_auth_file=codex_auth_file,
agent_provider_template=agent_provider_template,
)
@@ -204,19 +206,45 @@ class TestProvisionProviderAuth(unittest.TestCase):
),
)
def test_noop_without_codex_auth_file(self):
def test_noop_for_non_codex_provider(self):
cp_p, ex_p = self._patch()
with cp_p as cp, ex_p as ex:
_provider_auth.provision_provider_auth(_plan(), "bot-bottle-demo-abc12")
self.assertEqual(0, cp.call_count)
self.assertEqual(0, ex.call_count)
def test_codex_provider_trusts_workspace_without_auth_file(self):
cp_p, ex_p = self._patch()
with cp_p as cp, ex_p as ex:
ex.return_value = SmolvmRunResult(0, "", "")
_provider_auth.provision_provider_auth(
_plan(agent_provider_template="codex"),
"bot-bottle-demo-abc12",
)
self.assertEqual(0, cp.call_count)
argv_seen = [call.args[1] for call in ex.call_args_list]
self.assertIn(["mkdir", "-p", "/home/node/.codex"], argv_seen)
trust_config = next(
a for a in argv_seen
if a[:2] == ["sh", "-c"] and "config.toml" in a[2]
)
self.assertIn('[projects."/home/node/workspace"]', trust_config[2])
self.assertIn('trust_level = "trusted"', trust_config[2])
self.assertIn(
["chown", "node:node", "/home/node/.codex/config.toml"],
argv_seen,
)
self.assertIn(["chmod", "600", "/home/node/.codex/config.toml"], argv_seen)
def test_copies_dummy_auth_json_to_codex_home(self):
cp_p, ex_p = self._patch()
with cp_p as cp, ex_p as ex:
ex.return_value = SmolvmRunResult(0, "Logged in using ChatGPT\n", "")
_provider_auth.provision_provider_auth(
_plan(codex_auth_file=Path("/tmp/codex-auth.json")),
_plan(
agent_provider_template="codex",
codex_auth_file=Path("/tmp/codex-auth.json"),
),
"bot-bottle-demo-abc12",
)
cp.assert_called_once_with(
@@ -269,6 +297,7 @@ class TestProvisionProviderAuth(unittest.TestCase):
ex.return_value = SmolvmRunResult(0, "Logged in using ChatGPT\n", "")
_provider_auth.provision_provider_auth(
_plan(
agent_provider_template="codex",
codex_auth_file=Path("/tmp/codex-auth.json"),
guest_env={"CODEX_HOME": "/run/codex-home"},
),
@@ -297,6 +326,7 @@ class TestProvisionProviderAuth(unittest.TestCase):
with self.assertRaises(SystemExit):
_provider_auth.provision_provider_auth(
_plan(
agent_provider_template="codex",
codex_auth_file=Path("/tmp/codex-auth.json"),
),
"bot-bottle-demo-abc12",
@@ -313,6 +343,9 @@ class TestProvisionProviderAuth(unittest.TestCase):
SmolvmRunResult(0, "", ""), # chown CODEX_HOME
SmolvmRunResult(0, "", ""), # chmod CODEX_HOME
SmolvmRunResult(0, "", ""), # reset runtime db files
SmolvmRunResult(0, "", ""), # write config.toml
SmolvmRunResult(0, "", ""), # chown config.toml
SmolvmRunResult(0, "", ""), # chmod config.toml
SmolvmRunResult(0, "", ""), # chown auth.json
SmolvmRunResult(0, "", ""), # chmod auth.json
SmolvmRunResult(1, "Not logged in\n", ""), # login status
@@ -320,6 +353,7 @@ class TestProvisionProviderAuth(unittest.TestCase):
with self.assertRaises(SystemExit):
_provider_auth.provision_provider_auth(
_plan(
agent_provider_template="codex",
codex_auth_file=Path("/tmp/codex-auth.json"),
),
"bot-bottle-demo-abc12",