Publish SHA-256 checksums for Windows runtime archives and require both plugin bootstraps to verify fresh and cached downloads before extraction.
Co-authored-by: Stefan Broenner <stbrnner@microsoft.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Follow-up to the offline-fallback fix. Six independent failure modes, each
reproduced against the real 1.10.7 cache before being fixed.
A truncated archive wedged the plugin permanently: the cached tag still
matched, so no download was attempted, yet extraction failed on every run
thereafter. Presence was being treated as integrity. The archive is now
opened and validated before it is trusted, downloads land in a temp file
that is renamed into place, and a failed install retries once with a fresh
download instead of failing forever.
Extraction deleted the release directory up front. Remove-Item -Recurse
removes every sibling file before it reaches a locked executable and then
fails, which destroyed a working install and left nothing usable behind.
Extraction now stages into a scratch directory and swaps it in, and the
executable is probed for a lock before anything is removed, so a runtime
that is currently running is kept rather than half overwritten.
Concurrent sessions raced on the same archive path and release directory;
installs are now serialized with a named mutex.
Release lookups now send GITHUB_TOKEN or GH_TOKEN when present.
Unauthenticated GitHub API access is 60 requests/hour per source IP, shared
by everyone behind a corporate NAT, and is the usual reason the metadata is
unreachable in the first place.
Outside a Copilot session the session id is the constant "standalone", so
it always equalled the previously recorded one and the freshness check
never fired again. PATH and shim installs were pinned forever to whatever
they first downloaded. Those now re-check on a time window.
The resolved runtime's version is verified from the version stamped into
the file rather than by running it with --version, which performs its own
network update check and would defeat the point of an offline-safe path.
Nine new tests cover these paths; each was mutation-verified to fail
against the unfixed script. The harness now builds real archives so
integrity handling is exercised rather than mocked away, and it scrubs
COPILOT_AGENT_SESSION_ID, GITHUB_TOKEN and GH_TOKEN so an ambient
environment cannot change what the tests actually assert.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: edb4d8c2-36e0-4719-ab55-4d501b7a2462
* fix(plugins): preserve quoted arguments and survive an unreachable release API
Two defects made the published excel-cli and excel-mcp plugins fail in normal use.
Quoted arguments were destroyed in transit. Windows PowerShell rebuilds the command
line when invoking a native executable and drops embedded double quotes, so every
documented inline JSON example arrived as [[Name,Amount]] instead of
[["Name","Amount"]] when run through the plugin wrapper or the generated PATH shim.
Escaping at the call site cannot fix this. start-cli.ps1 now builds the command line
itself using the standard MSVCRT quoting rules and passes it to ProcessStartInfo
verbatim; stdio is inherited, so interactive and piped use are unchanged. The .cmd
shim had a second, independent mangling layer -- powershell -File strips quotes
before the wrapper ever runs -- so it now resolves the executable up front and
invokes it directly, letting cmd forward %* untouched.
The bootstrap also aborted whenever the GitHub release API was unreachable, even
with the correct runtime already downloaded and extracted. A rate limit (60/hr per
IP, shared behind corporate NAT) or an offline machine therefore stopped the MCP
server from starting at all. A failed freshness check now degrades to the cached
runtime and warns on stderr -- never stdout, which carries the resolved path and is
the MCP stdio channel -- and records the attempt so one dead endpoint is not retried
by every command in the session. With no usable cached runtime the failure stays
loud and still points at the release page.
Relatedly, the download was attempted before checking whether a valid runtime was
already present, leaving the early return unreachable. Any cleanup tool that
reclaimed the cached .zip bricked the plugin offline even though the extracted
binary was intact and tag-matched. Resolution now happens first and short-circuits.
The two download.ps1 copies remain byte-identical modulo 13 plugin-specific tokens;
a normalize-and-compare test now enforces that so a fix applied to one and forgotten
in the other fails in CI instead of shipping. Argument escaping is verified by
round-tripping through CommandLineToArgvW, the same parser the CRT uses to split a
process command line, which keeps the assertion independent of the PowerShell
version running the tests.
start-mcp.ps1 shares the wrapper pattern but is deliberately left alone: it never
receives arguments, so the bug cannot manifest there, and it is not worth perturbing
the MCP stdio handshake in a fix release.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: edb4d8c2-36e0-4719-ab55-4d501b7a2462
* fix(plugins): validate download.ps1 before writing excelcli shims
install-global.ps1 generates a .cmd shim that resolves the runtime by
invoking bin\download.ps1, but it only validated that bin\start-cli.ps1
existed. With download.ps1 missing or corrupt the installer reported
success and wrote shims that failed later, at first use, with an opaque
error from cmd rather than a pointer to the real problem.
Guard the dependency up front, alongside the existing wrapper check and
before any shim or PATH mutation, so a broken plugin tree fails fast and
leaves nothing behind.
The new test pins the "leaves nothing behind" half specifically: it runs
the real installer against a sandbox plugin tree with only download.ps1
absent, redirects USERPROFILE so a regression writes into the sandbox,
and asserts both a non-zero exit and that ~/.copilot/bin was never
created. Mutation-verified: removing the guard makes it fail.
excel-mcp's installer has no such dependency, so this is excel-cli only.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: edb4d8c2-36e0-4719-ab55-4d501b7a2462
---------
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: edb4d8c2-36e0-4719-ab55-4d501b7a2462
This is a scratch verification commit for the release-automation fix in
PR #739 (direct changelog push using RELEASE_PAT as a ruleset bypass
actor). It will be reverted immediately by a follow-up commit.