From ebe74ee0b8c371e3fe66bff41c8d1128785a2a9f Mon Sep 17 00:00:00 2001 From: gargsaumya Date: Wed, 12 Aug 2026 11:21:32 +0530 Subject: [PATCH 1/5] FIX: Remove credential exposure from CI/CD pipelines Eliminate secret leakage via bash xtrace, process arguments, and world-readable files across ADO/OneBranch pipelines and the devcontainer: - Replace 'set -eux' with 'set -euo pipefail' in all secret-handling blocks and nested shells - Map secrets through step env: and reference shell vars instead of ADO \ macros - Use SQLCMDPASSWORD and stdin for sqlcmd; inherit Docker env vars by name (-e VAR) - Replace SQL Server installer /SAPWD= with an ACL-restricted /ConfigurationFile= deleted in finally - devcontainer: use --env-file (0600) for docker run and a user-only env file instead of world-readable /etc/environment --- .devcontainer/post-create.sh | 29 ++- .../stages/build-linux-single-stage.yml | 28 +-- .../stages/build-macos-single-stage.yml | 8 +- .../stages/build-windows-single-stage.yml | 2 +- OneBranchPipelines/stress-test-pipeline.yml | 36 ++-- eng/pipelines/pr-validation-pipeline.yml | 196 +++++++++++------- 6 files changed, 186 insertions(+), 113 deletions(-) diff --git a/.devcontainer/post-create.sh b/.devcontainer/post-create.sh index 63062828b..2a565b821 100755 --- a/.devcontainer/post-create.sh +++ b/.devcontainer/post-create.sh @@ -51,9 +51,11 @@ fi # Generate random password for SQL Server echo "" echo "Generating SQL Server password..." +umask 077 SA_PASSWORD="$(openssl rand -base64 16 | tr -dc 'A-Za-z0-9' | head -c 16)Aa1!" -echo "$SA_PASSWORD" > /tmp/.sqlserver_sa_password -chmod 600 /tmp/.sqlserver_sa_password +SQL_ENV_FILE="$(mktemp)" +printf 'ACCEPT_EULA=Y\nMSSQL_SA_PASSWORD=%s\n' "$SA_PASSWORD" > "$SQL_ENV_FILE" +chmod 600 "$SQL_ENV_FILE" # Start SQL Server container (use Azure SQL Edge for ARM64 compatibility) # This is optional - if Docker-in-Docker fails, the devcontainer still works @@ -63,15 +65,16 @@ echo "Starting SQL Server container (optional)..." ARCH=$(uname -m) if [[ "$ARCH" == "aarch64" || "$ARCH" == "arm64" ]]; then echo "Detected ARM64 - using Azure SQL Edge..." - docker run -e 'ACCEPT_EULA=Y' -e "MSSQL_SA_PASSWORD=$SA_PASSWORD" \ + docker run --env-file "$SQL_ENV_FILE" \ -p 1433:1433 --name sqlserver \ -d mcr.microsoft.com/azure-sql-edge:latest && SQL_STARTED=true || SQL_STARTED=false else echo "Detected x86_64 - using SQL Server 2025..." - docker run -e 'ACCEPT_EULA=Y' -e "MSSQL_SA_PASSWORD=$SA_PASSWORD" \ + docker run --env-file "$SQL_ENV_FILE" \ -p 1433:1433 --name sqlserver \ -d mcr.microsoft.com/mssql/server:2025-latest && SQL_STARTED=true || SQL_STARTED=false fi +rm -f "$SQL_ENV_FILE" if [ "$SQL_STARTED" = "true" ]; then echo "Waiting for SQL Server to start..." @@ -85,12 +88,18 @@ fi # Set DB_CONNECTION_STRING environment variable (persist across all terminals) DB_CONNECTION_STRING="Server=localhost,1433;Database=master;UID=sa;PWD=$SA_PASSWORD;TrustServerCertificate=Yes;Encrypt=Yes" -# Write to /etc/environment for system-wide persistence -echo "DB_CONNECTION_STRING=\"$DB_CONNECTION_STRING\"" | sudo tee -a /etc/environment > /dev/null - -# Also add to shell rc files for immediate availability in new terminals -echo "export DB_CONNECTION_STRING=\"$DB_CONNECTION_STRING\"" >> ~/.bashrc -echo "export DB_CONNECTION_STRING=\"$DB_CONNECTION_STRING\"" >> ~/.zshrc +# Keep the credential in a user-only file and source it from interactive shells. +MSSQL_ENV_FILE="$HOME/.mssql_python_env" +printf "export DB_CONNECTION_STRING='%s'\n" "$DB_CONNECTION_STRING" > "$MSSQL_ENV_FILE" +chmod 600 "$MSSQL_ENV_FILE" + +# Remove plaintext entries left by older versions of this script. +[ -f /etc/environment ] && sudo sed -i '/^DB_CONNECTION_STRING=/d' /etc/environment +[ -f ~/.bashrc ] && sed -i '/^export DB_CONNECTION_STRING=/d' ~/.bashrc +[ -f ~/.zshrc ] && sed -i '/^export DB_CONNECTION_STRING=/d' ~/.zshrc +rm -f /tmp/.sqlserver_sa_password +grep -qxF 'source ~/.mssql_python_env' ~/.bashrc 2>/dev/null || echo 'source ~/.mssql_python_env' >> ~/.bashrc +grep -qxF 'source ~/.mssql_python_env' ~/.zshrc 2>/dev/null || echo 'source ~/.mssql_python_env' >> ~/.zshrc # Export for current session export DB_CONNECTION_STRING diff --git a/OneBranchPipelines/stages/build-linux-single-stage.yml b/OneBranchPipelines/stages/build-linux-single-stage.yml index da258e0bf..7b5f634fb 100644 --- a/OneBranchPipelines/stages/build-linux-single-stage.yml +++ b/OneBranchPipelines/stages/build-linux-single-stage.yml @@ -136,7 +136,7 @@ stages: displayName: 'Start $(LINUX_TAG) $(ARCH) container' - script: | - set -euxo pipefail + set -euo pipefail export PATH=$PATH:`pwd`/docker CONTAINER="build-$(LINUX_TAG)-$(ARCH)" @@ -170,7 +170,7 @@ stages: # manager is flaky under emulation (the header gate below is the real check). if [[ "$(LINUX_TAG)" == "manylinux_2_28" ]]; then docker exec "$CONTAINER" bash -lc ' - set -uxo pipefail + set -uo pipefail if command -v dnf >/dev/null 2>&1; then dnf -y install gcc gcc-c++ make cmake unixODBC-devel krb5-libs keyutils-libs ccache curl || true elif command -v yum >/dev/null 2>&1; then @@ -181,7 +181,7 @@ stages: ' else docker exec "$CONTAINER" sh -lc ' - set -uxo pipefail + set -uo pipefail apk add --no-cache bash build-base cmake unixodbc-dev krb5-libs keyutils-libs ccache curl || true gcc --version || true cmake --version || true @@ -199,20 +199,20 @@ stages: # Start SQL Server container for pytest execution # Runs on host (not in build container) to be accessible from build container via network - script: | - set -euxo pipefail + set -euo pipefail echo "Starting SQL Server 2022 container for testing..." docker run -d --name sqlserver-$(LINUX_TAG)-$(ARCH) \ --platform linux/amd64 \ -e ACCEPT_EULA=Y \ - -e MSSQL_SA_PASSWORD="$(DB_PASSWORD)" \ + -e MSSQL_SA_PASSWORD \ -p 1433:1433 \ mcr.microsoft.com/mssql/server:2022-latest echo "Waiting for SQL Server to be ready..." for i in {1..30}; do - if docker exec sqlserver-$(LINUX_TAG)-$(ARCH) /opt/mssql-tools18/bin/sqlcmd \ - -S localhost -U SA -P "$(DB_PASSWORD)" -C -Q "SELECT 1" >/dev/null 2>&1; then + if docker exec -e SQLCMDPASSWORD sqlserver-$(LINUX_TAG)-$(ARCH) /opt/mssql-tools18/bin/sqlcmd \ + -S localhost -U SA -C -Q "SELECT 1" >/dev/null 2>&1; then echo "✓ SQL Server is ready!" break fi @@ -226,6 +226,8 @@ stages: displayName: 'Start SQL Server container for testing' env: DB_PASSWORD: $(DB_PASSWORD) + MSSQL_SA_PASSWORD: $(DB_PASSWORD) + SQLCMDPASSWORD: $(DB_PASSWORD) # ========================= # PHASE 2: EXTERNAL ODBC DRIVER PACKAGE @@ -256,7 +258,7 @@ stages: # Build wheels for all Python versions (3.10-3.14) and test each one - script: | - set -euxo pipefail + set -euo pipefail if [[ "$(LINUX_TAG)" == "manylinux_2_28" ]]; then SHELL_EXE=bash; else SHELL_EXE=sh; fi docker exec build-$(LINUX_TAG)-$(ARCH) $SHELL_EXE -lc 'mkdir -p /workspace/dist' @@ -269,8 +271,8 @@ stages: if [[ "$(LINUX_TAG)" == "manylinux_2_28" ]]; then # Manylinux (glibc-based) - use bash - docker exec -e PYBIN=$PYBIN -e SQL_IP=$(SQL_IP) -e DB_PASSWORD="$(DB_PASSWORD)" -e MANYLINUX_TAG="$(LINUX_TAG)" -e PIP_FIND_LINKS="/workspace/odbc_wheels" build-$(LINUX_TAG)-$(ARCH) bash -lc ' - set -euxo pipefail; + docker exec -e PYBIN=$PYBIN -e SQL_IP=$(SQL_IP) -e DB_PASSWORD -e MANYLINUX_TAG="$(LINUX_TAG)" -e PIP_FIND_LINKS="/workspace/odbc_wheels" build-$(LINUX_TAG)-$(ARCH) bash -lc ' + set -euo pipefail; # Step 1: Setup Python environment PY=/opt/python/${PYBIN}-${PYBIN}/bin/python; @@ -337,8 +339,8 @@ stages: ' else # Musllinux (musl libc-based) - use sh - docker exec -e PYBIN=$PYBIN -e SQL_IP=$(SQL_IP) -e DB_PASSWORD="$(DB_PASSWORD)" -e MANYLINUX_TAG="$(LINUX_TAG)" -e PIP_FIND_LINKS="/workspace/odbc_wheels" build-$(LINUX_TAG)-$(ARCH) sh -lc ' - set -euxo pipefail; + docker exec -e PYBIN=$PYBIN -e SQL_IP=$(SQL_IP) -e DB_PASSWORD -e MANYLINUX_TAG="$(LINUX_TAG)" -e PIP_FIND_LINKS="/workspace/odbc_wheels" build-$(LINUX_TAG)-$(ARCH) sh -lc ' + set -euo pipefail; # Step 1: Setup Python environment PY=/opt/python/${PYBIN}-${PYBIN}/bin/python; @@ -418,7 +420,7 @@ stages: # Copy built artifacts from container to host for publishing - script: | - set -euxo pipefail + set -euo pipefail # Copy all wheels (5 Python versions) to output directory echo "Copying wheels to host..." diff --git a/OneBranchPipelines/stages/build-macos-single-stage.yml b/OneBranchPipelines/stages/build-macos-single-stage.yml index 20962ce66..ef69b61b8 100644 --- a/OneBranchPipelines/stages/build-macos-single-stage.yml +++ b/OneBranchPipelines/stages/build-macos-single-stage.yml @@ -165,20 +165,22 @@ stages: docker pull mcr.microsoft.com/mssql/server:2022-latest docker run --name sqlserver \ -e ACCEPT_EULA=Y \ - -e MSSQL_SA_PASSWORD="${DB_PASSWORD}" \ + -e MSSQL_SA_PASSWORD \ -p 1433:1433 -d \ mcr.microsoft.com/mssql/server:2022-latest # Wait for SQL Server to accept connections (up to 60 seconds) # sqlcmd -C flag = trust server certificate (for TLS connection) for i in {1..30}; do - docker exec sqlserver /opt/mssql-tools18/bin/sqlcmd \ - -S localhost -U SA -P "$DB_PASSWORD" -C -Q "SELECT 1" && break + docker exec -e SQLCMDPASSWORD sqlserver /opt/mssql-tools18/bin/sqlcmd \ + -S localhost -U SA -C -Q "SELECT 1" && break sleep 2 done displayName: 'Start SQL Server (Docker)' env: DB_PASSWORD: $(DB_PASSWORD) + MSSQL_SA_PASSWORD: $(DB_PASSWORD) + SQLCMDPASSWORD: $(DB_PASSWORD) # ========================= # MSSQL_PY_CORE INSTALLATION diff --git a/OneBranchPipelines/stages/build-windows-single-stage.yml b/OneBranchPipelines/stages/build-windows-single-stage.yml index db1c4b1eb..8b0ba7c36 100644 --- a/OneBranchPipelines/stages/build-windows-single-stage.yml +++ b/OneBranchPipelines/stages/build-windows-single-stage.yml @@ -169,7 +169,7 @@ stages: - powershell: | sqlcmd -S "(localdb)\MSSQLLocalDB" -Q "CREATE DATABASE TestDB" - sqlcmd -S "(localdb)\MSSQLLocalDB" -Q "CREATE LOGIN testuser WITH PASSWORD = '$(DB_PASSWORD)'" + "CREATE LOGIN testuser WITH PASSWORD = '$env:DB_PASSWORD'" | sqlcmd -S "(localdb)\MSSQLLocalDB" sqlcmd -S "(localdb)\MSSQLLocalDB" -d TestDB -Q "CREATE USER testuser FOR LOGIN testuser" sqlcmd -S "(localdb)\MSSQLLocalDB" -d TestDB -Q "ALTER ROLE db_owner ADD MEMBER testuser" displayName: 'Setup database and user' diff --git a/OneBranchPipelines/stress-test-pipeline.yml b/OneBranchPipelines/stress-test-pipeline.yml index bf0000849..d0f753f87 100644 --- a/OneBranchPipelines/stress-test-pipeline.yml +++ b/OneBranchPipelines/stress-test-pipeline.yml @@ -103,7 +103,7 @@ jobs: - powershell: | Write-Host "Creating database and user for stress tests..." sqlcmd -S "(localdb)\MSSQLLocalDB" -Q "CREATE DATABASE StressTestDB" - sqlcmd -S "(localdb)\MSSQLLocalDB" -Q "CREATE LOGIN testuser WITH PASSWORD = '$env:DB_PASSWORD'" + "CREATE LOGIN testuser WITH PASSWORD = '$env:DB_PASSWORD'" | sqlcmd -S "(localdb)\MSSQLLocalDB" sqlcmd -S "(localdb)\MSSQLLocalDB" -d StressTestDB -Q "CREATE USER testuser FOR LOGIN testuser" sqlcmd -S "(localdb)\MSSQLLocalDB" -d StressTestDB -Q "ALTER ROLE db_owner ADD MEMBER testuser" Write-Host "Database setup completed" @@ -113,7 +113,7 @@ jobs: # Run multi-threaded stress tests in an isolated subprocess. - powershell: | - $env:DB_CONNECTION_STRING = 'Server=(localdb)\MSSQLLocalDB;Database=StressTestDB;Uid=testuser;Pwd=$(DB_PASSWORD);TrustServerCertificate=yes' + $env:DB_CONNECTION_STRING = "Server=(localdb)\MSSQLLocalDB;Database=StressTestDB;Uid=testuser;Pwd=$env:DB_PASSWORD;TrustServerCertificate=yes" Write-Host "Starting stress tests..." $xmlFile = "stress-test-results.xml" @@ -154,17 +154,21 @@ jobs: Write-Host "Test failures detected or XML not found" exit 1 displayName: 'Run Multi-Threaded Stress Tests' + env: + DB_PASSWORD: $(DB_PASSWORD) continueOnError: true # Run original stress tests - powershell: | - $env:DB_CONNECTION_STRING = 'Server=(localdb)\MSSQLLocalDB;Database=StressTestDB;Uid=testuser;Pwd=$(DB_PASSWORD);TrustServerCertificate=yes' + $env:DB_CONNECTION_STRING = "Server=(localdb)\MSSQLLocalDB;Database=StressTestDB;Uid=testuser;Pwd=$env:DB_PASSWORD;TrustServerCertificate=yes" python -m pytest tests/test_011_singlethreaded_stress.py -v -m "stress" --junitxml=perf-stress-test-results.xml --timeout=1800 --capture=tee-sys $exitCode = $LASTEXITCODE Write-Host "Pytest exit code: $exitCode" exit $exitCode displayName: 'Run Single-Threaded Stress Tests' + env: + DB_PASSWORD: $(DB_PASSWORD) continueOnError: true # Publish test results @@ -257,20 +261,20 @@ jobs: # Start SQL Server container for stress tests - script: | - set -euxo pipefail + set -euo pipefail echo "Starting SQL Server 2022 container for stress tests..." docker run -d --name sqlserver-stress \ --platform linux/amd64 \ -e ACCEPT_EULA=Y \ - -e MSSQL_SA_PASSWORD="$(DB_PASSWORD)" \ + -e MSSQL_SA_PASSWORD \ -p 1433:1433 \ mcr.microsoft.com/mssql/server:2022-latest echo "Waiting for SQL Server to be ready..." for i in {1..30}; do - if docker exec sqlserver-stress /opt/mssql-tools18/bin/sqlcmd \ - -S localhost -U SA -P "$(DB_PASSWORD)" -C -Q "SELECT 1" >/dev/null 2>&1; then + if docker exec -e SQLCMDPASSWORD sqlserver-stress /opt/mssql-tools18/bin/sqlcmd \ + -S localhost -U SA -C -Q "SELECT 1" >/dev/null 2>&1; then echo "SQL Server is ready!" break fi @@ -279,19 +283,21 @@ jobs: done echo "Creating database and user for stress tests..." - docker exec sqlserver-stress /opt/mssql-tools18/bin/sqlcmd \ - -S localhost -U SA -P "$(DB_PASSWORD)" -C -Q "CREATE DATABASE StressTestDB" - docker exec sqlserver-stress /opt/mssql-tools18/bin/sqlcmd \ - -S localhost -U SA -P "$(DB_PASSWORD)" -C -Q "CREATE LOGIN testuser WITH PASSWORD = '$(DB_PASSWORD)'" - docker exec sqlserver-stress /opt/mssql-tools18/bin/sqlcmd \ - -S localhost -U SA -P "$(DB_PASSWORD)" -C -d StressTestDB -Q "CREATE USER testuser FOR LOGIN testuser" - docker exec sqlserver-stress /opt/mssql-tools18/bin/sqlcmd \ - -S localhost -U SA -P "$(DB_PASSWORD)" -C -d StressTestDB -Q "ALTER ROLE db_owner ADD MEMBER testuser" + docker exec -e SQLCMDPASSWORD sqlserver-stress /opt/mssql-tools18/bin/sqlcmd \ + -S localhost -U SA -C -Q "CREATE DATABASE StressTestDB" + printf "CREATE LOGIN testuser WITH PASSWORD = '%s'\n" "$DB_PASSWORD" | \ + docker exec -i -e SQLCMDPASSWORD sqlserver-stress /opt/mssql-tools18/bin/sqlcmd -S localhost -U SA -C + docker exec -e SQLCMDPASSWORD sqlserver-stress /opt/mssql-tools18/bin/sqlcmd \ + -S localhost -U SA -C -d StressTestDB -Q "CREATE USER testuser FOR LOGIN testuser" + docker exec -e SQLCMDPASSWORD sqlserver-stress /opt/mssql-tools18/bin/sqlcmd \ + -S localhost -U SA -C -d StressTestDB -Q "ALTER ROLE db_owner ADD MEMBER testuser" echo "Database setup completed" displayName: 'Start SQL Server container and setup database' env: DB_PASSWORD: $(DB_PASSWORD) + MSSQL_SA_PASSWORD: $(DB_PASSWORD) + SQLCMDPASSWORD: $(DB_PASSWORD) # Run multi-threaded stress tests in an isolated subprocess. - script: | diff --git a/eng/pipelines/pr-validation-pipeline.yml b/eng/pipelines/pr-validation-pipeline.yml index f0323fb0b..9902b964e 100644 --- a/eng/pipelines/pr-validation-pipeline.yml +++ b/eng/pipelines/pr-validation-pipeline.yml @@ -85,7 +85,7 @@ jobs: # Create database and user for LocalDB - powershell: | sqlcmd -S "(localdb)\MSSQLLocalDB" -Q "CREATE DATABASE TestDB" - sqlcmd -S "(localdb)\MSSQLLocalDB" -Q "CREATE LOGIN testuser WITH PASSWORD = '$(DB_PASSWORD)'" + "CREATE LOGIN testuser WITH PASSWORD = '$env:DB_PASSWORD'" | sqlcmd -S "(localdb)\MSSQLLocalDB" sqlcmd -S "(localdb)\MSSQLLocalDB" -d TestDB -Q "CREATE USER testuser FOR LOGIN testuser" sqlcmd -S "(localdb)\MSSQLLocalDB" -d TestDB -Q "ALTER ROLE db_owner ADD MEMBER testuser" displayName: 'Setup database and user for LocalDB' @@ -112,7 +112,27 @@ jobs: Start-Process -FilePath $setupFile.FullName -ArgumentList "/x:$env:TEMP\SQLSetup","/u" -Wait Write-Host "Running SQL Server setup..." - Start-Process -FilePath "$env:TEMP\SQLSetup\setup.exe" -ArgumentList "/Q","/ACTION=Install","/FEATURES=SQLEngine","/INSTANCENAME=MSSQLSERVER","/SQLSVCACCOUNT=`"NT AUTHORITY\SYSTEM`"","/SQLSYSADMINACCOUNTS=`"BUILTIN\Administrators`"","/TCPENABLED=1","/SECURITYMODE=SQL","/SAPWD=$(DB_PASSWORD)","/IACCEPTSQLSERVERLICENSETERMS" -Wait + $configPath = Join-Path $env:TEMP "sql2022-setup.ini" + @" +[OPTIONS] +QUIET="True" +ACTION="Install" +FEATURES=SQLEngine +INSTANCENAME=MSSQLSERVER +SQLSVCACCOUNT="NT AUTHORITY\SYSTEM" +SQLSYSADMINACCOUNTS="BUILTIN\Administrators" +TCPENABLED="1" +SECURITYMODE="SQL" +SAPWD="$env:DB_PASSWORD" +IACCEPTSQLSERVERLICENSETERMS="True" +"@ | Set-Content -Path $configPath -Encoding ASCII + $identity = [System.Security.Principal.WindowsIdentity]::GetCurrent().Name + icacls $configPath /inheritance:r /grant:r "${identity}:(R)" "SYSTEM:(R)" | Out-Null + try { + Start-Process -FilePath "$env:TEMP\SQLSetup\setup.exe" -ArgumentList "/ConfigurationFile=$configPath" -Wait + } finally { + Remove-Item $configPath -Force -ErrorAction SilentlyContinue + } } else { Write-Error "Failed to download SQL Server setup file" exit 1 @@ -126,6 +146,7 @@ jobs: # Create database for SQL Server 2022 - powershell: | + $env:SQLCMDPASSWORD = $env:DB_PASSWORD # Wait for SQL Server to start $maxAttempts = 30 $attempt = 0 @@ -134,7 +155,7 @@ jobs: Write-Host "Waiting for SQL Server 2022 to start..." while (-not $connected -and $attempt -lt $maxAttempts) { try { - sqlcmd -S "localhost" -U "sa" -P "$(DB_PASSWORD)" -Q "SELECT 1" -C + sqlcmd -S "localhost" -U "sa" -Q "SELECT 1" -C $connected = $true Write-Host "SQL Server is ready!" } catch { @@ -150,10 +171,10 @@ jobs: } # Create database and user - sqlcmd -S "localhost" -U "sa" -P "$(DB_PASSWORD)" -Q "CREATE DATABASE TestDB" -C - sqlcmd -S "localhost" -U "sa" -P "$(DB_PASSWORD)" -Q "CREATE LOGIN testuser WITH PASSWORD = '$(DB_PASSWORD)'" -C - sqlcmd -S "localhost" -U "sa" -P "$(DB_PASSWORD)" -d TestDB -Q "CREATE USER testuser FOR LOGIN testuser" -C - sqlcmd -S "localhost" -U "sa" -P "$(DB_PASSWORD)" -d TestDB -Q "ALTER ROLE db_owner ADD MEMBER testuser" -C + sqlcmd -S "localhost" -U "sa" -Q "CREATE DATABASE TestDB" -C + "CREATE LOGIN testuser WITH PASSWORD = '$env:DB_PASSWORD'" | sqlcmd -S "localhost" -U "sa" -C + sqlcmd -S "localhost" -U "sa" -d TestDB -Q "CREATE USER testuser FOR LOGIN testuser" -C + sqlcmd -S "localhost" -U "sa" -d TestDB -Q "ALTER ROLE db_owner ADD MEMBER testuser" -C displayName: 'Setup database and user for SQL Server 2022' condition: eq(variables['sqlVersion'], 'SQL2022') env: @@ -178,7 +199,27 @@ jobs: Start-Process -FilePath $setupFile.FullName -ArgumentList "/x:$env:TEMP\SQL2025Setup","/u" -Wait Write-Host "Running SQL Server setup..." - Start-Process -FilePath "$env:TEMP\SQL2025Setup\setup.exe" -ArgumentList "/Q","/ACTION=Install","/FEATURES=SQLEngine","/INSTANCENAME=MSSQLSERVER","/SQLSVCACCOUNT=`"NT AUTHORITY\SYSTEM`"","/SQLSYSADMINACCOUNTS=`"BUILTIN\Administrators`"","/TCPENABLED=1","/SECURITYMODE=SQL","/SAPWD=$(DB_PASSWORD)","/IACCEPTSQLSERVERLICENSETERMS" -Wait + $configPath = Join-Path $env:TEMP "sql2025-setup.ini" + @" +[OPTIONS] +QUIET="True" +ACTION="Install" +FEATURES=SQLEngine +INSTANCENAME=MSSQLSERVER +SQLSVCACCOUNT="NT AUTHORITY\SYSTEM" +SQLSYSADMINACCOUNTS="BUILTIN\Administrators" +TCPENABLED="1" +SECURITYMODE="SQL" +SAPWD="$env:DB_PASSWORD" +IACCEPTSQLSERVERLICENSETERMS="True" +"@ | Set-Content -Path $configPath -Encoding ASCII + $identity = [System.Security.Principal.WindowsIdentity]::GetCurrent().Name + icacls $configPath /inheritance:r /grant:r "${identity}:(R)" "SYSTEM:(R)" | Out-Null + try { + Start-Process -FilePath "$env:TEMP\SQL2025Setup\setup.exe" -ArgumentList "/ConfigurationFile=$configPath" -Wait + } finally { + Remove-Item $configPath -Force -ErrorAction SilentlyContinue + } } else { Write-Error "Failed to download SQL Server setup file" exit 1 @@ -192,6 +233,7 @@ jobs: # Create database for SQL Server 2025 - powershell: | + $env:SQLCMDPASSWORD = $env:DB_PASSWORD # Wait for SQL Server to start $maxAttempts = 30 $attempt = 0 @@ -200,7 +242,7 @@ jobs: Write-Host "Waiting for SQL Server 2025 to start..." while (-not $connected -and $attempt -lt $maxAttempts) { try { - sqlcmd -S "localhost" -U "sa" -P "$(DB_PASSWORD)" -Q "SELECT 1" -C + sqlcmd -S "localhost" -U "sa" -Q "SELECT 1" -C $connected = $true Write-Host "SQL Server is ready!" } catch { @@ -216,10 +258,10 @@ jobs: } # Create database and user - sqlcmd -S "localhost" -U "sa" -P "$(DB_PASSWORD)" -Q "CREATE DATABASE TestDB" -C - sqlcmd -S "localhost" -U "sa" -P "$(DB_PASSWORD)" -Q "CREATE LOGIN testuser WITH PASSWORD = '$(DB_PASSWORD)'" -C - sqlcmd -S "localhost" -U "sa" -P "$(DB_PASSWORD)" -d TestDB -Q "CREATE USER testuser FOR LOGIN testuser" -C - sqlcmd -S "localhost" -U "sa" -P "$(DB_PASSWORD)" -d TestDB -Q "ALTER ROLE db_owner ADD MEMBER testuser" -C + sqlcmd -S "localhost" -U "sa" -Q "CREATE DATABASE TestDB" -C + "CREATE LOGIN testuser WITH PASSWORD = '$env:DB_PASSWORD'" | sqlcmd -S "localhost" -U "sa" -C + sqlcmd -S "localhost" -U "sa" -d TestDB -Q "CREATE USER testuser FOR LOGIN testuser" -C + sqlcmd -S "localhost" -U "sa" -d TestDB -Q "ALTER ROLE db_owner ADD MEMBER testuser" -C displayName: 'Setup database and user for SQL Server 2025' condition: eq(variables['sqlVersion'], 'SQL2025') env: @@ -260,14 +302,15 @@ jobs: # Download and restore AdventureWorks2022 database for benchmarking - powershell: | + $env:SQLCMDPASSWORD = $env:DB_PASSWORD Write-Host "Downloading AdventureWorks2022.bak..." $ProgressPreference = 'SilentlyContinue' Invoke-WebRequest -Uri "https://github.com/Microsoft/sql-server-samples/releases/download/adventureworks/AdventureWorks2022.bak" -OutFile "$env:TEMP\AdventureWorks2022.bak" Write-Host "Restoring AdventureWorks2022 database..." # Get the default data and log paths - $dataPath = sqlcmd -S "localhost" -U "sa" -P "$(DB_PASSWORD)" -Q "SET NOCOUNT ON; SELECT SERVERPROPERTY('InstanceDefaultDataPath') AS DataPath" -h -1 -C | Out-String - $logPath = sqlcmd -S "localhost" -U "sa" -P "$(DB_PASSWORD)" -Q "SET NOCOUNT ON; SELECT SERVERPROPERTY('InstanceDefaultLogPath') AS LogPath" -h -1 -C | Out-String + $dataPath = sqlcmd -S "localhost" -U "sa" -Q "SET NOCOUNT ON; SELECT SERVERPROPERTY('InstanceDefaultDataPath') AS DataPath" -h -1 -C | Out-String + $logPath = sqlcmd -S "localhost" -U "sa" -Q "SET NOCOUNT ON; SELECT SERVERPROPERTY('InstanceDefaultLogPath') AS LogPath" -h -1 -C | Out-String $dataPath = $dataPath.Trim() $logPath = $logPath.Trim() @@ -276,7 +319,7 @@ jobs: Write-Host "Log path: $logPath" # Restore the database - sqlcmd -S "localhost" -U "sa" -P "$(DB_PASSWORD)" -C -Q @" + sqlcmd -S "localhost" -U "sa" -C -Q @" RESTORE DATABASE AdventureWorks2022 FROM DISK = '$env:TEMP\AdventureWorks2022.bak' WITH @@ -511,23 +554,24 @@ jobs: docker run \ --name sqlserver \ -e ACCEPT_EULA=Y \ - -e MSSQL_SA_PASSWORD="${DB_PASSWORD}" \ + -e MSSQL_SA_PASSWORD \ -p 1433:1433 \ -d $(sqlServerImage) # Starting SQL Server container… for i in {1..30}; do - docker exec sqlserver \ + docker exec -e SQLCMDPASSWORD sqlserver \ /opt/mssql-tools18/bin/sqlcmd \ -S localhost \ -U SA \ - -P "$DB_PASSWORD" \ -C -Q "SELECT 1" && break sleep 2 done displayName: 'Pull & start SQL Server (Docker)' env: DB_PASSWORD: $(DB_PASSWORD) + MSSQL_SA_PASSWORD: $(DB_PASSWORD) + SQLCMDPASSWORD: $(DB_PASSWORD) - script: | python -m pip install --upgrade pip @@ -597,8 +641,8 @@ jobs: docker cp /tmp/AdventureWorks2022.bak sqlserver:/tmp/AdventureWorks2022.bak echo "Restoring AdventureWorks2022 database..." - docker exec sqlserver /opt/mssql-tools18/bin/sqlcmd \ - -S localhost -U SA -P "$DB_PASSWORD" -C \ + docker exec -e SQLCMDPASSWORD sqlserver /opt/mssql-tools18/bin/sqlcmd \ + -S localhost -U SA -C \ -Q "RESTORE DATABASE AdventureWorks2022 FROM DISK = '/tmp/AdventureWorks2022.bak' WITH MOVE 'AdventureWorks2022' TO '/var/opt/mssql/data/AdventureWorks2022.mdf', MOVE 'AdventureWorks2022_log' TO '/var/opt/mssql/data/AdventureWorks2022_log.ldf', REPLACE" if [ $? -eq 0 ]; then @@ -614,6 +658,7 @@ jobs: continueOnError: true env: DB_PASSWORD: $(DB_PASSWORD) + SQLCMDPASSWORD: $(DB_PASSWORD) # Download macOS baseline from latest main run (for PR comparison) - task: DownloadPipelineArtifact@2 @@ -716,18 +761,17 @@ jobs: # Start SQL Server container docker run -d --name sqlserver-$(distroName) \ -e ACCEPT_EULA=Y \ - -e MSSQL_SA_PASSWORD="$(DB_PASSWORD)" \ + -e MSSQL_SA_PASSWORD \ -p 1433:1433 \ $(sqlServerImage) # Wait for SQL Server to be ready echo "Waiting for SQL Server to start..." for i in {1..60}; do - if docker exec sqlserver-$(distroName) \ + if docker exec -e SQLCMDPASSWORD sqlserver-$(distroName) \ /opt/mssql-tools18/bin/sqlcmd \ -S localhost \ -U SA \ - -P "$(DB_PASSWORD)" \ -C -Q "SELECT 1" >/dev/null 2>&1; then echo "SQL Server is ready!" break @@ -737,16 +781,17 @@ jobs: done # Create test database - docker exec sqlserver-$(distroName) \ + docker exec -e SQLCMDPASSWORD sqlserver-$(distroName) \ /opt/mssql-tools18/bin/sqlcmd \ -S localhost \ -U SA \ - -P "$(DB_PASSWORD)" \ -C -Q "CREATE DATABASE TestDB" displayName: 'Start SQL Server container for $(distroName)' condition: eq(variables['useAzureSQL'], 'false') env: DB_PASSWORD: $(DB_PASSWORD) + MSSQL_SA_PASSWORD: $(DB_PASSWORD) + SQLCMDPASSWORD: $(DB_PASSWORD) - script: | # Install dependencies in the container @@ -860,7 +905,7 @@ jobs: echo "Testing against Azure SQL Database" docker exec \ - -e DB_CONNECTION_STRING="$(AZURE_CONNECTION_STRING)" \ + -e DB_CONNECTION_STRING \ test-container-$(distroName) bash -c " source /opt/venv/bin/activate echo 'Build successful, running tests now on $(distroName) with Azure SQL' @@ -871,10 +916,11 @@ jobs: # Local SQL Server testing SQLSERVER_IP=$(docker inspect sqlserver-$(distroName) --format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}') echo "SQL Server IP: $SQLSERVER_IP" + export DB_CONNECTION_STRING="Server=$SQLSERVER_IP;Database=TestDB;Uid=SA;Pwd=$DB_PASSWORD;TrustServerCertificate=yes" docker exec \ - -e DB_CONNECTION_STRING="Server=$SQLSERVER_IP;Database=TestDB;Uid=SA;Pwd=$(DB_PASSWORD);TrustServerCertificate=yes" \ - -e DB_PASSWORD="$(DB_PASSWORD)" \ + -e DB_CONNECTION_STRING \ + -e DB_PASSWORD \ test-container-$(distroName) bash -c " source /opt/venv/bin/activate echo 'Build successful, running tests now on $(distroName)' @@ -886,6 +932,7 @@ jobs: condition: or(eq(variables['useAzureSQL'], 'false'), and(eq(variables['useAzureSQL'], 'true'), ne(variables['AZURE_CONNECTION_STRING'], ''))) env: DB_PASSWORD: $(DB_PASSWORD) + DB_CONNECTION_STRING: $(AZURE_CONNECTION_STRING) - script: | # Download and restore AdventureWorks2022 database for benchmarking on Ubuntu only @@ -897,10 +944,9 @@ jobs: docker cp /tmp/AdventureWorks2022.bak sqlserver-$(distroName):/tmp/AdventureWorks2022.bak echo "Restoring AdventureWorks2022 database..." - docker exec sqlserver-$(distroName) /opt/mssql-tools18/bin/sqlcmd \ + docker exec -e SQLCMDPASSWORD sqlserver-$(distroName) /opt/mssql-tools18/bin/sqlcmd \ -S localhost \ -U SA \ - -P "$(DB_PASSWORD)" \ -C \ -Q "RESTORE DATABASE AdventureWorks2022 FROM DISK = '/tmp/AdventureWorks2022.bak' WITH MOVE 'AdventureWorks2022' TO '/var/opt/mssql/data/AdventureWorks2022.mdf', MOVE 'AdventureWorks2022_log' TO '/var/opt/mssql/data/AdventureWorks2022_log.ldf', REPLACE" @@ -919,15 +965,17 @@ jobs: continueOnError: true env: DB_PASSWORD: $(DB_PASSWORD) + SQLCMDPASSWORD: $(DB_PASSWORD) - script: | # Run performance benchmarks on Ubuntu with SQL Server 2022 only if [ "$(distroName)" = "Ubuntu" ] && [ "$(useAzureSQL)" = "false" ]; then SQLSERVER_IP=$(docker inspect sqlserver-$(distroName) --format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}') echo "Running performance benchmarks on Ubuntu with SQL Server IP: $SQLSERVER_IP" + export DB_CONNECTION_STRING="Server=$SQLSERVER_IP;Database=AdventureWorks2022;Uid=SA;Pwd=$DB_PASSWORD;TrustServerCertificate=yes" docker exec \ - -e DB_CONNECTION_STRING="Server=$SQLSERVER_IP;Database=AdventureWorks2022;Uid=SA;Pwd=$(DB_PASSWORD);TrustServerCertificate=yes" \ + -e DB_CONNECTION_STRING \ test-container-$(distroName) bash -c " source /opt/venv/bin/activate @@ -1041,18 +1089,17 @@ jobs: docker run -d --name sqlserver-$(distroName)-$(archName) \ --platform linux/amd64 \ -e ACCEPT_EULA=Y \ - -e MSSQL_SA_PASSWORD="$(DB_PASSWORD)" \ + -e MSSQL_SA_PASSWORD \ -p 1433:1433 \ mcr.microsoft.com/mssql/server:2022-latest # Wait for SQL Server to be ready echo "Waiting for SQL Server to start..." for i in {1..60}; do - if docker exec sqlserver-$(distroName)-$(archName) \ + if docker exec -e SQLCMDPASSWORD sqlserver-$(distroName)-$(archName) \ /opt/mssql-tools18/bin/sqlcmd \ -S localhost \ -U SA \ - -P "$(DB_PASSWORD)" \ -C -Q "SELECT 1" >/dev/null 2>&1; then echo "SQL Server is ready!" break @@ -1062,15 +1109,16 @@ jobs: done # Create test database - docker exec sqlserver-$(distroName)-$(archName) \ + docker exec -e SQLCMDPASSWORD sqlserver-$(distroName)-$(archName) \ /opt/mssql-tools18/bin/sqlcmd \ -S localhost \ -U SA \ - -P "$(DB_PASSWORD)" \ -C -Q "CREATE DATABASE TestDB" displayName: 'Start SQL Server container for $(distroName) ARM64' env: DB_PASSWORD: $(DB_PASSWORD) + MSSQL_SA_PASSWORD: $(DB_PASSWORD) + SQLCMDPASSWORD: $(DB_PASSWORD) - script: | # Install dependencies in the ARM64 container @@ -1207,10 +1255,11 @@ jobs: # Get SQL Server container IP SQLSERVER_IP=$(docker inspect sqlserver-$(distroName)-$(archName) --format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}') echo "SQL Server IP: $SQLSERVER_IP" + export DB_CONNECTION_STRING="Server=$SQLSERVER_IP;Database=TestDB;Uid=SA;Pwd=$DB_PASSWORD;TrustServerCertificate=yes" docker exec \ - -e DB_CONNECTION_STRING="Server=$SQLSERVER_IP;Database=TestDB;Uid=SA;Pwd=$(DB_PASSWORD);TrustServerCertificate=yes" \ - -e DB_PASSWORD="$(DB_PASSWORD)" \ + -e DB_CONNECTION_STRING \ + -e DB_PASSWORD \ test-container-$(distroName)-$(archName) bash -c " source /opt/venv/bin/activate echo 'Build successful, running tests now on $(distroName) ARM64' @@ -1265,18 +1314,17 @@ jobs: # Start SQL Server container docker run -d --name sqlserver-rhel9 \ -e ACCEPT_EULA=Y \ - -e MSSQL_SA_PASSWORD="$(DB_PASSWORD)" \ + -e MSSQL_SA_PASSWORD \ -p 1433:1433 \ mcr.microsoft.com/mssql/server:2022-latest # Wait for SQL Server to be ready echo "Waiting for SQL Server to start..." for i in {1..60}; do - if docker exec sqlserver-rhel9 \ + if docker exec -e SQLCMDPASSWORD sqlserver-rhel9 \ /opt/mssql-tools18/bin/sqlcmd \ -S localhost \ -U SA \ - -P "$(DB_PASSWORD)" \ -C -Q "SELECT 1" >/dev/null 2>&1; then echo "SQL Server is ready!" break @@ -1286,15 +1334,16 @@ jobs: done # Create test database - docker exec sqlserver-rhel9 \ + docker exec -e SQLCMDPASSWORD sqlserver-rhel9 \ /opt/mssql-tools18/bin/sqlcmd \ -S localhost \ -U SA \ - -P "$(DB_PASSWORD)" \ -C -Q "CREATE DATABASE TestDB" displayName: 'Start SQL Server container for RHEL 9' env: DB_PASSWORD: $(DB_PASSWORD) + MSSQL_SA_PASSWORD: $(DB_PASSWORD) + SQLCMDPASSWORD: $(DB_PASSWORD) - script: | # Install dependencies in the RHEL 9 container @@ -1426,10 +1475,11 @@ jobs: # Get SQL Server container IP SQLSERVER_IP=$(docker inspect sqlserver-rhel9 --format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}') echo "SQL Server IP: $SQLSERVER_IP" + export DB_CONNECTION_STRING="Server=$SQLSERVER_IP;Database=TestDB;Uid=SA;Pwd=$DB_PASSWORD;TrustServerCertificate=yes" docker exec \ - -e DB_CONNECTION_STRING="Server=$SQLSERVER_IP;Database=TestDB;Uid=SA;Pwd=$(DB_PASSWORD);TrustServerCertificate=yes" \ - -e DB_PASSWORD="$(DB_PASSWORD)" \ + -e DB_CONNECTION_STRING \ + -e DB_PASSWORD \ test-container-rhel9 bash -c " source myvenv/bin/activate echo 'Build successful, running tests now on RHEL 9' @@ -1492,18 +1542,17 @@ jobs: docker run -d --name sqlserver-rhel9-arm64 \ --platform linux/amd64 \ -e ACCEPT_EULA=Y \ - -e MSSQL_SA_PASSWORD="$(DB_PASSWORD)" \ + -e MSSQL_SA_PASSWORD \ -p 1433:1433 \ mcr.microsoft.com/mssql/server:2022-latest # Wait for SQL Server to be ready echo "Waiting for SQL Server to start..." for i in {1..60}; do - if docker exec sqlserver-rhel9-arm64 \ + if docker exec -e SQLCMDPASSWORD sqlserver-rhel9-arm64 \ /opt/mssql-tools18/bin/sqlcmd \ -S localhost \ -U SA \ - -P "$(DB_PASSWORD)" \ -C -Q "SELECT 1" >/dev/null 2>&1; then echo "SQL Server is ready!" break @@ -1513,15 +1562,16 @@ jobs: done # Create test database - docker exec sqlserver-rhel9-arm64 \ + docker exec -e SQLCMDPASSWORD sqlserver-rhel9-arm64 \ /opt/mssql-tools18/bin/sqlcmd \ -S localhost \ -U SA \ - -P "$(DB_PASSWORD)" \ -C -Q "CREATE DATABASE TestDB" displayName: 'Start SQL Server container for RHEL 9 ARM64' env: DB_PASSWORD: $(DB_PASSWORD) + MSSQL_SA_PASSWORD: $(DB_PASSWORD) + SQLCMDPASSWORD: $(DB_PASSWORD) - script: | # Install dependencies in the RHEL 9 ARM64 container @@ -1657,10 +1707,11 @@ jobs: # Get SQL Server container IP SQLSERVER_IP=$(docker inspect sqlserver-rhel9-arm64 --format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}') echo "SQL Server IP: $SQLSERVER_IP" + export DB_CONNECTION_STRING="Server=$SQLSERVER_IP;Database=TestDB;Uid=SA;Pwd=$DB_PASSWORD;TrustServerCertificate=yes" docker exec \ - -e DB_CONNECTION_STRING="Server=$SQLSERVER_IP;Database=TestDB;Uid=SA;Pwd=$(DB_PASSWORD);TrustServerCertificate=yes" \ - -e DB_PASSWORD="$(DB_PASSWORD)" \ + -e DB_CONNECTION_STRING \ + -e DB_PASSWORD \ test-container-rhel9-arm64 bash -c " source myvenv/bin/activate echo 'Build successful, running tests now on RHEL 9 ARM64' @@ -1723,18 +1774,17 @@ jobs: docker run -d --name sqlserver-alpine \ --platform linux/amd64 \ -e ACCEPT_EULA=Y \ - -e MSSQL_SA_PASSWORD="$(DB_PASSWORD)" \ + -e MSSQL_SA_PASSWORD \ -p 1433:1433 \ mcr.microsoft.com/mssql/server:2022-latest # Wait for SQL Server to be ready echo "Waiting for SQL Server to start..." for i in {1..60}; do - if docker exec sqlserver-alpine \ + if docker exec -e SQLCMDPASSWORD sqlserver-alpine \ /opt/mssql-tools18/bin/sqlcmd \ -S localhost \ -U SA \ - -P "$(DB_PASSWORD)" \ -C -Q "SELECT 1" >/dev/null 2>&1; then echo "SQL Server is ready!" break @@ -1744,15 +1794,16 @@ jobs: done # Create test database - docker exec sqlserver-alpine \ + docker exec -e SQLCMDPASSWORD sqlserver-alpine \ /opt/mssql-tools18/bin/sqlcmd \ -S localhost \ -U SA \ - -P "$(DB_PASSWORD)" \ -C -Q "CREATE DATABASE TestDB" displayName: 'Start SQL Server container for Alpine x86_64' env: DB_PASSWORD: $(DB_PASSWORD) + MSSQL_SA_PASSWORD: $(DB_PASSWORD) + SQLCMDPASSWORD: $(DB_PASSWORD) - script: | # Install dependencies in the Alpine x86_64 container @@ -1897,10 +1948,11 @@ jobs: # Get SQL Server container IP SQLSERVER_IP=$(docker inspect sqlserver-alpine --format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}') echo "SQL Server IP: $SQLSERVER_IP" + export DB_CONNECTION_STRING="Server=$SQLSERVER_IP;Database=TestDB;Uid=SA;Pwd=$DB_PASSWORD;TrustServerCertificate=yes" docker exec \ - -e DB_CONNECTION_STRING="Server=$SQLSERVER_IP;Database=TestDB;Uid=SA;Pwd=$(DB_PASSWORD);TrustServerCertificate=yes" \ - -e DB_PASSWORD="$(DB_PASSWORD)" \ + -e DB_CONNECTION_STRING \ + -e DB_PASSWORD \ test-container-alpine bash -c " echo 'Build successful, running tests now on Alpine x86_64' echo 'Architecture:' \$(uname -m) @@ -1979,18 +2031,17 @@ jobs: docker run -d --name sqlserver-alpine-arm64 \ --platform linux/amd64 \ -e ACCEPT_EULA=Y \ - -e MSSQL_SA_PASSWORD="$(DB_PASSWORD)" \ + -e MSSQL_SA_PASSWORD \ -p 1433:1433 \ mcr.microsoft.com/mssql/server:2022-latest # Wait for SQL Server to be ready echo "Waiting for SQL Server to start..." for i in {1..60}; do - if docker exec sqlserver-alpine-arm64 \ + if docker exec -e SQLCMDPASSWORD sqlserver-alpine-arm64 \ /opt/mssql-tools18/bin/sqlcmd \ -S localhost \ -U SA \ - -P "$(DB_PASSWORD)" \ -C -Q "SELECT 1" >/dev/null 2>&1; then echo "SQL Server is ready!" break @@ -2000,15 +2051,16 @@ jobs: done # Create test database - docker exec sqlserver-alpine-arm64 \ + docker exec -e SQLCMDPASSWORD sqlserver-alpine-arm64 \ /opt/mssql-tools18/bin/sqlcmd \ -S localhost \ -U SA \ - -P "$(DB_PASSWORD)" \ -C -Q "CREATE DATABASE TestDB" displayName: 'Start SQL Server container for Alpine ARM64' env: DB_PASSWORD: $(DB_PASSWORD) + MSSQL_SA_PASSWORD: $(DB_PASSWORD) + SQLCMDPASSWORD: $(DB_PASSWORD) - script: | # Install dependencies in the Alpine ARM64 container @@ -2154,10 +2206,11 @@ jobs: # Get SQL Server container IP SQLSERVER_IP=$(docker inspect sqlserver-alpine-arm64 --format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}') echo "SQL Server IP: $SQLSERVER_IP" + export DB_CONNECTION_STRING="Server=$SQLSERVER_IP;Database=TestDB;Uid=SA;Pwd=$DB_PASSWORD;TrustServerCertificate=yes" docker exec \ - -e DB_CONNECTION_STRING="Server=$SQLSERVER_IP;Database=TestDB;Uid=SA;Pwd=$(DB_PASSWORD);TrustServerCertificate=yes" \ - -e DB_PASSWORD="$(DB_PASSWORD)" \ + -e DB_CONNECTION_STRING \ + -e DB_PASSWORD \ test-container-alpine-arm64 bash -c " echo 'Build successful, running tests now on Alpine ARM64' echo 'Architecture:' \$(uname -m) @@ -2403,7 +2456,7 @@ jobs: # # - script: | # docker exec \ -# -e DB_CONNECTION_STRING="$(AZURE_CONNECTION_STRING)" \ +# -e DB_CONNECTION_STRING \ # test-container-ubuntu-azuresql bash -c " # source /opt/venv/bin/activate # echo 'Running tests on Ubuntu against Azure SQL Database' @@ -2449,23 +2502,24 @@ jobs: docker run \ --name sqlserver \ -e ACCEPT_EULA=Y \ - -e MSSQL_SA_PASSWORD="$(DB_PASSWORD)" \ + -e MSSQL_SA_PASSWORD \ -p 1433:1433 \ -d mcr.microsoft.com/mssql/server:2022-latest # Wait until SQL Server is ready for i in {1..30}; do - docker exec sqlserver \ + docker exec -e SQLCMDPASSWORD sqlserver \ /opt/mssql-tools18/bin/sqlcmd \ -S localhost \ -U SA \ - -P "$(DB_PASSWORD)" \ -C -Q "SELECT 1" && break sleep 2 done displayName: 'Start SQL Server container' env: DB_PASSWORD: $(DB_PASSWORD) + MSSQL_SA_PASSWORD: $(DB_PASSWORD) + SQLCMDPASSWORD: $(DB_PASSWORD) - script: | # Install Python dependencies From f90d11d77b074e26dbb5e30202b2e74c0d3a8d21 Mon Sep 17 00:00:00 2001 From: gargsaumya Date: Thu, 13 Aug 2026 12:04:31 +0530 Subject: [PATCH 2/5] FIX: Scope umask to secret-file writes in devcontainer post-create Avoid mutating the global umask; create per-file with owner-only perms via a scoped subshell and pre-write chmod. --- .devcontainer/post-create.sh | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.devcontainer/post-create.sh b/.devcontainer/post-create.sh index 2a565b821..e32748373 100755 --- a/.devcontainer/post-create.sh +++ b/.devcontainer/post-create.sh @@ -51,11 +51,11 @@ fi # Generate random password for SQL Server echo "" echo "Generating SQL Server password..." -umask 077 SA_PASSWORD="$(openssl rand -base64 16 | tr -dc 'A-Za-z0-9' | head -c 16)Aa1!" +# mktemp creates 0600; chmod before writing keeps it owner-only without touching the global umask. SQL_ENV_FILE="$(mktemp)" -printf 'ACCEPT_EULA=Y\nMSSQL_SA_PASSWORD=%s\n' "$SA_PASSWORD" > "$SQL_ENV_FILE" chmod 600 "$SQL_ENV_FILE" +printf 'ACCEPT_EULA=Y\nMSSQL_SA_PASSWORD=%s\n' "$SA_PASSWORD" > "$SQL_ENV_FILE" # Start SQL Server container (use Azure SQL Edge for ARM64 compatibility) # This is optional - if Docker-in-Docker fails, the devcontainer still works @@ -90,7 +90,8 @@ DB_CONNECTION_STRING="Server=localhost,1433;Database=master;UID=sa;PWD=$SA_PASSW # Keep the credential in a user-only file and source it from interactive shells. MSSQL_ENV_FILE="$HOME/.mssql_python_env" -printf "export DB_CONNECTION_STRING='%s'\n" "$DB_CONNECTION_STRING" > "$MSSQL_ENV_FILE" +# Scope umask to this write only so the file is owner-only from creation; global umask stays untouched. +( umask 077; printf "export DB_CONNECTION_STRING='%s'\n" "$DB_CONNECTION_STRING" > "$MSSQL_ENV_FILE" ) chmod 600 "$MSSQL_ENV_FILE" # Remove plaintext entries left by older versions of this script. From 86a4eac31f1c751bc10106117bf61169be95e11a Mon Sep 17 00:00:00 2001 From: gargsaumya Date: Thu, 13 Aug 2026 13:11:53 +0530 Subject: [PATCH 3/5] FIX: Repair YAML block scalar broken by SQL setup config here-string The PowerShell here-string content sat at column 0, which dedented out of the YAML '|' block and made the ADO parser reject the pipeline. Replace it with an indented PowerShell array written via Set-Content, keeping clean INI output. --- eng/pipelines/pr-validation-pipeline.yml | 54 ++++++++++++------------ 1 file changed, 28 insertions(+), 26 deletions(-) diff --git a/eng/pipelines/pr-validation-pipeline.yml b/eng/pipelines/pr-validation-pipeline.yml index 9902b964e..4d6029aa0 100644 --- a/eng/pipelines/pr-validation-pipeline.yml +++ b/eng/pipelines/pr-validation-pipeline.yml @@ -113,19 +113,20 @@ jobs: Write-Host "Running SQL Server setup..." $configPath = Join-Path $env:TEMP "sql2022-setup.ini" - @" -[OPTIONS] -QUIET="True" -ACTION="Install" -FEATURES=SQLEngine -INSTANCENAME=MSSQLSERVER -SQLSVCACCOUNT="NT AUTHORITY\SYSTEM" -SQLSYSADMINACCOUNTS="BUILTIN\Administrators" -TCPENABLED="1" -SECURITYMODE="SQL" -SAPWD="$env:DB_PASSWORD" -IACCEPTSQLSERVERLICENSETERMS="True" -"@ | Set-Content -Path $configPath -Encoding ASCII + $configLines = @( + '[OPTIONS]' + 'QUIET="True"' + 'ACTION="Install"' + 'FEATURES=SQLEngine' + 'INSTANCENAME=MSSQLSERVER' + 'SQLSVCACCOUNT="NT AUTHORITY\SYSTEM"' + 'SQLSYSADMINACCOUNTS="BUILTIN\Administrators"' + 'TCPENABLED="1"' + 'SECURITYMODE="SQL"' + "SAPWD=`"$env:DB_PASSWORD`"" + 'IACCEPTSQLSERVERLICENSETERMS="True"' + ) + Set-Content -Path $configPath -Value $configLines -Encoding ASCII $identity = [System.Security.Principal.WindowsIdentity]::GetCurrent().Name icacls $configPath /inheritance:r /grant:r "${identity}:(R)" "SYSTEM:(R)" | Out-Null try { @@ -200,19 +201,20 @@ IACCEPTSQLSERVERLICENSETERMS="True" Write-Host "Running SQL Server setup..." $configPath = Join-Path $env:TEMP "sql2025-setup.ini" - @" -[OPTIONS] -QUIET="True" -ACTION="Install" -FEATURES=SQLEngine -INSTANCENAME=MSSQLSERVER -SQLSVCACCOUNT="NT AUTHORITY\SYSTEM" -SQLSYSADMINACCOUNTS="BUILTIN\Administrators" -TCPENABLED="1" -SECURITYMODE="SQL" -SAPWD="$env:DB_PASSWORD" -IACCEPTSQLSERVERLICENSETERMS="True" -"@ | Set-Content -Path $configPath -Encoding ASCII + $configLines = @( + '[OPTIONS]' + 'QUIET="True"' + 'ACTION="Install"' + 'FEATURES=SQLEngine' + 'INSTANCENAME=MSSQLSERVER' + 'SQLSVCACCOUNT="NT AUTHORITY\SYSTEM"' + 'SQLSYSADMINACCOUNTS="BUILTIN\Administrators"' + 'TCPENABLED="1"' + 'SECURITYMODE="SQL"' + "SAPWD=`"$env:DB_PASSWORD`"" + 'IACCEPTSQLSERVERLICENSETERMS="True"' + ) + Set-Content -Path $configPath -Value $configLines -Encoding ASCII $identity = [System.Security.Principal.WindowsIdentity]::GetCurrent().Name icacls $configPath /inheritance:r /grant:r "${identity}:(R)" "SYSTEM:(R)" | Out-Null try { From 6a073304272d876e9756c8edd86e564af3154fe3 Mon Sep 17 00:00:00 2001 From: gargsaumya Date: Fri, 4 Sep 2026 22:43:36 +0530 Subject: [PATCH 4/5] FIX: Escape database passwords in CI login setup Escape single quotes before embedding DB_PASSWORD in CREATE LOGIN, disable sqlcmd variable expansion, and make Windows setup fail immediately when sqlcmd rejects the login statement. --- .../stages/build-windows-single-stage.yml | 4 +++- OneBranchPipelines/stress-test-pipeline.yml | 9 ++++++--- eng/pipelines/pr-validation-pipeline.yml | 12 +++++++++--- 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/OneBranchPipelines/stages/build-windows-single-stage.yml b/OneBranchPipelines/stages/build-windows-single-stage.yml index bfdb670de..e8ef01e2e 100644 --- a/OneBranchPipelines/stages/build-windows-single-stage.yml +++ b/OneBranchPipelines/stages/build-windows-single-stage.yml @@ -169,7 +169,9 @@ stages: - powershell: | sqlcmd -S "(localdb)\MSSQLLocalDB" -Q "CREATE DATABASE TestDB" - "CREATE LOGIN testuser WITH PASSWORD = '$env:DB_PASSWORD'" | sqlcmd -S "(localdb)\MSSQLLocalDB" + $sqlPassword = $env:DB_PASSWORD.Replace("'", "''") + "CREATE LOGIN testuser WITH PASSWORD = '$sqlPassword'" | sqlcmd -S "(localdb)\MSSQLLocalDB" -b -x + if ($LASTEXITCODE -ne 0) { throw "Failed to create the testuser login" } sqlcmd -S "(localdb)\MSSQLLocalDB" -d TestDB -Q "CREATE USER testuser FOR LOGIN testuser" sqlcmd -S "(localdb)\MSSQLLocalDB" -d TestDB -Q "ALTER ROLE db_owner ADD MEMBER testuser" displayName: 'Setup database and user' diff --git a/OneBranchPipelines/stress-test-pipeline.yml b/OneBranchPipelines/stress-test-pipeline.yml index d0f753f87..4eb3f0354 100644 --- a/OneBranchPipelines/stress-test-pipeline.yml +++ b/OneBranchPipelines/stress-test-pipeline.yml @@ -103,7 +103,9 @@ jobs: - powershell: | Write-Host "Creating database and user for stress tests..." sqlcmd -S "(localdb)\MSSQLLocalDB" -Q "CREATE DATABASE StressTestDB" - "CREATE LOGIN testuser WITH PASSWORD = '$env:DB_PASSWORD'" | sqlcmd -S "(localdb)\MSSQLLocalDB" + $sqlPassword = $env:DB_PASSWORD.Replace("'", "''") + "CREATE LOGIN testuser WITH PASSWORD = '$sqlPassword'" | sqlcmd -S "(localdb)\MSSQLLocalDB" -b -x + if ($LASTEXITCODE -ne 0) { throw "Failed to create the testuser login" } sqlcmd -S "(localdb)\MSSQLLocalDB" -d StressTestDB -Q "CREATE USER testuser FOR LOGIN testuser" sqlcmd -S "(localdb)\MSSQLLocalDB" -d StressTestDB -Q "ALTER ROLE db_owner ADD MEMBER testuser" Write-Host "Database setup completed" @@ -285,8 +287,9 @@ jobs: echo "Creating database and user for stress tests..." docker exec -e SQLCMDPASSWORD sqlserver-stress /opt/mssql-tools18/bin/sqlcmd \ -S localhost -U SA -C -Q "CREATE DATABASE StressTestDB" - printf "CREATE LOGIN testuser WITH PASSWORD = '%s'\n" "$DB_PASSWORD" | \ - docker exec -i -e SQLCMDPASSWORD sqlserver-stress /opt/mssql-tools18/bin/sqlcmd -S localhost -U SA -C + SQL_PASSWORD=${DB_PASSWORD//\'/\'\'} + printf "CREATE LOGIN testuser WITH PASSWORD = '%s'\n" "$SQL_PASSWORD" | \ + docker exec -i -e SQLCMDPASSWORD sqlserver-stress /opt/mssql-tools18/bin/sqlcmd -S localhost -U SA -C -b -x docker exec -e SQLCMDPASSWORD sqlserver-stress /opt/mssql-tools18/bin/sqlcmd \ -S localhost -U SA -C -d StressTestDB -Q "CREATE USER testuser FOR LOGIN testuser" docker exec -e SQLCMDPASSWORD sqlserver-stress /opt/mssql-tools18/bin/sqlcmd \ diff --git a/eng/pipelines/pr-validation-pipeline.yml b/eng/pipelines/pr-validation-pipeline.yml index 8c140b1b7..e75c46845 100644 --- a/eng/pipelines/pr-validation-pipeline.yml +++ b/eng/pipelines/pr-validation-pipeline.yml @@ -85,7 +85,9 @@ jobs: # Create database and user for LocalDB - powershell: | sqlcmd -S "(localdb)\MSSQLLocalDB" -Q "CREATE DATABASE TestDB" - "CREATE LOGIN testuser WITH PASSWORD = '$env:DB_PASSWORD'" | sqlcmd -S "(localdb)\MSSQLLocalDB" + $sqlPassword = $env:DB_PASSWORD.Replace("'", "''") + "CREATE LOGIN testuser WITH PASSWORD = '$sqlPassword'" | sqlcmd -S "(localdb)\MSSQLLocalDB" -b -x + if ($LASTEXITCODE -ne 0) { throw "Failed to create the testuser login" } sqlcmd -S "(localdb)\MSSQLLocalDB" -d TestDB -Q "CREATE USER testuser FOR LOGIN testuser" sqlcmd -S "(localdb)\MSSQLLocalDB" -d TestDB -Q "ALTER ROLE db_owner ADD MEMBER testuser" displayName: 'Setup database and user for LocalDB' @@ -173,7 +175,9 @@ jobs: # Create database and user sqlcmd -S "localhost" -U "sa" -Q "CREATE DATABASE TestDB" -C - "CREATE LOGIN testuser WITH PASSWORD = '$env:DB_PASSWORD'" | sqlcmd -S "localhost" -U "sa" -C + $sqlPassword = $env:DB_PASSWORD.Replace("'", "''") + "CREATE LOGIN testuser WITH PASSWORD = '$sqlPassword'" | sqlcmd -S "localhost" -U "sa" -C -b -x + if ($LASTEXITCODE -ne 0) { throw "Failed to create the testuser login" } sqlcmd -S "localhost" -U "sa" -d TestDB -Q "CREATE USER testuser FOR LOGIN testuser" -C sqlcmd -S "localhost" -U "sa" -d TestDB -Q "ALTER ROLE db_owner ADD MEMBER testuser" -C displayName: 'Setup database and user for SQL Server 2022' @@ -261,7 +265,9 @@ jobs: # Create database and user sqlcmd -S "localhost" -U "sa" -Q "CREATE DATABASE TestDB" -C - "CREATE LOGIN testuser WITH PASSWORD = '$env:DB_PASSWORD'" | sqlcmd -S "localhost" -U "sa" -C + $sqlPassword = $env:DB_PASSWORD.Replace("'", "''") + "CREATE LOGIN testuser WITH PASSWORD = '$sqlPassword'" | sqlcmd -S "localhost" -U "sa" -C -b -x + if ($LASTEXITCODE -ne 0) { throw "Failed to create the testuser login" } sqlcmd -S "localhost" -U "sa" -d TestDB -Q "CREATE USER testuser FOR LOGIN testuser" -C sqlcmd -S "localhost" -U "sa" -d TestDB -Q "ALTER ROLE db_owner ADD MEMBER testuser" -C displayName: 'Setup database and user for SQL Server 2025' From 1bd4d3e06587b08afe815d6184373fef34479d95 Mon Sep 17 00:00:00 2001 From: gargsaumya Date: Fri, 4 Sep 2026 23:03:31 +0530 Subject: [PATCH 5/5] FIX: Write login SQL through redirected stdin Windows PowerShell 5.1 does not reliably pipe the generated SQL text to native sqlcmd. Start sqlcmd directly and write to its redirected standard input so the password stays off the command line and the login statement is encoded correctly. --- .../stages/build-windows-single-stage.yml | 12 +++++-- OneBranchPipelines/stress-test-pipeline.yml | 12 +++++-- eng/pipelines/pr-validation-pipeline.yml | 36 +++++++++++++++---- 3 files changed, 50 insertions(+), 10 deletions(-) diff --git a/OneBranchPipelines/stages/build-windows-single-stage.yml b/OneBranchPipelines/stages/build-windows-single-stage.yml index e8ef01e2e..e2e7a3cf8 100644 --- a/OneBranchPipelines/stages/build-windows-single-stage.yml +++ b/OneBranchPipelines/stages/build-windows-single-stage.yml @@ -170,8 +170,16 @@ stages: - powershell: | sqlcmd -S "(localdb)\MSSQLLocalDB" -Q "CREATE DATABASE TestDB" $sqlPassword = $env:DB_PASSWORD.Replace("'", "''") - "CREATE LOGIN testuser WITH PASSWORD = '$sqlPassword'" | sqlcmd -S "(localdb)\MSSQLLocalDB" -b -x - if ($LASTEXITCODE -ne 0) { throw "Failed to create the testuser login" } + $startInfo = New-Object System.Diagnostics.ProcessStartInfo + $startInfo.FileName = (Get-Command sqlcmd.exe).Source + $startInfo.Arguments = '-S "(localdb)\MSSQLLocalDB" -b -x' + $startInfo.UseShellExecute = $false + $startInfo.RedirectStandardInput = $true + $process = [System.Diagnostics.Process]::Start($startInfo) + $process.StandardInput.WriteLine("CREATE LOGIN testuser WITH PASSWORD = '$sqlPassword'") + $process.StandardInput.Close() + $process.WaitForExit() + if ($process.ExitCode -ne 0) { throw "Failed to create the testuser login" } sqlcmd -S "(localdb)\MSSQLLocalDB" -d TestDB -Q "CREATE USER testuser FOR LOGIN testuser" sqlcmd -S "(localdb)\MSSQLLocalDB" -d TestDB -Q "ALTER ROLE db_owner ADD MEMBER testuser" displayName: 'Setup database and user' diff --git a/OneBranchPipelines/stress-test-pipeline.yml b/OneBranchPipelines/stress-test-pipeline.yml index 4eb3f0354..53d116f89 100644 --- a/OneBranchPipelines/stress-test-pipeline.yml +++ b/OneBranchPipelines/stress-test-pipeline.yml @@ -104,8 +104,16 @@ jobs: Write-Host "Creating database and user for stress tests..." sqlcmd -S "(localdb)\MSSQLLocalDB" -Q "CREATE DATABASE StressTestDB" $sqlPassword = $env:DB_PASSWORD.Replace("'", "''") - "CREATE LOGIN testuser WITH PASSWORD = '$sqlPassword'" | sqlcmd -S "(localdb)\MSSQLLocalDB" -b -x - if ($LASTEXITCODE -ne 0) { throw "Failed to create the testuser login" } + $startInfo = New-Object System.Diagnostics.ProcessStartInfo + $startInfo.FileName = (Get-Command sqlcmd.exe).Source + $startInfo.Arguments = '-S "(localdb)\MSSQLLocalDB" -b -x' + $startInfo.UseShellExecute = $false + $startInfo.RedirectStandardInput = $true + $process = [System.Diagnostics.Process]::Start($startInfo) + $process.StandardInput.WriteLine("CREATE LOGIN testuser WITH PASSWORD = '$sqlPassword'") + $process.StandardInput.Close() + $process.WaitForExit() + if ($process.ExitCode -ne 0) { throw "Failed to create the testuser login" } sqlcmd -S "(localdb)\MSSQLLocalDB" -d StressTestDB -Q "CREATE USER testuser FOR LOGIN testuser" sqlcmd -S "(localdb)\MSSQLLocalDB" -d StressTestDB -Q "ALTER ROLE db_owner ADD MEMBER testuser" Write-Host "Database setup completed" diff --git a/eng/pipelines/pr-validation-pipeline.yml b/eng/pipelines/pr-validation-pipeline.yml index e75c46845..bd8c8d0ed 100644 --- a/eng/pipelines/pr-validation-pipeline.yml +++ b/eng/pipelines/pr-validation-pipeline.yml @@ -86,8 +86,16 @@ jobs: - powershell: | sqlcmd -S "(localdb)\MSSQLLocalDB" -Q "CREATE DATABASE TestDB" $sqlPassword = $env:DB_PASSWORD.Replace("'", "''") - "CREATE LOGIN testuser WITH PASSWORD = '$sqlPassword'" | sqlcmd -S "(localdb)\MSSQLLocalDB" -b -x - if ($LASTEXITCODE -ne 0) { throw "Failed to create the testuser login" } + $startInfo = New-Object System.Diagnostics.ProcessStartInfo + $startInfo.FileName = (Get-Command sqlcmd.exe).Source + $startInfo.Arguments = '-S "(localdb)\MSSQLLocalDB" -b -x' + $startInfo.UseShellExecute = $false + $startInfo.RedirectStandardInput = $true + $process = [System.Diagnostics.Process]::Start($startInfo) + $process.StandardInput.WriteLine("CREATE LOGIN testuser WITH PASSWORD = '$sqlPassword'") + $process.StandardInput.Close() + $process.WaitForExit() + if ($process.ExitCode -ne 0) { throw "Failed to create the testuser login" } sqlcmd -S "(localdb)\MSSQLLocalDB" -d TestDB -Q "CREATE USER testuser FOR LOGIN testuser" sqlcmd -S "(localdb)\MSSQLLocalDB" -d TestDB -Q "ALTER ROLE db_owner ADD MEMBER testuser" displayName: 'Setup database and user for LocalDB' @@ -176,8 +184,16 @@ jobs: # Create database and user sqlcmd -S "localhost" -U "sa" -Q "CREATE DATABASE TestDB" -C $sqlPassword = $env:DB_PASSWORD.Replace("'", "''") - "CREATE LOGIN testuser WITH PASSWORD = '$sqlPassword'" | sqlcmd -S "localhost" -U "sa" -C -b -x - if ($LASTEXITCODE -ne 0) { throw "Failed to create the testuser login" } + $startInfo = New-Object System.Diagnostics.ProcessStartInfo + $startInfo.FileName = (Get-Command sqlcmd.exe).Source + $startInfo.Arguments = '-S localhost -U sa -C -b -x' + $startInfo.UseShellExecute = $false + $startInfo.RedirectStandardInput = $true + $process = [System.Diagnostics.Process]::Start($startInfo) + $process.StandardInput.WriteLine("CREATE LOGIN testuser WITH PASSWORD = '$sqlPassword'") + $process.StandardInput.Close() + $process.WaitForExit() + if ($process.ExitCode -ne 0) { throw "Failed to create the testuser login" } sqlcmd -S "localhost" -U "sa" -d TestDB -Q "CREATE USER testuser FOR LOGIN testuser" -C sqlcmd -S "localhost" -U "sa" -d TestDB -Q "ALTER ROLE db_owner ADD MEMBER testuser" -C displayName: 'Setup database and user for SQL Server 2022' @@ -266,8 +282,16 @@ jobs: # Create database and user sqlcmd -S "localhost" -U "sa" -Q "CREATE DATABASE TestDB" -C $sqlPassword = $env:DB_PASSWORD.Replace("'", "''") - "CREATE LOGIN testuser WITH PASSWORD = '$sqlPassword'" | sqlcmd -S "localhost" -U "sa" -C -b -x - if ($LASTEXITCODE -ne 0) { throw "Failed to create the testuser login" } + $startInfo = New-Object System.Diagnostics.ProcessStartInfo + $startInfo.FileName = (Get-Command sqlcmd.exe).Source + $startInfo.Arguments = '-S localhost -U sa -C -b -x' + $startInfo.UseShellExecute = $false + $startInfo.RedirectStandardInput = $true + $process = [System.Diagnostics.Process]::Start($startInfo) + $process.StandardInput.WriteLine("CREATE LOGIN testuser WITH PASSWORD = '$sqlPassword'") + $process.StandardInput.Close() + $process.WaitForExit() + if ($process.ExitCode -ne 0) { throw "Failed to create the testuser login" } sqlcmd -S "localhost" -U "sa" -d TestDB -Q "CREATE USER testuser FOR LOGIN testuser" -C sqlcmd -S "localhost" -U "sa" -d TestDB -Q "ALTER ROLE db_owner ADD MEMBER testuser" -C displayName: 'Setup database and user for SQL Server 2025'