Commit Graph

8 Commits

Author SHA1 Message Date
Stefan Broenner 3ad8ca3831 Verify plugin runtime downloads (#813)
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>
2026-08-24 19:42:27 +02:00
Stefan Broenner d43a165f85 Preserve Agent Plugins 1.0 source fixes (#811)
* fix(plugin): preserve Agent Plugins 1.0 source

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* docs(plugin): define publication source of truth

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Stefan Broenner <stbrnner@microsoft.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
2026-08-24 15:40:28 +02:00
Stefan Broenner 3aa557cd7f fix(plugins): harden the runtime bootstrap against corrupt caches and races (#790)
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
2026-08-20 04:55:19 +00:00
Stefan Broenner f3f80acbf2 fix(plugins): preserve quoted arguments and survive an unreachable release API (#779)
* 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
2026-08-20 04:50:31 +00:00
Stefan Broenner b2eab4ca91 Migrate plugins to Agent Plugins 1.0 (#776)
Build plugins from canonical source templates, validate portable manifests and MCP configuration, synchronize complete Agent Skill directories, and scope Excel E2E to runtime-impacting changes.

Tests: 23 targeted SkillGeneration tests passed; Release build completed with 0 warnings and 0 errors; Excel E2E path classification passed for 12 cases; MCPB and Agent Skills packaging passed.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Co-authored-by: Stefan Brönner <sbroenne@openclaw.fritz.box>
Copilot-Session: 858e5fa0-f0ef-490f-a154-00c470943904
2026-08-16 10:11:38 +02:00
github-actions[bot] 352b1da895 Revert: remove RELEASE_PAT verification scratch file [skip ci]
Reverts the scratch verification commit; confirms PAT push authentication
and ruleset bypass work end-to-end for the release-automation fix.
2026-07-23 09:40:03 +02:00
github-actions[bot] f1d85698f3 test: verify RELEASE_PAT can push directly to protected main [skip ci]
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.
2026-07-23 09:39:47 +02:00
Stefan Broenner 3b54044d39 Ship plugin bootstrap runtime wrappers and packaging validation
## Summary
- Ship bootstrap-only Copilot CLI plugin packages for Excel CLI and MCP runtime launchers.
- Auto-download the latest self-contained Windows runtime on first invocation and refresh through wrapper scripts.
- Keep public skills concise by moving detailed CLI command guidance into references/cli-commands.md.
- Add packaging regressions for plugin bootstrap assets and CLI command reference inclusion.

## Validation
- dotnet test tests\ExcelMcp.SkillGeneration.Tests\ExcelMcp.SkillGeneration.Tests.csproj --filter "FullyQualifiedName~PluginBootstrapBuildTests|Feature=SkillGeneration" --blame-hang-timeout 5m --no-restore

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-27 13:35:17 +02:00