Repository navigation
Add assembly signing for Microsoft.SqlServer.Server - #4566
paulmedynski wants to merge 3 commits into
Conversation
There was a problem hiding this comment.
Pull request overview
Updates the Azure DevOps pipeline templates to enable strong-name (assembly) signing for Microsoft.SqlServer.Server in internal build scenarios, and centralizes secure-file key download logic into a reusable step template.
Changes:
- Added a shared
download-assembly-signing-key.ymlstep template to download signing keys from secure files. - Threaded
isInternalBuild(andreferenceType) through the CI core → SqlServer stage/job to conditionally applySigningKeyPathduring packing. - Updated OneBranch build steps and the internal package CI pipeline to use the shared download template and the new
driverKeyFilereference.
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| eng/pipelines/stages/build-sqlserver-package-ci-stage.yml | Adds referenceType / isInternalBuild parameters and forwards them to the SqlServer pack job. |
| eng/pipelines/onebranch/steps/build-buildproj-step.yml | Switches to the shared signing-key download template and uses driverKeyFile.secureFilePath. |
| eng/pipelines/onebranch/jobs/validate-signed-package-job.yml | Comment wording tweak around strong-name signing verification. |
| eng/pipelines/jobs/pack-sqlserver-package-ci-job.yml | Conditionally downloads signing key + passes SigningKeyPath for internal Package-mode packing. |
| eng/pipelines/dotnet-sqlclient-ci-project-reference-pipeline.yml | Passes isInternalBuild into the core template based on System.TeamProject. |
| eng/pipelines/dotnet-sqlclient-ci-package-reference-pipeline.yml | Passes isInternalBuild into the core template based on System.TeamProject. |
| eng/pipelines/dotnet-sqlclient-ci-core.yml | Introduces isInternalBuild parameter and forwards it into the SqlServer build stage. |
| eng/pipelines/common/steps/download-assembly-signing-key.yml | New reusable step template to download driver/test SNK secure files. |
| eng/pipelines/ci/package/sqlclient-ci-package-pipeline.yml | Uses the shared signing-key download template in internal package CI pipeline. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| inputs: | ||
| secureFile: netfxKeypair.snk | ||
| name: driverKeyFile | ||
| - template: /eng/pipelines/common/steps/download-assembly-signing-key.yml@self |
There was a problem hiding this comment.
This PR adds a shared helper template to download signing keys, so you will see changes to several pipeline like this.
| - Project | ||
|
|
||
| # True when building on the internal ADO.Net project. | ||
| - name: isInternalBuild |
There was a problem hiding this comment.
You will see this concept throughout the PR stack, used to determine when assembly signing is required.
The PR pipelines (legacy and modern) always use Project mode, and never sign any assemblies. They will not have this concept.
The modern CI pipeline always uses Package mode, and when running on ADO.Net, it will sign all assemblies (driver and test).
The legacy CI pipelines use both Project and Package mode. In Project mode, no signing occurs, so internal vs public doesn't matter. In Package mode and internal, we will be signing everything to satisfy InternalsVisibleTo safely.
There was a problem hiding this comment.
Is this because the PR pipelines run on the public ADO project and don't have access to those secrets? If it's not, I'd argue maybe it's just easier to always strong name sign the assemblies.
There was a problem hiding this comment.
The legacy CI pipelines run in both projects (public and internal). That's the pipeline these changes (and the next 4 PRs in the stack) are targeting. Each of these CI PRs is pretty small, and we need to keep them functioning while the new CI pipelines are brought online, hence what seems like a bunch of work on the legacy stuff.
1da18ed to
9bb6342
Compare
9bb6342 to
a222a0c
Compare
f4e55a0 to
7af5b71
Compare
There was a problem hiding this comment.
🟢 Approval recommended
The parameter threading and conditional secure-file/key usage is consistent across updated pipelines and appears to correctly constrain signing to internal Package-reference builds.
Review details
- Files reviewed: 11/11 changed files
- Comments generated: 0 new
- Review effort level: Lite
- Split download-assembly-signing-key.yml into download-driver-signing-key-step.yml and download-test-signing-key-step.yml, each parameterless with its own output. - Restore "strong-name signing" terminology; always name the driver or test key. - Remove parameter defaults added in this branch; pass values explicitly, including isInternalBuild: false in both PR pipelines. - Fold the driver key download into the existing signing conditional in the pack job.
- Split download-assembly-signing-key.yml into download-driver-signing-key-step.yml and download-test-signing-key-step.yml, each parameterless with its own output. - Restore "strong-name signing" terminology; always name the driver or test key. - Remove parameter defaults added in this branch; pass values explicitly, including isInternalBuild: false in both PR pipelines. - Fold the driver key download into the existing signing conditional in the pack job.
Pre-emptively align this PR with the review feedback already addressed lower in the stack, so the same comments aren't raised again. - Reference the split download-driver-signing-key-step.yml and download-test-signing-key-step.yml templates instead of the removed download-assembly-signing-key.yml. - Quote SigningKeyPath and TestSigningKeyPath to tolerate whitespace in the secure file paths. - Fold the driver key download into the existing signing conditional in the pack job, removing the duplicated conditional. - Use positive referenceType comparisons (eq 'Package'). - Drop the referenceType and isInternalBuild parameter defaults; both are already passed explicitly by every caller. - Move the BuildNumber/FileVersion note directly above buildProperties in every pack branch. - Restore "strong-name signing" terminology and name the driver or test key explicitly.
- Split download-assembly-signing-key.yml into download-driver-signing-key-step.yml and download-test-signing-key-step.yml, each parameterless with its own output. - Restore "strong-name signing" terminology; always name the driver or test key. - Remove parameter defaults added in this branch; pass values explicitly, including isInternalBuild: false in both PR pipelines. - Fold the driver key download into the existing signing conditional in the pack job.
Pre-emptively align this PR with the review feedback already addressed lower in the stack, so the same comments aren't raised again. - Reference the split download-driver-signing-key-step.yml and download-test-signing-key-step.yml templates instead of the removed download-assembly-signing-key.yml. - Use positive referenceType comparisons (eq 'Package'). - Drop the isInternalBuild parameter defaults; every caller already passes it explicitly. - Use "strong-name signing" terminology and name the driver or test key in the signingKeyPath/testSigningKeyPath parameter docs, correcting the stale note about test-filter categories.
- Split download-assembly-signing-key.yml into download-driver-signing-key-step.yml and download-test-signing-key-step.yml, each parameterless with its own output. - Restore "strong-name signing" terminology; always name the driver or test key. - Remove parameter defaults added in this branch; pass values explicitly, including isInternalBuild: false in both PR pipelines. - Fold the driver key download into the existing signing conditional in the pack job.
Pre-emptively align this PR with the review feedback already addressed lower in the stack, so the same comments aren't raised again. - Reference the split download-driver-signing-key-step.yml and download-test-signing-key-step.yml templates instead of the removed download-assembly-signing-key.yml. - Quote SigningKeyPath and TestSigningKeyPath to tolerate whitespace in the secure file paths. - Fold the driver key download into the existing signing conditional in the pack job, removing the duplicated conditional. - Use positive referenceType comparisons (eq 'Package'). - Drop the isInternalBuild parameter defaults; every caller already passes it explicitly. - Normalize the BuildNumber/FileVersion note across all pack branches. - Restore an accidentally dropped blank line in Azure.Test.csproj.
Introduce the shared signing-key download step and thread isInternalBuild through the CI core so the SqlServer package is strong-name signed on internal Package-mode builds. - Add eng/pipelines/common/steps/download-assembly-signing-key.yml, which exports driverKeyFile or testKeyFile from ADO secure files. - Adopt that step in the OneBranch build and nightly CI package pipelines, renaming keyFile to driverKeyFile. - Declare isInternalBuild in dotnet-sqlclient-ci-core.yml and set it from the CI package- and project-reference pipelines. - Sign the SqlServer package when isInternalBuild is true and referenceType is not Project.
- Quote SigningKeyPath in buildProperties so the secure-file path is robust to spaces, matching build-buildproj-step.yml and sqlclient-ci-package-pipeline.yml. - Move the BuildNumber/FileVersion note directly above buildProperties in both the signed and unsigned pack branches. No change to signing behaviour: signing stays gated on internal Package-reference builds.
- Split download-assembly-signing-key.yml into download-driver-signing-key-step.yml and download-test-signing-key-step.yml, each parameterless with its own output. - Restore "strong-name signing" terminology; always name the driver or test key. - Remove parameter defaults added in this branch; pass values explicitly, including isInternalBuild: false in both PR pipelines. - Fold the driver key download into the existing signing conditional in the pack job.
- Split download-assembly-signing-key.yml into download-driver-signing-key-step.yml and download-test-signing-key-step.yml, each parameterless with its own output. - Restore "strong-name signing" terminology; always name the driver or test key. - Remove parameter defaults added in this branch; pass values explicitly, including isInternalBuild: false in both PR pipelines. - Fold the driver key download into the existing signing conditional in the pack job.
7af5b71 to
bddc940
Compare
- Split download-assembly-signing-key.yml into download-driver-signing-key-step.yml and download-test-signing-key-step.yml, each parameterless with its own output. - Restore "strong-name signing" terminology; always name the driver or test key. - Remove parameter defaults added in this branch; pass values explicitly, including isInternalBuild: false in both PR pipelines. - Fold the driver key download into the existing signing conditional in the pack job.
Pre-emptively align this PR with the review feedback already addressed lower in the stack, so the same comments aren't raised again. - Reference the split download-driver-signing-key-step.yml and download-test-signing-key-step.yml templates instead of the removed download-assembly-signing-key.yml. - Quote SigningKeyPath and TestSigningKeyPath to tolerate whitespace in the secure file paths. - Fold the driver key download into the existing signing conditional in the pack job, removing the duplicated conditional. - Use positive referenceType comparisons (eq 'Package'). - Drop the referenceType and isInternalBuild parameter defaults; both are already passed explicitly by every caller. - Move the BuildNumber/FileVersion note directly above buildProperties in every pack branch. - Restore "strong-name signing" terminology and name the driver or test key explicitly.
- Split download-assembly-signing-key.yml into download-driver-signing-key-step.yml and download-test-signing-key-step.yml, each parameterless with its own output. - Restore "strong-name signing" terminology; always name the driver or test key. - Remove parameter defaults added in this branch; pass values explicitly, including isInternalBuild: false in both PR pipelines. - Fold the driver key download into the existing signing conditional in the pack job.
Pre-emptively align this PR with the review feedback already addressed lower in the stack, so the same comments aren't raised again. - Reference the split download-driver-signing-key-step.yml and download-test-signing-key-step.yml templates instead of the removed download-assembly-signing-key.yml. - Use positive referenceType comparisons (eq 'Package'). - Drop the isInternalBuild parameter defaults; every caller already passes it explicitly. - Use "strong-name signing" terminology and name the driver or test key in the signingKeyPath/testSigningKeyPath parameter docs, correcting the stale note about test-filter categories.
- Split download-assembly-signing-key.yml into download-driver-signing-key-step.yml and download-test-signing-key-step.yml, each parameterless with its own output. - Restore "strong-name signing" terminology; always name the driver or test key. - Remove parameter defaults added in this branch; pass values explicitly, including isInternalBuild: false in both PR pipelines. - Fold the driver key download into the existing signing conditional in the pack job.
Pre-emptively align this PR with the review feedback already addressed lower in the stack, so the same comments aren't raised again. - Reference the split download-driver-signing-key-step.yml and download-test-signing-key-step.yml templates instead of the removed download-assembly-signing-key.yml. - Quote SigningKeyPath and TestSigningKeyPath to tolerate whitespace in the secure file paths. - Fold the driver key download into the existing signing conditional in the pack job, removing the duplicated conditional. - Use positive referenceType comparisons (eq 'Package'). - Drop the isInternalBuild parameter defaults; every caller already passes it explicitly. - Normalize the BuildNumber/FileVersion note across all pack branches. - Restore an accidentally dropped blank line in Azure.Test.csproj.
There was a problem hiding this comment.
🟢 Approval recommended
The change is limited to pipeline wiring for internal signing behavior and only surfaces a minor consistency/clarity nit in the conditional expression.
Review details
- Files reviewed: 11/11 changed files
- Comments generated: 1
- Review effort level: Lite
| buildProperties: SqlServerPackageVersion=${{ parameters.sqlServerPackageVersion }};BuildNumber=$(Build.BuildNumber) | ||
| # Create the NuGet packages. Internal Package-mode builds strong-name sign the assemblies | ||
| # with the driver key. | ||
| - ${{ if and(eq(parameters.isInternalBuild, true), ne(parameters.referenceType, 'Project')) }}: |
What's This All About?
The first 5 PRs in this stack are all about adding assembly signing and public-key-protected InternalsVisibleTo support to the legacy CI pipeline. This is infrastructure work necessary to support the Native AOT fix in the final PR.
We have never been including assembly signing in our CI, which IMO was a blind spot. Now, when CI runs in our internal ADO.Net project, all assemblies will be signed, we will be running tests against signed assemblies, and fully testing our nascent inter-assembly IVT just as it would be in a real app. Public project CI and all of our PR pipelines will continue to use unsigned assemblies, and testing that requires inter-assembly IVT will only be done in Project mode (PR, legacy CI Project-mode pipeline) or via internal CI with signed assemblies.
The 6th and final PR in the stack addresses the Native AOT issue #4193 by eliminating inter-assembly reflection and using signed IVT with proper package dependencies.
Description
This PR sets up assembly signing in the legacy CI pipeline for the SqlServer project.
Microsoft.SqlServer.Serverwas not receivingSigningKeyPathwhen it was packed by the internal, Package-reference CI flow. As a result, that package could be produced without the strong-name signing applied to the other internal package artifacts. Internal Package-mode builds need a consistent set of signed assemblies; public builds and Project-reference builds should continue to build without access to the internal signing key.This PR:
driverKeyFileoutput name;isInternalBuildandreferenceTypethrough the CI core, SqlServer stage, and SqlServer pack job;SigningKeyPathwhen packingMicrosoft.SqlServer.Serveronly for internal Package-reference builds; andSupplying
SigningKeyPathactivates the existing signing behavior insrc/Directory.Build.props; this PR does not change product source, public APIs, package contents beyond assembly signing, or compatibility behavior.Issues
Works towards addressing #4193.
Testing
This is a pipeline-only change, so no unit or integration tests were added.
The GitHub PR validation pipelines exercise the public Package-reference and Project-reference paths and are currently running. The internal signing branch requires the ADO.Net secure file and is exercised only by an internal Package-reference pipeline run.
CI pipeline runs
The GitHub PR pipelines never set
isInternalBuild, so they always take the unsigned path. The CI runs below are what actually exercise this change, and together they cover all four quadrants of the signing matrix:Artifact verification
The
SqlServer.Artifactspackage produced by each run was downloaded and inspected withtools/PackageValidator, which reads signing state from CLI metadata. It requires both a public key and theCorFlags.StrongNameSignedbit, so it distinguishes a fully signed assembly from a delay-signed one.23ec7fc2d6eaa4a5Only the internal + Package quadrant is signed, both target frameworks report
Signedrather thanDelaySigned, and23ec7fc2d6eaa4a5is the SqlClient family public key token. PackageValidator'sunsignedfinding count across the four runs above is 2, 2, 2, and 0 respectively, dropping to zero only where signing is expected.All four runs were re-queued after addressing review feedback: the public pair on
0fd3a4000, and the internal pair on the synced branch tip3d0c96fc, which carries that commit in its ancestry. The verification above was re-run against these current artifacts. Each package embeds its source commit in the informational version (...-ci23809+0fd3a400for the public pair,...+3d0c96fcfor the internal pair), confirming which commit produced each result.