diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index e9eb6b30..8263484b 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -21,8 +21,8 @@ on: - cron: '37 9 * * 2' env: - DOTNET_VERSION: 'net7.0' - DOTNET_FRAMEWORK_VERSION: '7.x' + DOTNET_VERSION: 'net8.0' + DOTNET_FRAMEWORK_VERSION: '8.x' jobs: analyze: diff --git a/.github/workflows/container-build.yml b/.github/workflows/container-build.yml index fb8791f1..cb5fe37b 100644 --- a/.github/workflows/container-build.yml +++ b/.github/workflows/container-build.yml @@ -39,6 +39,7 @@ jobs: context: "{{defaultContext}}:src" platforms: linux/amd64,linux/arm64 push: true + provenance: false tags: | ghcr.io/${{ github.repository_owner }}/sqlbuildmanager:${{ steps.date.outputs.date }} ghcr.io/${{ github.repository_owner }}/sqlbuildmanager:latest-vNext diff --git a/.github/workflows/dotnetcore-build.yml b/.github/workflows/dotnetcore-build.yml index ff6634ac..e4a6f256 100644 --- a/.github/workflows/dotnetcore-build.yml +++ b/.github/workflows/dotnetcore-build.yml @@ -10,8 +10,8 @@ on: - master env: - DOTNET_VERSION: 'net7.0' - DOTNET_FRAMEWORK_VERSION: '7.x' + DOTNET_VERSION: 'net8.0' + DOTNET_FRAMEWORK_VERSION: '8.x' jobs: build: diff --git a/CHANGELOG.md b/CHANGELOG.md index 903a41d5..71fa7492 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # SQL Build Manager Change Log +### Version 15.6.0 +- *UPDATED:* Now targets .NET 8.0 +- *UPDATED:* Simplified data object classes and regenerated typed DataSet classes +- *UPDATED:* Docker base set to .NET Runtime 8.0 and .NET SDK to 8.0 +- *REMOVED:* Removed fall back Settings File Key generation from machine value. Now must be provided via `--settingsfilekey` argument or `sbm-settingsfilekey` Environment variable +- *ADDED:* `--settingsfilekey` is no longer required when a Key Vault Name is provided. This will bypass any settings file decryption and only retrieve the secrets directly from Key Vault + ### Version 15.5.0 - *NEW:* For muti-database target builds, you can now specify custom concurrency tag. Previously, the only concurrency differentitor was by SQL Server Name. Please see the docs on [Concurrency](/docs/concurrency_options.md) and [Database targeting options](docs/override_options.md) to understand how to use this new feature. - *UPDATED:* DACPAC creation timeouts now set to the value of `--defaultscripttimeout`. Previously, it was using the default settings. diff --git a/scripts/templates/-mi.json b/scripts/templates/-mi.json new file mode 100644 index 00000000..9d1ce948 --- /dev/null +++ b/scripts/templates/-mi.json @@ -0,0 +1,42 @@ +{ + "AuthenticationArgs": { + "AuthenticationType": "Password" + }, + "ConnectionArgs": { + "KeyVaultName": "sbm235keyvault", + "ServiceBusTopicConnectionString": "0WzwQWxjx4WQa5rJTbSb/kPl0YBdfitD73Q1lt/4rX065uiufICp5kSzwrMGSahu139FfgGpCmxpJPDRporxKACd\u002BiaCtwFSmIOAIgcBwfMgC38eoXI/qp2Y9uHG51b97UgdJ9gQXUduMFiAsEh8vxwaije1ZpBFuqNcCu66XOcviiIAq233GFP6UkL89o394LJQqCcsX22QMLEdQOTwXUMYBq5Hz7/46dHhuyaryKIusN3gtrETZiyHrmjF2kLx", + "StorageAccountName": "sbm235storage" + }, + "ContainerAppArgs": { + "EnvironmentName": "sbm235containerappenv", + "SubscriptionId": "0d901325-d643-4db7-ae90-58b4e3834629", + "ResourceGroup": "sbm235-rg", + "Location": "South Central US", + "MaxContainerCount": 10 + }, + "ContainerRegistryArgs": { + "RegistryServer": "sbm235containerregistry.azurecr.io", + "ImageName": "sqlbuildmanager", + "ImageTag": "latest-vNext", + "RegistryUserName": "sbm235containerregistry" + }, + "EventHubArgs": { + "ResourceGroup": "sbm235-rg", + "SubscriptionId": "0d901325-d643-4db7-ae90-58b4e3834629", + "Logging": [ + "EssentialOnly", + "ScriptErrors" + ] + }, + "IdentityArgs": { + "IdentityName": "sbm235identity", + "ClientId": "837e7b19-7a0c-4820-9df6-7b6913e4380a", + "ResourceGroup": "sbm235-rg", + "SubscriptionId": "0d901325-d643-4db7-ae90-58b4e3834629", + "TenantId": "16b3c013-d300-468d-ac64-7eda0820b6d3" + }, + "Concurrency": 10, + "ConcurrencyType": "Count", + "TimeoutRetryCount": 0, + "DefaultScriptTimeout": 500 +} \ No newline at end of file diff --git a/scripts/templates/.json b/scripts/templates/.json new file mode 100644 index 00000000..53df4d7b --- /dev/null +++ b/scripts/templates/.json @@ -0,0 +1,39 @@ +{ + "AuthenticationArgs": { + "AuthenticationType": "Password" + }, + "ConnectionArgs": { + "KeyVaultName": "sbm235keyvault", + "ServiceBusTopicConnectionString": "0WzwQWxjx4WQa5rJTbSb/kPl0YBdfitD73Q1lt/4rX065uiufICp5kSzwrMGSahu139FfgGpCmxpJPDRporxKACd\u002BiaCtwFSmIOAIgcBwfMgC38eoXI/qp2Y9uHG51b97UgdJ9gQXUduMFiAsEh8vxwaije1ZpBFuqNcCu66XOcviiIAq233GFP6UkL89o394LJQqCcsX22QMLEdQOTwXUMYBq5Hz7/46dHhuyaryKIusN3gtrETZiyHrmjF2kLx", + "StorageAccountName": "sbm235storage" + }, + "ContainerAppArgs": { + "EnvironmentName": "sbm235containerappenv", + "SubscriptionId": "0d901325-d643-4db7-ae90-58b4e3834629", + "ResourceGroup": "sbm235-rg", + "Location": "South Central US", + "MaxContainerCount": 10 + }, + "ContainerRegistryArgs": { + "RegistryServer": "sbm235containerregistry.azurecr.io", + "ImageName": "sqlbuildmanager", + "ImageTag": "latest-vNext", + "RegistryUserName": "sbm235containerregistry" + }, + "EventHubArgs": { + "ResourceGroup": "sbm235-rg", + "SubscriptionId": "0d901325-d643-4db7-ae90-58b4e3834629", + "Logging": [ + "EssentialOnly", + "ScriptErrors" + ] + }, + "IdentityArgs": { + "SubscriptionId": "0d901325-d643-4db7-ae90-58b4e3834629", + "TenantId": "16b3c013-d300-468d-ac64-7eda0820b6d3" + }, + "Concurrency": 10, + "ConcurrencyType": "Count", + "TimeoutRetryCount": 0, + "DefaultScriptTimeout": 500 +} \ No newline at end of file diff --git a/scripts/templates/Batch/build_and_upload_batch.ps1 b/scripts/templates/Batch/build_and_upload_batch.ps1 index 274cb869..3cddf689 100644 --- a/scripts/templates/Batch/build_and_upload_batch.ps1 +++ b/scripts/templates/Batch/build_and_upload_batch.ps1 @@ -15,7 +15,7 @@ $frameworkTarget = Invoke-Expression -Command (Join-Path $scriptDir ..\get_targe Write-Host "Target Framework: $frameworkTarget" -ForegroundColor DarkGreen -Write-Output "Using Batch Account: $batchAcctName" -ForegroundColor DarkGreen +Write-Host "Using Batch Account: $batchAcctName" -ForegroundColor DarkGreen $winenv =@{ ApplicationName = "SqlBuildManagerWindows" diff --git a/scripts/templates/Modules/database.bicep b/scripts/templates/Modules/database.bicep index 918f64b7..3c4693ce 100644 --- a/scripts/templates/Modules/database.bicep +++ b/scripts/templates/Modules/database.bicep @@ -47,7 +47,7 @@ module identityResource 'identity.bicep' = { // SQL Server 'A' resources -resource sqlserverAResource 'Microsoft.Sql/servers@2021-02-01-preview' = { +resource sqlserverAResource 'Microsoft.Sql/servers@2021-11-01' = { name: '${sqlserverNameVar}-a' location: location @@ -67,7 +67,7 @@ resource sqlserverAResource 'Microsoft.Sql/servers@2021-02-01-preview' = { } } -resource sqlserverAFirewallRule 'Microsoft.Sql/servers/firewallRules@2021-02-01-preview' = if(currentIpAddress != '') { +resource sqlserverAFirewallRule 'Microsoft.Sql/servers/firewallRules@2021-11-01' = if(currentIpAddress != '') { parent: sqlserverAResource name: '${sqlserverNameVar}A_AllowIp' properties: { @@ -76,7 +76,7 @@ resource sqlserverAFirewallRule 'Microsoft.Sql/servers/firewallRules@2021-02-01- } } -resource sqlserverA_VnetRule 'Microsoft.Sql/servers/virtualNetworkRules@2022-11-01-preview' = [for subnet in subnetNamesArray:{ +resource sqlserverA_VnetRule 'Microsoft.Sql/servers/virtualNetworkRules@2021-11-01' = [for subnet in subnetNamesArray:{ parent: sqlserverAResource name: '${sqlserverNameVar}A_${subnet}' properties: { @@ -86,7 +86,7 @@ resource sqlserverA_VnetRule 'Microsoft.Sql/servers/virtualNetworkRules@2022-11- } }] -resource sqlserverAResource_Pool 'Microsoft.Sql/servers/elasticPools@2021-02-01-preview' = { +resource sqlserverAResource_Pool 'Microsoft.Sql/servers/elasticPools@2021-11-01' = { parent: sqlserverAResource name: '${sqlpoolNameVar}-a' location: location @@ -105,7 +105,7 @@ resource sqlserverAResource_Pool 'Microsoft.Sql/servers/elasticPools@2021-02-01- } } -resource sqlserverAResourceDatabase 'Microsoft.Sql/servers/databases@2021-02-01-preview' = [for i in range(1,testDbCountPerServer):{ +resource sqlserverAResourceDatabase 'Microsoft.Sql/servers/databases@2021-11-01' = [for i in range(1,testDbCountPerServer):{ parent: sqlserverAResource name: 'SqlBuildTest${i}' location: location @@ -128,7 +128,7 @@ resource sqlserverAResourceDatabase 'Microsoft.Sql/servers/databases@2021-02-01- // SQL Server 'B' resources -resource sqlserverBResource 'Microsoft.Sql/servers@2021-02-01-preview' = { +resource sqlserverBResource 'Microsoft.Sql/servers@2021-11-01' = { name: '${sqlserverNameVar}-b' location: location properties: { @@ -145,7 +145,7 @@ resource sqlserverBResource 'Microsoft.Sql/servers@2021-02-01-preview' = { } } } -resource sqlserverBFirewallRule 'Microsoft.Sql/servers/firewallRules@2021-02-01-preview' = if(currentIpAddress != '') { +resource sqlserverBFirewallRule 'Microsoft.Sql/servers/firewallRules@2021-11-01' = if(currentIpAddress != '') { parent: sqlserverBResource name: '${sqlserverNameVar}B_AllowIp' properties: { @@ -154,7 +154,7 @@ resource sqlserverBFirewallRule 'Microsoft.Sql/servers/firewallRules@2021-02-01- } } -resource sqlserverB_VnetRule 'Microsoft.Sql/servers/virtualNetworkRules@2022-11-01-preview' = [for subnet in subnetNamesArray:{ +resource sqlserverB_VnetRule 'Microsoft.Sql/servers/virtualNetworkRules@2021-11-01' = [for subnet in subnetNamesArray:{ parent: sqlserverBResource name: '${sqlserverNameVar}B_${subnet}' properties: { @@ -164,7 +164,7 @@ resource sqlserverB_VnetRule 'Microsoft.Sql/servers/virtualNetworkRules@2022-11- } }] -resource sqlserverBResource_Pool 'Microsoft.Sql/servers/elasticPools@2021-02-01-preview' = { +resource sqlserverBResource_Pool 'Microsoft.Sql/servers/elasticPools@2021-11-01' = { parent: sqlserverBResource name: '${sqlpoolNameVar}-b' location: location @@ -183,7 +183,7 @@ resource sqlserverBResource_Pool 'Microsoft.Sql/servers/elasticPools@2021-02-01- } } -resource sqlserverBResource_Database 'Microsoft.Sql/servers/databases@2021-02-01-preview' = [for i in range(1,testDbCountPerServer):{ +resource sqlserverBResource_Database 'Microsoft.Sql/servers/databases@2021-11-01' = [for i in range(1,testDbCountPerServer):{ parent: sqlserverBResource name: 'SqlBuildTest${i}' location: location diff --git a/scripts/templates/create_azure_resources.ps1 b/scripts/templates/create_azure_resources.ps1 index b8d988f6..51e16da5 100644 --- a/scripts/templates/create_azure_resources.ps1 +++ b/scripts/templates/create_azure_resources.ps1 @@ -116,7 +116,7 @@ if($shouldDeploy) ############################################################################################ # Storage Account, Event Hub and Service Bus Topic, Key Vault, Identity and RBAC Assignments ############################################################################################ - $ipAddress = (Invoke-WebRequest ifconfig.me/ip).Content.Trim() + $ipAddress = (Invoke-WebRequest https://api.ipify.org/?format=text).Content.Trim() Write-Host "Using IP Address: $ipAddress" -ForegroundColor Green $userIdGuid = az ad signed-in-user show -o tsv --query id diff --git a/scripts/templates/key_file_names.ps1 b/scripts/templates/key_file_names.ps1 index 791da14b..c519afbc 100644 --- a/scripts/templates/key_file_names.ps1 +++ b/scripts/templates/key_file_names.ps1 @@ -8,8 +8,9 @@ if($false -eq (Test-Path $path)) { New-Item -Path $path -ItemType Directory } +$resolvedPath = Resolve-Path $path -$keyFile = Resolve-Path (Join-Path $path "settingsfilekey.txt") +$keyFile = (Join-Path $resolvedPath "settingsfilekey.txt") if($false -eq (Test-Path $keyFile)) { Write-Host "Writing new key file $keyFile" -ForegroundColor DarkGreen @@ -19,8 +20,8 @@ if($false -eq (Test-Path $keyFile)) $settingsFileKey | Set-Content -Path $keyFile } -$unFile = Resolve-Path (Join-Path $path "un.txt") -$pwFile = Resolve-Path (Join-Path $path "pw.txt") +$unFile = (Join-Path $resolvedPath "un.txt") +$pwFile = (Join-Path $resolvedPath "pw.txt") if(Test-Path $unFile) { @@ -48,6 +49,11 @@ if([string]::IsNullOrWhiteSpace($sqlUserName)) if([string]::IsNullOrWhiteSpace($sqlPassword)) { + Write-Host "Generating new SQL Password" -ForegroundColor DarkGreen + $AESKey = New-Object Byte[] 32 + [Security.Cryptography.RNGCryptoServiceProvider]::Create().GetBytes($AESKey) + $sqlPassword = [System.Convert]::ToBase64String($AESKey); + Write-Host "Writing new password file" -ForegroundColor DarkGreen Write-Host "Saving content of $pwFile" -ForegroundColor DarkGreen $sqlPassword | Set-Content -Path $pwFile diff --git a/src/AssemblyVersioning.cs b/src/AssemblyVersioning.cs index 615c1a80..286ad276 100644 --- a/src/AssemblyVersioning.cs +++ b/src/AssemblyVersioning.cs @@ -24,5 +24,5 @@ // 2) Update the installer version to match the AssemblyVersion below. // These can be found in SqlBuildManager.Setup -> Organize Your Setup -> General Information -[assembly: AssemblyVersion("15.5.1")] -[assembly: AssemblyFileVersion("15.5.1")] +[assembly: AssemblyVersion("15.6.0")] +[assembly: AssemblyFileVersion("15.6.0")] diff --git a/src/Dockerfile b/src/Dockerfile index 20f49d91..2a618d0e 100644 --- a/src/Dockerfile +++ b/src/Dockerfile @@ -1,9 +1,9 @@ #See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging. -FROM mcr.microsoft.com/dotnet/runtime:7.0 AS base +FROM mcr.microsoft.com/dotnet/runtime:8.0 AS base WORKDIR /app -FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build +FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build WORKDIR /src @@ -30,16 +30,16 @@ COPY ["SqlSync.SqlBuild/SqlSync.SqlBuild.csproj", "SqlSync.SqlBuild/SqlSync.SqlB RUN true COPY ["SqlBuildManager.ScriptHandling/SqlBuildManager.ScriptHandling.csproj", "SqlBuildManager.ScriptHandling/"] -RUN true -RUN dotnet restore "SqlBuildManager.Console/sbm.csproj" +#RUN true +#RUN dotnet restore "SqlBuildManager.Console/sbm.csproj" COPY . . WORKDIR "/src/SqlBuildManager.Console" -RUN dotnet build "sbm.csproj" --configuration Release -f net7.0 -o /app/build -r linux-x64 --self-contained +#RUN dotnet build "sbm.csproj" --configuration Release -f net8.0 -o /app/build -r linux-x64 --self-contained FROM build AS publish -RUN dotnet publish "sbm.csproj" --configuration Release -f net7.0 -o /app/publish -r linux-x64 --self-contained +RUN dotnet publish "sbm.csproj" --configuration Release -f net8.0 -o /app/publish -r linux-x64 --self-contained FROM base AS final WORKDIR /app diff --git a/src/SqlBuildManager.Console.Dependent.UnitTest/SqlBuildManager.Console.Dependent.UnitTest.csproj b/src/SqlBuildManager.Console.Dependent.UnitTest/SqlBuildManager.Console.Dependent.UnitTest.csproj index 34b69114..8ff050ef 100644 --- a/src/SqlBuildManager.Console.Dependent.UnitTest/SqlBuildManager.Console.Dependent.UnitTest.csproj +++ b/src/SqlBuildManager.Console.Dependent.UnitTest/SqlBuildManager.Console.Dependent.UnitTest.csproj @@ -1,6 +1,6 @@  - net7.0 + net8.0 false false false @@ -60,9 +60,9 @@ - + - + diff --git a/src/SqlBuildManager.Console.ExternalTest/BatchTests.cs b/src/SqlBuildManager.Console.ExternalTest/BatchTests.cs index e8c55bec..d5381301 100644 --- a/src/SqlBuildManager.Console.ExternalTest/BatchTests.cs +++ b/src/SqlBuildManager.Console.ExternalTest/BatchTests.cs @@ -1964,5 +1964,60 @@ public async Task CreateBatchPool_Success(string settingsFile, string settingsFi } } + + + [DataRow("run", "TestConfig/settingsfile-batch-windows-queue-keyvault.json", ConcurrencyType.Tag, 2)] + [DataRow("run", "TestConfig/settingsfile-batch-linux-queue-keyvault.json", ConcurrencyType.Tag, 2)] + [DataRow("run", "TestConfig/settingsfile-batch-windows-queue-keyvault-mi.json", ConcurrencyType.Tag, 2)] + [DataRow("run", "TestConfig/settingsfile-batch-linux-queue-keyvault-mi.json", ConcurrencyType.Tag, 2)] + [DataRow("runthreaded", "TestConfig/settingsfile-batch-windows-queue-keyvault.json", ConcurrencyType.MaxPerTag, 5)] + [DataTestMethod] + public void Batch_Queue_SBMSource_KeyVault_NoSettingsFileKey_Success(string batchMethod, string settingsFile, ConcurrencyType concurType, int concurrency) + { + settingsFile = Path.GetFullPath(settingsFile); + string sbmFileName = Path.GetFullPath("SimpleSelect.sbm"); + if (!File.Exists(sbmFileName)) + { + File.WriteAllBytes(sbmFileName, Properties.Resources.SimpleSelect); + } + string jobName = GetUniqueBatchJobName("batch-sbm-tag"); + int startingLine = LogFileCurrentLineCount(); + + var args = new string[]{ + "batch", "enqueue", + "--settingsfile", settingsFile, + "--override" , overrideWithTagFilePath, + "--concurrencytype", concurType.ToString(), + "--jobname", jobName}; + + RootCommand rootCommand = CommandLineBuilder.SetUp(); + Task val = rootCommand.InvokeAsync(args); + val.Wait(); + var result = val.Result; + + var logFileContents = ReleventLogFileContents(startingLine); + Assert.AreEqual(0, result, StandardExecutionErrorMessage(logFileContents)); + + args = new string[]{ + "--loglevel", "debug", + "batch", batchMethod, + "--settingsfile", settingsFile, + "--override", overrideWithTagFilePath, + "--packagename", sbmFileName, + "--concurrencytype", concurType.ToString(), + "--concurrency", concurrency.ToString(), + "--jobname", jobName, + "--unittest", + "--monitor", + "--stream" }; + + + val = rootCommand.InvokeAsync(args); + val.Wait(); + result = val.Result; + + logFileContents = ReleventLogFileContents(startingLine); + Assert.AreEqual(0, result, StandardExecutionErrorMessage(logFileContents)); + } } } diff --git a/src/SqlBuildManager.Console.ExternalTest/SqlBuildManager.Console.ExternalTest.csproj b/src/SqlBuildManager.Console.ExternalTest/SqlBuildManager.Console.ExternalTest.csproj index 30c5c744..6a6c44ae 100644 --- a/src/SqlBuildManager.Console.ExternalTest/SqlBuildManager.Console.ExternalTest.csproj +++ b/src/SqlBuildManager.Console.ExternalTest/SqlBuildManager.Console.ExternalTest.csproj @@ -1,14 +1,14 @@  - net7.0 + net8.0 false 1701;1702;NU1608 - - + + diff --git a/src/SqlBuildManager.Console.UnitTest/CommandLineArgsTest.cs b/src/SqlBuildManager.Console.UnitTest/CommandLineArgsTest.cs index ac198002..a9210188 100644 --- a/src/SqlBuildManager.Console.UnitTest/CommandLineArgsTest.cs +++ b/src/SqlBuildManager.Console.UnitTest/CommandLineArgsTest.cs @@ -57,6 +57,161 @@ public void Duplicate_ArgumentCheck_Test() } } } - + + [TestMethod] + public void WorkerInit_success_with_keyfile() + { + var tmpJsonFile = Path.GetTempFileName(); + var tmpSecretFile = Path.GetTempFileName(); + try + { + + File.WriteAllBytes(tmpJsonFile, Properties.Resources.batch_settings_encrypted); + File.WriteAllText(tmpSecretFile, Properties.Resources.settingsfilekey); + var cmdLine = new CommandLineArgs(); + cmdLine.SettingsFileKey = tmpSecretFile; + cmdLine.SettingsFile = tmpJsonFile; + (bool success, cmdLine) = Worker.Init(cmdLine, false); + + Assert.IsTrue(success); + Assert.IsTrue(cmdLine.Decrypted); + Assert.IsTrue(cmdLine.AuthenticationArgs.Password.EndsWith("=")); + } + finally + { + if (File.Exists(tmpJsonFile)) + File.Delete(tmpJsonFile); + + if (File.Exists(tmpSecretFile)) + File.Delete(tmpSecretFile); + } + } + + [TestMethod] + public void WorkerInit_fail_with_bad_keyfile() + { + var tmpJsonFile = Path.GetTempFileName(); + var tmpSecretFile = Path.GetTempFileName(); + try + { + + File.WriteAllBytes(tmpJsonFile, Properties.Resources.batch_settings_encrypted); + File.WriteAllText(tmpSecretFile, "QDQE@Q!EQQEQD#EQ#DQ#DQ#D#DQ#DQ"); + var cmdLine = new CommandLineArgs(); + cmdLine.SettingsFileKey = tmpSecretFile; + cmdLine.SettingsFile = tmpJsonFile; + (bool success, cmdLine) = Worker.Init(cmdLine, false); + + Assert.IsFalse(success); + Assert.IsFalse(cmdLine.Decrypted); + } + finally + { + if (File.Exists(tmpJsonFile)) + File.Delete(tmpJsonFile); + + if (File.Exists(tmpSecretFile)) + File.Delete(tmpSecretFile); + } + + } + + [TestMethod] + public void WorkerInit_success_with_keystring() + { + var tmpJsonFile = Path.GetTempFileName(); + try + { + + File.WriteAllBytes(tmpJsonFile, Properties.Resources.batch_settings_encrypted); + var cmdLine = new CommandLineArgs(); + cmdLine.SettingsFileKey = Properties.Resources.settingsfilekey; + cmdLine.SettingsFile = tmpJsonFile; + (bool success, cmdLine) = Worker.Init(cmdLine, false); + + Assert.IsTrue(success); + Assert.IsTrue(cmdLine.Decrypted); + Assert.IsTrue(cmdLine.AuthenticationArgs.Password.EndsWith("=")); + } + finally + { + if (File.Exists(tmpJsonFile)) + File.Delete(tmpJsonFile); + } + + } + + [TestMethod] + public void WorkerInit_decrypt_success_and_keyvault_fail() + { + var tmpJsonFile = Path.GetTempFileName(); + try + { + + File.WriteAllBytes(tmpJsonFile, Properties.Resources.batch_settings_encrypted); + var cmdLine = new CommandLineArgs(); + cmdLine.SettingsFileKey = Properties.Resources.settingsfilekey; + cmdLine.SettingsFile = tmpJsonFile; + cmdLine.KeyVaultName = "doesnotexistawtgfs"; + (bool success, cmdLine) = Worker.Init(cmdLine, false); + + Assert.IsFalse(success); + Assert.IsTrue(cmdLine.Decrypted); + Assert.IsTrue(cmdLine.AuthenticationArgs.Password.EndsWith("=")); + } + finally + { + if (File.Exists(tmpJsonFile)) + File.Delete(tmpJsonFile); + } + + } + [TestMethod] + public void WorkerInit_fail_with_bad_keystring() + { + var tmpJsonFile = Path.GetTempFileName(); + try + { + + File.WriteAllBytes(tmpJsonFile, Properties.Resources.batch_settings_encrypted); + var cmdLine = new CommandLineArgs(); + cmdLine.SettingsFileKey = "XXXXX"; + cmdLine.SettingsFile = tmpJsonFile; + (bool success, cmdLine) = Worker.Init(cmdLine, false); + Assert.IsFalse(success); + Assert.IsFalse(cmdLine.Decrypted); + } + finally + { + if (File.Exists(tmpJsonFile)) + File.Delete(tmpJsonFile); + } + + } + + [TestMethod] + public void WorkerInit_fail_with_missing_keystring() + { + var tmpJsonFile = Path.GetTempFileName(); + try + { + + File.WriteAllBytes(tmpJsonFile, Properties.Resources.batch_settings_encrypted); + var cmdLine = new CommandLineArgs(); + cmdLine.SettingsFile = tmpJsonFile; + (bool success, cmdLine) = Worker.Init(cmdLine, false); + + Assert.IsFalse(success); + Assert.IsFalse(cmdLine.Decrypted); + } + finally + { + if (File.Exists(tmpJsonFile)) + File.Delete(tmpJsonFile); + } + + } + + } } diff --git a/src/SqlBuildManager.Console.UnitTest/CommandLineParsingTest.cs b/src/SqlBuildManager.Console.UnitTest/CommandLineParsingTest.cs index 83594701..855930f6 100644 --- a/src/SqlBuildManager.Console.UnitTest/CommandLineParsingTest.cs +++ b/src/SqlBuildManager.Console.UnitTest/CommandLineParsingTest.cs @@ -54,7 +54,7 @@ public void SettingsFile_basic() public void SettingsFile_oldstyle_eventhublogging() { var tmpCfg = Path.GetTempPath() + Guid.NewGuid().ToString() + ".json"; - File.WriteAllBytes(tmpCfg, Properties.Resources.batch_setting_oldstyle_eventhublogging); + File.WriteAllBytes(tmpCfg, Properties.Resources.batch_settings_oldstyle_eventhublogging); try { string[] args = new string[] { diff --git a/src/SqlBuildManager.Console.UnitTest/Properties/Resources.Designer.cs b/src/SqlBuildManager.Console.UnitTest/Properties/Resources.Designer.cs index 7a1e1237..f2f0bd4c 100644 --- a/src/SqlBuildManager.Console.UnitTest/Properties/Resources.Designer.cs +++ b/src/SqlBuildManager.Console.UnitTest/Properties/Resources.Designer.cs @@ -19,7 +19,7 @@ namespace SqlBuildManager.Console.UnitTest.Properties { // class via a tool like ResGen or Visual Studio. // To add or remove a member, edit your .ResX file then rerun ResGen // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] internal class Resources { @@ -63,46 +63,49 @@ internal Resources() { /// /// Looks up a localized resource of type System.Byte[]. /// - internal static byte[] dbconfig { + internal static byte[] batch_settings { get { - object obj = ResourceManager.GetObject("dbconfig", resourceCulture); + object obj = ResourceManager.GetObject("batch-settings", resourceCulture); return ((byte[])(obj)); } } - - internal static byte[] concurrency - { - get - { - object obj = ResourceManager.GetObject("concurrency", resourceCulture); + + /// + /// Looks up a localized resource of type System.Byte[]. + /// + internal static byte[] batch_settings_encrypted { + get { + object obj = ResourceManager.GetObject("batch_settings_encrypted", resourceCulture); return ((byte[])(obj)); } } - - internal static byte[] concurrency_tag - { - get - { - object obj = ResourceManager.GetObject("concurrency_tag", resourceCulture); + + /// + /// Looks up a localized resource of type System.Byte[]. + /// + internal static byte[] batch_settings_multipleeh { + get { + object obj = ResourceManager.GetObject("batch_settings_multipleeh", resourceCulture); return ((byte[])(obj)); } } - - internal static byte[] concurrency_doubledb - { - get - { - object obj = ResourceManager.GetObject("concurrency_doubledb", resourceCulture); + + /// + /// Looks up a localized resource of type System.Byte[]. + /// + internal static byte[] batch_settings_multipleeh_oldstyle { + get { + object obj = ResourceManager.GetObject("batch_settings_multipleeh_oldstyle", resourceCulture); return ((byte[])(obj)); } } - + /// /// Looks up a localized resource of type System.Byte[]. /// - internal static byte[] InsertForThreadedTest { + internal static byte[] batch_settings_oldstyle_eventhublogging { get { - object obj = ResourceManager.GetObject("InsertForThreadedTest", resourceCulture); + object obj = ResourceManager.GetObject("batch-settings-oldstyle-eventhublogging", resourceCulture); return ((byte[])(obj)); } } @@ -110,50 +113,63 @@ internal static byte[] InsertForThreadedTest { /// /// Looks up a localized resource of type System.Byte[]. /// - internal static byte[] NoTrans_MultiDb_multidb { + internal static byte[] concurrency { get { - object obj = ResourceManager.GetObject("NoTrans_MultiDb_multidb", resourceCulture); + object obj = ResourceManager.GetObject("concurrency", resourceCulture); return ((byte[])(obj)); } } - - internal static byte[] batch_settings - { - get - { - object obj = ResourceManager.GetObject("batch-settings", resourceCulture); + + /// + /// Looks up a localized resource of type System.Byte[]. + /// + internal static byte[] concurrency_doubledb { + get { + object obj = ResourceManager.GetObject("concurrency_doubledb", resourceCulture); return ((byte[])(obj)); } } - - internal static byte[] batch_setting_oldstyle_eventhublogging - { - get - { - object obj = ResourceManager.GetObject("batch-settings-oldstyle-eventhublogging", resourceCulture); + + /// + /// Looks up a localized resource of type System.Byte[]. + /// + internal static byte[] concurrency_tag { + get { + object obj = ResourceManager.GetObject("concurrency_tag", resourceCulture); return ((byte[])(obj)); } } - - - - internal static byte[] batch_settings_multipleeh - { - get - { - object obj = ResourceManager.GetObject("batch_settings_multipleeh", resourceCulture); + + /// + /// Looks up a localized resource of type System.Byte[]. + /// + internal static byte[] dbconfig { + get { + object obj = ResourceManager.GetObject("dbconfig", resourceCulture); return ((byte[])(obj)); } } - - internal static byte[] batch_settings_multipleeh_oldstyle { - get - { - object obj = ResourceManager.GetObject("batch_settings_multipleeh_oldstyle", resourceCulture); + + /// + /// Looks up a localized resource of type System.Byte[]. + /// + internal static byte[] InsertForThreadedTest { + get { + object obj = ResourceManager.GetObject("InsertForThreadedTest", resourceCulture); return ((byte[])(obj)); } } - + + /// + /// Looks up a localized resource of type System.Byte[]. + /// + internal static byte[] NoTrans_MultiDb_multidb { + get { + object obj = ResourceManager.GetObject("NoTrans_MultiDb_multidb", resourceCulture); + return ((byte[])(obj)); + } + } + /// /// Looks up a localized resource of type System.Byte[]. /// @@ -164,6 +180,15 @@ internal static byte[] NoTrans_MultiDb_sbm { } } + /// + /// Looks up a localized string similar to jbsUw8PLkrBu6HAf/O9jJEDiDxFrTivdvvMkYiMvTqU=. + /// + internal static string settingsfilekey { + get { + return ResourceManager.GetString("settingsfilekey", resourceCulture); + } + } + /// /// Looks up a localized resource of type System.Byte[]. /// diff --git a/src/SqlBuildManager.Console.UnitTest/Properties/Resources.resx b/src/SqlBuildManager.Console.UnitTest/Properties/Resources.resx index 5aa3e3c0..ea1c6def 100644 --- a/src/SqlBuildManager.Console.UnitTest/Properties/Resources.resx +++ b/src/SqlBuildManager.Console.UnitTest/Properties/Resources.resx @@ -163,4 +163,10 @@ ..\Resources\concurrency_tag.cfg;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + ..\Resources\batch_settings_encrypted.json;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + ..\Resources\settingsfilekey.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 + \ No newline at end of file diff --git a/src/SqlBuildManager.Console.UnitTest/Resources/batch_settings_encrypted.json b/src/SqlBuildManager.Console.UnitTest/Resources/batch_settings_encrypted.json new file mode 100644 index 00000000..af83afd5 --- /dev/null +++ b/src/SqlBuildManager.Console.UnitTest/Resources/batch_settings_encrypted.json @@ -0,0 +1,50 @@ +{ + "AuthenticationArgs": { + "UserName": "F39bg\u002BQaoKOwtaYvs8BYsmBZOJ\u002BbhTxjIed7qPk\u002BVlk=", + "Password": "KcH/HBM2FbiT80tqvDu5G9bSxTgvDEAzqeRXBogsgnMNUo3Ztus7pqDfu/eVyTf5", + "AuthenticationType": "Password" + }, + "BatchArgs": { + "ResourceGroup": "sbm234-rg", + "BatchNodeCount": 2, + "BatchVmSize": "STANDARD_D1_V2", + "DeleteBatchPool": false, + "DeleteBatchJob": false, + "PollBatchPoolStatus": true, + "BatchPoolName": "SqlBuildManagerPoolWindows", + "BatchPoolOs": "Windows", + "JobMonitorTimeout": 30 + }, + "ConnectionArgs": { + "EventHubConnectionString": "wsow/erDnj5v/3eNE5zuC2/tyIzyJyc1cuv/Wt7ZCD3FbGK2sInbGJf9roULUSdHDYecQTdGPCYPoAkAWKjaWwpPYYFT8Elh4he20/JQsDvlLSKsioxhvFfXG9VnFmzKUaHuHb/RNG3FDHJUMH\u002B65a7GUcUFwxakUUrN3KJ/YHDmrg/eeuffoZqt86BtrunvQ4uxLvKa0\u002BTeVtzIl8BqqaPzcm1Ja6ovZNddylUxIeeG6Q3ZYEvnsq5AOTnNk2\u002B8", + "StorageAccountName": "sbm234storage", + "StorageAccountKey": "XX15nKpTGr4X\u002Bt30g7VRqR8FvLpT\u002BmB/OWMpR4dbA2I5cso8Ar5SNQZxg/S3\u002BbkQdJaPCLR3DQwuAegoRjfe1TFgFFqAAyV80edf0Tq9SE4MazCbEzyA\u002BXht94JT7bXc", + "BatchAccountName": "sbm234batchacct", + "BatchAccountKey": "jenSRh6XpaXAmGJ6\u002BgkMqp2c1TEgd/Wo3WVKD6JYnvTmLr\u002BU6XZU/yGdwxsM5wWRCcjzrtd92mlhl3Hc2AYpMa7h3NmsazPiTazBqmnZJVpPAUjF3WtgimW6eJWuYeEC", + "BatchAccountUrl": "https://sbm234batchacct.southcentralus.batch.azure.com" + }, + "EventHubArgs": { + "ResourceGroup": "sbm234-rg", + "SubscriptionId": "0d901325-d643-4db7-ae90-58b4e3834629", + "Logging": [ + "EssentialOnly", + "ScriptErrors" + ] + }, + "IdentityArgs": { + "IdentityName": "sbm234identity", + "ResourceGroup": "sbm234-rg", + "SubscriptionId": "0d901325-d643-4db7-ae90-58b4e3834629", + "TenantId": "16b3c013-d300-468d-ac64-7eda0820b6d3" + }, + "NetworkArgs": { + "VnetName": "sbm234vnet", + "SubnetName": "sbm234batchsubnet", + "ResourceGroup": "sbm234-rg" + }, + "Concurrency": 5, + "ConcurrencyType": "Count", + "TimeoutRetryCount": 0, + "DefaultScriptTimeout": 500, + "RootLoggingPath": "C:/temp" +} \ No newline at end of file diff --git a/src/SqlBuildManager.Console.UnitTest/Resources/settingsfilekey.txt b/src/SqlBuildManager.Console.UnitTest/Resources/settingsfilekey.txt new file mode 100644 index 00000000..a35887dd --- /dev/null +++ b/src/SqlBuildManager.Console.UnitTest/Resources/settingsfilekey.txt @@ -0,0 +1 @@ +jbsUw8PLkrBu6HAf/O9jJEDiDxFrTivdvvMkYiMvTqU= \ No newline at end of file diff --git a/src/SqlBuildManager.Console.UnitTest/SqlBuildManager.Console.UnitTest.csproj b/src/SqlBuildManager.Console.UnitTest/SqlBuildManager.Console.UnitTest.csproj index 68107474..6bf55508 100644 --- a/src/SqlBuildManager.Console.UnitTest/SqlBuildManager.Console.UnitTest.csproj +++ b/src/SqlBuildManager.Console.UnitTest/SqlBuildManager.Console.UnitTest.csproj @@ -1,6 +1,6 @@ - net7.0 + net8.0 false false false @@ -17,6 +17,9 @@ Always + + + @@ -28,8 +31,8 @@ - - + + @@ -48,4 +51,17 @@ + + + True + True + Resources.resx + + + + + ResXFileCodeGenerator + Resources.Designer.cs + + \ No newline at end of file diff --git a/src/SqlBuildManager.Console/Batch/BatchManager.cs b/src/SqlBuildManager.Console/Batch/BatchManager.cs index 05051e88..41ade5b8 100644 --- a/src/SqlBuildManager.Console/Batch/BatchManager.cs +++ b/src/SqlBuildManager.Console/Batch/BatchManager.cs @@ -1,6 +1,6 @@ using Azure.Core; using Azure.ResourceManager; -using arb = Azure.ResourceManager.Batch; +using azB = Azure.ResourceManager.Batch; using Azure.ResourceManager.Batch.Models; using Azure.ResourceManager.Models; using Microsoft.Azure.Batch; @@ -560,15 +560,15 @@ public async Task CreateBatchPool(CommandLineArgs cmdLine, string poolId) // get your azure access token, for more details of how Azure SDK get your access token, please refer to https://learn.microsoft.com/en-us/dotnet/azure/sdk/authentication?tabs=command-line ArmClient client = new ArmClient(AadHelper.TokenCredential); - ResourceIdentifier batchAccountResourceId = arb.BatchAccountResource.CreateResourceIdentifier(subscriptionId, resourceGroupName, batchAccountName); - arb.BatchAccountResource batchAccount = client.GetBatchAccountResource(batchAccountResourceId); + ResourceIdentifier batchAccountResourceId = azB.BatchAccountResource.CreateResourceIdentifier(subscriptionId, resourceGroupName, batchAccountName); + azB.BatchAccountResource batchAccount = client.GetBatchAccountResource(batchAccountResourceId); // get the collection of this BatchAccountPoolResource - arb.BatchAccountPoolCollection collection = batchAccount.GetBatchAccountPools(); + azB.BatchAccountPoolCollection collection = batchAccount.GetBatchAccountPools(); // invoke the operation - arb.BatchAccountPoolData data = new arb.BatchAccountPoolData(); + azB.BatchAccountPoolData data = new azB.BatchAccountPoolData(); data.Identity = new ManagedServiceIdentity("UserAssigned") { diff --git a/src/SqlBuildManager.Console/CommandLine/CommandLineBuilder.cs b/src/SqlBuildManager.Console/CommandLine/CommandLineBuilder.cs index c6728ec7..3b45473c 100644 --- a/src/SqlBuildManager.Console/CommandLine/CommandLineBuilder.cs +++ b/src/SqlBuildManager.Console/CommandLine/CommandLineBuilder.cs @@ -448,7 +448,7 @@ private static List