Release v1.18.0 - #405
Merged
Merged
Conversation
Dependabot (.github/dependabot.yml): Covers all 8 project directories explicitly rather than the solution, because PlanViewer.sln does not contain server/PlanShare, PlanViewer.Ssms, or PlanViewer.Ssms.Installer - a solution-level scan silently skips them, which is how PlanShare drifted. Also covers github-actions. Minor/patch are grouped into one PR per ecosystem; majors stay separate so a breaking change is never buried in a batch. Ignore rules encode the deliberate pins, without which Dependabot would file PRs that break the build or ship a broken runtime: - Avalonia* major: 12 is a parked migration (upgrade/avalonia-12) - ScottPlot.Avalonia >= 5.1.59: requires Avalonia 12 and NU1605s. This is a PATCH bump, so an update-type ignore would not catch it. - SkiaSharp.NativeAssets.* major: the pin exists to keep native libs in the range managed SkiaSharp 3.x needs (GitHub issue #139) - Microsoft.VisualStudio.SDK / VSSDK.BuildTools major: 18.x targets VS 18 and is not restorable from nuget.org - Velopack: must move in lockstep with the vpk CLI pin in release.yml Repository-side Dependabot alerts and automated security fixes were disabled; both are now enabled. Deployment (.github/workflows/deploy-planshare.yml): PlanShare had no deploy path at all - server/** is paths-ignored by CI and it is absent from the solution, so a merged PR shipped nothing. Production had drifted ~3.5 months behind main, missing the XSS fix (#249) and the change from Random.Shared to RandomNumberGenerator for share IDs, where the 8-char id is the only access control on a shared plan. Triggers on push to main touching server/PlanShare/**, plus manual dispatch. Backs up binary, native lib, and plans.db before swapping, restarts, verifies through nginx, and rolls back automatically if verification fails. Keeps the 3 most recent backup sets. Security posture: authenticates as a dedicated unprivileged `deploy` user, not root, with a CI-only keypair (not a personal key). Its sudo rights are limited to restarting and querying this one unit; verified that stopping nginx and reading /etc/shadow are refused. The host key is pinned rather than accepted on first use. Verified end-to-end using the restricted key: upload, backup, swap, restart, and nginx verification all succeed, service active, existing shared plan still returns 200. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Policy (.signpath/policies/PerformanceStudio/release-signing.yml): Path must match the project-slug and signing-policy-slug passed to the SignPath action in release.yml. Only takes effect from the default branch (main), so it is inert until the next dev -> main merge. It requires GitHub-hosted runners, so a self-hosted runner - which an attacker could register, or which could carry dirty state between jobs - can never produce a signed build. Note this file does NOT enable automatic approval; approval mode is a setting on the signing policy in the SignPath dashboard. This file adds constraints SignPath enforces before it will sign. Two fields are deliberately omitted, documented inline, because adding them without the matching repo change would break signing outright: - build.disallow_reruns would have blocked the v1.17.0 recovery, since re-running is the current remedy for a signing failure that already published an empty release. - branch_rulesets requires the protections it names to actually exist, and main currently has no branch protection at all, so any ruleset rule would reject every signing request. Timeout (release.yml): the SignPath action defaults to 600s, so a policy requiring manual approval must be approved inside 10 minutes or the job fails after the release is already published - which is exactly how v1.17.0 ended up public with only the VSIX attached. Raised to 1800s. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
First live run of the review workflow failed on PR #399: permission_denials_count: 10 ##[error]Execution failed: Reached maximum number of turns (20) --allowedTools REPLACES the default tool set rather than adding to it, so the resolved list was exactly the four entries I passed - no Read, Grep, or Glob. The prompt tells the reviewer "the PR branch is already checked out in the working directory", then denied it every tool needed to open a file. It spent its turns on denied calls and hit the cap without posting a review. PR #400 passed only because its diff is two small files, so it fit. Adds Read/Grep/Glob plus read-only git diff/log, and raises the cap to 40 turns since a real review needs to read several files. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Add SignPath GitHub policy and raise the signing timeout
…lanshare-deploy Add Dependabot config and automated PlanShare deployment
Fix PR reviewer: it was denied the tools needed to read code
"Get Actual Plan" on a loaded plan file prompted for a connection and then ran the query. The query-session path already confirmed first; this one did not, and it is the riskier of the two - the SQL comes out of a .sqlplan the user opened rather than something they typed, and plan files get emailed around. The dialog names the target server and database, so "which server was that?" is answered before the query runs rather than after. Extracts the dialog into Dialogs/ConfirmationDialog.cs instead of copying it. The two paths having separate implementations is how one of them ended up with no confirmation at all; DdlScripter has the same history of a duplicated helper drifting. QuerySessionControl now delegates to the shared version, so its behavior is unchanged. Verified: clean build 0 warnings, 202/202 tests, app launches and paints. AppButton resolves from Application.Resources, so looking it up from the owner window works the same as from the control. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Both from the quarterly maintenance security review. Search order: FindApp checked PATH before the known install locations, so any writable directory on PATH holding a PlanViewer.App.exe would be launched instead of the installed app. PATH is now the last resort, behind the installer-written registry value and the real install paths. Temp files: every analysis wrote %TEMP%\ssms_plan_<random>.sqlplan and never removed it, so query text and literal parameter values from every plan ever opened accumulated at rest. Files are swept on the way in rather than deleted after launch, because the file is handed to another process to open and deleting it immediately would race that read; anything older than an hour has certainly been read. Cleanup is best-effort throughout - a file that cannot be deleted must never break opening a plan. Verified by building the VSIX locally with MSBuild (Build Tools 2022): produces PlanViewer.Ssms.vsix with no errors or warnings. Worth doing by hand since ci.yml paths-ignores this project and release.yml only builds it under continue-on-error, so a break here would surface as a release silently missing the VSIX. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Confirm before executing a plan file's query against a server
Harden SSMS launcher: PATH search order and temp file cleanup
All four version sources, kept in sync: - src/Directory.Build.props (single source for SDK-style projects) - src/PlanViewer.Ssms/source.extension.vsixmanifest - src/PlanViewer.Ssms/Properties/AssemblyInfo.cs - CITATION.cff The two SSMS files are not covered by Directory.Build.props because PlanViewer.Ssms is a legacy non-SDK project, so they are bumped by hand. date-released in CITATION.cff is already today. Verified: clean Release build 0 warnings, 202/202 tests, no stale 1.17.0 strings remaining. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Bump version to 1.18.0
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Release v1.18.0. Merging this triggers
release.yml: builds and publishes win-x64, linux-x64, osx-x64, osx-arm64, signs Windows via SignPath, packs and uploads Velopack, builds the SSMS VSIX and pushes it to the SSMS Gallery.This is the release that turns on everything built today
Each of these only takes effect from the default branch, so they have been inert on
devuntil now:PlanViewer.slnomitsserver/PlanShareand both SSMS projects, which is how PlanShare drifted 3.5 monthsmaintouchingserver/PlanShare/**; backs up binary, native lib and DB, restarts, verifies through nginx, rolls back on failure. Runs as an unprivilegeddeployuser, not rootRead/Grep/Glob, so it spent its turns on permission denials and posted nothingSecurity fixes
Consent before executing a plan file's query (#402). "Get Actual Plan" on a loaded plan prompted for a connection and then ran the query. The query-session path already confirmed first; this one did not - and it is the riskier of the two, since the SQL comes from a
.sqlplanthe user opened rather than something they typed. The dialog names the target server and database. Extracted into a sharedConfirmationDialograther than copied, because two independent copies is exactly how one path ended up with no confirmation at all.SSMS launcher hardening (#403).
PATHwas searched before the known install locations, so any writable directory onPATHcontaining aPlanViewer.App.exewould be launched instead of the installed app. And every analysis left a%TEMP%\ssms_plan_*.sqlplancontaining query text and literal parameter values, permanently.Not included
#388 (Repl pilot) remains open and deliberately excluded - it is still a draft, and its author describes it as an unsolicited proposal for which "declining or closing it is a completely valid outcome".
Verification
1.17.0release.ymlbuilds it undercontinue-on-error, so this is its only pre-release signalmainat 1.17.0, socheck-version-bumppasses andrelease.ymlwill create a new release rather than clobbering v1.17.0Signing will pause and needs you
SignPath offers manual approval only. The job will sit at "Sign Windows build" waiting. If it is not approved, the run fails after the release is already published, leaving it public with only the VSIX attached - exactly what happened to v1.17.0. The window is now 30 minutes rather than 10.
🤖 Generated with Claude Code