From bd2f4a947aae14ec2664dc371931c2827550c7f2 Mon Sep 17 00:00:00 2001 From: Paul Medynski <31868385+paulmedynski@users.noreply.github.com> Date: Fri, 21 Aug 2026 11:27:42 -0300 Subject: [PATCH] Add assembly signing for Microsoft.Data.SqlClient and the AKV Provider Sign the SqlClient and AKV Provider assemblies, and the SqlClient test assemblies, on internal Package-mode CI builds. SqlClient references Abstractions, Logging and SqlServer.Server, so those packages must already be signed for this to build; a strong-named assembly referencing a weak-named one fails with CS8002. - Thread isInternalBuild from the CI core into the SqlClient package stage and the test stage, and download the driver and test signing keys in the build and test jobs. - Pass signingKeyPath to the project build step and both signing key paths to the test steps. - Thread SigningKeyPath into the build.proj TestSqlClientFunctional and TestSqlClientManual targets, and both key arguments into TestSqlClientUnit. --- build.proj | 23 +++++++-- .../templates/jobs/ci-build-nugets-job.yml | 13 +++++ .../templates/jobs/ci-run-tests-job.yml | 18 +++++++ .../templates/stages/ci-run-tests-stage.yml | 7 +++ .../templates/steps/ci-project-build-step.yml | 8 ++++ .../templates/steps/run-all-tests-step.yml | 48 +++++++++++++++++++ eng/pipelines/dotnet-sqlclient-ci-core.yml | 2 + .../build-sqlclient-package-ci-stage.yml | 6 +++ 8 files changed, 122 insertions(+), 3 deletions(-) diff --git a/build.proj b/build.proj index c7c70e9e5b..b0d04a4ebb 100644 --- a/build.proj +++ b/build.proj @@ -637,7 +637,12 @@ "$(DotnetPath)dotnet" test "$(SqlClientFunctionalTestProjectPath)" + + -p:Configuration=$(Configuration) + $(SigningKeyPathArgument) + + $(TestBlameArgument) $(TestCodeCoverageArgument) $(TestFiltersArgument) @@ -681,7 +686,12 @@ "$(DotnetPath)dotnet" test "$(SqlClientManualTestProjectPath)" + + -p:Configuration=$(Configuration) + $(SigningKeyPathArgument) + + $(TestBlameArgument) $(TestCodeCoverageArgument) $(ManualTestFiltersArgument) @@ -710,17 +720,24 @@ "$(DotnetPath)dotnet" test "$(SqlClientUnitTestProjectPath)" + + -p:Configuration=$(Configuration) + $(SigningKeyPathArgument) + $(TestSigningKeyPathArgument) + + $(TestBlameArgument) $(TestCodeCoverageArgument) $(TestFiltersArgument) $(TestFrameworkArgument) + --results-directory "$(TestResultsFolderPath)" + --logger:"trx;LogFilePrefix=$(LogFilePrefix)" + + $(ReferenceTypeArgument) - $(TestSigningKeyPathArgument) $(PackageVersionSqlClientArgument) $(PackageVersionSqlServerArgument) - --results-directory "$(TestResultsFolderPath)" - --logger:"trx;LogFilePrefix=$(LogFilePrefix)" diff --git a/eng/pipelines/common/templates/jobs/ci-build-nugets-job.yml b/eng/pipelines/common/templates/jobs/ci-build-nugets-job.yml index 95d5d0b7d0..c4ba7017d4 100644 --- a/eng/pipelines/common/templates/jobs/ci-build-nugets-job.yml +++ b/eng/pipelines/common/templates/jobs/ci-build-nugets-job.yml @@ -76,6 +76,11 @@ parameters: type: string default: SqlServer.Artifacts + # True when building on the internal ADO.Net project. + - name: isInternalBuild + type: boolean + default: false + jobs: - job: build_mds_akv_packages_job displayName: Build MDS & AKV Packages @@ -126,6 +131,10 @@ jobs: # Restore dotnet CLI tools (e.g. pwsh, apicompat) before building. - template: /eng/pipelines/common/steps/restore-dotnet-tools.yml@self + # Download the assembly signing key for internal Package-mode builds. + - ${{ if and(eq(parameters.isInternalBuild, true), ne(parameters.referenceType, 'Project')) }}: + - template: /eng/pipelines/common/steps/download-assembly-signing-key.yml@self + # When we're performing a Debug build, we still want to try _compiling_ the # code in Release mode to ensure downstream pipelines don't encounter # compilation errors. We won't use the Release artifacts for anything else @@ -147,6 +156,8 @@ jobs: build: MDS packageVersion: ${{ parameters.packageVersion }} sqlServerPackageVersion: ${{ parameters.sqlServerPackageVersion }} + ${{ if and(eq(parameters.isInternalBuild, true), ne(parameters.referenceType, 'Project')) }}: + signingKeyPath: $(driverKeyFile.secureFilePath) - task: DotNetCoreCLI@2 displayName: 'Create MDS NuGet Package' @@ -189,6 +200,8 @@ jobs: build: AkvProvider packageVersion: ${{ parameters.packageVersion }} sqlServerPackageVersion: ${{ parameters.sqlServerPackageVersion }} + ${{ if and(eq(parameters.isInternalBuild, true), ne(parameters.referenceType, 'Project')) }}: + signingKeyPath: $(driverKeyFile.secureFilePath) - task: DotNetCoreCLI@2 displayName: 'Create AKV Provider NuGet Package' diff --git a/eng/pipelines/common/templates/jobs/ci-run-tests-job.yml b/eng/pipelines/common/templates/jobs/ci-run-tests-job.yml index 4752e09e43..b5e9cd6a3a 100644 --- a/eng/pipelines/common/templates/jobs/ci-run-tests-job.yml +++ b/eng/pipelines/common/templates/jobs/ci-run-tests-job.yml @@ -148,6 +148,11 @@ parameters: - name: saPassword type: string + # True when building on the internal ADO.Net project. + - name: isInternalBuild + type: boolean + default: false + jobs: - job: ${{ format('{0}', coalesce(parameters.jobDisplayName, parameters.image, 'unknown_image')) }} @@ -205,6 +210,13 @@ jobs: # Restore dotnet CLI tools (e.g. pwsh, apicompat) before building. - template: /eng/pipelines/common/steps/restore-dotnet-tools.yml@self + # Download the assembly signing keys for internal Package-mode builds. + - ${{ if and(eq(parameters.isInternalBuild, true), ne(parameters.referenceType, 'Project')) }}: + - template: /eng/pipelines/common/steps/download-assembly-signing-key.yml@self + - template: /eng/pipelines/common/steps/download-assembly-signing-key.yml@self + parameters: + isTest: true + - ${{ if ne(parameters.prebuildSteps, '') }}: - ${{ parameters.prebuildSteps }} # extra steps to run before the build like downloading sni and the required configuration @@ -358,6 +370,9 @@ jobs: operatingSystem: ${{ parameters.operatingSystem }} packageVersion: ${{ parameters.packageVersion }} sqlServerPackageVersion: ${{ parameters.sqlServerPackageVersion }} + ${{ if and(eq(parameters.isInternalBuild, true), ne(parameters.referenceType, 'Project')) }}: + signingKeyPath: $(driverKeyFile.secureFilePath) + testSigningKeyPath: $(testKeyFile.secureFilePath) - ${{ if and(eq(parameters.enableX86Test, true), eq(parameters.operatingSystem, 'Windows')) }}: - template: /eng/pipelines/common/templates/steps/run-all-tests-step.yml@self @@ -372,6 +387,9 @@ jobs: operatingSystem: ${{ parameters.operatingSystem }} packageVersion: ${{ parameters.packageVersion }} sqlServerPackageVersion: ${{ parameters.sqlServerPackageVersion }} + ${{ if and(eq(parameters.isInternalBuild, true), ne(parameters.referenceType, 'Project')) }}: + signingKeyPath: $(driverKeyFile.secureFilePath) + testSigningKeyPath: $(testKeyFile.secureFilePath) - template: /eng/pipelines/common/templates/steps/publish-test-results-step.yml@self parameters: diff --git a/eng/pipelines/common/templates/stages/ci-run-tests-stage.yml b/eng/pipelines/common/templates/stages/ci-run-tests-stage.yml index 7ed67c1af9..e85762a423 100644 --- a/eng/pipelines/common/templates/stages/ci-run-tests-stage.yml +++ b/eng/pipelines/common/templates/stages/ci-run-tests-stage.yml @@ -71,6 +71,11 @@ parameters: - name: testJobTimeout type: number + # True when building on the internal ADO.Net project. + - name: isInternalBuild + type: boolean + default: false + stages: - ${{ each config in parameters.testConfigurations }}: - ${{ each image in config.value.images }}: @@ -114,6 +119,7 @@ stages: packageVersion: $(packageVersion) loggingArtifactsName: ${{ parameters.loggingArtifactsName }} mdsArtifactsName: ${{ parameters.mdsArtifactsName }} + isInternalBuild: ${{ parameters.isInternalBuild }} sqlServerArtifactsName: ${{ parameters.sqlServerArtifactsName }} sqlServerPackageVersion: $(sqlServerPackageVersion) prebuildSteps: ${{ parameters.prebuildSteps }} @@ -149,6 +155,7 @@ stages: packageVersion: $(packageVersion) loggingArtifactsName: ${{ parameters.loggingArtifactsName }} mdsArtifactsName: ${{ parameters.mdsArtifactsName }} + isInternalBuild: ${{ parameters.isInternalBuild }} sqlServerArtifactsName: ${{ parameters.sqlServerArtifactsName }} sqlServerPackageVersion: $(sqlServerPackageVersion) prebuildSteps: ${{ parameters.prebuildSteps }} diff --git a/eng/pipelines/common/templates/steps/ci-project-build-step.yml b/eng/pipelines/common/templates/steps/ci-project-build-step.yml index c80de64fd4..cc10c03439 100644 --- a/eng/pipelines/common/templates/steps/ci-project-build-step.yml +++ b/eng/pipelines/common/templates/steps/ci-project-build-step.yml @@ -58,6 +58,12 @@ parameters: type: string default: $(sqlServerPackageVersion) + # Path to the assembly signing key file. When non-empty, passed as -p:SigningKeyPath="" to the + # build. The calling job is responsible for providing the key. + - name: signingKeyPath + type: string + default: '' + steps: # Build MDS - ${{ if or(eq(parameters.build, 'MDS'), eq(parameters.build, 'all'), eq(parameters.build, 'allNoDocs')) }}: @@ -74,6 +80,7 @@ steps: -p:BuildNumber=${{ parameters.buildNumber }} -p:PackageVersionSqlClient=${{ parameters.packageVersion }} -p:PackageVersionSqlServer=${{ parameters.sqlServerPackageVersion }} + -p:SigningKeyPath="${{ parameters.signingKeyPath }}" # Build AKV Provider - ${{ if or(eq(parameters.build, 'AkvProvider'), eq(parameters.build, 'all'), eq(parameters.build, 'allNoDocs')) }}: @@ -90,3 +97,4 @@ steps: -p:BuildNumber=${{ parameters.buildNumber }} -p:PackageVersionSqlClient=${{ parameters.packageVersion }} -p:PackageVersionSqlServer=${{ parameters.sqlServerPackageVersion }} + -p:SigningKeyPath="${{ parameters.signingKeyPath }}" diff --git a/eng/pipelines/common/templates/steps/run-all-tests-step.yml b/eng/pipelines/common/templates/steps/run-all-tests-step.yml index 928c2e3abc..57f63a7f46 100644 --- a/eng/pipelines/common/templates/steps/run-all-tests-step.yml +++ b/eng/pipelines/common/templates/steps/run-all-tests-step.yml @@ -68,6 +68,18 @@ parameters: type: number default: 2 + # Path to the assembly signing key file. When non-empty, passed to build.proj so that the + # test-filter logic can include category=signed tests. + - name: signingKeyPath + type: string + default: '' + + # Path to the test assembly signing key file. When non-empty, passed to build.proj so that test + # assemblies are signed and can satisfy InternalsVisibleTo grants from signed source assemblies. + - name: testSigningKeyPath + type: string + default: '' + steps: - ${{ if parameters.debug }}: - powershell: 'dotnet sdk check' @@ -90,6 +102,8 @@ steps: -p:PackageVersionSqlClient=${{ parameters.packageVersion }} -p:PackageVersionSqlServer=${{ parameters.sqlServerPackageVersion }} -p:TestResultsFolderPath=TestResults + -p:SigningKeyPath="${{ parameters.signingKeyPath }}" + -p:TestSigningKeyPath="${{ parameters.testSigningKeyPath }}" ${{ else }}: # x86 arguments: >- -t:TestSqlClientUnit @@ -100,6 +114,8 @@ steps: -p:PackageVersionSqlServer=${{ parameters.sqlServerPackageVersion }} -p:DotnetPath=${{ parameters.dotnetx86RootPath }} -p:TestResultsFolderPath=TestResults + -p:SigningKeyPath="${{ parameters.signingKeyPath }}" + -p:TestSigningKeyPath="${{ parameters.testSigningKeyPath }}" - task: DotNetCoreCLI@2 displayName: 'Run Flaky Unit Tests ${{parameters.msbuildArchitecture }}' @@ -118,6 +134,8 @@ steps: -p:TestFilters="category=flaky" -p:TestResultsFolderPath=TestResults -p:TestCodeCoverage=false + -p:SigningKeyPath="${{ parameters.signingKeyPath }}" + -p:TestSigningKeyPath="${{ parameters.testSigningKeyPath }}" ${{ else }}: # x86 arguments: >- -t:TestSqlClientUnit @@ -130,6 +148,8 @@ steps: -p:TestFilters="category=flaky" -p:TestResultsFolderPath=TestResults -p:TestCodeCoverage=false + -p:SigningKeyPath="${{ parameters.signingKeyPath }}" + -p:TestSigningKeyPath="${{ parameters.testSigningKeyPath }}" continueOnError: true - task: DotNetCoreCLI@2 @@ -147,6 +167,8 @@ steps: -p:PackageVersionSqlClient=${{ parameters.packageVersion }} -p:PackageVersionSqlServer=${{ parameters.sqlServerPackageVersion }} -p:TestResultsFolderPath=TestResults + -p:SigningKeyPath="${{ parameters.signingKeyPath }}" + -p:TestSigningKeyPath="${{ parameters.testSigningKeyPath }}" ${{ else }}: # x86 arguments: >- -t:TestSqlClientFunctional @@ -157,6 +179,8 @@ steps: -p:PackageVersionSqlServer=${{ parameters.sqlServerPackageVersion }} -p:DotnetPath=${{ parameters.dotnetx86RootPath }} -p:TestResultsFolderPath=TestResults + -p:SigningKeyPath="${{ parameters.signingKeyPath }}" + -p:TestSigningKeyPath="${{ parameters.testSigningKeyPath }}" - task: DotNetCoreCLI@2 displayName: 'Run Flaky Functional Tests ${{parameters.msbuildArchitecture }}' @@ -175,6 +199,8 @@ steps: -p:TestFilters="category=flaky" -p:TestResultsFolderPath=TestResults -p:TestCodeCoverage=false + -p:SigningKeyPath="${{ parameters.signingKeyPath }}" + -p:TestSigningKeyPath="${{ parameters.testSigningKeyPath }}" ${{ else }}: # x86 arguments: >- -t:TestSqlClientFunctional @@ -187,6 +213,8 @@ steps: -p:TestFilters="category=flaky" -p:TestResultsFolderPath=TestResults -p:TestCodeCoverage=false + -p:SigningKeyPath="${{ parameters.signingKeyPath }}" + -p:TestSigningKeyPath="${{ parameters.testSigningKeyPath }}" continueOnError: true - task: DotNetCoreCLI@2 @@ -205,6 +233,8 @@ steps: -p:PackageVersionSqlClient=${{ parameters.packageVersion }} -p:PackageVersionSqlServer=${{ parameters.sqlServerPackageVersion }} -p:TestResultsFolderPath=TestResults + -p:SigningKeyPath="${{ parameters.signingKeyPath }}" + -p:TestSigningKeyPath="${{ parameters.testSigningKeyPath }}" ${{ else }}: # x86 arguments: >- -t:TestSqlClientManual @@ -216,6 +246,8 @@ steps: -p:PackageVersionSqlServer=${{ parameters.sqlServerPackageVersion }} -p:DotnetPath=${{ parameters.dotnetx86RootPath }} -p:TestResultsFolderPath=TestResults + -p:SigningKeyPath="${{ parameters.signingKeyPath }}" + -p:TestSigningKeyPath="${{ parameters.testSigningKeyPath }}" retryCountOnTaskFailure: ${{parameters.retryCountOnManualTests }} - task: DotNetCoreCLI@2 @@ -236,6 +268,8 @@ steps: -p:TestFilters="category=flaky" -p:TestResultsFolderPath=TestResults -p:TestCodeCoverage=false + -p:SigningKeyPath="${{ parameters.signingKeyPath }}" + -p:TestSigningKeyPath="${{ parameters.testSigningKeyPath }}" ${{ else }}: # x86 arguments: >- -t:TestSqlClientManual @@ -249,6 +283,8 @@ steps: -p:TestFilters="category=flaky" -p:TestResultsFolderPath=TestResults -p:TestCodeCoverage=false + -p:SigningKeyPath="${{ parameters.signingKeyPath }}" + -p:TestSigningKeyPath="${{ parameters.testSigningKeyPath }}" continueOnError: true - ${{ else }}: # Linux or macOS @@ -266,6 +302,8 @@ steps: -p:PackageVersionSqlClient=${{ parameters.packageVersion }} -p:PackageVersionSqlServer=${{ parameters.sqlServerPackageVersion }} -p:TestResultsFolderPath=TestResults + -p:SigningKeyPath="${{ parameters.signingKeyPath }}" + -p:TestSigningKeyPath="${{ parameters.testSigningKeyPath }}" - task: DotNetCoreCLI@2 displayName: 'Run Flaky Unit Tests' @@ -283,6 +321,8 @@ steps: -p:TestFilters="category=flaky" -p:TestResultsFolderPath=TestResults -p:TestCodeCoverage=false + -p:SigningKeyPath="${{ parameters.signingKeyPath }}" + -p:TestSigningKeyPath="${{ parameters.testSigningKeyPath }}" continueOnError: true - task: DotNetCoreCLI@2 @@ -299,6 +339,8 @@ steps: -p:PackageVersionSqlClient=${{ parameters.packageVersion }} -p:PackageVersionSqlServer=${{ parameters.sqlServerPackageVersion }} -p:TestResultsFolderPath=TestResults + -p:SigningKeyPath="${{ parameters.signingKeyPath }}" + -p:TestSigningKeyPath="${{ parameters.testSigningKeyPath }}" - task: DotNetCoreCLI@2 displayName: 'Run Flaky Functional Tests' @@ -316,6 +358,8 @@ steps: -p:TestFilters="category=flaky" -p:TestResultsFolderPath=TestResults -p:TestCodeCoverage=false + -p:SigningKeyPath="${{ parameters.signingKeyPath }}" + -p:TestSigningKeyPath="${{ parameters.testSigningKeyPath }}" continueOnError: true - task: DotNetCoreCLI@2 displayName: 'Run Manual Tests' @@ -332,6 +376,8 @@ steps: -p:PackageVersionSqlClient=${{ parameters.packageVersion }} -p:PackageVersionSqlServer=${{ parameters.sqlServerPackageVersion }} -p:TestResultsFolderPath=TestResults + -p:SigningKeyPath="${{ parameters.signingKeyPath }}" + -p:TestSigningKeyPath="${{ parameters.testSigningKeyPath }}" retryCountOnTaskFailure: ${{parameters.retryCountOnManualTests }} - task: DotNetCoreCLI@2 @@ -351,4 +397,6 @@ steps: -p:TestFilters="category=flaky" -p:TestResultsFolderPath=TestResults -p:TestCodeCoverage=false + -p:SigningKeyPath="${{ parameters.signingKeyPath }}" + -p:TestSigningKeyPath="${{ parameters.testSigningKeyPath }}" continueOnError: true diff --git a/eng/pipelines/dotnet-sqlclient-ci-core.yml b/eng/pipelines/dotnet-sqlclient-ci-core.yml index 1ce914db02..bfaa8b4620 100644 --- a/eng/pipelines/dotnet-sqlclient-ci-core.yml +++ b/eng/pipelines/dotnet-sqlclient-ci-core.yml @@ -201,6 +201,7 @@ stages: loggingArtifactsName: $(loggingArtifactsName) mdsArtifactsName: $(mdsArtifactsName) referenceType: ${{ parameters.referenceType }} + isInternalBuild: ${{ parameters.isInternalBuild }} sqlServerArtifactsName: $(sqlServerArtifactsName) SNIVersion: ${{ parameters.SNIVersion }} SNIValidationFeed: ${{ parameters.SNIValidationFeed }} @@ -254,6 +255,7 @@ stages: abstractionsArtifactsName: $(abstractionsArtifactsName) loggingArtifactsName: $(loggingArtifactsName) mdsArtifactsName: $(mdsArtifactsName) + isInternalBuild: ${{ parameters.isInternalBuild }} sqlServerArtifactsName: $(sqlServerArtifactsName) testJobTimeout: ${{ parameters.testJobTimeout }} diff --git a/eng/pipelines/stages/build-sqlclient-package-ci-stage.yml b/eng/pipelines/stages/build-sqlclient-package-ci-stage.yml index 70fa122d5f..86f1c4db10 100644 --- a/eng/pipelines/stages/build-sqlclient-package-ci-stage.yml +++ b/eng/pipelines/stages/build-sqlclient-package-ci-stage.yml @@ -64,6 +64,11 @@ parameters: type: string default: '' + # True when building on the internal ADO.Net project. + - name: isInternalBuild + type: boolean + default: false + stages: - stage: build_sqlclient_package_stage @@ -93,6 +98,7 @@ stages: packageVersion: $(packageVersion) sqlServerArtifactsName: ${{ parameters.sqlServerArtifactsName }} sqlServerPackageVersion: $(sqlServerPackageVersion) + isInternalBuild: ${{ parameters.isInternalBuild }} ${{ if ne(parameters.SNIVersion, '') }}: prebuildSteps: - template: /eng/pipelines/common/templates/steps/override-sni-version.yml@self