Pin workflow actions to commit SHAs and sign the SSMS extension - #610
Merged
Merged
Conversation
Every `uses:` line in .github/workflows now names a 40-character commit SHA, with the exact version tag in a trailing comment. Each pin is the commit that the major tag pointed at, so no action changes version: checkout v7.0.1, setup-dotnet v6.0.0, upload-artifact v7.0.1, deploy-pages v5.0.1, upload-pages-artifact v5.0.0, setup-msbuild v3.0.0, signpath submit-signing-request v3.0, paths-filter v4.0.3 and claude-code-action v1.0.236. .github/dependabot.yml already has a github-actions entry (directory /, target-branch dev, weekly on Monday), so Dependabot keeps proposing updates to the pins and rewrites the version comments. No change there. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019n3G844aTidqrD6A6iMgza
release.yml built PlanViewer.Ssms.vsix and InstallSsmsExtension.exe but uploaded them unsigned. They now go through SignPath, using the "Vsix" artifact configuration in the PerformanceStudio project. New steps, after the App is signed and before the release is created: - Stage the two files at the root of ssms-unsigned/ and upload that folder as the Ssms-unsigned artifact (if-no-files-found: error). - Submit it to SignPath: same organization, project, policy and 1800 s timeout as the App, artifact-configuration-slug Vsix, output in signed/ssms. - If signing succeeded, copy both signed files over the ones in releases/. The release upload, the SSMS Gallery upload and the checksums all read from releases/, so they use the signed files. - If it did not, write a ::warning:: annotation and ship the unsigned files, which is what the release did before. SSMS problems must never block the cross-platform release, so the staging, upload and signing steps are all continue-on-error. The copy step is gated on the signing step's outcome, not its conclusion, and copies both files or neither. SHA256SUMS.txt now also lists PlanViewer.Ssms.vsix and InstallSsmsExtension.exe when they were built. The line format is unchanged. Each SignPath request needs a manual approval, so a release run now waits for two approvals: the App first, then the SSMS files. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019n3G844aTidqrD6A6iMgza
erikdarlingdata
marked this pull request as ready for review
September 28, 2026 22:54
- Replace step: if copying a signed file fails, put the unsigned pair back from ssms-unsigned/ and warn, instead of stopping the release. The job stops only if that restore fails, before anything is published. - Upload SSMS extension to release: continue-on-error, so a failed SSMS upload no longer stops the App files from reaching a release that already exists. - Installer: Release builds look for the VSIX only in the argument or next to the exe. The build-folder search is now Debug-only. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019n3G844aTidqrD6A6iMgza
|
Reviewed the workflow and installer changes. I found nothing that needs fixing before merge.
One thing to be aware of: this now needs two manual SignPath approvals per release. The SSMS one falls back to unsigned after a 30-minute timeout. |
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.
What does this PR do?
This PR hardens the GitHub Actions workflows. It has three commits.
Which component(s) does this affect?
The SSMS box is checked because the release now signs the extension and its installer, and commit 3 changes the installer. Every other change is in
.github/workflows.Commit 1: pin actions to commit SHAs
Every
uses:line in.github/workflowsnow names a full 40-character commit SHA. A comment after the SHA names the exact version tag. The change touches 23 lines in 8 files.Each pin is the commit that the action's major tag pointed at. So no action moves to a new version. I resolved each SHA with
gh api repos/OWNER/REPO/commits/TAG. I then found the exact version tag on that commit. After the edit, I resolved each exact tag and each major tag again. Both matched the SHA in the file.3d3c42e5aac5ba805825da76410c181273ba90b1a98b56852c35b8e3190ac28c8c2271da59106c68043fb46d1a93c77aae656e7c1c64a875d1fc6a0a368f82528645a54fb793d4d04e342629a3f51346fc324d3547104276b827a68afc52ff2a11cc49c930375c66a4eea26614e0d39710365f22f8b0af57f6d04783b4569d051e0c80105fe66e82819d0092ceb8a2b8f2d89434be7ff52d3de7ec3738c5cc9d8ce9314fa9a404564fa7e954cd84f25bcba2b829.github/dependabot.ymlalready has agithub-actionsentry, added in commit 06a0081. It usesdirectory: "/"andtarget-branch: dev. It has the same weekly Monday 06:00 America/New_York schedule as the nuget entry. Dependabot updates a SHA pin and its version comment together.I added no second entry, because a second entry duplicates the first. The existing entry uses the commit prefix
ci, and the nuget entry usesdeps. I left the prefix alone.Commit 2: sign the SSMS extension and installer
The release built
PlanViewer.Ssms.vsixandInstallSsmsExtension.exebut uploaded them unsigned. This commit adds five steps torelease.yml. They run afterReplace unsigned Windows build with signedand beforeCreate release. Each step runs only when the SSMS build step setBUILTtotrue.Stage SSMS files for signingcopies exactlyInstallSsmsExtension.exeandPlanViewer.Ssms.vsixto the root of a new folder namedssms-unsigned.Upload SSMS files for signinguploads that folder as the artifactSsms-unsigned, withif-no-files-found: error.Sign SSMS extension and installersubmits the artifact to SignPath with theVsixartifact configuration. It uses the same organization, project, policy and 1800 second timeout as the App. It saves the signed files insigned/ssms.Replace unsigned SSMS files with signedcopies both signed files over the files inreleases/. It runs only when step 3 has the outcomesuccess.Warn that SSMS files are unsignedwrites a::warning::annotation. It runs when step 3 has any other outcome.The upload to the GitHub release, the upload to the SSMS Gallery and the checksums all read the files in
releases/. So they use the signed files.SHA256SUMS.txtnow also listsPlanViewer.Ssms.vsixandInstallSsmsExtension.exewhen they were built. The line format did not change. The zips come first, and the two SSMS files follow them.When signing fails
Steps 1 to 3 have
continue-on-error: true. A failed signing request does not stop the release. An approval that times out does not stop it either. The release then ships the unsigned SSMS files, as it did before this PR. Step 5 writes the warning that the SSMS files shipped unsigned.Step 4 copies both files or neither. If SignPath reports success but a signed file is missing, step 4 writes a warning and keeps both unsigned files. Commit 3 covers a copy that fails partway.
I also set
continue-on-error: trueon steps 1 and 2. The workflow already says that a VSIX problem must never block the cross-platform release. Without it, a failed artifact upload stops the job before it creates the release.Commit 3: fail-safe steps and the installer's search
Replace unsigned SSMS files with signedno longer stops the release when a copy fails. The step then copies both unsigned files back fromssms-unsigned/and writes a warning, and the release ships both unsigned files. The step fails only if that copy back fails too. The step has nocontinue-on-error, so the job then stops beforeCreate releaseand nothing is published. A pair of one signed file and one unsigned file is never published.Upload SSMS extension to releasenow hascontinue-on-error: true, like the SSMS Gallery step after it. The release already exists when this step runs. Before this change, a failed SSMS upload stopped the job, and the release had no App files.InstallSsmsExtension.exelooked forPlanViewer.Ssms.vsixin three kinds of places: the path in its argument, its own folder, and build output folders near it. Release builds now look only in the first two. Debug builds still search the build folders.Two approvals per release
SignPath requires a manual approval for each request (FOSS plan). A release run now waits for two approvals. The App request comes first. The SSMS request comes second. Each request waits up to 30 minutes. If nobody approves the SSMS request in time, the release continues with the unsigned SSMS files and the warning.
Location of the DLL in the VSIX
The
Vsixartifact configuration in SignPath expectsPlanViewer.Ssms.dllat the root of the VSIX. It is there. The project file setsIncludeAssemblyInVSIXContainerto true and sets noVSIXSubPath. The v1.27.0 release VSIX lists the DLL at its root, next toextension.vsixmanifestandPlanViewer.Ssms.pkgdef. That DLL is the only PE file in the VSIX. No change is needed on the SignPath side.How was this tested?
I cannot run the release, so I checked the change in these ways.
yamlparses every workflow anddependabot.yml.actionlint1.7.12 reports no findings for.github/workflows. It reported none before my change either.release.ymldiff by hand. Everyif:and everysteps.<id>reference points to an earlier step. The output names areartifact-idfrom the upload step andBUILTfrom the SSMS build step.$ErrorActionPreference = 'stop'. The stage block copies exactly two files. The replace block copies both signed files, and it copies nothing when one is missing. The checksum block writes six lines when the SSMS files were built and four when they were not. Each hash matched its file.releases/were unsigned.PlanViewer.slndoes not include the installer, so pull-request CI does not build it. I built it in Release and in Debug, with 0 warnings each time. The Release exe no longer contains the build-folder paths, and the Debug exe still does.dependabot.yml.Not done
Vsixconfiguration, the output foldersigned/ssmsand the approval wait. If any of them fail, the release still ships the unsigned files with the warning.nightly.ymldoes not build the SSMS files, so it has no signing change.dev, the review bot skips every pull request todevuntildevis merged tomain. The bot runs only when its workflow file matches the copy onmain, and this PR changes that file. A skipped review still shows as a passed check. Each merged Dependabot update toclaude-code-actionhas the same effect.ci. If you want the prefix to match the nuget entry, change it todeps.🤖 Generated with Claude Code
https://claude.ai/code/session_019n3G844aTidqrD6A6iMgza