diff --git a/build/ci-build.yml b/build/ci-build.yml index 83e91248..e52d0f0a 100644 --- a/build/ci-build.yml +++ b/build/ci-build.yml @@ -18,6 +18,10 @@ parameters: - name: 'Package.Version.ManualTrigger' type: string default: 'preview' + - name: azureServiceConnection + displayName: 'Azure service connection' + type: string + default: 'Azure Codit-Arcus Service Principal' - name: 'UnitTests' type: object default: @@ -62,9 +66,9 @@ resources: variables: - group: 'Build Configuration' - group: 'Arcus Scripting - Integration Testing' - - group: 'Arcus - GitHub Package Registry' - group: 'MyGet' - template: ./variables/build.yml + - template: ./variables/test.yml - name: 'Package.Version' value: '0.$(Build.BuildNumber)' - name: 'Prerelease' @@ -111,6 +115,7 @@ stages: parameters: projectName: '$(Project).Tests.Unit' testName: '$(Project).${{UnitTest.name}}' + azureServiceConnection: ${{ parameters.azureServiceConnection }} - stage: IntegrationTests displayName: Integration Tests @@ -139,6 +144,7 @@ stages: parameters: projectName: '$(Project).Tests.Integration' testName: '$(Project).${{IntegrationTest.name}}' + azureServiceConnection: ${{ parameters.azureServiceConnection }} - stage: ReleaseToMyget displayName: 'Release to MyGet' diff --git a/build/deploy-test-resources.yml b/build/deploy-test-resources.yml new file mode 100644 index 00000000..05f18103 --- /dev/null +++ b/build/deploy-test-resources.yml @@ -0,0 +1,78 @@ +name: Arcus Scripting - Deploy test resources + +trigger: none +pr: none + +parameters: + - name: azureServiceConnection + displayName: 'Azure service connection' + type: string + default: 'Azure Codit-Arcus Service Principal' + - name: resourceGroupName + displayName: 'Resource group name' + default: arcus-scripting-dev-we-rg + +variables: + - template: ./variables/build.yml + - template: ./variables/test.yml + +stages: + - stage: Deploy + jobs: + - job: DeployBicep + displayName: 'Deploy test resources' + pool: + vmImage: '$(Vm.Linux.Image)' + steps: + - task: AzureCLI@2 + env: + SYSTEM_ACCESSTOKEN: $(System.AccessToken) + inputs: + azureSubscription: '${{ parameters.azureServiceConnection }}' + addSpnToEnvironment: true + scriptType: 'pscore' + scriptLocation: 'inlineScript' + inlineScript: | + az deployment sub create ` + --location westeurope ` + --template-file ./build/templates/deploy-resource-group.bicep ` + --parameters resourceGroupName=$env:ARCUS_SCRIPTING_RESOURCEGROUP_NAME ` + --parameters location=westeurope + + $objectId = (az ad sp show --id $env:servicePrincipalId | ConvertFrom-Json).id + + $symbols = '!@#$%^&*=(),.?'.ToCharArray() + $characterList = 'a'..'z' + 'A'..'Z' + '0'..'9' + $symbols + function Gen-Password { + param($length) + do { + $password = "" + for ($i = 0; $i -lt $length; $i++) { + $randomIndex = [System.Security.Cryptography.RandomNumberGenerator]::GetInt32(0, $characterList.Length) + $password += $characterList[$randomIndex] + } + + $hasLowerChar = $password -cmatch '[a-z]' + $hasUpperChar = $password -cmatch '[A-Z]' + $hasDigit = $password -match '[0-9]' + $hasSymbol = $password.IndexOfAny($symbols) -ne -1 + } + until (($hasLowerChar + $hasUpperChar + $hasDigit + $hasSymbol) -ge 3) + $password + } + + $sqlAdminPassword = Gen-Password 14 + az deployment group create ` + --resource-group $env:ARCUS_SCRIPTING_RESOURCEGROUP_NAME ` + --template-file ./build/templates/deploy-test-resources.bicep ` + --parameters location=westeurope ` + --parameters keyVaultName=$env:ARCUS_SCRIPTING_KEYVAULT_NAME ` + --parameters storageAccountName=$env:ARCUS_SCRIPTING_STORAGEACCOUNT_NAME ` + --parameters appServiceName=$env:ARCUS_SCRIPTING_APPSERVICE_NAME ` + --parameters sqlServerName=$env:ARCUS_SCRIPTING_SQL_SERVERNAME ` + --parameters sqlDatabaseName=$env:ARCUS_SCRIPTING_SQL_DATABASENAME ` + --parameters sqlAdminUserName=$env:ARCUS_SCRIPTING_SQL_USERNAME ` + --parameters sqlAdminPassword=$sqlAdminPassword ` + --parameters sqlAdminPassword_secretName=$env:ARCUS_SCRIPTING_SQL_PASSWORD_SECRETNAME ` + --parameters integrationAccountName=$env:ARCUS_SCRIPTING_INTEGRATIONACCOUNT_NAME ` + --parameters servicePrincipal_objectId=$objectId diff --git a/build/psgallery-release.yml b/build/psgallery-release.yml index e3ab9c20..3e43761d 100644 --- a/build/psgallery-release.yml +++ b/build/psgallery-release.yml @@ -10,6 +10,10 @@ parameters: displayName: 'Prerelease string (ex. -alpha, -alpha1, -BETA, -update20171020) or none' type: 'string' default: 'none' + - name: azureServiceConnection + displayName: 'Azure service connection' + type: string + default: 'Azure Codit-Arcus Service Principal' - name: 'UnitTests' type: object default: @@ -56,6 +60,7 @@ variables: - group: 'Arcus Scripting - Integration Testing' - group: 'Arcus.Scripting - Releasing PS Gallery' - template: ./variables/build.yml + - template: ./variables/test.yml - name: 'Repository' value: 'arcus-azure/arcus.scripting' - name: 'Package.Version' @@ -104,6 +109,7 @@ stages: parameters: projectName: '$(Project).Tests.Unit' testName: '$(Project).${{UnitTest.name}}' + azureServiceConnection: ${{ parameters.azureServiceConnection }} - stage: IntegrationTests displayName: Integration Tests @@ -132,6 +138,7 @@ stages: parameters: projectName: '$(Project).Tests.Integration' testName: '$(Project).${{IntegrationTest.name}}' + azureServiceConnection: ${{ parameters.azureServiceConnection }} - stage: Release displayName: 'Release to PowerShell Gallery' diff --git a/build/templates/deploy-resource-group.bicep b/build/templates/deploy-resource-group.bicep new file mode 100644 index 00000000..f21d0090 --- /dev/null +++ b/build/templates/deploy-resource-group.bicep @@ -0,0 +1,15 @@ +// Define the name of the resource group. +param resourceGroupName string + +// Define the location for the deployment of the components. +param location string + +targetScope='subscription' + +module resourceGroup 'br/public:avm/res/resources/resource-group:0.2.3' = { + name: 'resourceGroupDeployment' + params: { + name: resourceGroupName + location: location + } +} diff --git a/build/templates/deploy-test-resources.bicep b/build/templates/deploy-test-resources.bicep new file mode 100644 index 00000000..372d0205 --- /dev/null +++ b/build/templates/deploy-test-resources.bicep @@ -0,0 +1,155 @@ +// Define the location for the deployment of the components. +param location string + +// Define the name of the storage account that will be created. +param storageAccountName string + +// Define the name of the Azure Functions app service that will be created. +param appServiceName string + +// Define the name of the Azure SQL server instance that will be created. +param sqlServerName string + +// Define the username of the administrator login for the Azure SQL server instance. +param sqlAdminUserName string + +// Define the password of the administrator login for the Azure SQL server instance. +@secure() +param sqlAdminPassword string + +// Define the Azure Key vault secret name of the administrator login password for the Azure SQL server instance. +param sqlAdminPassword_secretName string + +// Define the name of the Azure SQL database that will be created within the Azure SQL server instance. +param sqlDatabaseName string + +// Define the name of the integration account that will be created. +param integrationAccountName string + +// Define the name of the Key Vault. +param keyVaultName string + +// Define the Service Principal ID that needs access full access to the deployed resource group. +param servicePrincipal_objectId string + +module storageAccount 'br/public:avm/res/storage/storage-account:0.9.1' = { + name: 'storageAccountDeployment' + params: { + name: storageAccountName + location: location + allowBlobPublicAccess: true + publicNetworkAccess: 'Enabled' + networkAcls: { + bypass: 'AzureServices' + defaultAction: 'Allow' + ipRules: [] + virtualNetworkRules: [] + } + roleAssignments: [ + { + principalId: servicePrincipal_objectId + roleDefinitionIdOrName: 'Storage Blob Data Contributor' + } + { + principalId: servicePrincipal_objectId + roleDefinitionIdOrName: 'Storage Table Data Contributor' + } + ] + } +} + +module serverfarm 'br/public:avm/res/web/serverfarm:0.2.2' = { + name: 'serverfarmDeployment' + params: { + name: '${appServiceName}-plan' + skuCapacity: 2 + skuName: 'Y1' + location: location + } +} + +module functionApp 'br/public:avm/res/web/site:0.3.9' = { + name: 'functionAppDeployment' + params: { + kind: 'functionapp' + name: appServiceName + serverFarmResourceId: serverfarm.outputs.resourceId + location: location + enableTelemetry: false + siteConfig: { + alwaysOn: false + } + } +} + +module sqlServer 'br/public:avm/res/sql/server:0.4.1' = { + name: 'sqlServerDeployment' + params: { + name: sqlServerName + location: location + administratorLogin: sqlAdminUserName + administratorLoginPassword: sqlAdminPassword + enableTelemetry: false + publicNetworkAccess: 'Enabled' + restrictOutboundNetworkAccess: 'Disabled' + auditSettings: { + state: 'Disabled' + } + databases: [ + { + name: sqlDatabaseName + skuName: 'Basic' + skuTier: 'Basic' + maxSizeBytes: 2147483648 + } + ] + } +} + +resource integrationAccount 'Microsoft.Logic/integrationAccounts@2019-05-01' = { + name: integrationAccountName + location: location + properties: { + state: 'Enabled' + } + sku: { + name: 'Free' + } +} + +module vault 'br/public:avm/res/key-vault/vault:0.6.1' = { + name: 'vaultDeployment' + params: { + name: keyVaultName + location: location + enableRbacAuthorization: false + sku: 'standard' + accessPolicies: [ + { + objectId: servicePrincipal_objectId + permissions: { + secrets: [ + 'get', 'list', 'set', 'delete' + ] + keys: [ + 'get', 'list', 'create', 'delete' + ] + } + } + { + objectId: '0d926a02-88dc-4279-8265-fbcd8178ecb0' // (built-in) Azure Logic Apps service principal + permissions: { + keys: [ + 'list', 'get', 'decrypt', 'sign' + ] + } + } + ] + secrets: [ + { + name: sqlAdminPassword_secretName + value: sqlAdminPassword + } + ] + } +} diff --git a/build/templates/run-pester-tests.yml b/build/templates/run-pester-tests.yml index c3e1ce06..a2f76f72 100644 --- a/build/templates/run-pester-tests.yml +++ b/build/templates/run-pester-tests.yml @@ -1,16 +1,9 @@ parameters: + azureServiceConnection: '' projectName: '' testName: '' steps: - - pwsh: | - Import-Module Microsoft.PowerShell.Management -Force - wget -O - https://aka.ms/install-powershell.sh | sudo bash - displayName: 'Update Powershell on Linux' - condition: eq( variables['Agent.OS'], 'Linux' ) - - powershell: 'Invoke-Expression -Command "& { $(Invoke-RestMethod -Uri ''https://aka.ms/install-powershell.ps1'') } -UseMSI -quiet" ' - displayName: 'Update Powershell on Windows' - condition: eq( variables['Agent.OS'], 'Windows_NT' ) - bash: | if [ -z "$PROJECT_NAME" ]; then echo "##vso[task.logissue type=error;]Missing template parameter \"projectName\"" @@ -19,8 +12,43 @@ steps: env: PROJECT_NAME: ${{ parameters.projectName }} displayName: 'Guard against invalid parameters' + + - task: AzureCLI@2 + displayName: 'Import secrets from Azure Key Vault' + condition: contains('${{ parameters.projectName }}', 'Integration') + inputs: + azureSubscription: '${{ parameters.azureServiceConnection }}' + addSpnToEnvironment: true + scriptType: 'pscore' + scriptLocation: 'inlineScript' + inlineScript: | + Set-PSRepository -Name PSGallery -InstallationPolicy Trusted + Install-Module -Name Arcus.Scripting.DevOps -AllowClobber -MinimumVersion 1.3.0 + + $subscriptionId = (az account show | ConvertFrom-Json).id + Set-AzDevOpsVariable -Name 'Arcus.Scripting.SubscriptionId' -Value $subscriptionId -AsSecret + Set-AzDevOpsVariable -Name 'Arcus.Scripting.TenantId' -Value $env:tenantId -AsSecret + Set-AzDevOpsVariable -Name 'Arcus.Scripting.ServicePrincipal.ClientId' -Value $env:servicePrincipalId -AsSecret + Set-AzDevOpsVariable -Name 'Arcus.Scripting.ServicePrincipal.ClientSecret' -Value $env:servicePrincipalKey -AsSecret + + $sqlAdminPasswordSecret = az keyvault secret show --name $env:ARCUS_SCRIPTING_SQL_PASSWORD_SECRETNAME --vault-name $env:ARCUS_SCRIPTING_KEYVAULT_NAME | ConvertFrom-Json + Set-AzDevOpsVariable -Name 'Arcus.Scripting.Sql.Password' -Value $sqlAdminPasswordSecret.value -AsSecret + + $mainAppClientIdSecret = az keyvault secret show --name $env:ARCUS_GENERAL_ACTIVEDIRECTORY_MAINAPP_CLIENTID_SECRETNAME --vault-name $env:ARCUS_GENERAL_KEYVAULT_NAME | ConvertFrom-Json + $clientAppClientIdSecret = az keyvault secret show --name $env:ARCUS_GENERAL_ACTIVEDIRECTORY_CLIENTAPP_CLIENTID_SECRETNAME --vault-name $env:ARCUS_GENERAL_KEYVAULT_NAME | ConvertFrom-Json + Set-AzDevOpsVariable -Name 'Arcus.ActiveDirectory.MainApp.ClientId' -Value $mainAppClientIdSecret.value -AsSecret + Set-AzDevOpsVariable -Name 'Arcus.ActiveDirectory.ClientApp.ClientId' -Value $clientAppClientIdSecret.value -AsSecret + + $activeDirectoryTenantIdSecret = az keyvault secret show --name $env:ARCUS_GENERAL_ACTIVEDIRECTORY_TENANTID_SECRETNAME --vault-name $env:ARCUS_GENERAL_KEYVAULT_NAME | ConvertFrom-Json + $activeDirectoryServicePrincipalClientIdSecret = az keyvault secret show --name $env:ARCUS_GENERAL_ACTIVEDIRECTORY_SERVICEPRINCIPAL_CLIENTID_SECRETNAME --vault-name $env:ARCUS_GENERAL_KEYVAULT_NAME | ConvertFrom-Json + $activeDirectoryServicePrincipalClientSecretSecret = az keyvault secret show --name $env:ARCUS_GENERAL_ACTIVEDIRECTORY_SERVICEPRINCIPAL_CLIENTSECRET_SECRETNAME --vault-name $env:ARCUS_GENERAL_KEYVAULT_NAME | ConvertFrom-Json + Set-AzDevOpsVariable -Name 'Arcus.Scripting.ActiveDirectory.TenantId' -Value $activeDirectoryTenantIdSecret.value + Set-AzDevOpsVariable -Name 'Arcus.Scripting.ActiveDirectory.ServicePrincipal.ClientId' -Value $activeDirectoryServicePrincipalClientIdSecret.value -AsSecret + Set-AzDevOpsVariable -Name 'Arcus.Scripting.ActiveDirectory.ServicePrincipal.ClientSecret' -Value $activeDirectoryServicePrincipalClientSecretSecret.value -AsSecret + - task: qetza.replacetokens.replacetokens-task.replacetokens@3 displayName: 'Replace integration test tokens' + condition: contains('${{ parameters.projectName }}', 'Integration') inputs: rootDirectory: 'src/${{ parameters.projectName }}/' targetFiles: 'appsettings.json' @@ -31,6 +59,7 @@ steps: keepToken: false tokenPrefix: '#{' tokenSuffix: '}#' + - powershell: | Write-Host "Installing Pester test framework and Az required modules" Install-Module -Name Pester -Force -SkipPublisherCheck -MaximumVersion 5.1.1 @@ -46,6 +75,7 @@ steps: Install-Module -Name Microsoft.Graph.Applications -Force -SkipPublisherCheck -MaximumVersion 1.15.0 Write-Host "Done installing, start importing modules" displayName: 'Install Pester test framework and Az required modules' + - pwsh: | Import-Module ./src/Arcus.Scripting.Security Get-ChildItem -Path ./src -Filter *.psm1 -Recurse -Exclude "*Arcus.Scripting.Security*", "*.All.psm1" | @@ -56,8 +86,10 @@ steps: failOnStderr: true env: SYSTEM_ACCESSTOKEN: $(System.AccessToken) + - task: PublishTestResults@2 displayName: 'Publish test results' + condition: always() inputs: testResultsFormat: 'NUnit' testResultsFiles: '**/pester.test.results*.xml' diff --git a/build/variables/test.yml b/build/variables/test.yml new file mode 100644 index 00000000..31136230 --- /dev/null +++ b/build/variables/test.yml @@ -0,0 +1,20 @@ +variables: + Arcus.General.KeyVault.Name: 'arcus-kv' + Arcus.General.ActiveDirectory.TenantId.SecretName: 'Arcus-ActiveDirectory-TenantId' + Arcus.General.ActiveDirectory.ServicePrincipal.ClientId.SecretName: 'Arcus-ActiveDirectory-ServicePrincipal-ClientId' + Arcus.General.ActiveDirectory.ServicePrincipal.ClientSecret.SecretName: 'Arcus-ActiveDirectory-ServicePrincipal-ClientSecret' + Arcus.General.ActiveDirectory.MainApp.ClientId.SecretName: 'ActiveDirectory-MainApp-ClientId' + Arcus.General.ActiveDirectory.ClientApp.ClientId.SecretName: 'ActiveDirectory-ClientApp-ClientId' + Arcus.Scripting.ResourceGroup.Name: 'arcus-scripting-dev-we-rg' + Arcus.Scripting.DevOps.VariableGroup.Name: 'Arcus Scripting - Integration Testing - DevOps (existing variable group)' + Arcus.Scripting.DevOps.VariableGroup.UrlEncoded: 'Arcus%20Scripting%20-%20Integration%20Testing%20-%20DevOps%20(existing%20variable%20group)' + Arcus.Scripting.KeyVault.Name: 'arcus-scripting-kv' + Arcus.Scripting.AppService.Name: 'arcus-scripting-dev-we' + Arcus.Scripting.IntegrationAccount.Name: 'arcus-scripting-dev-ne-ia' + Arcus.Scripting.IoTHub.Name: 'arcus-scripting-dev-we-iot-hub' + Arcus.Scripting.LogicApps.TriggerName: 'arc-dev-we-rcv-http-trigger' + Arcus.Scripting.Sql.DatabaseName: 'arcus-scripting-sql-db' + Arcus.Scripting.Sql.ServerName: 'arcus-scripting-dev-we-sql-svr' + Arcus.Scripting.Sql.UserName: 'arcusAdmin' + Arcus.Scripting.Sql.Password.SecretName: 'Arcus-Scripting-Sql-Password' + Arcus.Scripting.StorageAccount.Name: 'arcusscriptingdev' \ No newline at end of file diff --git a/src/Arcus.Scripting.Management/Scripts/Get-AzApiManagementSoftDeletedResources.ps1 b/src/Arcus.Scripting.Management/Scripts/Get-AzApiManagementSoftDeletedResources.ps1 index 7aed067f..30ad7d43 100644 --- a/src/Arcus.Scripting.Management/Scripts/Get-AzApiManagementSoftDeletedResources.ps1 +++ b/src/Arcus.Scripting.Management/Scripts/Get-AzApiManagementSoftDeletedResources.ps1 @@ -8,6 +8,7 @@ param( Write-Verbose "Checking if the Azure API Management service '$Name' is listed as a soft deleted service..." $getUri = "$ResourceManagerUrl" + "subscriptions/$SubscriptionId/providers/Microsoft.ApiManagement/deletedservices" + "?api-version=$ApiVersion" +Write-Host "Get soft deleted services at: $getUri $AuthHeader" $deletedServices = (Invoke-RestMethod -Method GET -Uri $getUri -Headers $AuthHeader) diff --git a/src/Arcus.Scripting.Tests.Integration/Arcus.Scripting.ActiveDirectory.tests.ps1 b/src/Arcus.Scripting.Tests.Integration/Arcus.Scripting.ActiveDirectory.tests.ps1 index f4f96be9..ae6e66ea 100644 --- a/src/Arcus.Scripting.Tests.Integration/Arcus.Scripting.ActiveDirectory.tests.ps1 +++ b/src/Arcus.Scripting.Tests.Integration/Arcus.Scripting.ActiveDirectory.tests.ps1 @@ -5,8 +5,33 @@ InModuleScope Arcus.Scripting.ActiveDirectory { Describe "Arcus Azure Active Directory integration tests" { BeforeEach { $config = & $PSScriptRoot\Load-JsonAppsettings.ps1 - & $PSScriptRoot\Connect-AzAccountFromConfig.ps1 -config $config - & $PSScriptRoot\Connect-MgGraphFromConfig.ps1 -config $config + $clientSecret = ConvertTo-SecureString $config.Arcus.ActiveDirectory.ServicePrincipal.ClientSecret -AsPlainText -Force + $pscredential = New-Object -TypeName System.Management.Automation.PSCredential($config.Arcus.ActiveDirectory.ServicePrincipal.ClientId, $clientSecret) + Disable-AzContextAutosave -Scope Process + Connect-AzAccount -Credential $pscredential -TenantId $config.Arcus.ActiveDirectory.TenantId -ServicePrincipal + + $tenantid = $config.Arcus.ActiveDirectory.TenantId + $body = @{ + Grant_Type = "client_credentials" + Scope = "https://graph.microsoft.com/.default" + Client_Id = $config.Arcus.ActiveDirectory.ServicePrincipal.ClientId + Client_Secret = $config.Arcus.ActiveDirectory.ServicePrincipal.ClientSecret + } + + $connection = Invoke-RestMethod ` + -Uri https://login.microsoftonline.com/$tenantid/oauth2/v2.0/token ` + -Method POST ` + -Body $body + + $token = $connection.access_token + + $targetParameter = (Get-Command Connect-MgGraph).Parameters['AccessToken'] + + if ($targetParameter.ParameterType -eq [securestring]) { + Connect-MgGraph -AccessToken ($token | ConvertTo-SecureString -AsPlainText -Force) + } else { + Connect-MgGraph -AccessToken $token + } } Context "Add an Active Directory Application Role Assignment" { It "Creating a new role and assigning it should succeed" { diff --git a/src/Arcus.Scripting.Tests.Integration/Arcus.Scripting.Management.tests.ps1 b/src/Arcus.Scripting.Tests.Integration/Arcus.Scripting.Management.tests.ps1 index adcaa169..e546589f 100644 --- a/src/Arcus.Scripting.Tests.Integration/Arcus.Scripting.Management.tests.ps1 +++ b/src/Arcus.Scripting.Tests.Integration/Arcus.Scripting.Management.tests.ps1 @@ -30,4 +30,4 @@ InModuleScope Arcus.Scripting.Management { } } } -} \ No newline at end of file +} diff --git a/src/Arcus.Scripting.Tests.Integration/Arcus.Scripting.Security.tests.ps1 b/src/Arcus.Scripting.Tests.Integration/Arcus.Scripting.Security.tests.ps1 index 842e3b23..850b8d23 100644 --- a/src/Arcus.Scripting.Tests.Integration/Arcus.Scripting.Security.tests.ps1 +++ b/src/Arcus.Scripting.Tests.Integration/Arcus.Scripting.Security.tests.ps1 @@ -43,10 +43,12 @@ InModuleScope Arcus.Scripting.Security { BeforeEach { $config = & $PSScriptRoot\Load-JsonAppsettings.ps1 -fileName "appsettings.json" & $PSScriptRoot\Connect-AzAccountFromConfig.ps1 -config $config + + Remove-AzResourceGroupLocks -ResourceGroupName $config.Arcus.ResourceGroupName } It "Newly added resource lock gets removed by removing all resource locks with a given lock name" { # Arrange - $lockName = "NewTestingLockWithName" + $lockName = "NewTestingLockWithName-$([System.Guid]::NewGuid())" $targetResourceName = $config.Arcus.KeyVault.VaultName $targetResourceGroupName = $config.Arcus.ResourceGroupName New-AzResourceLock ` @@ -82,7 +84,7 @@ InModuleScope Arcus.Scripting.Security { } It "Newly added resource lock gets removed by removing all resource locks without giving any lock name" { # Arrange - $lockName = "NewTestingLockWithoutName" + $lockName = "NewTestingLockWithName-$([System.Guid]::NewGuid())" $targetResourceName = $config.Arcus.KeyVault.VaultName $targetResourceGroupName = $config.Arcus.ResourceGroupName New-AzResourceLock ` diff --git a/src/Arcus.Scripting.Tests.Integration/Arcus.Scripting.Sql.tests.ps1 b/src/Arcus.Scripting.Tests.Integration/Arcus.Scripting.Sql.tests.ps1 index 49d4fa0a..738c3357 100644 --- a/src/Arcus.Scripting.Tests.Integration/Arcus.Scripting.Sql.tests.ps1 +++ b/src/Arcus.Scripting.Tests.Integration/Arcus.Scripting.Sql.tests.ps1 @@ -85,7 +85,7 @@ function global:Retry-Function ($func, $retryCount = 5, $retryIntervalSeconds = $success = $true } catch { if (++$attempt -eq $retryCount) { - Write-Error "Task failed. With all $attempt attempts. Error: $($Error[0])" + Write-Error "Task failed. With all $attempt attempts. Error: $($_.Exception.ToString()) $($Error[0])" throw } @@ -101,8 +101,9 @@ InModuleScope Arcus.Scripting.Sql { Describe "Arcus Azure SQL integration tests" { BeforeAll { $config = & $PSScriptRoot\Load-JsonAppsettings.ps1 + $serverInstance = $config.Arcus.Sql.ServerName + '.database.windows.net' $params = @{ - 'ServerInstance' = $config.Arcus.Sql.ServerName + 'ServerInstance' = $serverInstance 'Database' = $config.Arcus.Sql.DatabaseName 'Username' = $config.Arcus.Sql.UserName 'Password' = $config.Arcus.Sql.Password @@ -142,7 +143,7 @@ InModuleScope Arcus.Scripting.Sql { # Act Invoke-AzSqlDatabaseMigration ` - -ServerName $config.Arcus.Sql.ServerName ` + -ServerName $serverInstance ` -DatabaseName $config.Arcus.Sql.DatabaseName ` -Username $config.Arcus.Sql.Username ` -Password $config.Arcus.Sql.Password ` @@ -164,7 +165,7 @@ InModuleScope Arcus.Scripting.Sql { # Act Invoke-AzSqlDatabaseMigration ` - -ServerName $config.Arcus.Sql.ServerName ` + -ServerName $serverInstance ` -DatabaseName $config.Arcus.Sql.DatabaseName ` -Username $config.Arcus.Sql.Username ` -Password $config.Arcus.Sql.Password ` @@ -196,7 +197,7 @@ InModuleScope Arcus.Scripting.Sql { # Act Invoke-AzSqlDatabaseMigration ` - -ServerName $config.Arcus.Sql.ServerName ` + -ServerName $serverInstance ` -DatabaseName $config.Arcus.Sql.DatabaseName ` -Username $config.Arcus.Sql.Username ` -Password $config.Arcus.Sql.Password ` @@ -230,7 +231,7 @@ InModuleScope Arcus.Scripting.Sql { try { # Act: execute the specified migration-scripts Invoke-AzSqlDatabaseMigration ` - -ServerName $config.Arcus.Sql.ServerName ` + -ServerName $serverInstance ` -DatabaseName $config.Arcus.Sql.DatabaseName ` -Username $config.Arcus.Sql.Username ` -Password $config.Arcus.Sql.Password ` @@ -277,7 +278,7 @@ InModuleScope Arcus.Scripting.Sql { # Act and arrange: execute the specified migration-scripts { Invoke-AzSqlDatabaseMigration ` - -ServerName $config.Arcus.Sql.ServerName ` + -ServerName $serverInstance ` -DatabaseName $config.Arcus.Sql.DatabaseName ` -Username $config.Arcus.Sql.Username ` -Password $config.Arcus.Sql.Password ` @@ -296,7 +297,7 @@ InModuleScope Arcus.Scripting.Sql { # is a mix between the old (versionnumber_description.sql) naming convention # and the new (major.minor.patch_description.sql) naming convention. Invoke-AzSqlDatabaseMigration ` - -ServerName $config.Arcus.Sql.ServerName ` + -ServerName $serverInstance ` -DatabaseName $config.Arcus.Sql.DatabaseName ` -Username $config.Arcus.Sql.Username ` -Password $config.Arcus.Sql.Password ` @@ -311,7 +312,7 @@ InModuleScope Arcus.Scripting.Sql { try { # Act and arrange: execute the specified migration-scripts Invoke-AzSqlDatabaseMigration ` - -ServerName $config.Arcus.Sql.ServerName ` + -ServerName $serverInstance ` -DatabaseName $config.Arcus.Sql.DatabaseName ` -Username $config.Arcus.Sql.Username ` -Password $config.Arcus.Sql.Password ` diff --git a/src/Arcus.Scripting.Tests.Integration/Connect-MgGraphFromConfig.ps1 b/src/Arcus.Scripting.Tests.Integration/Connect-MgGraphFromConfig.ps1 index 7f366860..726569fb 100644 --- a/src/Arcus.Scripting.Tests.Integration/Connect-MgGraphFromConfig.ps1 +++ b/src/Arcus.Scripting.Tests.Integration/Connect-MgGraphFromConfig.ps1 @@ -20,7 +20,10 @@ $token = $connection.access_token $targetParameter = (Get-Command Connect-MgGraph).Parameters['AccessToken'] if ($targetParameter.ParameterType -eq [securestring]) { - Connect-MgGraph -AccessToken ($token | ConvertTo-SecureString -AsPlainText -Force) + $secureToken = $token | ConvertTo-SecureString -AsPlainText -Force + Connect-MgGraph -AccessToken $secureToken + return ConvertFrom-SecureString -SecureString $secureToken -AsPlainText } else { Connect-MgGraph -AccessToken $token + return $token } \ No newline at end of file diff --git a/src/Arcus.Scripting.Tests.Integration/appsettings.json b/src/Arcus.Scripting.Tests.Integration/appsettings.json index 565d2d6f..1b2bc141 100644 --- a/src/Arcus.Scripting.Tests.Integration/appsettings.json +++ b/src/Arcus.Scripting.Tests.Integration/appsettings.json @@ -1,40 +1,45 @@ { "Arcus": { - "SubscriptionId": "#{Arcus.SubscriptionId}#", - "TenantId": "#{Arcus.TenantId}#", - "ResourceGroupName": "#{Arcus.ResourceGroupName}#", + "SubscriptionId": "#{Arcus.Scripting.SubscriptionId}#", + "TenantId": "#{Arcus.Scripting.TenantId}#", + "ResourceGroupName": "#{Arcus.Scripting.ResourceGroup.Name}#", "ServicePrincipal": { - "ClientId": "#{Arcus.ServicePrincipal.ClientId}#", - "ClientSecret": "#{Arcus.ServicePrincipal.ClientSecret}#" + "ClientId": "#{Arcus.Scripting.ServicePrincipal.ClientId}#", + "ClientSecret": "#{Arcus.Scripting.ServicePrincipal.ClientSecret}#" }, "DevOps": { "VariableGroup": { - "Name": "#{Arcus.DevOps.VariableGroup.Name}#", - "NameUrlEncoded": "#{Arcus.DevOps.VariableGroup.Name.UrlEncoded}#", - "Authorization": "#{Arcus.DevOps.VariableGroup.Authorization}#" + "Name": "#{Arcus.Scripting.DevOps.VariableGroup.Name}#", + "Authorization": "#{Arcus.DevOps.VariableGroup.Authorization}#", + "NameUrlEncoded": "#{Arcus.Scripting.DevOps.VariableGroup.UrlEncoded}#" } }, "KeyVault": { - "VaultName": "#{Arcus.KeyVault.VaultName}#" + "VaultName": "#{Arcus.Scripting.KeyVault.Name}#" }, "IntegrationAccount": { - "Name": "#{Arcus.IntegrationAccount.Name}#" + "Name": "#{Arcus.Scripting.IntegrationAccount.Name}#" }, "AppService": { - "Name": "#{Arcus.AppService.Name}#" + "Name": "#{Arcus.Scripting.AppService.Name}#" }, "Storage": { "StorageAccount": { - "Name": "#{Arcus.Storage.StorageAccount.Name}#" + "Name": "#{Arcus.Scripting.StorageAccount.Name}#" } }, "Sql": { - "ServerName": "#{Arcus.Sql.ServerName}#", - "DatabaseName": "#{Arcus.Sql.DatabaseName}#", - "Username": "#{Arcus.Sql.Username}#", - "Password": "#{Arcus.Sql.Password}#" + "ServerName": "#{Arcus.Scripting.Sql.ServerName}#", + "DatabaseName": "#{Arcus.Scripting.Sql.DatabaseName}#", + "UserName": "#{Arcus.Scripting.Sql.UserName}#", + "Password": "#{Arcus.Scripting.Sql.Password}#" }, "ActiveDirectory": { + "TenantId": "#{Arcus.Scripting.ActiveDirectory.TenantId}#", + "ServicePrincipal": { + "ClientId": "#{Arcus.Scripting.ActiveDirectory.ServicePrincipal.ClientId}#", + "ClientSecret": "#{Arcus.Scripting.ActiveDirectory.ServicePrincipal.ClientSecret}#" + }, "MainAppClientId": "#{Arcus.ActiveDirectory.MainApp.ClientId}#", "ClientAppClientId": "#{Arcus.ActiveDirectory.ClientApp.ClientId}#" }