Skip to content

fix(config): confine discovered bridge.toml to its own directory - #16

Merged
PyYoshi merged 2 commits into
mainfrom
fix/confine-project-config
Oct 22, 2026
Merged

PyYoshi merged 2 commits into
mainfrom
fix/confine-project-config

Conversation

@PyYoshi

@PyYoshi PyYoshi commented Oct 22, 2026

Copy link
Copy Markdown
Owner

Summary

  • A bridge.toml found by upward discovery from the launch directory is now treated as project-local. It took precedence over the user config, yet a cloned repository could commit one that authorized workspaces anywhere (for example allowed_roots = ["/"] with a workspace-write default).
  • Project-local files may only list allowed_roots that resolve inside the directory holding the file. On POSIX the file must also be owned by the current user and not world-writable; group-writable files stay accepted for umask 002 setups. Violations fail startup with CONFIG_KEY_DENIED.
  • allowed_roots are resolved once at startup, for every config source, and PolicyStore.check_workspace no longer re-resolves them per call. Before, a symlink created after startup, for example by a workspace-write turn, could redirect a root outside the configured path. This also covers the resume path.
  • init applies the same confinement when it checks an existing project-local file, and doctor reports the confinement.
  • Explicit --config files and the user config stay unconfined.
  • Docs: README (en/ja), docs/configuration.md, docs/security.md, docs/testing.md, and CHANGELOG.md.
  • A separate commit ignores .omc/ (local tool state).

Behavior changes

  • A project-local file listing roots outside its directory no longer loads. Use --config PATH for such setups. The user config is still not read while a project-local file exists.
  • Symlinked roots in any config are fixed to their target at startup.

Residual risk (accepted)

  • A repository can still authorize itself, including workspace-write, through a committed bridge.toml.

Validation

  • uv run --frozen pytest -m 'not live' -q: 160 passed, 4 deselected
  • uv run --frozen ruff check src tests and ruff format --check src tests: clean
  • uv build: OK
  • The new symlink regression test fails when the policy.py change is reverted, and passes with it.
  • Not run locally: aqua is not installed, so I used uv 0.12.23 instead of the pinned 0.12.13, with the same frozen uv.lock; betterleaks; and live tests.

Evidence is fake, unit, and subprocess only. There is no live-runtime or real-application validation.

A bridge.toml found by upward discovery was trusted as operator policy
and replaced the user config, so a cloned repository could commit one
with allowed_roots = ["/"] and a workspace-write default to authorize
Codex outside the project.

- Discovered (project-local) files may only list allowed_roots that
  resolve inside the directory holding the file, and on POSIX must be
  owned by the current user and not world-writable.
- allowed_roots are resolved once at startup and never re-resolved per
  call, so a symlink created after startup cannot redirect a root.
- init applies the same confinement when checking an existing
  project-local file, and doctor reports the confinement.
- Explicit --config files and the user config stay unconfined.
@PyYoshi
PyYoshi merged commit 4bba2c6 into main Oct 22, 2026
1 check passed
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.

1 participant