diff --git a/src/skillspector/providers/_agent_cli.py b/src/skillspector/providers/_agent_cli.py index a2f9e02b0..7d2a44319 100644 --- a/src/skillspector/providers/_agent_cli.py +++ b/src/skillspector/providers/_agent_cli.py @@ -503,7 +503,10 @@ def _prepare_opencode_env( independently as defense in depth. The real OpenCode authentication store remains available so this CLI - provider can use the user's existing login. All mutable config, cache, + provider can use the user's existing login. OpenCode's internal plugins stay + enabled for the same reason: they implement the OAuth logins (ChatGPT, + Copilot, GitLab, ...) and register no tools. External plugins remain off + through ``--pure`` / ``OPENCODE_PURE``. All mutable config, cache, state, database, and temporary paths are redirected below the invocation's already-isolated temporary root. """ @@ -536,7 +539,6 @@ def _prepare_opencode_env( "OPENCODE_DISABLE_AUTOCOMPACT": "1", "OPENCODE_DISABLE_AUTOUPDATE": "1", "OPENCODE_DISABLE_CLAUDE_CODE": "1", - "OPENCODE_DISABLE_DEFAULT_PLUGINS": "1", "OPENCODE_DISABLE_EXTERNAL_SKILLS": "1", "OPENCODE_DISABLE_LSP_DOWNLOAD": "1", "OPENCODE_DISABLE_MODELS_FETCH": "1", @@ -674,7 +676,9 @@ def _build_opencode_argv(binary: str, model: str, max_output_tokens: int = 0) -> SKILLSPECTOR_MODEL is set). The shared runner also isolates every OpenCode config/state path, disables - ambient instructions, skills, plugins, auto-sharing, snapshots and updates, + ambient instructions, skills, external plugins (the internal OAuth/provider + plugins stay enabled, see ``_prepare_opencode_env``), auto-sharing, + snapshots and updates, scrubs secret-bearing environment variables, delivers untrusted content via stdin only, and never passes ``--auto``. diff --git a/tests/provider/test_opencode_cli.py b/tests/provider/test_opencode_cli.py index 1271f4b16..9028c4e8b 100644 --- a/tests/provider/test_opencode_cli.py +++ b/tests/provider/test_opencode_cli.py @@ -302,6 +302,8 @@ def test_policy_overrides_hostile_ambient_configuration(self, tmp_path: Path) -> "OPENCODE_CONFIG_CONTENT": '{"permission":"allow","share":"auto"}', "OPENCODE_PERMISSION": '{"*":"allow"}', "OPENCODE_EXPERIMENTAL": "1", + # An ambient value must not switch the OAuth login plugins back off (#809). + "OPENCODE_DISABLE_DEFAULT_PLUGINS": "1", } argv = _build_opencode_argv(OPENCODE_BINARY, "", 0) @@ -317,7 +319,10 @@ def test_policy_overrides_hostile_ambient_configuration(self, tmp_path: Path) -> assert config["autoshare"] is False assert env["OPENCODE_AUTO_SHARE"] == "0" assert env["OPENCODE_DISABLE_PROJECT_CONFIG"] == "1" - assert env["OPENCODE_DISABLE_DEFAULT_PLUGINS"] == "1" + # Internal plugins carry the OAuth logins (ChatGPT, Copilot, ...) and + # register no tools; disabling them breaks the user's login (#809). + # External plugins stay off through OPENCODE_PURE below. + assert "OPENCODE_DISABLE_DEFAULT_PLUGINS" not in env assert env["OPENCODE_DISABLE_EXTERNAL_SKILLS"] == "1" assert env["OPENCODE_DISABLE_CLAUDE_CODE"] == "1" assert env["OPENCODE_PURE"] == "1"