fix(tier2): expand %TEMP% deny patterns to catch env-var forms

Follow-up to the 'NEVER USE APPDATA' directive. The agent kept
trying to use \C:\Users\Ed\AppData\Local\Temp / \C:\Users\Ed\AppData\Local\Temp / %TEMP% / %TMP% — the previous
deny rule (*AppData\\\\* and *AppData\\Local\\Temp\\*) only matched
the literal expanded path, not the env-var form. The agent would
self-block based on its own interpretation of the rule, but it still
TRIED before self-blocking (the 'fucking tired of it fucking with
AppData' complaint).

Fix:
1. opencode.json.fragment: add bash deny patterns matched against
   the LITERAL command string (before shell expansion):
     *\C:\Users\Ed\AppData\Local\Temp*    - PowerShell env var (the form the agent tried)
     *\C:\Users\Ed\AppData\Local\Temp*     - PowerShell env var
     *%TEMP%*        - cmd env var
     *%TMP%*         - cmd env var
     *GetTempPath*   - .NET API
     *gettempdir*    - Python tempfile module
     *mkstemp*       - Python tempfile.mkstemp
   Applied to BOTH the top-level permission.bash (for default agents)
   and the tier2-autonomous agent's permission.bash.

2. conductor/tier2/agents/tier2-autonomous.md: rewrite the Temp
   files section to explicitly list ALL forbidden literals and
   reiterate 'every one of those literal command strings is denied
   at the bash level'. Updated changelog note.

3. conductor/tier2/commands/tier-2-auto-execute.md: same.

4. tests/test_tier2_slash_command_spec.py: extend
   test_config_fragment_denies_temp_writes to assert each of the 9
   patterns in both the top-level and the agent's bash.

Verified: re-ran setup against the live clone. tier2 agent's bash
has 13 deny patterns (9 AppData/temp + 4 git). 37/37 default-on
tests pass.

Note: the user's prior commit (fix(tier2): remove AppData allow
rules from OpenCode permission JSON) already removed the AppData
allow rules from read/write and added the broader *AppData\\\\*
deny rule. This commit layers on top of that with the env-var-form
deny patterns.
This commit is contained in:
ed
2026-06-19 07:41:15 -04:00
parent aa3c993f4a
commit 387adff579
4 changed files with 36 additions and 9 deletions
+20 -7
View File
@@ -167,15 +167,28 @@ def test_config_fragment_has_top_level_permission() -> None:
def test_config_fragment_denies_temp_writes() -> None:
"""Regression test (2026-06-17): the agent wrote audit output to
"""Regression test (2026-06-17, expanded 2026-06-19 to catch all
env-var forms): the agent wrote audit output to
C:\\Users\\Ed\\AppData\\Local\\Temp\\ which is outside the sandbox.
Both the top-level and the tier2-autonomous agent's bash MUST deny
commands targeting AppData\\Local\\Temp\\ so the agent cannot write
there, and so the session-level 'ask' prompt is never triggered."""
commands targeting the global temp dir in ANY form (literal path,
$env:TEMP, $env:TMP, %TEMP%, %TMP%, GetTempPath, gettempdir,
mkstemp, NamedTemporaryFile)."""
data = json.loads(CONFIG_PATH.read_text(encoding="utf-8"))
top_bash = data["permission"]["bash"]
agent_bash = data["agent"]["tier2-autonomous"]["permission"]["bash"]
temp_deny_keys = [k for k in top_bash if "Temp" in k and top_bash[k] == "deny"]
assert temp_deny_keys, "top-level bash must have a deny rule for AppData\\Local\\Temp\\ paths"
temp_deny_keys_agent = [k for k in agent_bash if "Temp" in k and agent_bash[k] == "deny"]
assert temp_deny_keys_agent, "tier2-autonomous agent bash must have a deny rule for AppData\\Local\\Temp\\ paths"
# Required deny patterns (matched against the literal command string)
required = [
"*AppData\\*",
"*AppData\\Local\\Temp\\*",
"*$env:TEMP*",
"*$env:TMP*",
"*%TEMP%*",
"*%TMP%*",
"*GetTempPath*",
"*gettempdir*",
"*mkstemp*",
]
for pat in required:
assert top_bash.get(pat) == "deny", f"top-level bash must deny pattern: {pat!r}"
assert agent_bash.get(pat) == "deny", f"tier2-autonomous agent bash must deny pattern: {pat!r}"