Private
Public Access
fix(tier2): top-level permission allowlist - sandbox paths now enforced
Regression: a Tier 2 session was denied access to
C:\\projects\\manual_slop_tier2\\scripts\\run_tests_batched.py
with 'Allowed base directories are: gencpp, manual_slop'. The
tier2-autonomous agent had a correct permission.read allowlist, but
the top-level permission block (inherited from the main repo's
opencode.json via 'git clone') had no read/write keys, and OpenCode
uses the top-level for the default agent path. The agent's
permission.read was merged but apparently not enforced for the
default-agent access check.
Fix:
1. Add a top-level 'permission' block to
conductor/tier2/opencode.json.fragment with:
- permission.edit: 'deny' (default agents locked down)
- permission.read: deny *, allow sandbox clone + app-data dirs
- permission.write: same
- permission.bash: deny *, allowlist of read-only git commands +
uv run python scripts/{run_tests_batched.py,tier2/*} + basic
shell commands. git push/checkout/restore/reset remain denied.
2. Update setup_tier2_clone.ps1 to also patch the top-level
'permission' block (was only merging the tier2-autonomous agent
block). The script preserves the user's mcp, model, instructions,
watcher, and plugin settings from the inherited opencode.json.
3. Update test_tier2_slash_command_spec.py:
- Rename test_command_fetches_origin_main -> ..._master (we
changed the slash command on 2026-06-17).
- Add test_config_fragment_has_top_level_permission to assert
the new top-level permission block has the right deny-all +
allowlist shape.
The tier2-autonomous agent's permission block is unchanged; it
overrides the top-level for that agent's tool calls.
This commit is contained in:
@@ -42,9 +42,9 @@ def test_command_uses_git_switch_not_checkout() -> None:
|
||||
assert all("checkout" not in line for line in shell_lines), f"protocol uses git checkout: {shell_lines}"
|
||||
|
||||
|
||||
def test_command_fetches_origin_main() -> None:
|
||||
def test_command_fetches_origin_master() -> None:
|
||||
content = COMMAND_PATH.read_text(encoding="utf-8")
|
||||
assert "git fetch origin main" in content
|
||||
assert "git fetch origin master" in content
|
||||
|
||||
|
||||
def test_command_initializes_failcount_state() -> None:
|
||||
@@ -87,3 +87,26 @@ def test_config_fragment_valid_json() -> None:
|
||||
assert "git checkout*" in perms["bash"]
|
||||
assert "git restore*" in perms["bash"]
|
||||
assert "git reset*" in perms["bash"]
|
||||
|
||||
|
||||
def test_config_fragment_has_top_level_permission() -> None:
|
||||
"""Top-level permission.read/write MUST allow the sandbox dirs (added
|
||||
2026-06-17 after the bug where the agent's permission.read was not
|
||||
enforced for the default agent, leading to ACCESS DENIED on
|
||||
manual_slop_tier2 paths)."""
|
||||
data = json.loads(CONFIG_PATH.read_text(encoding="utf-8"))
|
||||
assert "permission" in data
|
||||
top = data["permission"]
|
||||
assert "read" in top, "top-level permission.read is required"
|
||||
assert top["read"].get("*") == "deny", "top-level permission.read MUST deny *"
|
||||
assert top["read"].get("C:\\projects\\manual_slop_tier2\\**") == "allow", "sandbox clone path must be allowlisted"
|
||||
assert "write" in top
|
||||
assert top["write"].get("*") == "deny"
|
||||
assert top["write"].get("C:\\projects\\manual_slop_tier2\\**") == "allow"
|
||||
assert "bash" in top
|
||||
assert top["bash"].get("*") == "deny", "top-level bash MUST deny * (default agents are locked down)"
|
||||
assert top["bash"].get("git status*") == "allow", "read-only git commands must be in the allowlist"
|
||||
assert top["bash"].get("git push*") == "deny"
|
||||
assert top["bash"].get("git checkout*") == "deny"
|
||||
assert top["bash"].get("git restore*") == "deny"
|
||||
assert top["bash"].get("git reset*") == "deny"
|
||||
|
||||
Reference in New Issue
Block a user