From 179f858092bd30804c000b67cafb81fb3a4b6170 Mon Sep 17 00:00:00 2001 From: Paul Medynski <31868385+paulmedynski@users.noreply.github.com> Date: Wed, 11 Feb 2026 13:38:56 -0400 Subject: [PATCH 01/13] Update README with fork PR pipeline note Added a note about testing fork PR pipeline runs. --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 1a066c52d4..6064bfe774 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,8 @@ [![Nuget](https://img.shields.io/nuget/dt/Microsoft.Data.SqlClient?label=Nuget.org%20Downloads&style=flat-square&color=blue)](https://www.nuget.org/packages/Microsoft.Data.SqlClient) [![Build status](https://sqlclientdrivers.visualstudio.com/public/_apis/build/status/ADO/CI-SqlClient)](https://sqlclientdrivers.visualstudio.com/public/_build/latest?definitionId=1879) +Change to test fork PR pipeline runs. + # Microsoft SqlClient Data Provider for SQL Server Microsoft.Data.SqlClient is a .NET data provider for [Microsoft SQL Server]([url](https://aka.ms/sql)) and the [Azure SQL]([url](https://aka.ms/azure_sql)) family of databases. It grew from a union of the two System.Data.SqlClient components which live independently in .NET and .NET Framework. Going forward, support for new SQL Server and Azure SQL features will only be implemented in Microsoft.Data.SqlClient. From 2888148e6a67b0d98a77629b320c7614f3560398 Mon Sep 17 00:00:00 2001 From: Paul Medynski <31868385+paulmedynski@users.noreply.github.com> Date: Wed, 11 Feb 2026 13:41:05 -0400 Subject: [PATCH 02/13] Add no-op edit to build.proj Added a comment to trigger PR pipelines. --- build.proj | 2 ++ 1 file changed, 2 insertions(+) diff --git a/build.proj b/build.proj index 45365168c1..edb853dee6 100644 --- a/build.proj +++ b/build.proj @@ -1,6 +1,8 @@ + + From 5f0f6b1e466f2524a525e7a57f8f305f01aa81f0 Mon Sep 17 00:00:00 2001 From: Paul Medynski <31868385+paulmedynski@users.noreply.github.com> Date: Wed, 11 Feb 2026 14:05:35 -0400 Subject: [PATCH 03/13] Revert "Add no-op edit to build.proj" This reverts commit 2888148e6a67b0d98a77629b320c7614f3560398. --- build.proj | 2 -- 1 file changed, 2 deletions(-) diff --git a/build.proj b/build.proj index edb853dee6..45365168c1 100644 --- a/build.proj +++ b/build.proj @@ -1,8 +1,6 @@ - - From c48bc70d0b77fe21e6325e8b7268c64bcb0dccdc Mon Sep 17 00:00:00 2001 From: Paul Medynski <31868385+paulmedynski@users.noreply.github.com> Date: Wed, 11 Feb 2026 14:05:56 -0400 Subject: [PATCH 04/13] Revert "Update README with fork PR pipeline note" This reverts commit 179f858092bd30804c000b67cafb81fb3a4b6170. --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index 6064bfe774..1a066c52d4 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,6 @@ [![Nuget](https://img.shields.io/nuget/dt/Microsoft.Data.SqlClient?label=Nuget.org%20Downloads&style=flat-square&color=blue)](https://www.nuget.org/packages/Microsoft.Data.SqlClient) [![Build status](https://sqlclientdrivers.visualstudio.com/public/_apis/build/status/ADO/CI-SqlClient)](https://sqlclientdrivers.visualstudio.com/public/_build/latest?definitionId=1879) -Change to test fork PR pipeline runs. - # Microsoft SqlClient Data Provider for SQL Server Microsoft.Data.SqlClient is a .NET data provider for [Microsoft SQL Server]([url](https://aka.ms/sql)) and the [Azure SQL]([url](https://aka.ms/azure_sql)) family of databases. It grew from a union of the two System.Data.SqlClient components which live independently in .NET and .NET Framework. Going forward, support for new SQL Server and Azure SQL features will only be implemented in Microsoft.Data.SqlClient. From 121b4bb2b52160909e52c88a74c1e97747c5b3ed Mon Sep 17 00:00:00 2001 From: Paul Medynski <31868385+paulmedynski@users.noreply.github.com> Date: Wed, 11 Feb 2026 14:08:36 -0400 Subject: [PATCH 05/13] Fixed typo comparing System.PullRequest.IsFork value. --- eng/pipelines/common/templates/jobs/ci-run-tests-job.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 5e03693f82..7e6392e884 100644 --- a/eng/pipelines/common/templates/jobs/ci-run-tests-job.yml +++ b/eng/pipelines/common/templates/jobs/ci-run-tests-job.yml @@ -171,7 +171,7 @@ jobs: # # https://learn.microsoft.com/en-us/azure/devops/pipelines/build/variables?view=azure-devops&tabs=yaml#system-variables # - - ${{ if eq(variables['System.PullRequest.IsFork'], 'true') }}: + - ${{ if eq(variables['System.PullRequest.IsFork'], 'True') }}: - pwsh: | $guid = [guid]::NewGuid().ToString() Write-Host "##vso[task.setvariable variable=Password;isSecret=true]$guid" From 59fdfeaff1dec052e610c55259f276b3d45a96ab Mon Sep 17 00:00:00 2001 From: Paul Medynski <31868385+paulmedynski@users.noreply.github.com> Date: Wed, 11 Feb 2026 14:44:33 -0400 Subject: [PATCH 06/13] Removed IsFork check, and now generating a password all the time. --- .../templates/jobs/ci-run-tests-job.yml | 27 +++++++++---------- 1 file changed, 12 insertions(+), 15 deletions(-) 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 7e6392e884..9330742831 100644 --- a/eng/pipelines/common/templates/jobs/ci-run-tests-job.yml +++ b/eng/pipelines/common/templates/jobs/ci-run-tests-job.yml @@ -158,24 +158,21 @@ jobs: referenceType: ${{ parameters.referenceType }} mdsPackageVersion: ${{ parameters.mdsPackageVersion }} - # Pipelines running via forks of the repo won't have access to secrets brought in from Azure - # DevOps Library groups. This includes the $(Password) used to configure local SQL Server - # instances. In such a case, we must generate a random password and clobber $(Password). + # Some of the connection strings brought in from Azure DevOps Library groups expect a runtime + # $(Password) variable to exist. This is used for username/password logins to SQL Servers running + # locally on the agent. We must generate a random password here so it is available when those + # connection strings are expanded. We cannot use a Library variable because it will be deemed a + # secret, and will not be available to forked repos. # # From this point forward in this job, any pipeline runtime expansion of $(Password) will use the - # random value. This includes the SQL Server config templates (configure-sql-server-*.yml), and - # the expansion of connection strings via our configProperties parameter. + # random value we generate below. This includes the SQL Server config templates + # (configure-sql-server-*.yml), and the expansion of connection strings via our configProperties + # parameter. # - # Azure Pipelines provides the System.PullRequest.IsFork variable that is available at template - # expansion time. See: - # - # https://learn.microsoft.com/en-us/azure/devops/pipelines/build/variables?view=azure-devops&tabs=yaml#system-variables - # - - ${{ if eq(variables['System.PullRequest.IsFork'], 'True') }}: - - pwsh: | - $guid = [guid]::NewGuid().ToString() - Write-Host "##vso[task.setvariable variable=Password;isSecret=true]$guid" - displayName: Generate random SQL Server password for forked repo + - pwsh: | + $guid = [guid]::NewGuid().ToString() + Write-Host "##vso[task.setvariable variable=Password;isSecret=true]$guid" + displayName: Generate local SQL Server password - ${{ if ne(parameters.configProperties, '{}') }}: - template: /eng/pipelines/common/templates/steps/update-config-file-step.yml@self # update config.json file From c54fbf3573b95309c07a67a1ed4dbb40d307e493 Mon Sep 17 00:00:00 2001 From: Paul Medynski <31868385+paulmedynski@users.noreply.github.com> Date: Wed, 11 Feb 2026 16:13:25 -0400 Subject: [PATCH 07/13] - Now generating secrets for the entire pipeline. - Plumbed saPassword down through all of the stages, jobs, and steps that need it. - No more global $(Password) variable. --- .../templates/jobs/ci-run-tests-job.yml | 22 +- .../templates/stages/ci-run-tests-stage.yml | 6 + .../steps/configure-sql-server-linux-step.yml | 89 ++-- .../steps/configure-sql-server-macos-step.yml | 180 ++++---- .../steps/configure-sql-server-step.yml | 10 + .../steps/configure-sql-server-win-step.yml | 393 +++++++++--------- .../steps/update-config-file-step.yml | 137 +++--- eng/pipelines/dotnet-sqlclient-ci-core.yml | 15 + eng/pipelines/jobs/stress-tests-ci-job.yml | 12 +- .../jobs/test-azure-package-ci-job.yml | 6 + .../stages/build-azure-package-ci-stage.yml | 9 + .../stages/generate-secrets-ci-stage.yml | 40 ++ .../stages/stress-tests-ci-stage.yml | 25 +- 13 files changed, 526 insertions(+), 418 deletions(-) create mode 100644 eng/pipelines/stages/generate-secrets-ci-stage.yml 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 9330742831..ab863860be 100644 --- a/eng/pipelines/common/templates/jobs/ci-run-tests-job.yml +++ b/eng/pipelines/common/templates/jobs/ci-run-tests-job.yml @@ -99,6 +99,10 @@ parameters: type: boolean default: false + # The SA password to set when configuring SQL Server. + - name: saPassword + type: string + jobs: - job: ${{ format('{0}', coalesce(parameters.jobDisplayName, parameters.image, 'unknown_image')) }} @@ -158,26 +162,11 @@ jobs: referenceType: ${{ parameters.referenceType }} mdsPackageVersion: ${{ parameters.mdsPackageVersion }} - # Some of the connection strings brought in from Azure DevOps Library groups expect a runtime - # $(Password) variable to exist. This is used for username/password logins to SQL Servers running - # locally on the agent. We must generate a random password here so it is available when those - # connection strings are expanded. We cannot use a Library variable because it will be deemed a - # secret, and will not be available to forked repos. - # - # From this point forward in this job, any pipeline runtime expansion of $(Password) will use the - # random value we generate below. This includes the SQL Server config templates - # (configure-sql-server-*.yml), and the expansion of connection strings via our configProperties - # parameter. - # - - pwsh: | - $guid = [guid]::NewGuid().ToString() - Write-Host "##vso[task.setvariable variable=Password;isSecret=true]$guid" - displayName: Generate local SQL Server password - - ${{ if ne(parameters.configProperties, '{}') }}: - template: /eng/pipelines/common/templates/steps/update-config-file-step.yml@self # update config.json file parameters: debug: ${{ parameters.debug }} + saPassword: ${{ parameters.saPassword }} UseManagedSNIOnWindows: ${{ parameters.usemanagedSNI }} ${{ if parameters.configProperties.TCPConnectionString }}: TCPConnectionString: ${{ parameters.configProperties.TCPConnectionString }} @@ -254,6 +243,7 @@ jobs: parameters: operatingSystem: ${{ parameters.operatingSystem }} netcoreVersionTestUtils: ${{ parameters.netcoreVersionTestUtils }} + saPassword: ${{ parameters.saPassword }} ${{ if parameters.configProperties.instanceName }}: instanceName: ${{ parameters.configProperties.instanceName }} ${{ if parameters.configProperties.user }}: 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 defba05d9f..c8073e3981 100644 --- a/eng/pipelines/common/templates/stages/ci-run-tests-stage.yml +++ b/eng/pipelines/common/templates/stages/ci-run-tests-stage.yml @@ -45,6 +45,10 @@ parameters: - Project - Package + # The SA password to set when configuring SQL Server. + - name: saPassword + type: string + - name: testConfigurations type: object @@ -87,6 +91,7 @@ stages: configSqlFor: ${{ config.value.configSqlFor }} operatingSystem: ${{ config.value.operatingSystem }} isArm64: ${{ eq(config.value.isArm64, 'true') }} + saPassword: ${{ parameters.saPassword }} ${{if ne(config.value.configProperties, '{}') }}: ${{ each x86TF in config.value.configProperties.x86TestTargetFrameworks }}: ${{ if eq(x86TF, targetFramework) }}: @@ -123,6 +128,7 @@ stages: configSqlFor: ${{ config.value.configSqlFor }} operatingSystem: ${{ config.value.operatingSystem }} isArm64: ${{ eq(config.value.isArm64, 'true') }} + saPassword: ${{ parameters.saPassword }} ${{if and(eq(usemanagedSNI, false), ne(config.value.configProperties, '{}')) }}: ${{ each x86TF in config.value.configProperties.x86TestTargetFrameworks }}: ${{ if eq(x86TF, targetFramework) }}: diff --git a/eng/pipelines/common/templates/steps/configure-sql-server-linux-step.yml b/eng/pipelines/common/templates/steps/configure-sql-server-linux-step.yml index e423ac7392..15de459d50 100644 --- a/eng/pipelines/common/templates/steps/configure-sql-server-linux-step.yml +++ b/eng/pipelines/common/templates/steps/configure-sql-server-linux-step.yml @@ -7,48 +7,51 @@ # This step configures an existing SQL Server running on the local Linux host. For example, our 1ES # Hosted Pool has images like ADO-UB20-SQL22 that come with SQL Server 2022 pre-installed and # running. -# -# The SA password is set to the value of the $(Password) variable defined in the ADO Library "ADO -# Test Configuration properties", brought in by common/templates/libraries/ci-build-variables.yml. + +parameters: + + # The SA password to set when configuring SQL Server. + - name: saPassword + type: string steps: -# Linux only steps -- bash: | - sudo systemctl stop mssql-server - - # Password for the SA user (required) - - MSSQL_SA_PW="$(Password)" - - # Product ID of the version of SQL server you're installing - # Must be evaluation, developer, express, web, standard, enterprise, or your 25 digit product key - MSSQL_PID="enterprise" - - echo Running mssql-conf setup... - sudo MSSQL_SA_PASSWORD="$MSSQL_SA_PW" \ - MSSQL_PID="$MSSQL_PID" \ - /opt/mssql/bin/mssql-conf -n setup accept-eula - - # Connect to server and get the version: - counter=1 - errstatus=1 - while [ $counter -le 5 ] && [ $errstatus = 1 ] - do - echo Waiting for SQL Server to start... - sleep 3s - /opt/mssql-tools/bin/sqlcmd \ - -S localhost \ - -U SA \ - -P $MSSQL_SA_PW\ - -Q "SELECT @@VERSION" 2>/dev/null - errstatus=$? - ((counter++)) - done - - # Display error if connection failed: - if [ $errstatus = 1 ] - then - echo Cannot connect to SQL Server, installation aborted - exit $errstatus - fi - displayName: 'Configure SQL Server [Linux]' + + # Configure SQL Server. + - bash: | + sudo systemctl stop mssql-server + + # Password for the SA user (required) + MSSQL_SA_PW="${{ parameters.saPassword }}" + + # Product ID of the version of SQL server you're installing + # Must be evaluation, developer, express, web, standard, enterprise, or your 25 digit product key + MSSQL_PID="enterprise" + + echo Running mssql-conf setup... + sudo MSSQL_SA_PASSWORD="$MSSQL_SA_PW" \ + MSSQL_PID="$MSSQL_PID" \ + /opt/mssql/bin/mssql-conf -n setup accept-eula + + # Connect to server and get the version: + counter=1 + errstatus=1 + while [ $counter -le 5 ] && [ $errstatus = 1 ] + do + echo Waiting for SQL Server to start... + sleep 3s + /opt/mssql-tools/bin/sqlcmd \ + -S localhost \ + -U SA \ + -P "$MSSQL_SA_PW" \ + -Q "SELECT @@VERSION" 2>/dev/null + errstatus=$? + ((counter++)) + done + + # Display error if connection failed: + if [ $errstatus = 1 ] + then + echo Cannot connect to SQL Server, installation aborted + exit $errstatus + fi + displayName: 'Configure SQL Server [Linux]' diff --git a/eng/pipelines/common/templates/steps/configure-sql-server-macos-step.yml b/eng/pipelines/common/templates/steps/configure-sql-server-macos-step.yml index 8e3ae589b0..38c42513b7 100644 --- a/eng/pipelines/common/templates/steps/configure-sql-server-macos-step.yml +++ b/eng/pipelines/common/templates/steps/configure-sql-server-macos-step.yml @@ -6,114 +6,118 @@ # This step installs the latest SQL Server 2022 onto the macOS host as a docker container and # configures it for use. -# -# The SA password is set to the value of the $(Password) variable defined in the ADO Library "ADO -# Test Configuration properties", brought in by common/templates/libraries/ci-build-variables.yml. + +parameters: + + # The SA password to set when configuring SQL Server. + - name: saPassword + type: string steps: -# macOS only steps -- bash: | - # The "user" pipeline variable conflicts with homebrew, causing errors during install. Set it - # back to the pipeline user. - USER=`whoami` + # Configure SQL Server. This includes installing Docker and the SQLCMD tools, starting a SQL + # Server container, and verifying we can connect to it. + - bash: | + # The "user" pipeline variable conflicts with homebrew, causing errors during install. Set it + # back to the pipeline user. + USER=`whoami` - SQLCMD_ERRORS=$(Agent.TempDirectory)/sqlcmd_err.log - echo "Errors will be written to: $SQLCMD_ERRORS" + SQLCMD_ERRORS=$(Agent.TempDirectory)/sqlcmd_err.log + echo "Errors will be written to: $SQLCMD_ERRORS" - # Configure the prompt to show the current timestamp so we can see how long each command takes. - export PS4='+ [$(date "+%Y-%m-%d %H:%M:%S")] ' - set -x + # Configure the prompt to show the current timestamp so we can see how long each command takes. + export PS4='+ [$(date "+%Y-%m-%d %H:%M:%S")] ' + set -x - # Install Docker and SQLCMD tools. - brew install colima - brew install --cask docker - brew tap microsoft/mssql-release https://github.com/Microsoft/homebrew-mssql-release - brew update - HOMEBREW_ACCEPT_EULA=Y brew install mssql-tools18 - colima start --arch x86_64 - docker --version - docker pull mcr.microsoft.com/mssql/server:2022-latest + # Install Docker and SQLCMD tools. + brew install colima + brew install --cask docker + brew tap microsoft/mssql-release https://github.com/Microsoft/homebrew-mssql-release + brew update + HOMEBREW_ACCEPT_EULA=Y brew install mssql-tools18 + colima start --arch x86_64 + docker --version + docker pull mcr.microsoft.com/mssql/server:2022-latest - # Password for the SA user (required) - MSSQL_SA_PW="$(Password)" + # Password for the SA user (required) + MSSQL_SA_PW="${{ parameters.saPassword }}" - docker run -e "ACCEPT_EULA=Y" -e "MSSQL_SA_PASSWORD=$MSSQL_SA_PW" -p 1433:1433 -p 1434:1434 --name sql1 --hostname sql1 -d mcr.microsoft.com/mssql/server:2022-latest + docker run -e "ACCEPT_EULA=Y" -e "MSSQL_SA_PASSWORD=$MSSQL_SA_PW" -p 1433:1433 -p 1434:1434 --name sql1 --hostname sql1 -d mcr.microsoft.com/mssql/server:2022-latest - sleep 5 + sleep 5 - docker ps -a + docker ps -a - # Connect to the SQL Server container and get its version. - # - # It can take a while for the docker container to start listening and be - # ready for connections, so we will wait for up to 2 minutes, checking every - # 3 seconds. + # Connect to the SQL Server container and get its version. + # + # It can take a while for the docker container to start listening and be + # ready for connections, so we will wait for up to 2 minutes, checking every + # 3 seconds. - # Wait 3 seconds between attempts. - delay=3 + # Wait 3 seconds between attempts. + delay=3 - # Try up to 40 times (2 minutes) to connect. - maxAttempts=40 + # Try up to 40 times (2 minutes) to connect. + maxAttempts=40 - # Attempt counter. - attempt=1 + # Attempt counter. + attempt=1 - # Flag to indicate when SQL Server is ready to accept connections. - ready=0 + # Flag to indicate when SQL Server is ready to accept connections. + ready=0 - while [ $attempt -le $maxAttempts ] - do + while [ $attempt -le $maxAttempts ] + do - echo "Waiting for SQL Server to start (attempt #$attempt of $maxAttempts)..." + echo "Waiting for SQL Server to start (attempt #$attempt of $maxAttempts)..." - sqlcmd -S 127.0.0.1 -No -U sa -P $MSSQL_SA_PW -Q "SELECT @@VERSION" >> $SQLCMD_ERRORS 2>&1 + sqlcmd -S 127.0.0.1 -No -U sa -P $MSSQL_SA_PW -Q "SELECT @@VERSION" >> $SQLCMD_ERRORS 2>&1 - # If the command was successful, then the SQL Server is ready. - if [ $? -eq 0 ]; then - ready=1 - break - fi + # If the command was successful, then the SQL Server is ready. + if [ $? -eq 0 ]; then + ready=1 + break + fi + + # Increment the attempt counter. + ((attempt++)) - # Increment the attempt counter. - ((attempt++)) + # Wait before trying again. + sleep $delay - # Wait before trying again. - sleep $delay + done - done + # Is the SQL Server ready? + if [ $ready -eq 0 ] + then + # No, so report the error(s) and exit. + echo Cannot connect to SQL Server; installation aborted; errors were: + cat $SQLCMD_ERRORS + rm -f $SQLCMD_ERRORS + exit 1 + fi - # Is the SQL Server ready? - if [ $ready -eq 0 ] - then - # No, so report the error(s) and exit. - echo Cannot connect to SQL Server; installation aborted; errors were: - cat $SQLCMD_ERRORS rm -f $SQLCMD_ERRORS - exit 1 - fi - - rm -f $SQLCMD_ERRORS - - echo "Use sqlcmd to show which IP addresses are being listened on..." - echo 0.0.0.0 - sqlcmd -S 0.0.0.0 -No -U sa -P $MSSQL_SA_PW -Q "SELECT @@VERSION" -l 2 - echo 127.0.0.1 - sqlcmd -S 127.0.0.1 -No -U sa -P $MSSQL_SA_PW -Q "SELECT @@VERSION" -l 2 - echo ::1 - sqlcmd -S ::1 -No -U sa -P $MSSQL_SA_PW -Q "SELECT @@VERSION" -l 2 - echo localhost - sqlcmd -S localhost -No -U sa -P $MSSQL_SA_PW -Q "SELECT @@VERSION" -l 2 - echo "(sqlcmd default / not specified)" - sqlcmd -No -U sa -P $MSSQL_SA_PW -Q "SELECT @@VERSION" -l 2 - - echo "Configuring Dedicated Administer Connections to allow remote connections..." - sqlcmd -S 127.0.0.1 -No -U sa -P $MSSQL_SA_PW -Q "sp_configure 'remote admin connections', 1; RECONFIGURE;" - if [ $? = 1 ] - then - echo "Error configuring DAC for remote access." - exit $errstatus - else - echo "Configuration complete." - fi - - displayName: 'Configure SQL Server [macOS]' + + echo "Use sqlcmd to show which IP addresses are being listened on..." + echo 0.0.0.0 + sqlcmd -S 0.0.0.0 -No -U sa -P $MSSQL_SA_PW -Q "SELECT @@VERSION" -l 2 + echo 127.0.0.1 + sqlcmd -S 127.0.0.1 -No -U sa -P $MSSQL_SA_PW -Q "SELECT @@VERSION" -l 2 + echo ::1 + sqlcmd -S ::1 -No -U sa -P $MSSQL_SA_PW -Q "SELECT @@VERSION" -l 2 + echo localhost + sqlcmd -S localhost -No -U sa -P $MSSQL_SA_PW -Q "SELECT @@VERSION" -l 2 + echo "(sqlcmd default / not specified)" + sqlcmd -No -U sa -P $MSSQL_SA_PW -Q "SELECT @@VERSION" -l 2 + + echo "Configuring Dedicated Administer Connections to allow remote connections..." + sqlcmd -S 127.0.0.1 -No -U sa -P $MSSQL_SA_PW -Q "sp_configure 'remote admin connections', 1; RECONFIGURE;" + if [ $? = 1 ] + then + echo "Error configuring DAC for remote access." + exit $errstatus + else + echo "Configuration complete." + fi + + displayName: 'Configure SQL Server [macOS]' diff --git a/eng/pipelines/common/templates/steps/configure-sql-server-step.yml b/eng/pipelines/common/templates/steps/configure-sql-server-step.yml index 822070e5ca..605b7311a6 100644 --- a/eng/pipelines/common/templates/steps/configure-sql-server-step.yml +++ b/eng/pipelines/common/templates/steps/configure-sql-server-step.yml @@ -17,6 +17,11 @@ parameters: type: string default: $(saUser) + # The SA password to set when configuring SQL Server. This will also be used for user accounts + # if necessary. + - name: saPassword + type: string + - name: SQLRootPath type: string default: '' @@ -76,6 +81,7 @@ steps: instanceName: ${{parameters.instanceName}} user: ${{parameters.user}} saUser: ${{parameters.saUser}} + saPassword: ${{parameters.saPassword}} SQLRootPath: ${{parameters.SQLRootPath}} fileStreamDirectory: ${{parameters.fileStreamDirectory}} x64AliasRegistryPath: ${{parameters.x64AliasRegistryPath}} @@ -89,10 +95,14 @@ steps: - ${{ elseif eq(parameters.operatingSystem, 'Linux') }}: # Linux only steps - template: /eng/pipelines/common/templates/steps/configure-sql-server-linux-step.yml@self + parameters: + saPassword: ${{ parameters.saPassword }} - ${{ elseif eq(parameters.operatingSystem, 'Mac') }}: # macOS only steps - template: /eng/pipelines/common/templates/steps/configure-sql-server-macos-step.yml@self + parameters: + saPassword: ${{ parameters.saPassword }} # Common steps - task: DotNetCoreCLI@2 diff --git a/eng/pipelines/common/templates/steps/configure-sql-server-win-step.yml b/eng/pipelines/common/templates/steps/configure-sql-server-win-step.yml index f692d6424d..04dc8a505d 100644 --- a/eng/pipelines/common/templates/steps/configure-sql-server-win-step.yml +++ b/eng/pipelines/common/templates/steps/configure-sql-server-win-step.yml @@ -7,12 +7,9 @@ # This step configures an existing SQL Server running on the local Windows host. For example, our # 1ES Hosted Pool has images like ADO-MMS22-SQL22 that come with SQL Server 2022 pre-installed and # running. -# -# The SA password is set to the value of the $(Password) variable defined in the ADO Library "ADO -# Test Configuration properties", brought in by common/templates/libraries/ci-build-variables.yml. parameters: -# Windows only parameters + - name: instanceName type: string default: MSSQLSERVER @@ -25,6 +22,10 @@ parameters: type: string default: $(saUser) + # The SA password to set when configuring SQL Server. This is also used for the user password. + - name: saPassword + type: string + - name: SQLRootPath type: string default: '' @@ -62,85 +63,43 @@ parameters: default: $(LocalDbSharedInstanceName) steps: -# Windows only steps -- powershell: | - try - { - # enable TCP - Import-Module "sqlps" - $smo = 'Microsoft.SqlServer.Management.Smo.' - $wmi = new-object ($smo + 'Wmi.ManagedComputer'). - # List the object properties, including the instance names. - $Wmi - - # Enable the TCP protocol on the default instance. - $Tcp = $wmi.GetSmoObject("ManagedComputer[@Name='$env:COMPUTERNAME']/ ServerInstance[@Name='${{parameters.instanceName }}']/ServerProtocol[@Name='Tcp']") - $Tcp.IsEnabled = $true - $Tcp.Alter() - - # Enable the NP protocol on the default instance. - $Np = $wmi.GetSmoObject("ManagedComputer[@Name='$env:COMPUTERNAME']/ ServerInstance[@Name='${{parameters.instanceName }}']/ServerProtocol[@Name='Np']") - $Np.IsEnabled = $true - $Np.Alter() - - $Tcp - } - catch - { - $error[0] | format-list -force - throw - } - - New-NetFirewallRule -DisplayName "SQL TCP Ports" -Direction Inbound -Protocol TCP -LocalPort 1433 -Action allow - $sqlSrvPath = (Get-WmiObject win32_service | ?{$_.DisplayName -eq 'SQL Server (${{parameters.instanceName }})'} | select @{Name="Path"; Expression={$_.PathName.split('"')[1]}}).Path - New-NetFirewallRule -DisplayName "sqlservr.exe" -Program "$sqlSrvPath" - displayName: 'Enable TCP, NP & Firewall [Win]' - retryCountOnTaskFailure: 2 - -- powershell: | - $password = "$(Password)" - - $machineName = $env:COMPUTERNAME - - if ("${{parameters.instanceName }}" -ne "MSSQLSERVER"){ - $machineName += "\${{parameters.instanceName }}" - } - - Write-Host $machineName - Import-Module "sqlps" - $tries = 0 - while ($true) { - $tries++ - try { - Invoke-Sqlcmd -ServerInstance "$machineName" @" - CREATE LOGIN [${{parameters.user }}] WITH PASSWORD=N'$password', - DEFAULT_DATABASE=[master], DEFAULT_LANGUAGE=[us_english], CHECK_EXPIRATION=OFF, CHECK_POLICY=OFF; - CREATE USER [${{parameters.user }}] FROM LOGIN [${{parameters.user }}]; - ALTER SERVER ROLE [sysadmin] ADD MEMBER [${{parameters.user }}]; - ALTER LOGIN [${{parameters.saUser }}] ENABLE; - ALTER LOGIN [${{parameters.saUser }}] WITH PASSWORD = '$password'; - "@ - break - } catch { - if ($tries -ge 5) { - Write-Host "##[error]Failed to create database user after $tries tries." - break - } - Write-Host "Failed to connect to server. Retrying in 5 seconds..." - Start-Sleep -Seconds 5 - } - } - displayName: 'Create SQL user [Win]' - env: - SQL_USER: ${{parameters.user }} - SQL_PASSWD: $(Password) -- ${{ if ne(parameters.SQLRootPath, '') }}: - powershell: | - #Enable FileStream - $instance = "${{parameters.instanceName }}" - $wmi = Get-WmiObject -Namespace "${{parameters.SQLRootPath }}" -Class FilestreamSettings | where {$_.InstanceName -eq $instance} - $wmi.EnableFilestream(3, $instance) + try + { + # enable TCP + Import-Module "sqlps" + $smo = 'Microsoft.SqlServer.Management.Smo.' + $wmi = new-object ($smo + 'Wmi.ManagedComputer'). + # List the object properties, including the instance names. + $Wmi + + # Enable the TCP protocol on the default instance. + $Tcp = $wmi.GetSmoObject("ManagedComputer[@Name='$env:COMPUTERNAME']/ ServerInstance[@Name='${{parameters.instanceName }}']/ServerProtocol[@Name='Tcp']") + $Tcp.IsEnabled = $true + $Tcp.Alter() + + # Enable the NP protocol on the default instance. + $Np = $wmi.GetSmoObject("ManagedComputer[@Name='$env:COMPUTERNAME']/ ServerInstance[@Name='${{parameters.instanceName }}']/ServerProtocol[@Name='Np']") + $Np.IsEnabled = $true + $Np.Alter() + + $Tcp + } + catch + { + $error[0] | format-list -force + throw + } + + New-NetFirewallRule -DisplayName "SQL TCP Ports" -Direction Inbound -Protocol TCP -LocalPort 1433 -Action allow + $sqlSrvPath = (Get-WmiObject win32_service | ?{$_.DisplayName -eq 'SQL Server (${{parameters.instanceName }})'} | select @{Name="Path"; Expression={$_.PathName.split('"')[1]}}).Path + New-NetFirewallRule -DisplayName "sqlservr.exe" -Program "$sqlSrvPath" + displayName: 'Enable TCP, NP & Firewall [Win]' + retryCountOnTaskFailure: 2 + + - powershell: | + $password = "${{ parameters.saPassword }}" $machineName = $env:COMPUTERNAME @@ -148,128 +107,170 @@ steps: $machineName += "\${{parameters.instanceName }}" } - #Change the access level for FileStream for SQLServer - Set-ExecutionPolicy Unrestricted + Write-Host $machineName Import-Module "sqlps" - Invoke-Sqlcmd -ServerInstance "$machineName" @" - EXEC sp_configure filestream_access_level, 2; - RECONFIGURE; + $tries = 0 + while ($true) { + $tries++ + try { + Invoke-Sqlcmd -ServerInstance "$machineName" @" + CREATE LOGIN [${{parameters.user }}] WITH PASSWORD=N'$password', + DEFAULT_DATABASE=[master], DEFAULT_LANGUAGE=[us_english], CHECK_EXPIRATION=OFF, CHECK_POLICY=OFF; + CREATE USER [${{parameters.user }}] FROM LOGIN [${{parameters.user }}]; + ALTER SERVER ROLE [sysadmin] ADD MEMBER [${{parameters.user }}]; + ALTER LOGIN [${{parameters.saUser }}] ENABLE; + ALTER LOGIN [${{parameters.saUser }}] WITH PASSWORD = '$password'; "@ - displayName: 'Enable FileStream [Win]' + break + } catch { + if ($tries -ge 5) { + Write-Host "##[error]Failed to create database user after $tries tries." + break + } + Write-Host "Failed to connect to server. Retrying in 5 seconds..." + Start-Sleep -Seconds 5 + } + } + displayName: 'Create SQL user [Win]' env: SQL_USER: ${{parameters.user }} - SQL_PASSWD: $(Password) + SQL_PASSWD: ${{ parameters.saPassword }} -- ${{ if ne(parameters.FileStreamDirectory, '') }}: - - powershell: | - New-Item -Path ${{ parameters.fileStreamDirectory }} -ItemType Directory - displayName: 'Create FileStreamFolder' - retryCountOnTaskFailure: 1 - continueOnError: true - -- powershell: | - $SQLServerName = ("{0}" -f [System.Net.Dns]::GetHostByName($env:computerName).HostName) - Write-Host FQDN is: $SQLServerName - - if ((Test-Path -Path ${{parameters.x64AliasRegistryPath }}) -ne $true) { - New-Item ${{parameters.x64AliasRegistryPath }} - } - - if ((Test-Path -Path ${{parameters.x86AliasRegistryPath }}) -ne $true) { - New-Item ${{parameters.x86AliasRegistryPath }} - } - - $TCPAliasName = "DBMSSOCN, $SQLServerName, ${{parameters.SQLAliasPort }}" - - New-ItemProperty -Path ${{parameters.x86AliasRegistryPath }} -Name ${{parameters.SQLAliasName }} -PropertyType string -Value $TCPAliasName - New-ItemProperty -Path ${{parameters.x64AliasRegistryPath }} -Name ${{parameters.SQLAliasName }} -PropertyType string -Value $TCPAliasName - displayName: 'Setup SQL Alias [Win]' - -- powershell: | - # Create Certificate - $computerDnsName = [System.Net.Dns]::Resolve($null).HostName - $certificate = New-SelfSignedCertificate -DnsName $computerDnsName,localhost -CertStoreLocation cert:\LocalMachine\My -FriendlyName test99 -KeySpec KeyExchange - - # Get path to Private key (used later) - $keyPath = $certificate.PrivateKey.CspKeyContainerInfo.UniqueKeyContainerName - $machineKeyPath = "$env:ProgramData\Microsoft\Crypto\RSA\MachineKeys\$keyPath" - - # Add certificate to trusted roots - $store = new-object System.Security.Cryptography.X509Certificates.X509Store( - [System.Security.Cryptography.X509Certificates.StoreName]::Root, - "localmachine" - ) - - $store.open("MaxAllowed") - $store.add($certificate) - $store.close() - - # Get SQL Server instances and add the Certificate - $instances = Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server\Instance Names\SQL' - foreach ($instance in $instances){ - $instance | ForEach-Object { - $_.PSObject.Properties | Where-Object { $_.Name -notmatch '^PS.*' } | ForEach-Object { - Set-ItemProperty "HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server\$($_.Value)\MSSQLServer\SuperSocketNetLib" -Name Certificate -Value $certificate.Thumbprint.ToLower() - - # Grant read access to Private Key for SQL Service Account - if ($($_.Name) -eq "MSSQLSERVER") { - icacls $machineKeyPath /grant "NT Service\MSSQLSERVER:R" - } else { - icacls $machineKeyPath /grant "NT Service\MSSQL`$$($_.Name):R" - } - } - } - } - displayName: 'Add SQL Certificate [Win]' - -- powershell: | - # You need to restart SQL Server for the change to persist - # -Force takes care of any dependent services, like SQL Agent. - # Note: if the instance is named, replace MSSQLSERVER with MSSQL$ followed by - # the name of the instance (e.g. MSSQL$MYINSTANCE) - - $serviceName = "${{parameters.instanceName }}" - $InstancePrefix = 'MSSQL$' - - if ( "${{parameters.instanceName }}" -ne "MSSQLSERVER" ) - { - $serviceName = $InstancePrefix+"${{parameters.instanceName }}" - } - - Restart-Service -Name "$serviceName" -Force - Restart-Service -Name MSSQLSERVER* -Force - - displayName: 'Restart SQL Server [Win]' - -- powershell: | - $arrService = Get-Service -Name "SQLBrowser" - $arrService - - if ($arrService.Status -eq 'Stopped') { - Write-Host 'Attempt to run the service ...' - # updating the startup type to make sure it's not disabled - Set-Service -StartupType Automatic $arrService.Name - $arrService.Start() - - $arrService.WaitForStatus('Running', '00:00:30') - if ($arrService.Status -eq 'Running') { - $arrService - } else { - Write-Error 'Timed out waiting for service to start.' + - ${{ if ne(parameters.SQLRootPath, '') }}: + - powershell: | + #Enable FileStream + $instance = "${{parameters.instanceName }}" + $wmi = Get-WmiObject -Namespace "${{parameters.SQLRootPath }}" -Class FilestreamSettings | where {$_.InstanceName -eq $instance} + $wmi.EnableFilestream(3, $instance) + + $machineName = $env:COMPUTERNAME + + if ("${{parameters.instanceName }}" -ne "MSSQLSERVER"){ + $machineName += "\${{parameters.instanceName }}" } - } - displayName: 'Start Sql Server Browser [Win]' -- ${{ if parameters.enableLocalDB }}: + #Change the access level for FileStream for SQLServer + Set-ExecutionPolicy Unrestricted + Import-Module "sqlps" + Invoke-Sqlcmd -ServerInstance "$machineName" @" + EXEC sp_configure filestream_access_level, 2; + RECONFIGURE; + "@ + displayName: 'Enable FileStream [Win]' + env: + SQL_USER: ${{parameters.user }} + SQL_PASSWD: ${{ parameters.saPassword }} + + - ${{ if ne(parameters.FileStreamDirectory, '') }}: + - powershell: | + New-Item -Path ${{ parameters.fileStreamDirectory }} -ItemType Directory + displayName: 'Create FileStreamFolder' + retryCountOnTaskFailure: 1 + continueOnError: true + + - powershell: | + $SQLServerName = ("{0}" -f [System.Net.Dns]::GetHostByName($env:computerName).HostName) + Write-Host FQDN is: $SQLServerName + + if ((Test-Path -Path ${{parameters.x64AliasRegistryPath }}) -ne $true) { + New-Item ${{parameters.x64AliasRegistryPath }} + } + + if ((Test-Path -Path ${{parameters.x86AliasRegistryPath }}) -ne $true) { + New-Item ${{parameters.x86AliasRegistryPath }} + } + + $TCPAliasName = "DBMSSOCN, $SQLServerName, ${{parameters.SQLAliasPort }}" + + New-ItemProperty -Path ${{parameters.x86AliasRegistryPath }} -Name ${{parameters.SQLAliasName }} -PropertyType string -Value $TCPAliasName + New-ItemProperty -Path ${{parameters.x64AliasRegistryPath }} -Name ${{parameters.SQLAliasName }} -PropertyType string -Value $TCPAliasName + displayName: 'Setup SQL Alias [Win]' + + - powershell: | + # Create Certificate + $computerDnsName = [System.Net.Dns]::Resolve($null).HostName + $certificate = New-SelfSignedCertificate -DnsName $computerDnsName,localhost -CertStoreLocation cert:\LocalMachine\My -FriendlyName test99 -KeySpec KeyExchange + + # Get path to Private key (used later) + $keyPath = $certificate.PrivateKey.CspKeyContainerInfo.UniqueKeyContainerName + $machineKeyPath = "$env:ProgramData\Microsoft\Crypto\RSA\MachineKeys\$keyPath" + + # Add certificate to trusted roots + $store = new-object System.Security.Cryptography.X509Certificates.X509Store( + [System.Security.Cryptography.X509Certificates.StoreName]::Root, + "localmachine" + ) + + $store.open("MaxAllowed") + $store.add($certificate) + $store.close() + + # Get SQL Server instances and add the Certificate + $instances = Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server\Instance Names\SQL' + foreach ($instance in $instances){ + $instance | ForEach-Object { + $_.PSObject.Properties | Where-Object { $_.Name -notmatch '^PS.*' } | ForEach-Object { + Set-ItemProperty "HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server\$($_.Value)\MSSQLServer\SuperSocketNetLib" -Name Certificate -Value $certificate.Thumbprint.ToLower() + + # Grant read access to Private Key for SQL Service Account + if ($($_.Name) -eq "MSSQLSERVER") { + icacls $machineKeyPath /grant "NT Service\MSSQLSERVER:R" + } else { + icacls $machineKeyPath /grant "NT Service\MSSQL`$$($_.Name):R" + } + } + } + } + displayName: 'Add SQL Certificate [Win]' + - powershell: | - #script to enable local db + # You need to restart SQL Server for the change to persist + # -Force takes care of any dependent services, like SQL Agent. + # Note: if the instance is named, replace MSSQLSERVER with MSSQL$ followed by + # the name of the instance (e.g. MSSQL$MYINSTANCE) + + $serviceName = "${{parameters.instanceName }}" + $InstancePrefix = 'MSSQL$' + + if ( "${{parameters.instanceName }}" -ne "MSSQLSERVER" ) + { + $serviceName = $InstancePrefix+"${{parameters.instanceName }}" + } + + Restart-Service -Name "$serviceName" -Force + Restart-Service -Name MSSQLSERVER* -Force + + displayName: 'Restart SQL Server [Win]' + + - powershell: | + $arrService = Get-Service -Name "SQLBrowser" + $arrService + + if ($arrService.Status -eq 'Stopped') { + Write-Host 'Attempt to run the service ...' + # updating the startup type to make sure it's not disabled + Set-Service -StartupType Automatic $arrService.Name + $arrService.Start() + + $arrService.WaitForStatus('Running', '00:00:30') + if ($arrService.Status -eq 'Running') { + $arrService + } else { + Write-Error 'Timed out waiting for service to start.' + } + } + displayName: 'Start Sql Server Browser [Win]' + + - ${{ if parameters.enableLocalDB }}: + - powershell: | + #script to enable local db - SqlLocalDB info - #SqlLocalDB create ${{parameters.localDbAppName }} - SqlLocalDB info ${{parameters.localDbAppName }} - SqlLocalDB share ${{parameters.localDbAppName }} ${{parameters.LocalDbSharedInstanceName }} - SqlLocalDB start ${{parameters.localDbAppName }} - SqlLocalDB info ${{parameters.localDbAppName }} + SqlLocalDB info + #SqlLocalDB create ${{parameters.localDbAppName }} + SqlLocalDB info ${{parameters.localDbAppName }} + SqlLocalDB share ${{parameters.localDbAppName }} ${{parameters.LocalDbSharedInstanceName }} + SqlLocalDB start ${{parameters.localDbAppName }} + SqlLocalDB info ${{parameters.localDbAppName }} - sqlcmd -S "(localdb)\.\${{parameters.LocalDbSharedInstanceName }}" -q "SELECT @@VERSION" - displayName: 'Enable LocalDB [Win]' + sqlcmd -S "(localdb)\.\${{parameters.LocalDbSharedInstanceName }}" -q "SELECT @@VERSION" + displayName: 'Enable LocalDB [Win]' diff --git a/eng/pipelines/common/templates/steps/update-config-file-step.yml b/eng/pipelines/common/templates/steps/update-config-file-step.yml index 65ac9ecf08..7610fafcfa 100644 --- a/eng/pipelines/common/templates/steps/update-config-file-step.yml +++ b/eng/pipelines/common/templates/steps/update-config-file-step.yml @@ -8,6 +8,10 @@ parameters: type: boolean default: false + # The SA password to set when configuring SQL Server. + - name: saPassword + type: string + - name: TCPConnectionString type: string default: '' @@ -35,11 +39,11 @@ parameters: - name: TracingEnabled type: boolean default: false - + - name: AADAuthorityURL type: string default: '' - + - name: AADPasswordConnectionString type: string default: '' @@ -72,15 +76,15 @@ parameters: type: string default: '' - - name: LocalDbAppName + - name: LocalDbAppName type: string default: '' - - name: LocalDbSharedInstanceName + - name: LocalDbSharedInstanceName type: string default: '' - - name: AliasName + - name: AliasName type: string default: '' @@ -92,19 +96,19 @@ parameters: type: boolean default: false - - name: DNSCachingConnString + - name: DNSCachingConnString type: string default: '' - - name: DNSCachingServerCR + - name: DNSCachingServerCR type: string default: '' - - name: DNSCachingServerTR + - name: DNSCachingServerTR type: string default: '' - - name: EnclaveAzureDatabaseConnString + - name: EnclaveAzureDatabaseConnString type: string default: '' @@ -129,76 +133,93 @@ parameters: default: '' steps: -# All properties should be added here, and this template should be used for any manipulation of the config.json file. -- pwsh: | - $jdata = Get-Content -Raw "config.default.json" | ConvertFrom-Json - foreach ($p in $jdata) - { - $p.TCPConnectionString="${{parameters.TCPConnectionString }}" - $p.NPConnectionString="${{parameters.NPConnectionString }}" + # Some of the connection strings brought in from Azure DevOps Library groups expect a runtime + # $(Password) variable to exist. This is used for username/password logins to SQL Servers running + # locally on the agent. We must set $(Password) here so it is available when those connection + # strings are expanded. We cannot use a Library variable because it will be deemed a secret, and + # will not be available to forked repos. + # + # We use the saPassword parameter as the value for this variable. + # + # From this point forward in this step, any pipeline runtime expansion of $(Password) will use the + # saPassword parameter's value. + # + - pwsh: | + $password = "${{ parameters.saPassword }}" + Write-Host "##vso[task.setvariable variable=Password;isSecret=true]$password" + displayName: Set Connection String Password + + # All properties should be added here, and this template should be used for any manipulation of the config.json file. + - pwsh: | + $jdata = Get-Content -Raw "config.default.json" | ConvertFrom-Json + foreach ($p in $jdata) + { + $p.TCPConnectionString="${{parameters.TCPConnectionString }}" - $p.AADAuthorityURL="${{parameters.AADAuthorityURL }}" + $p.NPConnectionString="${{parameters.NPConnectionString }}" - $p.AADPasswordConnectionString="${{parameters.AADPasswordConnectionString }}" + $p.AADAuthorityURL="${{parameters.AADAuthorityURL }}" - $p.AADServicePrincipalId="${{parameters.AADServicePrincipalId }}" + $p.AADPasswordConnectionString="${{parameters.AADPasswordConnectionString }}" - $p.AADServicePrincipalSecret="${{parameters.AADServicePrincipalSecret }}" + $p.AADServicePrincipalId="${{parameters.AADServicePrincipalId }}" - $p.AzureKeyVaultUrl="${{parameters.AzureKeyVaultUrl }}" + $p.AADServicePrincipalSecret="${{parameters.AADServicePrincipalSecret }}" - $p.AzureKeyVaultTenantId="${{parameters.AzureKeyVaultTenantId }}" + $p.AzureKeyVaultUrl="${{parameters.AzureKeyVaultUrl }}" - $p.UserManagedIdentityClientId="${{parameters.UserManagedIdentityClientId }}" + $p.AzureKeyVaultTenantId="${{parameters.AzureKeyVaultTenantId }}" - $p.FileStreamDirectory="${{parameters.FileStreamDirectory }}" + $p.UserManagedIdentityClientId="${{parameters.UserManagedIdentityClientId }}" - $p.LocalDbSharedInstanceName="${{parameters.LocalDbSharedInstanceName }}" + $p.FileStreamDirectory="${{parameters.FileStreamDirectory }}" - $p.AliasName="${{parameters.AliasName }}" + $p.LocalDbSharedInstanceName="${{parameters.LocalDbSharedInstanceName }}" - $p.EnclaveAzureDatabaseConnString="${{parameters.EnclaveAzureDatabaseConnString }}" + $p.AliasName="${{parameters.AliasName }}" - $p.DNSCachingServerTR="${{parameters.DNSCachingServerTR }}" + $p.EnclaveAzureDatabaseConnString="${{parameters.EnclaveAzureDatabaseConnString }}" - $p.DNSCachingServerCR="${{parameters.DNSCachingServerCR }}" + $p.DNSCachingServerTR="${{parameters.DNSCachingServerTR }}" - $p.DNSCachingConnString="${{parameters.DNSCachingConnString }}" + $p.DNSCachingServerCR="${{parameters.DNSCachingServerCR }}" - $p.SupportsFileStream="${{parameters.SupportsFileStream }}" + $p.DNSCachingConnString="${{parameters.DNSCachingConnString }}" - $p.LocalDbAppName="${{parameters.LocalDbAppName }}" + $p.SupportsFileStream="${{parameters.SupportsFileStream }}" - $p.TCPConnectionStringAASSGX="${{parameters.TCPConnectionStringAASSGX }}" + $p.LocalDbAppName="${{parameters.LocalDbAppName }}" - $p.TCPConnectionStringNoneVBS="${{parameters.TCPConnectionStringNoneVBS }}" + $p.TCPConnectionStringAASSGX="${{parameters.TCPConnectionStringAASSGX }}" - $p.TCPConnectionStringHGSVBS="${{parameters.TCPConnectionStringHGSVBS }}" + $p.TCPConnectionStringNoneVBS="${{parameters.TCPConnectionStringNoneVBS }}" - $p.UseManagedSNIOnWindows=[System.Convert]::ToBoolean("${{parameters.UseManagedSNIOnWindows }}") - $p.SupportsIntegratedSecurity=[System.Convert]::ToBoolean("${{parameters.SupportsIntegratedSecurity }}") - $p.ManagedIdentitySupported=[System.Convert]::ToBoolean("${{parameters.ManagedIdentitySupported }}") - $p.IsAzureSynapse=[System.Convert]::ToBoolean("${{parameters.IsAzureSynapse }}") - $p.IsDNSCachingSupportedTR=[System.Convert]::ToBoolean("${{parameters.IsDNSCachingSupportedTR }}") - $p.IsDNSCachingSupportedCR=[System.Convert]::ToBoolean("${{parameters.IsDNSCachingSupportedCR }}") - $p.TracingEnabled=[System.Convert]::ToBoolean("${{parameters.TracingEnabled }}") - $p.EnclaveEnabled=[System.Convert]::ToBoolean("${{parameters.EnclaveEnabled }}") - $p.WorkloadIdentityFederationServiceConnectionId="${{parameters.WorkloadIdentityFederationServiceConnectionId }}" - } - $jdata | ConvertTo-Json | Set-Content "config.json" - workingDirectory: src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities - displayName: 'Update config.json' + $p.TCPConnectionStringHGSVBS="${{parameters.TCPConnectionStringHGSVBS }}" -- ${{ if eq(parameters.debug, true) }}: - - pwsh: | - $jdata = Get-Content -Raw "config.json" | ConvertFrom-Json - foreach ($p in $jdata) - { - foreach ($prop in $p.PSObject.Properties) - { - Write-Host "Property: $($prop.Name) Value: $($prop.Value)" - } + $p.UseManagedSNIOnWindows=[System.Convert]::ToBoolean("${{parameters.UseManagedSNIOnWindows }}") + $p.SupportsIntegratedSecurity=[System.Convert]::ToBoolean("${{parameters.SupportsIntegratedSecurity }}") + $p.ManagedIdentitySupported=[System.Convert]::ToBoolean("${{parameters.ManagedIdentitySupported }}") + $p.IsAzureSynapse=[System.Convert]::ToBoolean("${{parameters.IsAzureSynapse }}") + $p.IsDNSCachingSupportedTR=[System.Convert]::ToBoolean("${{parameters.IsDNSCachingSupportedTR }}") + $p.IsDNSCachingSupportedCR=[System.Convert]::ToBoolean("${{parameters.IsDNSCachingSupportedCR }}") + $p.TracingEnabled=[System.Convert]::ToBoolean("${{parameters.TracingEnabled }}") + $p.EnclaveEnabled=[System.Convert]::ToBoolean("${{parameters.EnclaveEnabled }}") + $p.WorkloadIdentityFederationServiceConnectionId="${{parameters.WorkloadIdentityFederationServiceConnectionId }}" } + $jdata | ConvertTo-Json | Set-Content "config.json" workingDirectory: src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities - displayName: '[Debug] Emit config.json' + displayName: 'Update config.json' + + - ${{ if eq(parameters.debug, true) }}: + - pwsh: | + $jdata = Get-Content -Raw "config.json" | ConvertFrom-Json + foreach ($p in $jdata) + { + foreach ($prop in $p.PSObject.Properties) + { + Write-Host "Property: $($prop.Name) Value: $($prop.Value)" + } + } + workingDirectory: src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities + displayName: '[Debug] Emit config.json' diff --git a/eng/pipelines/dotnet-sqlclient-ci-core.yml b/eng/pipelines/dotnet-sqlclient-ci-core.yml index a0f28d11d7..20f9375c64 100644 --- a/eng/pipelines/dotnet-sqlclient-ci-core.yml +++ b/eng/pipelines/dotnet-sqlclient-ci-core.yml @@ -122,6 +122,9 @@ variables: stages: + # Generate secrets used throughout the pipeline. + - template: /eng/pipelines/stages/generate-secrets-ci-stage.yml@self + # Build the Abstractions package, and publish it to the pipeline artifacts # under the given artifact name. - template: /eng/pipelines/stages/build-abstractions-package-ci-stage.yml@self @@ -174,12 +177,17 @@ stages: # packages. ${{ if eq(parameters.referenceType, 'Package') }}: dependsOn: + - secrets_stage - build_abstractions_package_stage - build_mds_akv_packages_stage + ${{ else }}: + dependsOn: + - secrets_stage dotnetVerbosity: ${{ parameters.dotnetVerbosity }} mdsArtifactsName: $(mdsArtifactsName) mdsPackageVersion: $(mdsPackageVersion) referenceType: ${{ parameters.referenceType }} + saPassword: $[stageDependencies.secrets_stage.secrets_job.outputs['SaPassword.Value']] # Run the stress tests, if desired. - ${{ if eq(parameters.enableStressTests, true) }}: @@ -187,12 +195,14 @@ stages: parameters: buildConfiguration: ${{ parameters.buildConfiguration }} dependsOn: + - secrets_stage - build_mds_akv_packages_stage - build_azure_package_stage mdsArtifactsName: $(mdsArtifactsName) mdsPackageVersion: $(mdsPackageVersion) azurePackageVersion: $(azurePackageVersion) dotnetVerbosity: ${{ parameters.dotnetVerbosity }} + saPassword: $[stageDependencies.secrets_stage.secrets_job.outputs['SaPassword.Value']] # Run the MDS and AKV tests. - template: /eng/pipelines/common/templates/stages/ci-run-tests-stage.yml@self @@ -204,15 +214,20 @@ stages: abstractionsPackageVersion: $(abstractionsPackageVersion) mdsArtifactsName: $(mdsArtifactsName) mdsPackageVersion: $(mdsPackageVersion) + saPassword: $[stageDependencies.secrets_stage.secrets_job.outputs['SaPassword.Value']] testJobTimeout: ${{ parameters.testJobTimeout }} # When testing MDS via packages, we must depend on the Abstractions, # MDS, and Azure packages. ${{ if eq(parameters.referenceType, 'Package') }}: dependsOn: + - secrets_stage - build_abstractions_package_stage - build_mds_akv_packages_stage - build_azure_package_stage + ${{ else }}: + dependsOn: + - secrets_stage # Steps to run prior to building and running tests on each job. prebuildSteps: diff --git a/eng/pipelines/jobs/stress-tests-ci-job.yml b/eng/pipelines/jobs/stress-tests-ci-job.yml index 53de7e407f..7477295f54 100644 --- a/eng/pipelines/jobs/stress-tests-ci-job.yml +++ b/eng/pipelines/jobs/stress-tests-ci-job.yml @@ -39,13 +39,8 @@ parameters: default: '' # The pipeline step to run to configure SQL Server. - # - # This step is expected to require no parameters. It must configure a SQL - # Server instance listening on localhost for SQL auth via the 'sa' user with - # the pipeline variable $(Password) as the password. - name: sqlSetupStep - type: string - default: '' + type: step # The name of the MDS pipeline artifacts to download. - name: mdsArtifactsName @@ -83,9 +78,6 @@ parameters: default: [] # The stress test config file contents to write to the config file. - # - # This should point to the SQL Server configured via the sqlSetupStep - # parameter, with user 'sa' and password of $(Password). - name: configContent type: string default: '' @@ -143,7 +135,7 @@ jobs: targetPath: $(Build.SourcesDirectory)/packages # Setup the local SQL Server. - - template: ${{ parameters.sqlSetupStep }}@self + - ${{ parameters.sqlSetupStep }} # We use the 'custom' command because the DotNetCoreCLI@2 task doesn't support # all of our argument combinations for the different build steps. diff --git a/eng/pipelines/jobs/test-azure-package-ci-job.yml b/eng/pipelines/jobs/test-azure-package-ci-job.yml index bb44facb73..54c82752f1 100644 --- a/eng/pipelines/jobs/test-azure-package-ci-job.yml +++ b/eng/pipelines/jobs/test-azure-package-ci-job.yml @@ -97,6 +97,11 @@ parameters: - Package - Project + # The SA password set by the sqlServerSetupSteps, if relevant. + - name: saPassword + type: string + default: '' + # Steps to run, if any, to configure a local SQL Server instance on the agent # VM. - name: sqlServerSetupSteps @@ -222,6 +227,7 @@ jobs: - template: /eng/pipelines/common/templates/steps/update-config-file-step.yml@self parameters: debug: ${{ parameters.debug }} + saPassword: ${{ parameters.saPassword }} # The config.json file has many options, but only some of them are # used by the Azure package tests. We only specify the ones that are diff --git a/eng/pipelines/stages/build-azure-package-ci-stage.yml b/eng/pipelines/stages/build-azure-package-ci-stage.yml index a756a48eb2..521d4e7883 100644 --- a/eng/pipelines/stages/build-azure-package-ci-stage.yml +++ b/eng/pipelines/stages/build-azure-package-ci-stage.yml @@ -119,6 +119,10 @@ parameters: - Package - Project + # The SA password to set when configuring SQL Server. + - name: saPassword + type: string + stages: - stage: build_azure_package_stage @@ -164,9 +168,12 @@ stages: netRuntimes: [net8.0, net9.0, net10.0] poolName: ${{ parameters.adoPoolName }} referenceType: ${{ parameters.referenceType }} + saPassword: ${{ parameters.saPassword }} # The image includes a SQL Server instance that we must configure. sqlServerSetupSteps: - template: /eng/pipelines/common/templates/steps/configure-sql-server-linux-step.yml@self + parameters: + saPassword: ${{ parameters.saPassword }} vmImage: ADO-UB22-SQL22 # ------------------------------------------------------------------------ @@ -206,11 +213,13 @@ stages: netRuntimes: [net8.0, net9.0, net10.0] poolName: ${{ parameters.adoPoolName }} referenceType: ${{ parameters.referenceType }} + saPassword: ${{ parameters.saPassword }} # The image includes a SQL Server instance that we must configure. sqlServerSetupSteps: - template: /eng/pipelines/common/templates/steps/configure-sql-server-win-step.yml@self # Use defaults for most parameters. parameters: + saPassword: ${{ parameters.saPassword }} enableLocalDB: true # These variables are from an Azure DevOps Library variable # group. diff --git a/eng/pipelines/stages/generate-secrets-ci-stage.yml b/eng/pipelines/stages/generate-secrets-ci-stage.yml new file mode 100644 index 0000000000..28a2e4bb40 --- /dev/null +++ b/eng/pipelines/stages/generate-secrets-ci-stage.yml @@ -0,0 +1,40 @@ +#################################################################################################### +# Licensed to the .NET Foundation under one or more agreements. The .NET Foundation licenses this +# file to you under the MIT license. See the LICENSE file in the project root for more information. +#################################################################################################### + +# This stage generates the following random secrets for use throughout the PR and CI pipelines: +# +# SaPassword - A random GUID suitable for use as the SA password of local SQL Server instances. +# +# Subsequent stages may reference these variables as: +# +# $[stageDependencies.secrets_stage.secrets_job.outputs['SaPassword.Value']] +# +# For further details on the stage-dependency syntax, see: +# +# https://learn.microsoft.com/en-us/azure/devops/pipelines/process/set-variables-scripts?view=azure-devops&tabs=bash#set-an-output-variable-for-use-in-future-stages +# +# Any stages that use these secrets must depend on this stage: +# +# secrets_stage + +stages: + - stage: secrets_stage + displayName: Generate Secrets + jobs: + - job: secrets_job + displayName: Generate Secrets + pool: + vmImage: ubuntu-latest + steps: + + # Generate a password suitable for the SA user of local SQL Server instances. + # + # This creates the SaPassword.Value variable. + # + - bash: | + guid=$(cat /proc/sys/kernel/random/uuid) + echo "##vso[task.setvariable variable=Value;isSecret=true;isOutput=true]$guid" + name: SaPassword + displayName: Generate SA password diff --git a/eng/pipelines/stages/stress-tests-ci-stage.yml b/eng/pipelines/stages/stress-tests-ci-stage.yml index d1eae30ff4..81f7170d79 100644 --- a/eng/pipelines/stages/stress-tests-ci-stage.yml +++ b/eng/pipelines/stages/stress-tests-ci-stage.yml @@ -12,9 +12,7 @@ # src/Microsoft.Data.SqlClient/tests/StressTests # # All tests use a localhost SQL Server configured for SQL auth via the 'sa' user -# and password of '$(Password)'. The $(Password) variable is defined in the ADO -# Library "ADO Test Configuration properties", brought in by -# common/templates/libraries/ci-build-variables.yml. +# and the provided password. # # This template defines a stage named 'run_stress_tests_stage' that can be # depended on by downstream stages. @@ -71,6 +69,10 @@ parameters: type: object default: [net8.0, net9.0, net10.0] + # The SA password to set when configuring SQL Server. + - name: saPassword + type: string + stages: - stage: run_stress_tests_stage displayName: Run Stress Tests @@ -116,7 +118,7 @@ stages: "isDefault": true, "dataSource": "localhost", "user": "sa", - "password": "$(Password)", + "password": "${{ parameters.saPassword }}", "supportsWindowsAuthentication": false, "isLocal": false, "disableMultiSubnetFailover": true, @@ -136,7 +138,10 @@ stages: displayNamePrefix: Linux poolName: $(ci_var_defaultPoolName) vmImage: ADO-UB22-SQL22 - sqlSetupStep: /eng/pipelines/common/templates/steps/configure-sql-server-linux-step.yml + sqlSetupStep: + template: /eng/pipelines/common/templates/steps/configure-sql-server-linux-step.yml@self + parameters: + saPassword: ${{ parameters.saPassword }} mdsArtifactsName: ${{ parameters.mdsArtifactsName }} solution: $(solution) testProject: $(testProject) @@ -156,7 +161,10 @@ stages: # The Windows images include a suitable .NET Framework runtime, so we # don't have to install one explicitly. vmImage: ADO-MMS22-SQL22 - sqlSetupStep: /eng/pipelines/common/templates/steps/configure-sql-server-win-step.yml + sqlSetupStep: + template: /eng/pipelines/common/templates/steps/configure-sql-server-win-step.yml@self + parameters: + saPassword: ${{ parameters.saPassword }} mdsArtifactsName: ${{ parameters.mdsArtifactsName }} solution: $(solution) testProject: $(testProject) @@ -179,7 +187,10 @@ stages: # generic one from Azure Pipelines. poolName: Azure Pipelines vmImage: macos-latest - sqlSetupStep: /eng/pipelines/common/templates/steps/configure-sql-server-macos-step.yml + sqlSetupStep: + template: /eng/pipelines/common/templates/steps/configure-sql-server-macos-step.yml@self + parameters: + saPassword: ${{ parameters.saPassword }} mdsArtifactsName: ${{ parameters.mdsArtifactsName }} solution: $(solution) testProject: $(testProject) From d4d4ec94a046971f6db52bd1e8ed96aa910ce33a Mon Sep 17 00:00:00 2001 From: Paul Medynski <31868385+paulmedynski@users.noreply.github.com> Date: Wed, 11 Feb 2026 16:53:02 -0400 Subject: [PATCH 08/13] Added debugging to see the generated secrets at generation time, and at use time. --- .../steps/configure-sql-server-linux-step.yml | 8 ++++++ .../steps/configure-sql-server-macos-step.yml | 8 ++++++ .../steps/configure-sql-server-step.yml | 7 +++++ .../steps/configure-sql-server-win-step.yml | 9 +++++++ eng/pipelines/dotnet-sqlclient-ci-core.yml | 2 ++ .../stages/build-azure-package-ci-stage.yml | 2 ++ .../stages/generate-secrets-ci-stage.yml | 27 +++++++++++++++++++ 7 files changed, 63 insertions(+) diff --git a/eng/pipelines/common/templates/steps/configure-sql-server-linux-step.yml b/eng/pipelines/common/templates/steps/configure-sql-server-linux-step.yml index 15de459d50..96cd328501 100644 --- a/eng/pipelines/common/templates/steps/configure-sql-server-linux-step.yml +++ b/eng/pipelines/common/templates/steps/configure-sql-server-linux-step.yml @@ -10,6 +10,10 @@ parameters: + - name: debug + type: boolean + default: false + # The SA password to set when configuring SQL Server. - name: saPassword type: string @@ -23,6 +27,10 @@ steps: # Password for the SA user (required) MSSQL_SA_PW="${{ parameters.saPassword }}" + if [ "${{ parameters.debug }}" = "True" ]; then + echo "SA password: $MSSQL_SA_PW" + fi + # Product ID of the version of SQL server you're installing # Must be evaluation, developer, express, web, standard, enterprise, or your 25 digit product key MSSQL_PID="enterprise" diff --git a/eng/pipelines/common/templates/steps/configure-sql-server-macos-step.yml b/eng/pipelines/common/templates/steps/configure-sql-server-macos-step.yml index 38c42513b7..2d059115e3 100644 --- a/eng/pipelines/common/templates/steps/configure-sql-server-macos-step.yml +++ b/eng/pipelines/common/templates/steps/configure-sql-server-macos-step.yml @@ -9,6 +9,10 @@ parameters: + - name: debug + type: boolean + default: false + # The SA password to set when configuring SQL Server. - name: saPassword type: string @@ -41,6 +45,10 @@ steps: # Password for the SA user (required) MSSQL_SA_PW="${{ parameters.saPassword }}" + if [ "${{ parameters.debug }}" = "True" ]; then + echo "SA password: $MSSQL_SA_PW" + fi + docker run -e "ACCEPT_EULA=Y" -e "MSSQL_SA_PASSWORD=$MSSQL_SA_PW" -p 1433:1433 -p 1434:1434 --name sql1 --hostname sql1 -d mcr.microsoft.com/mssql/server:2022-latest sleep 5 diff --git a/eng/pipelines/common/templates/steps/configure-sql-server-step.yml b/eng/pipelines/common/templates/steps/configure-sql-server-step.yml index 605b7311a6..9dd4c43039 100644 --- a/eng/pipelines/common/templates/steps/configure-sql-server-step.yml +++ b/eng/pipelines/common/templates/steps/configure-sql-server-step.yml @@ -59,6 +59,10 @@ parameters: default: $(LocalDbSharedInstanceName) # Common parameters + - name: debug + type: boolean + default: false + - name: netcoreVersionTestUtils type: string @@ -78,6 +82,7 @@ steps: # windows only steps - template: /eng/pipelines/common/templates/steps/configure-sql-server-win-step.yml@self parameters: + debug: ${{ parameters.debug }} instanceName: ${{parameters.instanceName}} user: ${{parameters.user}} saUser: ${{parameters.saUser}} @@ -96,12 +101,14 @@ steps: # Linux only steps - template: /eng/pipelines/common/templates/steps/configure-sql-server-linux-step.yml@self parameters: + debug: ${{ parameters.debug }} saPassword: ${{ parameters.saPassword }} - ${{ elseif eq(parameters.operatingSystem, 'Mac') }}: # macOS only steps - template: /eng/pipelines/common/templates/steps/configure-sql-server-macos-step.yml@self parameters: + debug: ${{ parameters.debug }} saPassword: ${{ parameters.saPassword }} # Common steps diff --git a/eng/pipelines/common/templates/steps/configure-sql-server-win-step.yml b/eng/pipelines/common/templates/steps/configure-sql-server-win-step.yml index 04dc8a505d..eb094ac0cf 100644 --- a/eng/pipelines/common/templates/steps/configure-sql-server-win-step.yml +++ b/eng/pipelines/common/templates/steps/configure-sql-server-win-step.yml @@ -10,6 +10,10 @@ parameters: + - name: debug + type: boolean + default: false + - name: instanceName type: string default: MSSQLSERVER @@ -101,6 +105,11 @@ steps: - powershell: | $password = "${{ parameters.saPassword }}" + if ("${{ parameters.debug }}" -eq "True") + { + Write-Host "SA password: $password" + } + $machineName = $env:COMPUTERNAME if ("${{parameters.instanceName }}" -ne "MSSQLSERVER"){ diff --git a/eng/pipelines/dotnet-sqlclient-ci-core.yml b/eng/pipelines/dotnet-sqlclient-ci-core.yml index 20f9375c64..3ce1487c3b 100644 --- a/eng/pipelines/dotnet-sqlclient-ci-core.yml +++ b/eng/pipelines/dotnet-sqlclient-ci-core.yml @@ -124,6 +124,8 @@ stages: # Generate secrets used throughout the pipeline. - template: /eng/pipelines/stages/generate-secrets-ci-stage.yml@self + parameters: + debug: ${{ parameters.debug }} # Build the Abstractions package, and publish it to the pipeline artifacts # under the given artifact name. diff --git a/eng/pipelines/stages/build-azure-package-ci-stage.yml b/eng/pipelines/stages/build-azure-package-ci-stage.yml index 521d4e7883..9824567f5e 100644 --- a/eng/pipelines/stages/build-azure-package-ci-stage.yml +++ b/eng/pipelines/stages/build-azure-package-ci-stage.yml @@ -173,6 +173,7 @@ stages: sqlServerSetupSteps: - template: /eng/pipelines/common/templates/steps/configure-sql-server-linux-step.yml@self parameters: + debug: ${{ parameters.debug }} saPassword: ${{ parameters.saPassword }} vmImage: ADO-UB22-SQL22 @@ -219,6 +220,7 @@ stages: - template: /eng/pipelines/common/templates/steps/configure-sql-server-win-step.yml@self # Use defaults for most parameters. parameters: + debug: ${{ parameters.debug }} saPassword: ${{ parameters.saPassword }} enableLocalDB: true # These variables are from an Azure DevOps Library variable diff --git a/eng/pipelines/stages/generate-secrets-ci-stage.yml b/eng/pipelines/stages/generate-secrets-ci-stage.yml index 28a2e4bb40..0d7759301d 100644 --- a/eng/pipelines/stages/generate-secrets-ci-stage.yml +++ b/eng/pipelines/stages/generate-secrets-ci-stage.yml @@ -19,16 +19,35 @@ # # secrets_stage +parameters: + + # True to emit debugging steps and messages. + - name: debug + type: boolean + default: false + stages: + + # The stage downstream stages must depend on to ensure the secrets are generated before they are + # used. - stage: secrets_stage displayName: Generate Secrets jobs: + + # The job that generates the secrets. Each secret is emitted as an output variable of a + # script step, and can be referenced by downstream stages via the stage-dependencies syntax. - job: secrets_job displayName: Generate Secrets pool: + # We don't need anything special, so use the standard Microsoft-hosted Ubuntu image, which + # is typcally very fast to spin up. vmImage: ubuntu-latest + steps: + # We don't need the repo checked out. + - checkout: none + # Generate a password suitable for the SA user of local SQL Server instances. # # This creates the SaPassword.Value variable. @@ -38,3 +57,11 @@ stages: echo "##vso[task.setvariable variable=Value;isSecret=true;isOutput=true]$guid" name: SaPassword displayName: Generate SA password + + # Emit the SA password, if desired. + - ${{ if eq(parameters.debug, true) }}: + - bash: | + # Avoid Azure Pipelines masking the value by introducing some indirection. + $pwd = "$[stageDependencies.secrets_stage.secrets_job.outputs['SaPassword.Value']]" + echo "SA password: $pwd" + displayName: Emit SA password From 538bbe3279100ec912fb5a49be200be03a6841b4 Mon Sep 17 00:00:00 2001 From: Paul Medynski <31868385+paulmedynski@users.noreply.github.com> Date: Wed, 11 Feb 2026 17:01:34 -0400 Subject: [PATCH 09/13] Forcing debug for forked repo pipeline runs. --- eng/pipelines/sqlclient-pr-project-ref-pipeline.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/eng/pipelines/sqlclient-pr-project-ref-pipeline.yml b/eng/pipelines/sqlclient-pr-project-ref-pipeline.yml index 2f4e8a2ee5..125ae6d388 100644 --- a/eng/pipelines/sqlclient-pr-project-ref-pipeline.yml +++ b/eng/pipelines/sqlclient-pr-project-ref-pipeline.yml @@ -130,7 +130,9 @@ extends: buildPlatforms: ${{ parameters.buildPlatforms }} referenceType: Project codeCovTargetFrameworks: ${{ parameters.codeCovTargetFrameworks }} - debug: ${{ parameters.debug }} + # TODO: Temporaryily forcing debug for forked repo pipeline runs. + # debug: ${{ parameters.debug }} + debug: true enableStressTests: ${{ parameters.enableStressTests }} targetFrameworks: ${{ parameters.targetFrameworks }} targetFrameworksUnix: ${{ parameters.targetFrameworksUnix }} From 478ba6c434b321f7f5fd4208ec82560f1572fbfa Mon Sep 17 00:00:00 2001 From: Paul Medynski <31868385+paulmedynski@users.noreply.github.com> Date: Wed, 11 Feb 2026 18:54:31 -0400 Subject: [PATCH 10/13] - Hopefully fixed expansion of stage dependencies. - Moved secrets_stage dependency into stages. --- .../templates/stages/ci-run-tests-stage.yml | 29 ++++++++++------ eng/pipelines/dotnet-sqlclient-ci-core.yml | 18 ++-------- .../stages/build-azure-package-ci-stage.yml | 33 ++++++++++-------- .../stages/generate-secrets-ci-stage.yml | 6 ++-- .../stages/stress-tests-ci-stage.yml | 34 +++++++++++-------- 5 files changed, 61 insertions(+), 59 deletions(-) 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 c8073e3981..f6b5ea9120 100644 --- a/eng/pipelines/common/templates/stages/ci-run-tests-stage.yml +++ b/eng/pipelines/common/templates/stages/ci-run-tests-stage.yml @@ -3,6 +3,9 @@ # The .NET Foundation licenses this file to you under the MIT license. # # See the LICENSE file in the project root for more information. # ################################################################################# + +# This stage depends on the secrets_stage. + parameters: - name: abstractionsArtifactsName type: string @@ -10,6 +13,10 @@ parameters: - name: abstractionsPackageVersion type: string + - name: additionalDependsOn + type: object + default: [] + - name: buildConfiguration type: string values: @@ -20,10 +27,6 @@ parameters: type: boolean default: false - - name: dependsOn - type: object - default: [] - - name: mdsArtifactsName type: string default: MDS.Artifacts @@ -45,10 +48,6 @@ parameters: - Project - Package - # The SA password to set when configuring SQL Server. - - name: saPassword - type: string - - name: testConfigurations type: object @@ -60,7 +59,15 @@ stages: - ${{ each config in parameters.testConfigurations }}: - ${{ each image in config.value.images }}: - stage: ${{ image.key }} - dependsOn: ${{ parameters.dependsOn }} + dependsOn: + - secrets_stage + - ${{ parameters.additionalDependsOn }} + + variables: + # Bring the SA password from the secrets_stage into scope here. + - name: saPassword + value: $[stageDependencies.secrets_stage.secrets_job.outputs['SaPassword.Value']] + jobs: - ${{ each targetFramework in config.value.TargetFrameworks }}: - ${{ each platform in config.value.buildPlatforms }}: @@ -91,7 +98,7 @@ stages: configSqlFor: ${{ config.value.configSqlFor }} operatingSystem: ${{ config.value.operatingSystem }} isArm64: ${{ eq(config.value.isArm64, 'true') }} - saPassword: ${{ parameters.saPassword }} + saPassword: $(saPassword) ${{if ne(config.value.configProperties, '{}') }}: ${{ each x86TF in config.value.configProperties.x86TestTargetFrameworks }}: ${{ if eq(x86TF, targetFramework) }}: @@ -128,7 +135,7 @@ stages: configSqlFor: ${{ config.value.configSqlFor }} operatingSystem: ${{ config.value.operatingSystem }} isArm64: ${{ eq(config.value.isArm64, 'true') }} - saPassword: ${{ parameters.saPassword }} + saPassword: $(saPassword) ${{if and(eq(usemanagedSNI, false), ne(config.value.configProperties, '{}')) }}: ${{ each x86TF in config.value.configProperties.x86TestTargetFrameworks }}: ${{ if eq(x86TF, targetFramework) }}: diff --git a/eng/pipelines/dotnet-sqlclient-ci-core.yml b/eng/pipelines/dotnet-sqlclient-ci-core.yml index 3ce1487c3b..948227ab90 100644 --- a/eng/pipelines/dotnet-sqlclient-ci-core.yml +++ b/eng/pipelines/dotnet-sqlclient-ci-core.yml @@ -178,33 +178,26 @@ stages: # When building via packages, we must depend on the Abstractions and MDS # packages. ${{ if eq(parameters.referenceType, 'Package') }}: - dependsOn: - - secrets_stage + additionalDependsOn: - build_abstractions_package_stage - build_mds_akv_packages_stage - ${{ else }}: - dependsOn: - - secrets_stage dotnetVerbosity: ${{ parameters.dotnetVerbosity }} mdsArtifactsName: $(mdsArtifactsName) mdsPackageVersion: $(mdsPackageVersion) referenceType: ${{ parameters.referenceType }} - saPassword: $[stageDependencies.secrets_stage.secrets_job.outputs['SaPassword.Value']] # Run the stress tests, if desired. - ${{ if eq(parameters.enableStressTests, true) }}: - template: /eng/pipelines/stages/stress-tests-ci-stage.yml@self parameters: buildConfiguration: ${{ parameters.buildConfiguration }} - dependsOn: - - secrets_stage + additionalDependsOn: - build_mds_akv_packages_stage - build_azure_package_stage mdsArtifactsName: $(mdsArtifactsName) mdsPackageVersion: $(mdsPackageVersion) azurePackageVersion: $(azurePackageVersion) dotnetVerbosity: ${{ parameters.dotnetVerbosity }} - saPassword: $[stageDependencies.secrets_stage.secrets_job.outputs['SaPassword.Value']] # Run the MDS and AKV tests. - template: /eng/pipelines/common/templates/stages/ci-run-tests-stage.yml@self @@ -216,20 +209,15 @@ stages: abstractionsPackageVersion: $(abstractionsPackageVersion) mdsArtifactsName: $(mdsArtifactsName) mdsPackageVersion: $(mdsPackageVersion) - saPassword: $[stageDependencies.secrets_stage.secrets_job.outputs['SaPassword.Value']] testJobTimeout: ${{ parameters.testJobTimeout }} # When testing MDS via packages, we must depend on the Abstractions, # MDS, and Azure packages. ${{ if eq(parameters.referenceType, 'Package') }}: - dependsOn: - - secrets_stage + additionalDependsOn: - build_abstractions_package_stage - build_mds_akv_packages_stage - build_azure_package_stage - ${{ else }}: - dependsOn: - - secrets_stage # Steps to run prior to building and running tests on each job. prebuildSteps: diff --git a/eng/pipelines/stages/build-azure-package-ci-stage.yml b/eng/pipelines/stages/build-azure-package-ci-stage.yml index 9824567f5e..db703c6d97 100644 --- a/eng/pipelines/stages/build-azure-package-ci-stage.yml +++ b/eng/pipelines/stages/build-azure-package-ci-stage.yml @@ -20,6 +20,8 @@ # The packages are published to pipeline artifacts with the name specified by # the azureArtifactsName parameter. # +# This stage depends on the secrets_stage. +# # This template defines a stage named 'build_azure_package_stage' that # can be depended on by downstream stages. @@ -38,6 +40,11 @@ parameters: - name: abstractionsPackageVersion type: string + # Additional stages we depend on, if any. + - name: additionalDependsOn + type: object + default: [] + # The name of the pool to use for jobs that require customized VM images. - name: adoPoolName type: string @@ -79,11 +86,6 @@ parameters: type: boolean default: false - # The stages we depend on, if any. - - name: dependsOn - type: object - default: [] - # The dotnet CLI verbosity to use. - name: dotnetVerbosity type: string @@ -119,16 +121,19 @@ parameters: - Package - Project - # The SA password to set when configuring SQL Server. - - name: saPassword - type: string - stages: - stage: build_azure_package_stage displayName: Build Azure Package - dependsOn: ${{ parameters.dependsOn }} + dependsOn: + - secrets_stage + - ${{ parameters.additionalDependsOn }} + + variables: + # Bring the SA password from the secrets_stage into scope here. + - name: saPassword + value: $[stageDependencies.secrets_stage.secrets_job.outputs['SaPassword.Value']] jobs: @@ -168,13 +173,13 @@ stages: netRuntimes: [net8.0, net9.0, net10.0] poolName: ${{ parameters.adoPoolName }} referenceType: ${{ parameters.referenceType }} - saPassword: ${{ parameters.saPassword }} + saPassword: $(saPassword) # The image includes a SQL Server instance that we must configure. sqlServerSetupSteps: - template: /eng/pipelines/common/templates/steps/configure-sql-server-linux-step.yml@self parameters: debug: ${{ parameters.debug }} - saPassword: ${{ parameters.saPassword }} + saPassword: $(saPassword) vmImage: ADO-UB22-SQL22 # ------------------------------------------------------------------------ @@ -214,14 +219,14 @@ stages: netRuntimes: [net8.0, net9.0, net10.0] poolName: ${{ parameters.adoPoolName }} referenceType: ${{ parameters.referenceType }} - saPassword: ${{ parameters.saPassword }} + saPassword: $(saPassword) # The image includes a SQL Server instance that we must configure. sqlServerSetupSteps: - template: /eng/pipelines/common/templates/steps/configure-sql-server-win-step.yml@self # Use defaults for most parameters. parameters: debug: ${{ parameters.debug }} - saPassword: ${{ parameters.saPassword }} + saPassword: $(saPassword) enableLocalDB: true # These variables are from an Azure DevOps Library variable # group. diff --git a/eng/pipelines/stages/generate-secrets-ci-stage.yml b/eng/pipelines/stages/generate-secrets-ci-stage.yml index 0d7759301d..5db45cc08f 100644 --- a/eng/pipelines/stages/generate-secrets-ci-stage.yml +++ b/eng/pipelines/stages/generate-secrets-ci-stage.yml @@ -54,14 +54,12 @@ stages: # - bash: | guid=$(cat /proc/sys/kernel/random/uuid) - echo "##vso[task.setvariable variable=Value;isSecret=true;isOutput=true]$guid" + echo "##vso[task.setvariable variable=Value;isOutput=true]$guid" name: SaPassword displayName: Generate SA password # Emit the SA password, if desired. - ${{ if eq(parameters.debug, true) }}: - bash: | - # Avoid Azure Pipelines masking the value by introducing some indirection. - $pwd = "$[stageDependencies.secrets_stage.secrets_job.outputs['SaPassword.Value']]" - echo "SA password: $pwd" + echo "SA password: $(SaPassword.Value)" displayName: Emit SA password diff --git a/eng/pipelines/stages/stress-tests-ci-stage.yml b/eng/pipelines/stages/stress-tests-ci-stage.yml index 81f7170d79..e8890e83e0 100644 --- a/eng/pipelines/stages/stress-tests-ci-stage.yml +++ b/eng/pipelines/stages/stress-tests-ci-stage.yml @@ -14,11 +14,19 @@ # All tests use a localhost SQL Server configured for SQL auth via the 'sa' user # and the provided password. # +# This stage depends on the secrets_stage. +# # This template defines a stage named 'run_stress_tests_stage' that can be # depended on by downstream stages. parameters: + # The names of any additional stages this stage depends on, for example the stages that publish + # the MDS package artifacts we will test. + - name: additionalDependsOn + type: object + default: [] + # The Azure package version to stress test. This version must be available in # one of the configured NuGet sources. - name: azurePackageVersion @@ -33,12 +41,6 @@ parameters: - Debug - Release - # The names of any stages this stage depends on, for example the stages - # that publish the MDS package artifacts we will test. - - name: dependsOn - type: object - default: [] - # The verbosity level for the dotnet CLI commands. - name: dotnetVerbosity type: string @@ -69,14 +71,12 @@ parameters: type: object default: [net8.0, net9.0, net10.0] - # The SA password to set when configuring SQL Server. - - name: saPassword - type: string - stages: - stage: run_stress_tests_stage displayName: Run Stress Tests - dependsOn: ${{ parameters.dependsOn }} + dependsOn: + - secrets_stage + - ${{ parameters.additionalDependsOn }} variables: # The directory where dotnet artifacts will be staged. Not to be @@ -106,6 +106,10 @@ stages: $(commonArguments) --configuration ${{parameters.buildConfiguration}} + # Bring the SA password from the secrets_stage into scope here. + - name: saPassword + value: $[stageDependencies.secrets_stage.secrets_job.outputs['SaPassword.Value']] + # The contents of the config file to use for all tests. We will write # this to a JSON file for each test job, and then point to it via the # STRESS_CONFIG_FILE environment variable. @@ -118,7 +122,7 @@ stages: "isDefault": true, "dataSource": "localhost", "user": "sa", - "password": "${{ parameters.saPassword }}", + "password": "$(saPassword)", "supportsWindowsAuthentication": false, "isLocal": false, "disableMultiSubnetFailover": true, @@ -141,7 +145,7 @@ stages: sqlSetupStep: template: /eng/pipelines/common/templates/steps/configure-sql-server-linux-step.yml@self parameters: - saPassword: ${{ parameters.saPassword }} + saPassword: $(saPassword) mdsArtifactsName: ${{ parameters.mdsArtifactsName }} solution: $(solution) testProject: $(testProject) @@ -164,7 +168,7 @@ stages: sqlSetupStep: template: /eng/pipelines/common/templates/steps/configure-sql-server-win-step.yml@self parameters: - saPassword: ${{ parameters.saPassword }} + saPassword: $(saPassword) mdsArtifactsName: ${{ parameters.mdsArtifactsName }} solution: $(solution) testProject: $(testProject) @@ -190,7 +194,7 @@ stages: sqlSetupStep: template: /eng/pipelines/common/templates/steps/configure-sql-server-macos-step.yml@self parameters: - saPassword: ${{ parameters.saPassword }} + saPassword: $(saPassword) mdsArtifactsName: ${{ parameters.mdsArtifactsName }} solution: $(solution) testProject: $(testProject) From 20d71034bb43ed9212bf90b6e0353b73afa9e494 Mon Sep 17 00:00:00 2001 From: Paul Medynski <31868385+paulmedynski@users.noreply.github.com> Date: Wed, 11 Feb 2026 20:58:34 -0400 Subject: [PATCH 11/13] Addressed Copilot comments, and fixed some runtime bugs. --- .../jobs/run-tests-package-reference-job.yml | 2 ++ .../steps/configure-sql-server-linux-step.yml | 6 +++++ .../steps/configure-sql-server-macos-step.yml | 25 +++++++++++-------- .../steps/configure-sql-server-win-step.yml | 24 +++++++++++------- .../jobs/test-azure-package-ci-job.yml | 2 +- .../stages/generate-secrets-ci-stage.yml | 11 +++++--- 6 files changed, 46 insertions(+), 24 deletions(-) diff --git a/eng/pipelines/common/templates/jobs/run-tests-package-reference-job.yml b/eng/pipelines/common/templates/jobs/run-tests-package-reference-job.yml index a6e7755c6b..30d284f166 100644 --- a/eng/pipelines/common/templates/jobs/run-tests-package-reference-job.yml +++ b/eng/pipelines/common/templates/jobs/run-tests-package-reference-job.yml @@ -46,6 +46,8 @@ jobs: - template: /eng/pipelines/common/templates/steps/update-config-file-step.yml parameters: + # We use the Library $(Password) variable as the SA password in this pipeline. + saPassword: $(Password) TCPConnectionString: $(SQL_TCP_CONN_STRING) NPConnectionString: $(SQL_NP_CONN_STRING) SupportsIntegratedSecurity: false diff --git a/eng/pipelines/common/templates/steps/configure-sql-server-linux-step.yml b/eng/pipelines/common/templates/steps/configure-sql-server-linux-step.yml index 96cd328501..98d1ae8b5b 100644 --- a/eng/pipelines/common/templates/steps/configure-sql-server-linux-step.yml +++ b/eng/pipelines/common/templates/steps/configure-sql-server-linux-step.yml @@ -20,6 +20,12 @@ parameters: steps: + # Emit the SA password, if desired. + - ${{ if eq(parameters.debug, true) }}: + - bash: | + echo "SA password: ${{ parameters.saPassword }}" + displayName: '[Debug] Emit SA password' + # Configure SQL Server. - bash: | sudo systemctl stop mssql-server diff --git a/eng/pipelines/common/templates/steps/configure-sql-server-macos-step.yml b/eng/pipelines/common/templates/steps/configure-sql-server-macos-step.yml index 2d059115e3..2c96a97b2b 100644 --- a/eng/pipelines/common/templates/steps/configure-sql-server-macos-step.yml +++ b/eng/pipelines/common/templates/steps/configure-sql-server-macos-step.yml @@ -18,6 +18,13 @@ parameters: type: string steps: + + # Emit the SA password, if desired. + - ${{ if eq(parameters.debug, true) }}: + - bash: | + echo "SA password: ${{ parameters.saPassword }}" + displayName: '[Debug] Emit SA password' + # Configure SQL Server. This includes installing Docker and the SQLCMD tools, starting a SQL # Server container, and verifying we can connect to it. - bash: | @@ -45,10 +52,6 @@ steps: # Password for the SA user (required) MSSQL_SA_PW="${{ parameters.saPassword }}" - if [ "${{ parameters.debug }}" = "True" ]; then - echo "SA password: $MSSQL_SA_PW" - fi - docker run -e "ACCEPT_EULA=Y" -e "MSSQL_SA_PASSWORD=$MSSQL_SA_PW" -p 1433:1433 -p 1434:1434 --name sql1 --hostname sql1 -d mcr.microsoft.com/mssql/server:2022-latest sleep 5 @@ -78,7 +81,7 @@ steps: echo "Waiting for SQL Server to start (attempt #$attempt of $maxAttempts)..." - sqlcmd -S 127.0.0.1 -No -U sa -P $MSSQL_SA_PW -Q "SELECT @@VERSION" >> $SQLCMD_ERRORS 2>&1 + sqlcmd -S 127.0.0.1 -No -U sa -P "$MSSQL_SA_PW" -Q "SELECT @@VERSION" >> $SQLCMD_ERRORS 2>&1 # If the command was successful, then the SQL Server is ready. if [ $? -eq 0 ]; then @@ -108,18 +111,18 @@ steps: echo "Use sqlcmd to show which IP addresses are being listened on..." echo 0.0.0.0 - sqlcmd -S 0.0.0.0 -No -U sa -P $MSSQL_SA_PW -Q "SELECT @@VERSION" -l 2 + sqlcmd -S 0.0.0.0 -No -U sa -P "$MSSQL_SA_PW" -Q "SELECT @@VERSION" -l 2 echo 127.0.0.1 - sqlcmd -S 127.0.0.1 -No -U sa -P $MSSQL_SA_PW -Q "SELECT @@VERSION" -l 2 + sqlcmd -S 127.0.0.1 -No -U sa -P "$MSSQL_SA_PW" -Q "SELECT @@VERSION" -l 2 echo ::1 - sqlcmd -S ::1 -No -U sa -P $MSSQL_SA_PW -Q "SELECT @@VERSION" -l 2 + sqlcmd -S ::1 -No -U sa -P "$MSSQL_SA_PW" -Q "SELECT @@VERSION" -l 2 echo localhost - sqlcmd -S localhost -No -U sa -P $MSSQL_SA_PW -Q "SELECT @@VERSION" -l 2 + sqlcmd -S localhost -No -U sa -P "$MSSQL_SA_PW" -Q "SELECT @@VERSION" -l 2 echo "(sqlcmd default / not specified)" - sqlcmd -No -U sa -P $MSSQL_SA_PW -Q "SELECT @@VERSION" -l 2 + sqlcmd -No -U sa -P "$MSSQL_SA_PW" -Q "SELECT @@VERSION" -l 2 echo "Configuring Dedicated Administer Connections to allow remote connections..." - sqlcmd -S 127.0.0.1 -No -U sa -P $MSSQL_SA_PW -Q "sp_configure 'remote admin connections', 1; RECONFIGURE;" + sqlcmd -S 127.0.0.1 -No -U sa -P "$MSSQL_SA_PW" -Q "sp_configure 'remote admin connections', 1; RECONFIGURE;" if [ $? = 1 ] then echo "Error configuring DAC for remote access." diff --git a/eng/pipelines/common/templates/steps/configure-sql-server-win-step.yml b/eng/pipelines/common/templates/steps/configure-sql-server-win-step.yml index eb094ac0cf..93c5571bab 100644 --- a/eng/pipelines/common/templates/steps/configure-sql-server-win-step.yml +++ b/eng/pipelines/common/templates/steps/configure-sql-server-win-step.yml @@ -68,7 +68,13 @@ parameters: steps: - - powershell: | + # Emit the SA password, if desired. + - ${{ if eq(parameters.debug, true) }}: + - pwsh: | + Write-Host "SA password: ${{ parameters.saPassword }}" + displayName: '[Debug] Emit SA password' + + - pwsh: | try { # enable TCP @@ -102,7 +108,7 @@ steps: displayName: 'Enable TCP, NP & Firewall [Win]' retryCountOnTaskFailure: 2 - - powershell: | + - pwsh: | $password = "${{ parameters.saPassword }}" if ("${{ parameters.debug }}" -eq "True") @@ -146,7 +152,7 @@ steps: SQL_PASSWD: ${{ parameters.saPassword }} - ${{ if ne(parameters.SQLRootPath, '') }}: - - powershell: | + - pwsh: | #Enable FileStream $instance = "${{parameters.instanceName }}" $wmi = Get-WmiObject -Namespace "${{parameters.SQLRootPath }}" -Class FilestreamSettings | where {$_.InstanceName -eq $instance} @@ -171,13 +177,13 @@ steps: SQL_PASSWD: ${{ parameters.saPassword }} - ${{ if ne(parameters.FileStreamDirectory, '') }}: - - powershell: | + - pwsh: | New-Item -Path ${{ parameters.fileStreamDirectory }} -ItemType Directory displayName: 'Create FileStreamFolder' retryCountOnTaskFailure: 1 continueOnError: true - - powershell: | + - pwsh: | $SQLServerName = ("{0}" -f [System.Net.Dns]::GetHostByName($env:computerName).HostName) Write-Host FQDN is: $SQLServerName @@ -195,7 +201,7 @@ steps: New-ItemProperty -Path ${{parameters.x64AliasRegistryPath }} -Name ${{parameters.SQLAliasName }} -PropertyType string -Value $TCPAliasName displayName: 'Setup SQL Alias [Win]' - - powershell: | + - pwsh: | # Create Certificate $computerDnsName = [System.Net.Dns]::Resolve($null).HostName $certificate = New-SelfSignedCertificate -DnsName $computerDnsName,localhost -CertStoreLocation cert:\LocalMachine\My -FriendlyName test99 -KeySpec KeyExchange @@ -232,7 +238,7 @@ steps: } displayName: 'Add SQL Certificate [Win]' - - powershell: | + - pwsh: | # You need to restart SQL Server for the change to persist # -Force takes care of any dependent services, like SQL Agent. # Note: if the instance is named, replace MSSQLSERVER with MSSQL$ followed by @@ -251,7 +257,7 @@ steps: displayName: 'Restart SQL Server [Win]' - - powershell: | + - pwsh: | $arrService = Get-Service -Name "SQLBrowser" $arrService @@ -271,7 +277,7 @@ steps: displayName: 'Start Sql Server Browser [Win]' - ${{ if parameters.enableLocalDB }}: - - powershell: | + - pwsh: | #script to enable local db SqlLocalDB info diff --git a/eng/pipelines/jobs/test-azure-package-ci-job.yml b/eng/pipelines/jobs/test-azure-package-ci-job.yml index 54c82752f1..11bdfa7d19 100644 --- a/eng/pipelines/jobs/test-azure-package-ci-job.yml +++ b/eng/pipelines/jobs/test-azure-package-ci-job.yml @@ -274,7 +274,7 @@ jobs: # List the DLLs in the output directory for debugging purposes. - ${{ if eq(parameters.debug, true) }}: - - pwsh: > + - pwsh: >- Get-ChildItem -Path "src/Microsoft.Data.SqlClient.Extensions/Azure/test/bin/${{ parameters.buildConfiguration }}" -Recurse diff --git a/eng/pipelines/stages/generate-secrets-ci-stage.yml b/eng/pipelines/stages/generate-secrets-ci-stage.yml index 5db45cc08f..507e18d279 100644 --- a/eng/pipelines/stages/generate-secrets-ci-stage.yml +++ b/eng/pipelines/stages/generate-secrets-ci-stage.yml @@ -18,7 +18,12 @@ # Any stages that use these secrets must depend on this stage: # # secrets_stage - +# +# None of the values produced here are actual secrets - they are just random values that are +# suitable for testing purposes, and do not need to be protected. For simplicity, they are emitted +# as regular output variables of script steps, are not formally marked as secrets, and not stored in +# the Azure DevOps Library or Key Vault. +# parameters: # True to emit debugging steps and messages. @@ -40,7 +45,7 @@ stages: displayName: Generate Secrets pool: # We don't need anything special, so use the standard Microsoft-hosted Ubuntu image, which - # is typcally very fast to spin up. + # is typically very fast to spin up. vmImage: ubuntu-latest steps: @@ -62,4 +67,4 @@ stages: - ${{ if eq(parameters.debug, true) }}: - bash: | echo "SA password: $(SaPassword.Value)" - displayName: Emit SA password + displayName: '[Debug] Emit SA password' From ad5438373925c20e03717f541de223d752d7154b Mon Sep 17 00:00:00 2001 From: Paul Medynski <31868385+paulmedynski@users.noreply.github.com> Date: Wed, 11 Feb 2026 22:15:00 -0400 Subject: [PATCH 12/13] Fixed debug DLL output and Windows WMI call. --- .../templates/jobs/ci-run-tests-job.yml | 1 + .../steps/configure-sql-server-win-step.yml | 40 +++++++++---------- .../jobs/test-azure-package-ci-job.yml | 4 +- 3 files changed, 23 insertions(+), 22 deletions(-) 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 ab863860be..321e92fdb6 100644 --- a/eng/pipelines/common/templates/jobs/ci-run-tests-job.yml +++ b/eng/pipelines/common/templates/jobs/ci-run-tests-job.yml @@ -241,6 +241,7 @@ jobs: - ${{ elseif eq(parameters.configSqlFor, 'local') }}: - template: /eng/pipelines/common/templates/steps/configure-sql-server-step.yml@self # configure SQL Server parameters: + debug: ${{ parameters.debug }} operatingSystem: ${{ parameters.operatingSystem }} netcoreVersionTestUtils: ${{ parameters.netcoreVersionTestUtils }} saPassword: ${{ parameters.saPassword }} diff --git a/eng/pipelines/common/templates/steps/configure-sql-server-win-step.yml b/eng/pipelines/common/templates/steps/configure-sql-server-win-step.yml index 93c5571bab..726179585c 100644 --- a/eng/pipelines/common/templates/steps/configure-sql-server-win-step.yml +++ b/eng/pipelines/common/templates/steps/configure-sql-server-win-step.yml @@ -77,29 +77,29 @@ steps: - pwsh: | try { - # enable TCP - Import-Module "sqlps" - $smo = 'Microsoft.SqlServer.Management.Smo.' - $wmi = new-object ($smo + 'Wmi.ManagedComputer'). - # List the object properties, including the instance names. - $Wmi - - # Enable the TCP protocol on the default instance. - $Tcp = $wmi.GetSmoObject("ManagedComputer[@Name='$env:COMPUTERNAME']/ ServerInstance[@Name='${{parameters.instanceName }}']/ServerProtocol[@Name='Tcp']") - $Tcp.IsEnabled = $true - $Tcp.Alter() - - # Enable the NP protocol on the default instance. - $Np = $wmi.GetSmoObject("ManagedComputer[@Name='$env:COMPUTERNAME']/ ServerInstance[@Name='${{parameters.instanceName }}']/ServerProtocol[@Name='Np']") - $Np.IsEnabled = $true - $Np.Alter() - - $Tcp + # enable TCP + Import-Module "sqlps" + $smo = 'Microsoft.SqlServer.Management.Smo.' + $wmi = new-object ($smo + 'Wmi.ManagedComputer') + # List the object properties, including the instance names. + $Wmi + + # Enable the TCP protocol on the default instance. + $Tcp = $wmi.GetSmoObject("ManagedComputer[@Name='$env:COMPUTERNAME']/ ServerInstance[@Name='${{parameters.instanceName }}']/ServerProtocol[@Name='Tcp']") + $Tcp.IsEnabled = $true + $Tcp.Alter() + + # Enable the NP protocol on the default instance. + $Np = $wmi.GetSmoObject("ManagedComputer[@Name='$env:COMPUTERNAME']/ ServerInstance[@Name='${{parameters.instanceName }}']/ServerProtocol[@Name='Np']") + $Np.IsEnabled = $true + $Np.Alter() + + $Tcp } catch { - $error[0] | format-list -force - throw + $error[0] | format-list -force + throw } New-NetFirewallRule -DisplayName "SQL TCP Ports" -Direction Inbound -Protocol TCP -LocalPort 1433 -Action allow diff --git a/eng/pipelines/jobs/test-azure-package-ci-job.yml b/eng/pipelines/jobs/test-azure-package-ci-job.yml index 11bdfa7d19..9b414e6eeb 100644 --- a/eng/pipelines/jobs/test-azure-package-ci-job.yml +++ b/eng/pipelines/jobs/test-azure-package-ci-job.yml @@ -276,8 +276,8 @@ jobs: - ${{ if eq(parameters.debug, true) }}: - pwsh: >- Get-ChildItem - -Path "src/Microsoft.Data.SqlClient.Extensions/Azure/test/bin/${{ parameters.buildConfiguration }}" - -Recurse + -Path "src/Microsoft.Data.SqlClient.Extensions/Azure/test/bin/${{ parameters.buildConfiguration }}" + -Recurse displayName: '[Debug] List Output DLLs' # Run the tests for each .NET runtime. From f428d9151c50eb64a55018d2043b01633e3e4f41 Mon Sep 17 00:00:00 2001 From: Paul Medynski <31868385+paulmedynski@users.noreply.github.com> Date: Wed, 11 Feb 2026 22:37:10 -0400 Subject: [PATCH 13/13] Fixed Windows-specific powershell commands, and removed unnecessary debug parameters. --- .../templates/jobs/ci-run-tests-job.yml | 1 - .../steps/configure-sql-server-linux-step.yml | 14 -------- .../steps/configure-sql-server-macos-step.yml | 10 ------ .../steps/configure-sql-server-step.yml | 7 ---- .../steps/configure-sql-server-win-step.yml | 36 ++++++------------- .../stages/build-azure-package-ci-stage.yml | 2 -- 6 files changed, 11 insertions(+), 59 deletions(-) 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 321e92fdb6..ab863860be 100644 --- a/eng/pipelines/common/templates/jobs/ci-run-tests-job.yml +++ b/eng/pipelines/common/templates/jobs/ci-run-tests-job.yml @@ -241,7 +241,6 @@ jobs: - ${{ elseif eq(parameters.configSqlFor, 'local') }}: - template: /eng/pipelines/common/templates/steps/configure-sql-server-step.yml@self # configure SQL Server parameters: - debug: ${{ parameters.debug }} operatingSystem: ${{ parameters.operatingSystem }} netcoreVersionTestUtils: ${{ parameters.netcoreVersionTestUtils }} saPassword: ${{ parameters.saPassword }} diff --git a/eng/pipelines/common/templates/steps/configure-sql-server-linux-step.yml b/eng/pipelines/common/templates/steps/configure-sql-server-linux-step.yml index 98d1ae8b5b..15de459d50 100644 --- a/eng/pipelines/common/templates/steps/configure-sql-server-linux-step.yml +++ b/eng/pipelines/common/templates/steps/configure-sql-server-linux-step.yml @@ -10,22 +10,12 @@ parameters: - - name: debug - type: boolean - default: false - # The SA password to set when configuring SQL Server. - name: saPassword type: string steps: - # Emit the SA password, if desired. - - ${{ if eq(parameters.debug, true) }}: - - bash: | - echo "SA password: ${{ parameters.saPassword }}" - displayName: '[Debug] Emit SA password' - # Configure SQL Server. - bash: | sudo systemctl stop mssql-server @@ -33,10 +23,6 @@ steps: # Password for the SA user (required) MSSQL_SA_PW="${{ parameters.saPassword }}" - if [ "${{ parameters.debug }}" = "True" ]; then - echo "SA password: $MSSQL_SA_PW" - fi - # Product ID of the version of SQL server you're installing # Must be evaluation, developer, express, web, standard, enterprise, or your 25 digit product key MSSQL_PID="enterprise" diff --git a/eng/pipelines/common/templates/steps/configure-sql-server-macos-step.yml b/eng/pipelines/common/templates/steps/configure-sql-server-macos-step.yml index 2c96a97b2b..0be4de6e2b 100644 --- a/eng/pipelines/common/templates/steps/configure-sql-server-macos-step.yml +++ b/eng/pipelines/common/templates/steps/configure-sql-server-macos-step.yml @@ -9,22 +9,12 @@ parameters: - - name: debug - type: boolean - default: false - # The SA password to set when configuring SQL Server. - name: saPassword type: string steps: - # Emit the SA password, if desired. - - ${{ if eq(parameters.debug, true) }}: - - bash: | - echo "SA password: ${{ parameters.saPassword }}" - displayName: '[Debug] Emit SA password' - # Configure SQL Server. This includes installing Docker and the SQLCMD tools, starting a SQL # Server container, and verifying we can connect to it. - bash: | diff --git a/eng/pipelines/common/templates/steps/configure-sql-server-step.yml b/eng/pipelines/common/templates/steps/configure-sql-server-step.yml index 9dd4c43039..605b7311a6 100644 --- a/eng/pipelines/common/templates/steps/configure-sql-server-step.yml +++ b/eng/pipelines/common/templates/steps/configure-sql-server-step.yml @@ -59,10 +59,6 @@ parameters: default: $(LocalDbSharedInstanceName) # Common parameters - - name: debug - type: boolean - default: false - - name: netcoreVersionTestUtils type: string @@ -82,7 +78,6 @@ steps: # windows only steps - template: /eng/pipelines/common/templates/steps/configure-sql-server-win-step.yml@self parameters: - debug: ${{ parameters.debug }} instanceName: ${{parameters.instanceName}} user: ${{parameters.user}} saUser: ${{parameters.saUser}} @@ -101,14 +96,12 @@ steps: # Linux only steps - template: /eng/pipelines/common/templates/steps/configure-sql-server-linux-step.yml@self parameters: - debug: ${{ parameters.debug }} saPassword: ${{ parameters.saPassword }} - ${{ elseif eq(parameters.operatingSystem, 'Mac') }}: # macOS only steps - template: /eng/pipelines/common/templates/steps/configure-sql-server-macos-step.yml@self parameters: - debug: ${{ parameters.debug }} saPassword: ${{ parameters.saPassword }} # Common steps diff --git a/eng/pipelines/common/templates/steps/configure-sql-server-win-step.yml b/eng/pipelines/common/templates/steps/configure-sql-server-win-step.yml index 726179585c..3f521caa7e 100644 --- a/eng/pipelines/common/templates/steps/configure-sql-server-win-step.yml +++ b/eng/pipelines/common/templates/steps/configure-sql-server-win-step.yml @@ -10,10 +10,6 @@ parameters: - - name: debug - type: boolean - default: false - - name: instanceName type: string default: MSSQLSERVER @@ -67,14 +63,9 @@ parameters: default: $(LocalDbSharedInstanceName) steps: - - # Emit the SA password, if desired. - - ${{ if eq(parameters.debug, true) }}: - - pwsh: | - Write-Host "SA password: ${{ parameters.saPassword }}" - displayName: '[Debug] Emit SA password' - - - pwsh: | + # GOTCHA: We must use the Windows-only powershell task here instead of the cross-platform pwsh + # task because we call some Windows-specific cmdlets. + - powershell: | try { # enable TCP @@ -108,14 +99,9 @@ steps: displayName: 'Enable TCP, NP & Firewall [Win]' retryCountOnTaskFailure: 2 - - pwsh: | + - powershell: | $password = "${{ parameters.saPassword }}" - if ("${{ parameters.debug }}" -eq "True") - { - Write-Host "SA password: $password" - } - $machineName = $env:COMPUTERNAME if ("${{parameters.instanceName }}" -ne "MSSQLSERVER"){ @@ -152,7 +138,7 @@ steps: SQL_PASSWD: ${{ parameters.saPassword }} - ${{ if ne(parameters.SQLRootPath, '') }}: - - pwsh: | + - powershell: | #Enable FileStream $instance = "${{parameters.instanceName }}" $wmi = Get-WmiObject -Namespace "${{parameters.SQLRootPath }}" -Class FilestreamSettings | where {$_.InstanceName -eq $instance} @@ -177,13 +163,13 @@ steps: SQL_PASSWD: ${{ parameters.saPassword }} - ${{ if ne(parameters.FileStreamDirectory, '') }}: - - pwsh: | + - powershell: | New-Item -Path ${{ parameters.fileStreamDirectory }} -ItemType Directory displayName: 'Create FileStreamFolder' retryCountOnTaskFailure: 1 continueOnError: true - - pwsh: | + - powershell: | $SQLServerName = ("{0}" -f [System.Net.Dns]::GetHostByName($env:computerName).HostName) Write-Host FQDN is: $SQLServerName @@ -201,7 +187,7 @@ steps: New-ItemProperty -Path ${{parameters.x64AliasRegistryPath }} -Name ${{parameters.SQLAliasName }} -PropertyType string -Value $TCPAliasName displayName: 'Setup SQL Alias [Win]' - - pwsh: | + - powershell: | # Create Certificate $computerDnsName = [System.Net.Dns]::Resolve($null).HostName $certificate = New-SelfSignedCertificate -DnsName $computerDnsName,localhost -CertStoreLocation cert:\LocalMachine\My -FriendlyName test99 -KeySpec KeyExchange @@ -238,7 +224,7 @@ steps: } displayName: 'Add SQL Certificate [Win]' - - pwsh: | + - powershell: | # You need to restart SQL Server for the change to persist # -Force takes care of any dependent services, like SQL Agent. # Note: if the instance is named, replace MSSQLSERVER with MSSQL$ followed by @@ -257,7 +243,7 @@ steps: displayName: 'Restart SQL Server [Win]' - - pwsh: | + - powershell: | $arrService = Get-Service -Name "SQLBrowser" $arrService @@ -277,7 +263,7 @@ steps: displayName: 'Start Sql Server Browser [Win]' - ${{ if parameters.enableLocalDB }}: - - pwsh: | + - powershell: | #script to enable local db SqlLocalDB info diff --git a/eng/pipelines/stages/build-azure-package-ci-stage.yml b/eng/pipelines/stages/build-azure-package-ci-stage.yml index db703c6d97..5f39a53269 100644 --- a/eng/pipelines/stages/build-azure-package-ci-stage.yml +++ b/eng/pipelines/stages/build-azure-package-ci-stage.yml @@ -178,7 +178,6 @@ stages: sqlServerSetupSteps: - template: /eng/pipelines/common/templates/steps/configure-sql-server-linux-step.yml@self parameters: - debug: ${{ parameters.debug }} saPassword: $(saPassword) vmImage: ADO-UB22-SQL22 @@ -225,7 +224,6 @@ stages: - template: /eng/pipelines/common/templates/steps/configure-sql-server-win-step.yml@self # Use defaults for most parameters. parameters: - debug: ${{ parameters.debug }} saPassword: $(saPassword) enableLocalDB: true # These variables are from an Azure DevOps Library variable