Harden the app's local surfaces: pipe, About links, SSMS temp plans, MCP host - #596
Conversation
…MCP host - Single-instance pipe: the app's server and client use PipeOptions.CurrentUserOnly (built in SingleInstance). The SSMS extension checks the pipe owner by hand (.NET Framework has no client option), accepting the user or token owner SID. - About window: OpenUrl opens only absolute http/https addresses. - SSMS handoff: the app deletes ssms_plan_*.sqlplan from the temp folder once read, and treats the tab like a pasted plan (no source path, not recent, not restored). - MCP host: CreateEmptyBuilder + UseKestrelCore + AddRoutingCore, so no appsettings or environment Kestrel section can add endpoints; requests from a non-loopback address get a 403. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G625JBNh45iTR1hpT4CxNR
A file that fails to load, or to delete, is left for the extension's sweep of files older than an hour. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G625JBNh45iTR1hpT4CxNR
|
Reviewed the diff. No blocking issues. Two low-severity notes:
The rest looks fine: the pipe owner check, the http/https-only |
What does this PR do?
Tightens four places where the desktop app deals with other processes or with the shell.
Single-instance pipe (
SingleInstance,Program,MainWindow, and the SSMS extension'sAppLauncher):PipeOptions.CurrentUserOnly, so only the user who started the app can connect to it.SingleInstance, so a test can check them.About window:
OpenUrlopens only absolute http and https addresses. The update link's address comes from the release server's reply.Plans sent from SSMS: the extension hands each plan to the app as
ssms_plan_*.sqlplanin the temp folder. The app now deletes that file once the plan loads. A file that fails to load stays for the extension's sweep. The tab then works like a pasted plan. It has no file behind it, it is not on the recent list, and it does not come back at the next start. "Save .sqlplan" still saves it.The app deletes only a file with that name directly in the temp folder, and only on Windows. The extension's sweep of files older than an hour stays as a backstop.
MCP server (
McpHostService):WebApplication.CreateEmptyBuilder, with Kestrel and routing added in code.CreateBuilderalso read appsettings files from the working directory and the process's environment variables. A Kestrel section in either one added endpoints beside the loopback one.Which component(s) does this affect?
How was this tested?
McpHostServiceTests: starts the real server on a free loopback port. An MCP client lists the tools and callslist_plansover HTTP. A request with another host name gets a 403. Loopback addresses pass the address check, IPv4-mapped ones included, and other addresses fail it.SingleInstanceTests: a line sent through the pipe arrives. On Windows, the pipe's access list has one entry, for its owner.AboutWindowLinkTests: http and https addresses open. File paths, network paths and other schemes do not.SsmsHandoffTests: a plan from SSMS is deleted once it is read, and it is on neither the recent list nor the restore list. A file with the same name in another folder is kept.Checklist
--no-incremental)dotnet test)🤖 Generated with Claude Code
https://claude.ai/code/session_01G625JBNh45iTR1hpT4CxNR