Repository navigation
feat(providers): add copilot_cli semantic-scan provider - #572
Yoseph-Zuskin wants to merge 28 commits into
Conversation
rng1995
left a comment
There was a problem hiding this comment.
[SkillSpector Review]
Reviewed exact head 6bb8dc5a6af1f8e59d4967f2e8133fd00d02bfa6.
The provider wiring, exact-version gate, stdin transport, output bounds, environment filtering, and zero-tool allowlist are well covered. One trust-boundary gap remains: the invocation leaves Copilot CLI's normal custom-instruction discovery enabled while deliberately preserving the user's home/login context. Ambient global or user instructions can therefore alter semantic-security judgments even though COPILOT_CUSTOM_INSTRUCTIONS_DIRS is stripped. Disable custom instructions explicitly for this provider and add an end-to-end argv/isolation regression before enabling it.
- Add providers/copilot_cli/provider.py and __init__.py mirroring opencode_cli; register copilot in _agent_cli.py CliSpec with _prepare_copilot_env wired in - Transport is flags + piped stdin: copilot -s --no-ask-user, prompt via stdin (verified by nonce round-trip); --available-tools names a fixed implausible tool (verified live: model left tool-less, no side effect) plus --deny-tool shell,write belt-and-braces; never --allow-all* - Auth probe is copilot --version (must equal pinned 1.0.85), scrubbed env, fail-closed; login session or COPILOT_GITHUB_TOKEN/GH_TOKEN/ GITHUB_TOKEN auth, everything else COPILOT_* stripped - Update docs trio: README provider table (+1.0.85 pin note), .env.example, docs/DEVELOPMENT.md - Add tests/provider/test_copilot_cli.py (argv, auth, parser, wiring, adversarial fake-host with POSIX-skip) + registry coverage - Verified: live probe on Copilot Free (CLI-default model), llm_available=true, 3/3 calls, 0/LOW, 0 findings; 375 passed / 14 skipped; ruff + format + diff-check clean Signed-off-by: Yoseph Zuskin <zuskinyoseph@gmail.com> Co-Authored-By: OpenCode Muse Spark 1.3 Free (1M context) <noreply@opencode.ai>
6bb8dc5 to
9f8f9c6
Compare
…to-update - Add --no-custom-instructions to copilot argv so ambient AGENTS.md and related files cannot steer the semantic verdict (COPILOT_HOME stays for login, hence flag-level disabling) - Add --disable-builtin-mcps as defense in depth alongside the tool allowlist, and --no-auto-update so the version pin cannot invalidate mid-scan - Extend exact-shape, flag-presence, and fake-host adversarial tests; document the flags in the builder docstring - Verified: 134 passed / 2 skipped, ruff clean; live regression with a hostile AGENTS.md fixture returns the exact requested reply Signed-off-by: Yoseph Zuskin <zuskinyoseph@gmail.com> Co-Authored-By: OpenCode Muse Spark 1.3 Free (1M context) <noreply@opencode.ai>
- Bump copilot pin 1.0.85 → 1.0.86 plus all version references (code comments, test fixtures, README pin note, DEVELOPMENT); all six sandbox flags still present in --help, no policy changes - Re-ran live AGENTS.md-ignored regression on the new release: PASS - Verified: file suite 41 passed / 2 skipped; ruff clean Signed-off-by: Yoseph Zuskin <zuskinyoseph@gmail.com> Co-Authored-By: OpenCode Muse Spark 1.3 Free (1M context) <noreply@opencode.ai>
yashrajp22
left a comment
There was a problem hiding this comment.
Two issues remain in the Copilot safety boundary: inference bypasses the exact-version check, and ambient user/plugin lifecycle hooks remain enabled.
Validation: fresh base/head wheels with verified package identity; selected tests passed (324 base, 367 head; 10 skipped each); all 48 no-LLM corpus runs matched across source/wheel and base/head, with nine samples retaining partial reports. Synthetic unsupported-version checks reproduced prompt delivery through both public scans and direct completion. The real 1.0.86 binary reported missing authentication as expected, and the scan retained two PE3 findings while explicitly marking semantic analysis failed.
The hook finding is based on the pinned runtime source. The credential-free marker check was inconclusive; authenticated inference and native hook/tool/MCP behavior remain unverified. Corpus parity is not a global accuracy claim.
…e homes - Add _preflight_copilot_policy as the copilot CliSpec preflight: [binary, --version] under the isolated child env rejects anything but exactly 1.0.86 before run_agent_cli delivers stdin — covers normal scans and direct complete() calls, which never hit the once-per-scan availability probe - _prepare_copilot_env redirects HOME/USERPROFILE/COPILOT_HOME to per-invocation temp dirs (user/plugin lifecycle hooks have no argv off-switch); auth survives only via forwarded token vars, persistent login sessions are no longer carried over - Tests: 5 preflight mocks incl. synthetic 9.9.99, home-redirect unit test, fake-host OPERATOR_HOME bait test; stale COPILOT_HOME expectations rewritten - Verified: file suite 46 passed / 3 skipped; provider-wide 87 passed / 6 skipped; ruff check + format + diff-check clean Signed-off-by: Yoseph Zuskin <zuskinyoseph@gmail.com> Co-Authored-By: OpenCode Muse Spark 1.3 Free (1M context) <noreply@opencode.ai>
- Codifies the NVIDIA#536/NVIDIA#572 review bar as entry criteria: exact-version preflight before stdin on every completion path, no-hook-material enforcement (isolation where usable, presence-refusal otherwise), adversarial fake-host tests, synthetic-version gate tests, no silent fallbacks - Kept as a standalone commit so it can be reverted on its own if maintainers prefer this guidance elsewhere Signed-off-by: Yoseph Zuskin <zuskinyoseph@gmail.com> Co-Authored-By: OpenCode Muse Spark 1.3 Free (1M context) <noreply@opencode.ai>
rng1995
left a comment
There was a problem hiding this comment.
[SkillSpector Review]
Re-reviewed exact head c9e001f29c7108fd3ecc23f7b6c4f15cac6fa53c, including the complete diff, provider/transport call path, tests, previous reviews and author replies, and CI.
Previous findings:
- Addressed: custom-instruction discovery is explicitly disabled with
--no-custom-instructions; built-in MCPs and auto-update are also disabled, with argv coverage. - Addressed in implementation: the exact-version check is now a registered per-completion preflight, invoked before
Popen/stdin delivery, including directcomplete()calls. The unsupported-version test currently calls the helper directly; please also exercise the public completion path so a future registry/wiring regression cannot bypass the gate unnoticed. - Still open: user/plugin hook isolation is only partially addressed. Rejecting nonempty
installed-plugins/does not reject user hook files or inline settings hooks. The inline finding supplies the concrete non-plugin paths requested in the author reply.
I inspected (did not execute) package/app.js and the version metadata from the official Copilot CLI 1.0.86 release, asset github-copilot-1.0.86-darwin-arm64.tgz. createNativeHookSession loads user settings and passes both settingsJson and userHooksDir to hookSessionCreate before adding plugin hooks separately. This is pinned-runtime evidence, not an assumption from newer documentation.
All six reported CI checks pass. Contributor code/tests and authenticated Copilot inference were not executed during this review; the remaining finding is based on source inspection. Approval remains blocked on closing and testing the non-plugin hook paths.
The copilot home audit only rejected installed-plugins/, but the pinned 1.0.86 runtime loads hooks from policy, user, project, then plugin sources with no argv off-switch (confirmed: no --disable*hook* flag in `copilot --help`). A plugin-free home carrying hooks/*.json or an inline hooks block in settings.json passed the audit while hooks stayed loadable outside the model tool allowlist. - _audit_copilot_home now also rejects hooks/*.json, a truthy top-level hooks block in settings.json (unreadable settings fail closed; messages name paths, never contents), and an explicitly set but missing COPILOT_HOME (unverifiable: the CLI may fall back to ~/.copilot). A missing default home still passes. Machine-wide policy hooks are documented as accepted residual risk (admin-owned, disableAllHooks-immune). - New _audit_tmp_cwd tripwire: repo-level hook material (.github/hooks, repo/Claude settings) in the fresh temp working dir raises; wired into the preflight (which now uses its tmp_cwd parameter). - Regressions: hook-file/inline/malformed/missing-home unit tests, parametrized tmp-cwd tests, a fake-binary end to end proving stdin never moves (invocation marker absent), and a preflight test asserting tmp-cwd rejection precedes the version probe. Fixed a latent Linux-CI failure where a preflight test assumed a nonexistent /tmp/iso/home. - Live validation on real 1.0.86: raw CLI executed both a hooks/*.json command hook and an inline settings hook headlessly (harmless marker files), then the real provider path rejected the same hook home with AgentCLIError and no markers. Temp hook home removed afterwards. Tests: tests/provider 105 passed, 6 skipped (win32 POSIX-shebang skips, incl. the new end to end, which follows the existing adversarial-transport pattern). Signed-off-by: Yoseph Zuskin <zuskinyoseph@gmail.com> Co-Authored-By: OpenCode Muse Spark 1.3 Free (1M context) <noreply@opencode.ai>
The CLI keeps several cached runtime generations on disk and disabling updates selects an older cached one: with COPILOT_AUTO_UPDATE=false or --no-auto-update (proven identical), the launcher reports and runs an older generation than the newest install, so any pin above the cached generation can never pass the gate. Drop both update-disabling controls and pin the executed 1.0.88 instead; a mid-scan update now fails loud at the per-completion preflight rather than drifting silently. - Pin 1.0.86 -> 1.0.88 across provider, tests, README, DEVELOPMENT - _prepare_copilot_env no longer forces COPILOT_AUTO_UPDATE (operator value stripped as before: updates stay enabled); --no-auto-update out of argv; docstrings explain why - Tests: exact-shape and fake-host posture assert the flag's absence; test_auto_update_not_forced replaces the forcing test - Live proof on this tree: hook home rejected with AgentCLIError and no markers; clean home returned the exact nonce Tests: file suite 64 passed / 3 skipped; ruff check + format clean. Revertable independently of the hook-audit commit. Signed-off-by: Yoseph Zuskin <zuskinyoseph@gmail.com> Co-Authored-By: OpenCode Muse Spark 1.3 Free (1M context) <noreply@opencode.ai>
rng1995
left a comment
There was a problem hiding this comment.
[SkillSpector Review]
Re-reviewed current head 05f3e3236ea5eae91ffa611faf1df4b5ba239a52, both follow-up commits, the current provider/transport code and regression tests, prior discussions, and CI.
The previous direct-home cases are now addressed: the audit rejects user hooks/*.json, inline settings.json hooks, unreadable settings, and missing explicit homes; the temp-directory tripwire and transport-level rejection test are also present. The custom-instruction/MCP restrictions and per-completion exact-version preflight remain wired in. I also independently checked the official Copilot 1.0.88 launcher: I am not requesting changes solely because auto-update was re-enabled.
One remaining user-hook path prevents approval: the new audit observes the home before Copilot's inference startup migrates legacy XDG hook material into it. The --version subprocess exits before those migrations, so it cannot make the subsequent home audit sufficient. This is a deterministic startup-order issue, not a hypothetical concurrent modification. The inline comment gives the affected configuration, exact pinned-runtime source path, and required correction.
Evidence: read-only inspection of package/app.js from the official Copilot CLI 1.0.88 release, asset github-copilot-1.0.88-darwin-arm64.tgz. The version branch returns before tOn(); tOn() calls X0n for XDG config/state migrations; normal session creation subsequently loads the destination home's hooks.
All six reported CI checks pass. Contributor code, tests, and downloaded Copilot code were not executed locally; this finding is source-traced. No merges or thread-resolution changes were made.
Startup moves $XDG_CONFIG_HOME/.copilot/hooks into the copilot home after the audit, so a hook-free home with hook material in the XDG tree still ends up loadable outside the tool allowlist. _scrub_env retains XDG variables and only the resolved home was inspected. - _audit_copilot_home now also inspects the XDG source (default ~/.config/.copilot when unset; explicit-but-missing XDG raises; same-tree dedup) via an extracted _audit_hook_tree helper shared by both trees. Pure audit extension, no environment behavior change; messages name paths, never contents. - 6 new tests: explicit/default/missing/clean XDG sources plus a fake-binary transport end to end (clean home, dirty XDG source) proving stdin never moves. - Live validation: real-home copy plus XDG marker hook rejected with the migration-source message, marker absent. Tests: file suite 69 passed / 4 skipped (win32 POSIX-shebang skips); ruff check + format clean. Signed-off-by: Yoseph Zuskin <zuskinyoseph@gmail.com> Co-Authored-By: OpenCode Muse Spark 1.3 Free (1M context) <noreply@opencode.ai>
… ones Linux CI sets XDG_CONFIG_HOME with no .copilot subdir, tripping the explicit-missing refusal in the adversarial-transport tests. Replace both missing-raises rules with fallback coverage: the audit now walks the override and default trees for the copilot home and the XDG migration source (deduped; missing dirs hold nothing and pass), so a fallback in either direction lands on verified ground. - Deleted the callerless _xdg_copilot_home helper after inlining. - Tests encode the new semantics (missing override/default splits, dirty-default-despite-clean-override both ways). Tests: file suite 75 passed / 4 skipped; ruff clean. Signed-off-by: Yoseph Zuskin <zuskinyoseph@gmail.com> Co-Authored-By: OpenCode Muse Spark 1.3 Free (1M context) <noreply@opencode.ai>
|
Hi @yashrajp22 and @rng1995, all comments have been addressed. Please resolve them or let me know if you would prefer I do so myself. The PR description has also been updated to reflect that the pinned CLI version is now 1.0.88. I will propose a minor automation to check for OpenCode and GitHub Copilot CLI releases once a week after this and #613 will be merged. |
rng1995
left a comment
There was a problem hiding this comment.
[SkillSpector Review]
Re-reviewed exact head a053ab575bdf23e46d5971af3aedeffc2f11a75b, including the complete fourteen-file diff, transport/provider integration, tests, all prior reviews/replies/thread states, and CI. I also inspected the official Copilot CLI 1.0.88 release source as inert text.
Addressed: explicit custom-instruction/built-in MCP restrictions remain in place; the exact-version preflight is registered before inference Popen; current/fallback home hooks and inline settings are audited; the previously reported XDG_CONFIG_HOME user-hook migration source is now audited and has transport-level rejection coverage.
Still requires changes: startup migration is not fully covered. The pinned runtime also migrates installed-plugins from XDG_STATE_HOME/.copilot, but this environment variable survives the child environment and its source tree is never audited. The new inline finding describes how plugin hook material can appear after the audit and how to close this path. This is a separate migration source from the CONFIG-hook example fixed in the previous thread, not a repetition of that resolved example.
The earlier requested public-path unsupported-version regression is also still absent: the 9.9.99 rejection test invokes _preflight_copilot_policy directly, while transport tests run the supported version. Please add that public completion rejection case while extending migration coverage, so removal of the registered preflight cannot silently bypass the gate.
All six reported hosted checks pass. Contributor code/tests, downloaded runtime code, and authenticated Copilot inference were not executed locally. No merge or thread-resolution changes were made.
- _audit_copilot_home now inspects explicit $XDG_STATE_HOME/.copilot and default ~/.local/state/.copilot: 1.0.88+ migrates installed-plugins at startup, loading plugin hooks post-audit. Redirecting is not a lever (inference refuses under any redirected home); deleting falls back unaudited; both sources audited in place - New regressions: STATE transport rejection via the public path (clean home, populated STATE plugins, empty markers) and 9.9.99 via the public completion path (preflight removal cannot silently bypass the gate) - Bump pin 1.0.88 -> 1.0.89 plus all references; --help surface identical, still no --disable*hook* flag; 1.0.89 source re-inspected (migration path unchanged, juo still lists installed-plugins) - Verified: 79 passed / 6 skipped (POSIX-only transport skips); ruff + format clean; preflight PASSES live on real 1.0.89 against a genuine user home Signed-off-by: Yoseph Zuskin <zuskinyoseph@gmail.com> Co-Authored-By: OpenCode Muse Spark 1.3 Free (1M context) <noreply@opencode.ai>
…ovider Signed-off-by: Yoseph Zuskin <zuskinyoseph@gmail.com>
- Add --disallow-temp-dir alongside --disable-builtin-mcps: prevents automatic access to the system temporary directory (verified live on 1.0.89: inference from a temp working dir still answers exactly) - Pinned shape test updated (RED-witnessed the new flag first) - Verified: file suite 79 passed / 6 skipped (POSIX-only transport skips); ruff + format + diff-check clean Signed-off-by: Yoseph Zuskin <zuskinyoseph@gmail.com> Co-Authored-By: OpenCode Muse Spark 1.3 Free (1M context) <noreply@opencode.ai>
rng1995
left a comment
There was a problem hiding this comment.
[SkillSpector Review]
Hi @Yoseph-Zuskin, thank you for the quick follow-up on the XDG state migration audit and the public-path version test!
Value and readiness: This PR adds a copilot_cli provider, so GitHub Copilot users can run semantic analysis without an OpenAI or Anthropic key (#8). Every earlier finding from this thread and from @yashrajp22's review is resolved on the current head. One new gap blocks approval: Copilot CLI personal extensions are another source of ambient code, and the preflight audit does not cover them. Once that is closed, the remaining questions (exact pin versus Copilot's release cadence, and token forwarding) are PIC decisions, not code defects.
Previous findings:
- Custom-instruction discovery (rng1995, 2026-09-18): Resolved.
--no-custom-instructionsis in_build_copilot_argv(_agent_cli.py:1009). The argv shape test and the fake host both assert it. - Inference bypasses the exact-version check (@yashrajp22): Resolved.
_preflight_copilot_policyis the registeredCliSpecpreflight (_agent_cli.py:1371-1378), andrun_agent_clicalls it beforePopenon every completion. - Ambient user/plugin lifecycle hooks (@yashrajp22), plus user hook files and inline settings hooks (rng1995, 2026-09-22): Resolved for the hook sources GitHub documents.
_audit_hook_treerefuses a non-emptyinstalled-plugins/,hooks/*.json, an inlinehooksblock insettings.json, and an unreadablesettings.json. - Public-path unsupported-version regression (rng1995, 2026-09-22 and 2026-09-28): Resolved.
test_public_completion_rejects_unsupported_versionsends 9.9.99 throughrun_agent_cli. If the registered preflight were removed, the run would return normally andpytest.raiseswould fail. XDG_CONFIG_HOMEhook migration (rng1995, 2026-09-23): Resolved.XDG_STATE_HOMEinstalled-pluginsmigration (rng1995, 2026-09-28): Resolved._audit_copilot_homenow audits both the explicit$XDG_STATE_HOME/.copilotand the default~/.local/state/.copilot(_agent_cli.py:1189-1198). Unit cases andtest_xdg_state_source_rejects_before_prompt_deliverycover it: a clean home plus populated STATE plugins is rejected, and the marker directory stays empty.- Upstream merge
1287da8: the PR's own change is identical before and after the merge, apart from context lines from main's OpenCode 1.18.32 bump.
Material findings
-
[Blocker]
src/skillspector/providers/_agent_cli.py:1201:_audit_hook_treedoes not check personal extensions.- GitHub's Copilot CLI config-directory reference lists
~/.copilot/extensions/as "Personal extensions loaded by the CLI". - The official changelog for 1.0.41 says extensions load in prompt mode and user extensions load by default. Piped-stdin runs like this one are prompt-mode runs; 1.0.78 aligned their hook behavior with
-p. - The CLI runs each extension as a forked Node.js process, and extensions can register tools and hook callbacks (changelog 1.0.3 and 1.0.85). They need experimental mode, which users can persist as
"experimental": truein~/.copilot/settings.json. - Failing configuration: a home with no plugins and no hooks,
settings.json={"experimental": true}, and~/.copilot/extensions/x/extension.mjs. The audit passes, and every completion forks that code with scanner privileges and the inherited environment, including the forwarded GitHub token variables. The--available-toolsallowlist does not control this. It is the same class of path as the hooks fixed in earlier rounds, and it contradicts the_audit_copilot_homedocstring, which says every user and plugin source is checked. - Expected fix:
- Refuse a non-empty
extensions/in every audited tree (home, default home, both XDG sources). - Add
.github/extensionsto_REPO_HOOK_PATHS. - Drop
GITHUB_COPILOT_*in_prepare_copilot_env. Line 930 drops onlyCOPILOT_*, soGITHUB_COPILOT_PROMPT_MODE_EXTENSIONS,GITHUB_COPILOT_PROMPT_MODE_REPO_HOOKSandGITHUB_COPILOT_PROMPT_MODE_WORKSPACE_MCPcurrently reach the child. - Add unit cases, plus a transport regression with a clean hook tree and a populated
extensions/that is rejected before prompt delivery.
- Refuse a non-empty
- Alternative: if the pinned 1.0.89 source shows extensions cannot load under this argv, cite that evidence instead (for example a verified gate you can force off).
- GitHub's Copilot CLI config-directory reference lists
-
[Non-blocking] User MCP and LSP servers:
--disable-builtin-mcpsdisables only the built-in GitHub server. The same reference lists~/.copilot/mcp-config.jsonandlsp-config.json, which define user server commands. Please confirm on 1.0.89 whether user MCP servers start on each completion under this argv. Their tools are hidden by--available-tools, but a local server is still a spawned command, and itsenvblock can reference the forwarded token variables. Either audit them like hooks or document them as residual risk next to the policy-hook note. Listing the surfaces you checked in the docstring would make the next pin bump easier to re-verify. -
[Non-blocking] Docs and comments disagree with the code:
src/skillspector/providers/copilot_cli/provider.py:27says the argv includes--no-auto-update, which was deliberately removed, and it omits--disallow-temp-dir._build_copilot_argvhas two "Deliberately NOT included" sections (lines 974 and 997).- The comment at
tests/provider/test_copilot_cli.py:292says a missingCOPILOT_HOMEis refused;_audit_copilot_homedocuments and implements the opposite.
-
[Non-blocking]
src/skillspector/providers/_agent_cli.py:1067and:1110:"1.0.89"is hard-coded in both gates and both error messages. Copilot ships a stable release about every two days. A single_COPILOT_SUPPORTED_VERSIONconstant, asopencode_cliuses, would stop a bump from updating one gate but not the other. -
[Non-blocking] The tests are not hermetic.
_audit_copilot_homealways audits the real~/.copilot,~/.config/.copilotand~/.local/state/.copilot, and several tests do not redirectHOME:TestPreflightCopilotPolicy.test_pinned_version_passesTestAuditCopilotHome.test_empty_plugins_passTestAdversarialTransport.test_adversarial_child_gets_no_usable_tools
test_pinned_version_passesalso audits the shared/tmpas its working directory. These tests fail on a contributor machine that has Copilot plugins or hooks installed. Add an autouse fixture that pointsHOME/USERPROFILEattmp_pathand clearsCOPILOT_HOME,XDG_CONFIG_HOMEandXDG_STATE_HOME, and passtmp_pathas the working directory. -
[Non-blocking] Two small fixes:
src/skillspector/cli.py:563-564: one extra leading space misaligns thescan --helptext.src/skillspector/providers/copilot_cli/__init__.py: the license header is missing thehttp://www.apache.org/licenses/LICENSE-2.0line that every other file has.
PIC tradeoffs:
- Exact pin versus release cadence. Copilot CLI shipped seven stable releases between 2026-09-16 and 2026-10-01. 1.0.90 (2026-09-30) and 1.0.91 (2026-10-01) have already superseded the 1.0.89 pin. Auto-update is deliberately left on, so default installs leave the pin within days.
copilot_clithen reports itself unavailable until SkillSpector ships a new pin. That failure is closed and visible, but those users get no semantic scans. The PIC should decide whether that level of availability is acceptable for a supported provider. If it is, re-verify and bump to the current stable release just before merge. - Token forwarding.
_scrub_envstripsGITHUB_TOKENfor every other CLI provider. This provider re-injectsGITHUB_TOKENandGH_TOKENalong withCOPILOT_GITHUB_TOKEN, and in CIGITHUB_TOKENis often a repo-scoped token unrelated to Copilot. Forwarding onlyCOPILOT_GITHUB_TOKEN(the one-line fallback the description offers) keeps headless Copilot auth without giving a general repo token to an agent process that reads untrusted content.GH_TOKENalready reaches all CLI providers because_scrub_envdoes not strip it; that gap predates this PR. - Merge order. This PR and #665 change adjacent README lines. Whichever lands second needs a small rebase.
Verification and gaps: What I checked, statically:
- The full 14-file diff at the head, the two author commits since
a053ab57(98adf47,87d0b4e), and the merge1287da8. I compared the PR's change before and after the merge; only context lines from main differ. - The call path
run_agent_cli→_prepare_copilot_env→_preflight_copilot_policy→Popen, and the final argv. - As text: GitHub's Copilot CLI hooks reference, config-directory reference and extension docs, and the official
github/copilot-clichangelog through 1.0.91.
Gaps:
- I did not download or inspect the 1.0.89 runtime. Findings 1 and 2 rest on vendor documentation and the changelog, not on tracing the pinned source.
- Per policy, I did not run the tests or authenticated Copilot inference.
All six CI checks pass on this head.
Decision: Changes Requested (reviewed head 87d0b4e1bb3b9d79d6c2aa27e13b356c826b31f0)
- Refuse non-empty extensions/ in all six audit trees (personal extensions fork outside --available-tools; no argv off-switch exists in 1.0.91); .github/extensions joins the repo tripwire - Refuse user mcp-config.json / lsp-config.json defining any servers (empty/missing pass); checked-surfaces inventory added to the audit docstring for future pin re-verification - Drop GITHUB_COPILOT_* prompt-mode opt-ins in _prepare_copilot_env; narrow token forwarding to COPILOT_GITHUB_TOKEN only (CI repo tokens must not reach the agent process) - Bump pin 1.0.89 -> 1.0.91 (Latest stable; 1.0.92-x prerelease) plus _COPILOT_SUPPORTED_VERSION constant in both gates; all references updated - Hygiene: merged duplicate NOT-included sections, corrected test comment, hermetic autouse fixture, cli.py indent, license header - Verified: 87 passed / 8 skipped (POSIX-only transport skips); 433/17 across six suites; ruff + format + diff-check clean; preflight PASSES live on real 1.0.91; nonce echo exact Signed-off-by: Yoseph Zuskin <zuskinyoseph@gmail.com> Co-Authored-By: OpenCode Muse Spark 1.3 Free (1M context) <noreply@opencode.ai>
…ovider Signed-off-by: Yoseph Zuskin <zuskinyoseph@gmail.com>
- _prepare_copilot_env drops GH_TOKEN, GH_ENTERPRISE_TOKEN,
GITHUB_ENTERPRISE_TOKEN explicitly (CLI reads them as
credentials after COPILOT_GITHUB_TOKEN; a CI gh token must
never become the agent's credential); shared scrub strips
them too
- Token tests build the base with _scrub_env() (production
path) and pin both layers, plus a hand-built-base case
- Audit directory-source plugin refs (enabledPlugins,
extraKnownMarketplaces) and the BYOK providers.json
registry in all six trees; accept all-empty server
collections (leftover {"mcpServers": {}} shape)
- Hermetic preflight tests (tmp_path); align help text,
docstrings, README/DEVELOPMENT with the single-token
reality; drop the duplicated --available-tools heading
Signed-off-by: Yoseph Zuskin <zuskinyoseph@gmail.com>
Co-Authored-By: OpenCode Muse Spark 1.3 Free (1M context) <noreply@opencode.ai>
- Re-verify the full argv flag surface against installed Copilot CLI 1.0.92 --help (-s, --no-ask-user, --no-custom-instructions, --disable-builtin-mcps, --disallow-temp-dir, --available-tools, --deny-tool, --model); no hook off-switch appeared, so the preflight-refusal posture stands. Real 1.0.92 runtime passes the gate; bump the exact pin across code, tests, README, and DEVELOPMENT (1.0.92 stable 2026-10-05) - Fold the all-empty server-collection guard and the settings.json plugin-ref checks into single guards (same logic, fewer lines) Signed-off-by: Yoseph Zuskin <zuskinyoseph@gmail.com> Co-Authored-By: OpenCode Muse Spark 1.3 Free (1M context) <noreply@opencode.ai>
…ovider Signed-off-by: Yoseph Zuskin <zuskinyoseph@gmail.com>
|
Hi @rng1995, thank you for the thorough review. Three things in this push. First, the Also in this push: pin bumped to 1.0.92 (stable since 2026-10-05). Full Two PIC calls left, both one-liners in the docs now: blocking the whole provider on any user hook/plugin/server, and the gh auth fallback. @yashrajp22's 2026-09-19 request still needs a re-review or a maintainer dismissal. Guidance welcome on any of it. |
rng1995
left a comment
There was a problem hiding this comment.
Re-reviewed all fourteen changed files, eleven historical inline threads, substantive prior review rounds, and the provider/transport trust boundary. The earlier feedback is implemented and the 246-case provider/transport suite passes (1 skipped, 4 deselected).
One new P1 remains: preflight audits a normalized XDG path relative to the scanner directory, while the pinned CLI resolves the unchanged value relative to inference's fresh temporary directory. Relative values and values ending in a space can therefore select an uninspected hooks/plugins migration tree. The inline finding contains reproducible transport evidence and source confirmation from the exact official 1.0.92 release. No authenticated inference or hook execution was performed. Please address this boundary before approval, and update the branch with main to resolve its current merge conflict.
…ovider Signed-off-by: Yoseph Zuskin <zuskinyoseph@gmail.com>
- _prepare_copilot_env forwards COPILOT_HOME scanner-resolved absolute (no strip, no expanduser): relative homes resolve in the scanner cwd for the audit but the temp cwd for the CLI, and trailing-space dirs resolve as-is - Adopt upstream allowlist scrub as the XDG_CONFIG/STATE_HOME mitigation (inherited values never reach the child; audited defaults apply); pin with scrub + transport regressions - Bump exact pin 1.0.92 -> 1.0.95 (--help rechecked, real 1.0.95 binary passes the gate); merge upstream/main - tests: relative/spaced/tilde/blank home, XDG-strip pins, env-recording transport stand-ins (RED witnessed) Signed-off-by: Yoseph Zuskin <zuskinyoseph@gmail.com> Co-Authored-By: OpenCode Muse Spark 1.3 Free (1M context) <noreply@opencode.ai>
|
Hi @rng1995, thank you for the thorough re-review and the transport evidence! Latest push closes the P1: Also in this push: pin bumped to 1.0.95 with the full Open items unchanged: the fail-closed availability posture and gh-fallback PIC calls, and @yashrajp22's 2026-09-19 request still needs a re-review or a maintainer dismissal. Guidance welcome on any of it. |
Linux CI failed 6 POSIX-gated tests: the fake `copilot` stub read ATTACK_MARKERS/FAKE_COPILOT_VERSION from the child env, but the product scrub correctly strips them, so the stub crashed with KeyError before any assertion. Skipped on Windows, so never seen locally. Bake the markers path and version into the stub source at write time, mirroring test_opencode_cli.py; drop the dead setenv lines; the version test passes version="9.9.99". No product-code change: adding the vars to the allowlist would ship a test hook. Signed-off-by: Yoseph Zuskin <zuskinyoseph@gmail.com> Co-Authored-By: OpenCode Muse Spark 1.3 Free (1M context) <noreply@opencode.ai>
- Nonce probes on the real 1.0.95 runtime (token auth): `-s` stdout carries only the response text; temp-cwd inference answers exactly; both exit 0 - Both live-provenance comments now cite 1.0.95; the 1.0.92 release-source note stays (static source analysis, pinned deliberately) - No behavior change; file suite 104/11 green, ruff clean Signed-off-by: Yoseph Zuskin <zuskinyoseph@gmail.com> Co-Authored-By: OpenCode Muse Spark 1.3 Free (1M context) <noreply@opencode.ai>
rng1995
left a comment
There was a problem hiding this comment.
[SkillSpector Review]
@Yoseph-Zuskin thank you for closing the home-resolution boundary so precisely, with transport regressions that mirror the reported repro.
Value and readiness
The last blocker is resolved:
COPILOT_HOMEis forwarded scanner-resolved, absolute and untrimmed, so the audit and the child name the same tree.- Inherited
XDG_CONFIG_HOME/XDG_STATE_HOMEcan no longer reach the child, so the CLI uses the audited defaults.
The branch merges cleanly into current main (b07f181d), and all six checks pass on 783e4442. I have no further required code changes. It is ready for final maintainer/PIC review, subject to the version-pin decision below and @yashrajp22's outstanding change request.
Material findings
Prior findings:
- [P1] Audit the same XDG/home tree that inference resolves: resolved.
_prepare_copilot_envforwardsos.path.abspath(COPILOT_HOME)with no strip and no expanduser (_agent_cli.py:935-943), and_copilot_homereads the identical value (:1143-1145).XDG_CONFIG_HOME/XDG_STATE_HOMEare not in the_RUNTIME_ENV_NAMESallowlist, so the CLI falls back to~/.config/.copilotand~/.local/state/.copilot. Both are audited unconditionally (:1221-1241).test_relative_copilot_home_forwarded_absoluteand the two…never_reaches_childcases exercise the realrun_agent_clitemp-cwd path.
- Merge conflict with
main: resolved. The branch is clean againstb07f181d, including #806. - Earlier rounds: still resolved.
GH_TOKENand the enterprise tokens are dropped (:861-865,:925-931), and the plugin-marketplace, BYOK, MCP/LSP and extensions audits are unchanged.
New (optional):
- Optional,
_agent_cli.py:1146,1216: the default-home branch usesos.path.expanduser("~"). A relativeHOMEorUSERPROFILEtherefore resolves against the scanner cwd for the audit, but against the fresh temp cwd in the child. This is the same class as the P1, but I don't consider it blocking: unlike XDG overrides, no legitimate setup uses a relativeHOME, and an attacker who controls the scanner's environment already controlsPATH. A cheap fix is to fail closed when the resolved home base is not absolute. - Optional,
:1227-1231: this comment still says deleting the STATE variable "falls back to an unaudited default". The scrub now deletes it, and:1238-1241audits that default, so please update the comment.
PIC tradeoffs
- The pin is already stale. Copilot CLI 1.0.96 and 1.0.97 are stable releases (1.0.97 on 2026-10-13), and auto-update stays on, so default installs will report
copilot_cliunavailable at merge. Bumping is more than a string change: 1.0.97 adds "agent-scoped declarative hooks for custom agents", a new hook source the audit inventory would need to cover first. That inventory is source-verified at 1.0.92; the 1.0.93–1.0.95 release notes show nothing new, and 1.0.93 narrows user settings tosettings.json. - Fail-closed availability (unchanged): any user hook, plugin, extension, MCP/LSP server or BYOK entry disables the provider.
gh auth tokenfallback (unchanged): this residual is documented in README and DEVELOPMENT.md.
Verification and gaps
- This round's delta: I read
606c2b57..783e4442in full (_agent_cli.py, tests, README, DEVELOPMENT.md) and the upstream merge. - Call path traced:
run_agent_cli→_scrub_env→_prepare_copilot_env→_preflight_copilot_policy→_audit_copilot_home, forCOPILOT_HOME, XDG andHOME. - Vendor notes: I read the Copilot CLI release notes for 1.0.93–1.0.97 as text.
- Unchanged code: I relied on the earlier full 14-file rounds and spot-checked it here.
- Not done: I did not run tests or any Copilot runtime.
- Merge order: #807 edits the adjacent
docs/DEVELOPMENT.mdline, so whichever of the two merges second needs a trivial conflict fix. - Other reviewer: @yashrajp22's 2026-09-19 CHANGES_REQUESTED still needs their re-review or a maintainer dismissal.
…ovider Signed-off-by: Yoseph Zuskin <zuskinyoseph@gmail.com> Co-Authored-By: OpenCode DeepSeek V4.1 Flash Free (200K context) <noreply@opencode.ai>
- Bump _COPILOT_SUPPORTED_VERSION from 1.0.95 to 1.0.98 (current stable; 1.0.96-1.0.98 carry no other sourcing changes) and update the --help/gate citations; the 1.0.95 live nonce citations stay until the 1.0.98 re-probe runs - Audit custom agent files (agents/*.md, nested included) for the agent-scoped frontmatter hooks added in 1.0.97: a truthy hooks map or unparseable frontmatter refuses inference; hook-free, frontmatter-free, and non-md files pass - Tripwire .github/agents in the temp working dir like other repo-level hook sources - Update the stale STATE migration comment per review: the scrubber deletes XDG_STATE_HOME and the default source is audited in place - Fold the new agent-audit test setup into a shared helper - README/DEVELOPMENT pin text to 1.0.98; copilot suite 114 passed / 11 POSIX-skipped; ruff clean Signed-off-by: Yoseph Zuskin <zuskinyoseph@gmail.com> Co-Authored-By: OpenCode DeepSeek V4.1 Flash Free (200K context) <noreply@opencode.ai>
|
A status recap to make re-review easy, plus one question below. Since the September change request, every finding from the earlier rounds @yashrajp22, would you be able to take another look when you have a The new commit bumps the pin to the current stable release and covers Question for the maintainers: the exact-version pin is already stale in Local verification on this head: copilot suite 114 passed, ruff clean, |
- The six heavy params flake just over the 10s bound on coverage-instrumented CI runners: PR #713 (run 39061867915, Windows, 10.30-11.85s) and PR #572 (run 39083380600, Linux, 10.32-11.59s); locally the first heavy param measured 10.41s cold on the same invocation. - 30s keeps a 2.5x margin over the worst CI observation while remaining a smoke bound: the findings, ledger, and recommendation asserts below stay the regression guard. Signed-off-by: Yoseph Zuskin <zuskinyoseph@gmail.com> Co-Authored-By: OpenCode DeepSeek V4.1 Flash Free (1M context) <noreply@opencode.ai>
…ovider Signed-off-by: Yoseph Zuskin <zuskinyoseph@gmail.com> Co-Authored-By: OpenCode DeepSeek V4.1 Flash Free (1M context) <noreply@opencode.ai>
- Bump _COPILOT_SUPPORTED_VERSION from 1.0.98 to 1.0.103 (npm latest, 2026-10-22; 1.0.99 never shipped) and update the --help/gate citations - Re-verify the flag surface on the running binary: all six argv flags still present; 1.0.103 retires the legacy --remote/--no-remote flags (never used here); new --trust-folder (1.0.100) is deliberately not passed so the fresh temp cwd stays untrusted - Release notes 1.0.99-1.0.103 carry no sourcing changes - README/DEVELOPMENT pin text to 1.0.103; copilot suite 114 passed / 11 POSIX-skipped; ruff clean Signed-off-by: Yoseph Zuskin <zuskinyoseph@gmail.com> Co-Authored-By: OpenCode DeepSeek V4.1 Flash Free (200K context) <noreply@opencode.ai>
- Re-probed the real 1.0.103 runtime from a repo cwd and the provider's temp cwd: `-s` stdout carried only the nonce and both calls exited 0 - Both live-provenance comments now cite 1.0.103; drop the pending re-probe note - No behavior change; copilot suite 114 passed / 11 POSIX-skipped; ruff check and format clean Signed-off-by: Yoseph Zuskin <zuskinyoseph@gmail.com> Co-Authored-By: OpenCode DeepSeek V4.1 Flash Free (200K context) <noreply@opencode.ai>
|
Hi @rng1995 and @yashrajp22, Thanks @rng1995 for approving the pre-bump head. Flagging that last push One scope question: would you be open to replacing the exact pin with an |
rng1995
left a comment
There was a problem hiding this comment.
[SkillSpector Review]
Value and readiness
Manual Review Needed at 1a8bde14e48845946e602b7c0edc6daf43bce558. The earlier custom-instruction, per-completion version, hook/migration, extension, token and home-resolution findings are implemented, and all 13 historical threads are resolved. The new agent-frontmatter audit also addresses the later agent-scoped hook surface. I cannot carry the earlier approval across the runtime expansion without settling the startup sources described below.
Material findings
The remaining uncertainty is specific to the pinned runtime, rather than the absence of local test execution. src/skillspector/providers/_agent_cli.py:1189 describes its hook inventory as verified against 1.0.92, while the actual gate now admits 1.0.103. The description says 1.0.99–1.0.103 introduce no sourcing changes, but the official 1.0.100 notes describe automatic trusted-repository plugin installation before chat, and 1.0.101 adds Team-assigned plugins from Team-defined GitHub marketplaces. These are relevant to a presence audit that runs before inference startup. Establish from the exact runtime source whether managed/team/repository activation can introduce hook-capable material after the clean-home checks, and provide focused evidence for the pinned piped-stdin/fresh-directory invocation. If those paths are intentionally covered by the administrator-policy residual, state that boundary explicitly for PIC acceptance. This is an unresolved assurance gap, not a reproduced hook-execution finding.
The earlier required fixes remain resolved: argv disables custom instructions/built-in MCPs; the registered preflight checks every completion before prompt delivery; home/default/XDG trees cover user hooks/plugins/extensions/server/BYOK material; unrelated GH credentials are dropped; the explicit home is absolute and untrimmed; inherited XDG variables are absent. The relative-HOME edge case from the last review remains a previously optional limitation.
PIC tradeoffs
The latest stable upstream release is already 1.0.105 (2026-10-28), following 1.0.104 on October 27. The exact 1.0.103 gate deliberately refuses those versions, so normal auto-updated installs may report this provider unavailable. Decide whether to ship that verified pin or verify a newer one. The stored gh-auth fallback and administrator-owned policy hooks remain documented residuals. Another reviewer's historical CHANGES_REQUESTED still requires their re-review or an authorized maintainer disposition.
Verification and gaps
Read the full current PR diff and pinned transport/provider/test source; traced prepare_env → registered preflight → stdin delivery; reviewed all historical inline findings and author replies plus the latest full approval. Static tests cover hostile environment/argv, version rejection before stdin, hook/migration/server/extension refusal and home-resolution transport. All six hosted checks succeeded. Independently read the official 1.0.100, 1.0.101, and subsequent release notes with gh. I did not inspect the exact 1.0.103 packaged runtime implementation or execute any contributor/vendor runtime or tests; consequently the newly documented activation paths are not established safe by this review.
…ovider Signed-off-by: Yoseph Zuskin <zuskinyoseph@gmail.com> Co-Authored-By: OpenCode DeepSeek V4.1 Flash Free (200K context) <noreply@opencode.ai>
…undary PIC feedback at 1a8bde1 asked whether 1.0.100/1.0.101 plugin and team activation was accounted for. The 1.0.103 pin in that review is already superseded by c577a0d, which pins 1.0.105. - In _agent_cli.py, qualify the preflight as covering local hook sources only: trusted-repository activation is inert in the fresh untrusted cwd, and Team-assigned startup installs are an explicit account/administrator residual, not a claim that the startup tree is hook-free - In _agent_cli.py, record that the 1.0.92 local source-order and XDG audit has no later release-note change and still matches the 1.0.105 packaged runtime tree names - In docs/DEVELOPMENT.md, restore the llm_analyzer_base link and unsplit the CLI-providers blockquote; this is merge hygiene, unrelated to the PIC finding - No behavior, argv, or test changes; copilot suite 114 passed / 11 POSIX-skipped; provider + agent-CLI suites 271 passed / 17 skipped / 4 deselected; ruff check and format clean Signed-off-by: Yoseph Zuskin <zuskinyoseph@gmail.com> Co-Authored-By: OpenCode DeepSeek V4.1 Flash Free (200K context) <noreply@opencode.ai>
|
Hi @rng1995 and @yashrajp22, Your review is against On the 1.0.100/1.0.101 activation point, I inspected the actual 1.0.105
I am not claiming the startup tree is hook-free. The new doc-only commit On provenance: the local hook source order and XDG sets were audited at I also fixed two
No hook execution was observed. Tests: The earlier |
rng1995
left a comment
There was a problem hiding this comment.
[SkillSpector Review]
Value and readiness
Manual Review Needed at 2ac8682ca0943b92e01c155140df74b75f258df8. The author has clarified the startup boundary and updated both runtime gates/tests to the currently published 1.0.105 pin. The earlier stale-pin concern is resolved, and the existing local hook, extension, migration, token and home-resolution fixes remain intact.
Material findings
The prior assurance question is now answered explicitly, but the acceptance decision remains open. src/skillspector/providers/_agent_cli.py:1308-1320 and the PR Risks section acknowledge that Team-assigned plugins can be fetched and installed during startup after the local preflight. A clean local installed-plugins/ tree therefore does not establish the provider's no-hook-execution boundary for those accounts. The code now correctly limits its absence guarantee to local material; it does not prevent that acknowledged account-controlled activation path. The author explicitly requests PIC acceptance of this residual. Record that decision, or provide an enforcement mechanism/proof that excludes such startup activation, before treating the provider as merge-ready. This is the same unresolved boundary from the previous review, rather than a new reproduced execution finding.
All historical local-source blockers remain resolved: custom instructions and built-in MCPs are disabled; the registered version preflight runs before stdin on every completion; default/home/XDG trees are audited; unrelated GH credentials and inherited XDG variables are removed; explicit Copilot homes are absolute and untrimmed; agent-frontmatter hooks are checked. All 12 conversations returned in the current thread snapshot are resolved. The previously optional relative-HOME limitation remains optional.
PIC tradeoffs
The current exact pin admits 1.0.105 only and still fails closed on unverified versions. Local audit provenance remains the 1.0.92 source inventory, supplemented by the author's later runtime/help/live checks. Account/administrator-controlled startup plugins, machine policy hooks and the documented stored gh-auth fallback remain separate residuals for acceptance. Another reviewer's historical CHANGES_REQUESTED still needs their re-review or authorized maintainer disposition.
Verification and gaps
Compared all changed source/tests against the prior completed assessment, inspected the complete current PR diff and upstream integration, reviewed earlier findings/replies, and rechecked the explicit local-versus-account startup documentation. Official gh release metadata confirms 1.0.105 as the current stable release. All six hosted checks succeeded on this head. The author's nonce and file-creation probes are reported evidence; I did not reproduce them or inspect/execute the packaged vendor runtime. No contributor code or tests were executed.
Add
copilot_clisemantic-scan providerProblem
SkillSpector ships CLI providers for Claude, Codex, Gemini, and OpenCode,
but none for GitHub Copilot, so Copilot users get static-only scans
(
llm_availablestays false and the semantic analyzers are skipped) unlessthey provide an OpenAI or Anthropic API key.
Fixes: #8, #680
Approach
copilot_cliprovider mirroring the mergedopencode_clishape:providers/copilot_cli/{provider.py,__init__.py}, registry entry,SKILLSPECTOR_PROVIDER=copilot_cliselection,provider_name()label,CLI help text.
copilot -s --no-ask-userwith no-pflag — the prompt is piped to stdin by run_agent_cli (verified by nonce
round-trip;
-p ""is rejected, so stdin is the cleaner path).Untrusted content never reaches argv; list form throughout, shell never
invoked. Windows hostile-prompt roundtrips covered by test.
--available-toolsnames a fixed implausible tool so the model is offered nothing usable
(verified live: file-creation refused, no side effect), plus
--deny-tool shell,writebelt-and-braces in the documentedKind(argument)form (deny wins over allow). Never--allow-all*.--model <label>validated and forwarded only whenSKILLSPECTOR_MODELis set;
max_output_tokensaccepted for CliSpec uniformity and ignored.copilot --versionwith a 15s timeout, scrubbed env,fail-closed: non-zero exit, unparseable output, or anything but the
pinned
1.0.105fails. No status subcommand exists; authentication worksvia login session or
COPILOT_GITHUB_TOKEN(_prepare_copilot_envre-reads only that token plus
COPILOT_HOME, dropping every otherCOPILOT_*, allGITHUB_COPILOT_*,GH_TOKEN, and the enterprisetoken variables; the shared scrub strips them too).
COPILOT_AUTO_UPDATEis deliberately neither forwarded nor forced:disabling updates selects an older cached runtime generation (probed
2026-09-23), which would brick the version pin; mid-scan drift is
covered by the per-completion version preflight instead.
copilot --versionunder theisolated child env on every call (a swapped/updated binary never
receives scan content), then audits the copilot home
(
installed-plugins/,extensions/,hooks/*.json, inlinehooksplus
enabledPlugins/extraKnownMarketplacesinsettings.json,user
mcp-config.json/lsp-config.json,providers.json), customagent files (
agents/**/*.md, nested included — a truthy frontmatterhooksmap or unparseable frontmatter refuses, covering 1.0.97'sagent-scoped declarative hooks), and the fresh temp working dir
(
.github/agentsjoins the repo-level hook tripwires) — inferencerefuses when hook/server material is present. No model registry (CLI
fallback, per the registry-split lesson).
COPILOT_HOMEis forwardedscanner-resolved absolute (no trim, no tilde expansion), so the
audit and the child name the same tree for relative and
trailing-space forms. Inherited
XDG_CONFIG/STATE_HOMEneverreach the child (shared allowlist scrub strips them); the audited
defaults apply. Transport regressions use an env-recording
stand-in through the real temp-cwd path.
_prepare_copilot_envpreservesonly
COPILOT_GITHUB_TOKENthrough the scrub (everything elseCOPILOT_*, allGITHUB_COPILOT_*,GH_TOKEN,GH_ENTERPRISE_TOKEN,and
GITHUB_ENTERPRISE_TOKENare dropped). Rationale: it is the CLI'sdocumented headless auth path — without it, token-only CI setups cannot
use the provider at all, and the issue being resolved is precisely
keyless operation. A CI
ghworkflow token must never become theagent's credential. The model itself gets no tools, so it cannot read
the environment; the CLI redacts these variables from its own output by
default. Residual (inherent to Copilot auth): the CLI falls back to
gh auth tokenwhen no other credential is available, so a stored ghlogin can still reach the child. If reviewers prefer login-only, the
fallback is a one-line change (extend the scrub, document fail-closed
for token setups).
.env.example,docs/DEVELOPMENT.md); provider tests live intests/provider/per repo convention.
Verification
tests/provider/test_copilot_cli.py: 114 passed, 11 POSIX-skipped(TDD: argv, auth, parser, wiring, registry label, agent-file hook
audit, adversarial). Combined with
tests/unit/test_agent_cli.py:199 passed / 11 skipped on
c577a0d7.Linux-CI follow-up fixed in-file: the fake
copilotstub readATTACK_MARKERS/FAKE_COPILOT_VERSIONfrom the scrubbed childenv and crashed with
KeyError(POSIX-gated, never seen onWindows); markers path and version are now baked into the stub
source at write time, mirroring
test_opencode_cli.py. Noproduct-code change.
tests/unit/test_agent_cli.pyregistry loop extended; adversarialfake-host checks (deny posture + hostile env) verified via a Windows
stand-in run: policy held, zero markers.
tests/provider,tests/unit/test_agent_cli):271 passed / 17 skipped / 4 deselected on this head.
ruff check+ruff format --check: clean on all ten touched Python files(
_agent_cli.py,_agent_cli_base.py,providers/__init__.py,copilot_cli/{__init__,provider}.py,cli.py,llm_utils.py,inference_usage.py,tests/provider/test_copilot_cli.py,tests/unit/test_agent_cli.py).--helpflag surface present (incl.
-s,--model, no hook off-switch), theinstalled 1.0.105 binary parses and passes the version gate, and the
six argv flags still exist. The exact pin stays deliberate: this bump
admits 1.0.105 only, not a range; 1.0.104 is still refused because it
was skipped, not re-verified. Provider
argv does not pass
--trust-folder(added 1.0.100) or anyteam/plugin activation surface (1.0.101's
--plugin-dirandpluginsubcommand are unused), so the fresh temp cwd stays untrusted and no
user/team plugin is activated by argv; the existing preflight audit
still refuses a non-empty
installed-plugins/tree. 1.0.100-1.0.105 add--trust-folder,--disable-client-telemetry,--sync-session, andhosting flags, and retire the legacy
--remote/--no-remoteflags(never used here);
--trust-folderis deliberately not passed. No1.0.93-1.0.105 release note announces a change to the audited local
hook source order or XDG migration sets; 1.0.100/1.0.101 add startup
plugin activation, documented as an explicit residual under Risks. The
live nonce round-trip (2026-10-28: answered exactly via the provider's
run_agent_clitemp cwd and from a repo working dir,-sstdoutcarries only the response text) is proven on 1.0.105; a file-creation
probe was refused with zero side effects under the same argv. The
1.0.92 release-source note stays (static source analysis for the
audited local sources, pinned deliberately).
upstream/main(d501c0d5, 2026-10-28), committed asc577a0d7; the merge left the tree clean and the merge commit unamended.Two doc-only edits in this branch are listed below. The only
conflict (
README.md, provider/CLI notes reworded by both sides) was resolvedto the union — upstream's multi-version
opencode_clinote kept verbatimalongside this branch's
copilot_clipin and gh-token residual.docs/DEVELOPMENT.mdfound while verifying themerge: the
llm_analyzer_basesource link is restored tosrc/skillspector/llm_analyzer_base.py(this branch had reverted upstream1d09e807to a nonexistentnodes/path), and thecopilot_clitokensentence is folded back into the single CLI-providers blockquote. No
behavior change.
_agent_cli.pydocstrings now record the local audit provenanceand the account/team startup boundary; this changes comments only.
upstream/main: 14 files changed, 2282 insertions(+),24 deletions(-) (1487 of the additions are
tests/provider/test_copilot_cli.py).Sample
Probe scan of one small skill returned
risk: score 0 / LOW / SAFE,llm_calls_attempted: 3,llm_calls_succeeded: 3, zero findings.Risks
and updates trusted-repository plugins before chat, but that path is
gated on folder trust; the fresh
mkdtempcwd is untrusted,--trust-folderis not passed, andCOPILOT_ALLOW_ALLis not set, soit is inert. 1.0.101 can assign Team plugins from Team-defined
marketplaces; the CLI fetches that assignment from the account and may
install missing plugins during its best-effort startup preparation,
after the local preflight. The preflight can audit
installed-plugins/before startup but cannot see an account assignment or a startup
download. This is an explicit account/administrator-policy residual,
not a claim that the startup tree is hook-free; PIC acceptance is
requested.
them — probes only, no bulk scanning on Free.
--available-toolsfixed-name posture depends on unknown names stayinginert (verified behavior: silent acceptance); the version
gate pins exactly 1.0.105 so any CLI behavior change fails closed first.
The exact pin is deliberate (matches the merged
opencode_clipolicy):the tool-deny behavior was verified against this release, and a silent
sandbox change must never pass unnoticed. Re-verification per Copilot
release is the known maintenance cost.
Signed-off-by(maintainer: verify on push).