Commit Graph
2 Commits
Author SHA1 Message Date
openqj 7b537c31a6 test: close unclosed file handles in tests (Path read/write)
Replace bare open().read()/write() in tests with Path.read_text/
write_text (or json.loads over read_text); the five remaining
open(...).close() empty-file creations become Path.write_text('').
No assertion, predicate, or production code changed; no behaviour
change beyond closing the handle deterministically.

Long-function splits and server.py module split intentionally not
included: the longest functions (_dispatch, _create_task,
_dispatch_project, ~375-395 lines in a 10430-line server.py) are
central routing/creation paths, and splitting them is not low-risk;
see PR body.
2026-11-03 02:48:54 +00:00
host 03a98124db Multi-tenant isolation for Docker tasks (per-project mounts + networks + drop caps)
Container-side isolation was project-blind: every task mounted
the shared /app/work (all worktrees + host-state), the shared
codex-home (all thread history), the shared repos dir and the
shared test-repo, and all containers shared the default bridge
network. With --tenant-isolation (Docker only; Local runs on
the host under one user and has no container boundary to
enforce), each project gets its own host dirs under
tenants_root/<project>/{work,codex-home,test-repo,<project>}:
- mounts: container paths stay identical (/app/work,
  codex-home, repos/<pid>, test-repo) so host.py config needs
  no change; only the host mount sources are per-project.
  Static --docker-extra-mounts are replaced per task (not
  appended), so a shared mount cannot leak back in.
- codex-home seeds ONLY the template's config.toml (relay
  endpoint/provider names, no secret values); thread_history
  is never copied (it holds other tasks' prompts/results).
  test-repo is a per-project copy of the fixture (worktree
  creation needs a writable repo; a shared writable fixture
  would let one tenant poison the next task's base code).
- repos: repo_url checkouts go to the tenant dir and task
  repo is set to the container path; no-repo_url tasks get
  the tenant test-repo copy instead of the shared fixture.
- network: one Docker network per project (codex-<pid>,
  created idempotently, already-exists is OK); network
  creation failure fails the task instead of silently
  falling back to the default network (a silent downgrade
  would make isolation fail quietly).
- hardening for all Docker runs: --cap-drop=ALL and
  --security-opt=no-new-privileges (non-root user was already
  the case); verified live by a good-model task, not assumed.
Honest limit, kept in README: the inner codex sandbox is
still danger-full-access (host kernel blocks user namespaces,
bwrap unusable), so the boundary is container + mounts +
network, not the inner sandbox.
Tests: 7 tenant tests (seeding incl. no-history, per-project
mounts, network sanitization, per-call override, ensure
network ok/fail). Full suites pass.
2026-10-26 07:24:54 +08:00