From dfd9c16f61080bbdbd1a882564252b483d7cf887 Mon Sep 17 00:00:00 2001 From: Torsten Brendgen Date: Thu, 9 Jul 2026 23:49:01 +0200 Subject: [PATCH] Add migration to update ApiClients with centralized authorization scopes This migration updates the ScopesJson for the ApiClient with Id 91000000-0000-0000-0000-000000000001 to include additional authorization scopes for improved API access control. The Down method reverts the changes if necessary. --- .tests/Api.Workflow.Tests.ps1 | 422 ++ .tests/OnPremClientCredentials.Api.Tests.ps1 | 62 +- Authorization/ApiPolicies.cs | 19 + Authorization/ApiScopes.cs | 19 + ...uthorizationServiceCollectionExtensions.cs | 50 + Context/DemoData.cs | 2 +- Controllers/ApiTokenController.cs | 13 +- .../ConfigurationDefinitionController.cs | 6 + Controllers/ConfigurationValueController.cs | 5 + Controllers/CredentialSecretController.cs | 7 + Controllers/DeploymentArtifactController.cs | 5 + Controllers/DeploymentBatchController.cs | 12 + Controllers/DeploymentController.cs | 11 + Controllers/DeploymentRuleController.cs | 9 +- Controllers/DomainController.cs | 8 + Controllers/EnvironmentController.cs | 6 + Controllers/ServiceController.cs | 9 + Controllers/TargetController.cs | 8 + Controllers/TemplateCategoryController.cs | 6 + Controllers/TemplateController.cs | 9 + Helper/MappingProfilesHelper.cs | 1 + ...CentralizedAuthorizationScopes.Designer.cs | 4884 +++++++++++++++++ ...71904_AddCentralizedAuthorizationScopes.cs | 33 + Migrations/DataContextModelSnapshot.cs | 2 +- Program.cs | 16 +- Services/ApiTokenService.cs | 21 +- appsettings.json | 6 + 27 files changed, 5617 insertions(+), 34 deletions(-) create mode 100644 .tests/Api.Workflow.Tests.ps1 create mode 100644 Authorization/ApiPolicies.cs create mode 100644 Authorization/ApiScopes.cs create mode 100644 Authorization/AuthorizationServiceCollectionExtensions.cs create mode 100644 Migrations/20260709171904_AddCentralizedAuthorizationScopes.Designer.cs create mode 100644 Migrations/20260709171904_AddCentralizedAuthorizationScopes.cs diff --git a/.tests/Api.Workflow.Tests.ps1 b/.tests/Api.Workflow.Tests.ps1 new file mode 100644 index 0000000..fcd947f --- /dev/null +++ b/.tests/Api.Workflow.Tests.ps1 @@ -0,0 +1,422 @@ +param( + [string]$ApiBaseUrl = 'http://localhost:5286/api', + + [string]$ClientId = 'ssp-demo-worker', + + [string]$ClientSecret = 'DemoOnly-DoNotUseInProduction!', + + [int]$ApiTimeoutSec = 30 +) + +$ErrorActionPreference = 'Stop' + +function Invoke-Api { + param( + [ValidateSet('GET', 'POST', 'PUT', 'DELETE')] + [string]$Method, + + [string]$Path, + + [object]$Body, + + [string]$BearerToken, + + [switch]$AllowNotFound + ) + + $uri = ('{0}/{1}' -f $ApiBaseUrl.TrimEnd('/'), $Path.TrimStart('/')) + $parameters = @{ + Method = $Method + Uri = $uri + TimeoutSec = $ApiTimeoutSec + ErrorAction = 'Stop' + } + + if ($Body) { + $parameters.Body = ($Body | ConvertTo-Json -Depth 20) + $parameters.ContentType = 'application/json' + } + + if ($BearerToken) { + $parameters.Headers = @{ + Authorization = "Bearer $BearerToken" + } + } + + try { + Invoke-RestMethod @parameters + } + catch { + $statusCode = $null + if ($_.Exception.Response -and $_.Exception.Response.StatusCode) { + $statusCode = [int]$_.Exception.Response.StatusCode + } + + if ($AllowNotFound -and $statusCode -eq 404) { + return $null + } + + $responseBody = '' + if ($_.Exception.Response) { + try { + $stream = $_.Exception.Response.GetResponseStream() + if ($stream) { + $reader = [System.IO.StreamReader]::new($stream) + $text = $reader.ReadToEnd() + if (-not [string]::IsNullOrWhiteSpace($text)) { + $responseBody = $text + } + } + } + catch { + $responseBody = '' + } + } + + throw "API request failed. Method=[$Method], Uri=[$uri], Response=[$responseBody]. $($_.Exception.Message)" + } +} + +function Get-AuthToken { + param([string]$Scope) + + $token = Invoke-Api -Method POST -Path 'auth/token' -Body @{ + clientId = $ClientId + clientSecret = $ClientSecret + scope = $Scope + } + + return $token.accessToken +} + +function Find-ByName { + param( + [object[]]$Items, + [string]$Name + ) + + return @($Items | Where-Object { $_.name -eq $Name })[0] +} + +function ConvertTo-GuidValue { + param([object]$Value) + + return [guid]@($Value)[0] +} + +function ConvertTo-ApiItems { + param([object]$Value) + + if ($null -eq $Value) { + return @() + } + + $items = @($Value) + if ($items.Count -eq 1 -and $items[0] -is [array]) { + return @($items[0]) + } + + if ($items.Count -eq 1 -and $items[0].PSObject.Properties['value']) { + return @($items[0].value) + } + + return $items +} + +function Write-TestSection { + param([string]$Name) + + Write-Host "" + Write-Host ("=== {0} ===" -f $Name) -ForegroundColor Cyan +} + +function Write-TestInfo { + param( + [string]$Label, + [object]$Value + ) + + Write-Host (" - {0}: {1}" -f $Label, $Value) +} + +Describe 'API controller workflow smoke test' { + $script:token = $null + $script:environmentId = $null + $script:domainIds = @() + $script:targetIds = @() + $script:deploymentBatchId = $null + $script:templateSelectionIds = @() + $script:targetAssignmentIds = @() + $script:configurationValueId = $null + $script:credentialSecretId = $null + $script:testRunId = ([guid]::NewGuid().ToString('N')).Substring(0, 8) + $script:environmentName = "Pester Environment $script:testRunId" + $script:domainName1 = "Pester Domain A $script:testRunId" + $script:domainName2 = "Pester Domain B $script:testRunId" + $script:targetName1 = "PST-$script:testRunId-01" + $script:targetName2 = "PST-$script:testRunId-02" + $script:targetName3 = "PST-$script:testRunId-03" + $script:credentialSecretName = "Pester/Workflow/$script:testRunId" + + try { + It 'creates an environment, links two domains, creates targets and composes a deployment batch' { + Write-TestSection -Name 'test run' + Write-TestInfo -Label 'API base URL' -Value $ApiBaseUrl + Write-TestInfo -Label 'Run id' -Value $script:testRunId + + Write-TestSection -Name 'auth and inventory' + $script:token = Get-AuthToken -Scope 'configuration.read configuration.write credential.read credential.write credential.resolve deployment.read deployment.write queue.read template.read token.manage token.admin' + Write-TestInfo -Label 'Bearer token' -Value 'issued' + + $allowedScopesResponse = Invoke-Api -Method GET -Path 'tokens/scopes' -BearerToken $script:token + $allowedScopes = @($allowedScopesResponse) + if ($allowedScopesResponse.PSObject.Properties['value']) { + $allowedScopes = @($allowedScopesResponse.value) + } + + $allowedScopes -contains 'deployment.write' | Should Be $true + Write-TestInfo -Label 'Allowed scopes' -Value @($allowedScopes).Count + + $myTokens = @(ConvertTo-ApiItems -Value (Invoke-Api -Method GET -Path 'tokens/my' -BearerToken $script:token)) + $myTokens.Count | Should BeGreaterThan 0 + Write-TestInfo -Label 'Managed tokens visible' -Value $myTokens.Count + + $services = @(ConvertTo-ApiItems -Value (Invoke-Api -Method GET -Path 'Service' -BearerToken $script:token)) + $services.Count | Should BeGreaterThan 0 + Write-TestInfo -Label 'Services' -Value $services.Count + $service = $services | Select-Object -First 1 + Invoke-Api -Method GET -Path ("Service/{0}" -f $service.id) -BearerToken $script:token | Should Not BeNullOrEmpty + Invoke-Api -Method GET -Path ("Service/{0}/RoleDefinitions" -f $service.id) -BearerToken $script:token | Out-Null + + $templateCategories = @(ConvertTo-ApiItems -Value (Invoke-Api -Method GET -Path 'TemplateCategory' -BearerToken $script:token)) + $templateCategories.Count | Should BeGreaterThan 0 + Write-TestInfo -Label 'Template categories' -Value $templateCategories.Count + Invoke-Api -Method GET -Path ("TemplateCategory/{0}" -f $templateCategories[0].id) -BearerToken $script:token | Should Not BeNullOrEmpty + + $deploymentRules = @(ConvertTo-ApiItems -Value (Invoke-Api -Method GET -Path 'deployment-rules' -BearerToken $script:token)) + $deploymentRules.Count | Should BeGreaterThan 0 + Write-TestInfo -Label 'Deployment rules' -Value $deploymentRules.Count + Invoke-Api -Method GET -Path ("deployment-rules/{0}" -f $deploymentRules[0].id) -BearerToken $script:token | Should Not BeNullOrEmpty + + $configurationDefinitions = @(ConvertTo-ApiItems -Value (Invoke-Api -Method GET -Path 'configuration-definitions' -BearerToken $script:token)) + $configurationDefinitions.Count | Should BeGreaterThan 0 + Write-TestInfo -Label 'Configuration definitions' -Value $configurationDefinitions.Count + $configurationDefinition = $configurationDefinitions | Select-Object -First 1 + Invoke-Api -Method GET -Path ("configuration-definitions/{0}" -f $configurationDefinition.id) -BearerToken $script:token | Should Not BeNullOrEmpty + Invoke-Api -Method GET -Path ("configuration-definitions/{0}/values" -f $configurationDefinition.id) -BearerToken $script:token | Out-Null + + Write-TestSection -Name 'credential secret' + $script:credentialSecretId = ConvertTo-GuidValue -Value (Invoke-Api -Method POST -Path 'credential-secrets' -BearerToken $script:token -Body @{ + name = $script:credentialSecretName + userName = "CONTOSO\svc-pester-$script:testRunId" + secretValue = 'PesterSecret!' + secretType = 'Credential' + metadataJson = (@{ source = 'Api.Workflow.Tests.ps1'; runId = $script:testRunId } | ConvertTo-Json -Compress) + isEnabled = $true + }) + Write-TestInfo -Label 'Created credential secret' -Value $script:credentialSecretId + Invoke-Api -Method GET -Path ("credential-secrets/{0}" -f $script:credentialSecretId) -BearerToken $script:token | Should Not BeNullOrEmpty + $resolvedSecret = Invoke-Api -Method GET -Path ("credential-secrets/resolve?name={0}" -f [uri]::EscapeDataString($script:credentialSecretName)) -BearerToken $script:token + $resolvedSecret.userName | Should Be "CONTOSO\svc-pester-$script:testRunId" + Write-TestInfo -Label 'Resolved credential user' -Value $resolvedSecret.userName + + Write-TestSection -Name 'environment and domains' + Invoke-Api -Method POST -Path 'Environment' -BearerToken $script:token -Body @{ + name = $script:environmentName + environmentType = 'Test' + hostingType = 'OnPrem' + providerType = 'Pester' + metadataJson = (@{ source = 'Api.Workflow.Tests.ps1'; runId = $script:testRunId } | ConvertTo-Json -Compress) + } | Out-Null + + $environment = Find-ByName -Items @(ConvertTo-ApiItems -Value (Invoke-Api -Method GET -Path 'Environment' -BearerToken $script:token)) -Name $script:environmentName + $environment | Should Not BeNullOrEmpty + $script:environmentId = ConvertTo-GuidValue -Value $environment.id + Write-TestInfo -Label 'Created environment' -Value ("{0} ({1})" -f $script:environmentName, $script:environmentId) + + $script:configurationValueId = ConvertTo-GuidValue -Value (Invoke-Api -Method POST -Path 'configuration-values' -BearerToken $script:token -Body @{ + configurationDefinitionId = [string](ConvertTo-GuidValue -Value $configurationDefinition.id) + scopeType = 'Environment' + scopeId = [string]$script:environmentId + valueSourceType = 'Static' + valueJson = (@{ value = "Pester-$script:testRunId" } | ConvertTo-Json -Compress) + sortOrder = 999 + }) + @(ConvertTo-ApiItems -Value (Invoke-Api -Method GET -Path ("configuration-values?scopeType=Environment&scopeId={0}" -f $script:environmentId) -BearerToken $script:token)).Count | Should BeGreaterThan 0 + Write-TestInfo -Label 'Created configuration value' -Value $script:configurationValueId + + $domainId1 = Invoke-Api -Method POST -Path 'Domain' -BearerToken $script:token -Body @{ + name = $script:domainName1 + fqdn = "pester-a-$script:testRunId.contoso.local" + netBIOS = "PSTA$($script:testRunId.Substring(0, 4))".ToUpper() + } + + $domainId2 = Invoke-Api -Method POST -Path 'Domain' -BearerToken $script:token -Body @{ + name = $script:domainName2 + fqdn = "pester-b-$script:testRunId.contoso.local" + netBIOS = "PSTB$($script:testRunId.Substring(0, 4))".ToUpper() + } + + $script:domainIds = @( + (ConvertTo-GuidValue -Value $domainId1), + (ConvertTo-GuidValue -Value $domainId2) + ) + Write-TestInfo -Label 'Created domains' -Value ($script:domainIds -join ', ') + + foreach ($domainId in $script:domainIds) { + Invoke-Api -Method POST -Path ("Domain/{0}/Environment/{1}" -f $domainId, $script:environmentId) -BearerToken $script:token | Out-Null + } + Write-TestInfo -Label 'Linked domains to environment' -Value $script:domainIds.Count + + Write-TestSection -Name 'targets' + $targetDefinitions = @( + @{ name = $script:targetName1; domainId = $script:domainIds[0]; role = 'WebFrontEnd'; order = 10 }, + @{ name = $script:targetName2; domainId = $script:domainIds[0]; role = 'Application'; order = 20 }, + @{ name = $script:targetName3; domainId = $script:domainIds[1]; role = 'Search'; order = 30 } + ) + + foreach ($targetDefinition in $targetDefinitions) { + $targetId = Invoke-Api -Method POST -Path 'Target' -BearerToken $script:token -Body @{ + domainID = $targetDefinition.domainId + name = $targetDefinition.name + targetType = 'VirtualMachine' + providerType = 'OnPrem' + externalId = $targetDefinition.name + metadataJson = (@{ source = 'Api.Workflow.Tests.ps1'; role = $targetDefinition.role } | ConvertTo-Json -Compress) + } + + $script:targetIds += ConvertTo-GuidValue -Value $targetId + Write-TestInfo -Label 'Created target' -Value ("{0} / {1} ({2})" -f $targetDefinition.name, $targetDefinition.role, $targetId) + } + + @($script:targetIds).Count | Should Be 3 + + Write-TestSection -Name 'template selection' + $templates = @(ConvertTo-ApiItems -Value (Invoke-Api -Method GET -Path 'Template' -BearerToken $script:token)) + $onPremServiceIds = @( + $services | + Where-Object { -not $_.isCloudService } | + ForEach-Object { [string]$_.id } + ) + $onPremCategoryIds = @( + $templateCategories | + Where-Object { $onPremServiceIds -contains [string]$_.serviceId } | + ForEach-Object { [string]$_.id } + ) + $selectedTemplates = @( + $templates | + Where-Object { $onPremCategoryIds -contains [string]$_.templateCategoryId } | + Select-Object -First 2 + ) + @($selectedTemplates).Count | Should BeGreaterThan 0 + Write-TestInfo -Label 'Available templates' -Value $templates.Count + Write-TestInfo -Label 'Selected templates' -Value (($selectedTemplates | ForEach-Object { $_.name }) -join ', ') + + $templateSelections = @() + $sortOrder = 10 + foreach ($template in $selectedTemplates) { + $versions = @(ConvertTo-ApiItems -Value (Invoke-Api -Method GET -Path ("Template/{0}/Versions" -f $template.id) -BearerToken $script:token)) + $version = $versions | Select-Object -First 1 + $version | Should Not BeNullOrEmpty + + $templateSelections += @{ + templateVersionId = [string](ConvertTo-GuidValue -Value $version.id) + templateRole = 'Service' + sortOrder = $sortOrder + alias = "Pester-$sortOrder" + } + + Write-TestInfo -Label 'Pinned template version' -Value ("{0} -> {1}" -f $template.name, $version.id) + $sortOrder += 10 + } + + $targetAssignments = @() + foreach ($targetDefinition in $targetDefinitions) { + $targetId = $script:targetIds[$targetDefinitions.IndexOf($targetDefinition)] + $targetAssignments += @{ + targetId = [string]$targetId + roleKey = $targetDefinition.role + sortOrder = $targetDefinition.order + nodeDataJson = (@{ nodeName = $targetDefinition.name; pester = $true } | ConvertTo-Json -Compress) + } + } + + Write-TestSection -Name 'deployment batch' + $script:deploymentBatchId = ConvertTo-GuidValue -Value (Invoke-Api -Method POST -Path 'deployment-batches' -BearerToken $script:token -Body @{ + status = 'Pending' + targetIds = @() + templateSelections = $templateSelections + targetAssignments = $targetAssignments + }) + + $script:deploymentBatchId | Should Not BeNullOrEmpty + Write-TestInfo -Label 'Created deployment batch' -Value $script:deploymentBatchId + + $composition = Invoke-Api -Method GET -Path ("deployment-batches/{0}/composition" -f $script:deploymentBatchId) -BearerToken $script:token + @($composition.templateSelections).Count | Should Be @($templateSelections).Count + + $composition = Invoke-Api -Method GET -Path ("deployment-batches/{0}/composition" -f $script:deploymentBatchId) -BearerToken $script:token + @($composition.targetAssignments).Count | Should Be 3 + $script:targetAssignmentIds = @($composition.targetAssignments | ForEach-Object { ConvertTo-GuidValue -Value $_.id }) + Write-TestInfo -Label 'Composition template selections' -Value @($composition.templateSelections).Count + Write-TestInfo -Label 'Composition target assignments' -Value @($composition.targetAssignments).Count + + $deployments = @(ConvertTo-ApiItems -Value (Invoke-Api -Method GET -Path 'Deployment' -BearerToken $script:token) | Where-Object { [string]$_.deploymentGroupId -eq [string]$script:deploymentBatchId }) + $deployments.Count | Should Be 3 + Write-TestInfo -Label 'Deployment rows' -Value $deployments.Count + Invoke-Api -Method GET -Path ("Deployment/{0}" -f $deployments[0].id) -BearerToken $script:token | Should Not BeNullOrEmpty + + Invoke-Api -Method GET -Path ("deployment-artifacts?deploymentGroupId={0}" -f $script:deploymentBatchId) -BearerToken $script:token | Out-Null + Invoke-Api -Method GET -Path 'Deployment/QueueJobs' -BearerToken $script:token | Out-Null + Write-TestInfo -Label 'Artifact and queue endpoints' -Value 'reachable' + } + } + finally { + if ($script:token) { + Write-TestSection -Name 'cleanup' + if ($script:credentialSecretId) { + Invoke-Api -Method DELETE -Path ("credential-secrets/{0}" -f $script:credentialSecretId) -BearerToken $script:token -AllowNotFound | Out-Null + Write-TestInfo -Label 'Deleted credential secret' -Value $script:credentialSecretId + } + + if ($script:configurationValueId) { + Invoke-Api -Method DELETE -Path ("configuration-values/{0}" -f $script:configurationValueId) -BearerToken $script:token -AllowNotFound | Out-Null + Write-TestInfo -Label 'Deleted configuration value' -Value $script:configurationValueId + } + + foreach ($assignmentId in @($script:targetAssignmentIds)) { + if ($script:deploymentBatchId) { + Invoke-Api -Method DELETE -Path ("deployment-batches/{0}/target-assignments/{1}" -f $script:deploymentBatchId, $assignmentId) -BearerToken $script:token -AllowNotFound | Out-Null + } + } + + if ($script:deploymentBatchId) { + Invoke-Api -Method DELETE -Path ("deployment-batches/{0}" -f $script:deploymentBatchId) -BearerToken $script:token -AllowNotFound | Out-Null + Write-TestInfo -Label 'Deleted deployment batch' -Value $script:deploymentBatchId + } + + foreach ($targetId in @($script:targetIds)) { + Invoke-Api -Method DELETE -Path ("Target/{0}" -f $targetId) -BearerToken $script:token -AllowNotFound | Out-Null + } + if (@($script:targetIds).Count -gt 0) { + Write-TestInfo -Label 'Deleted targets' -Value @($script:targetIds).Count + } + + foreach ($domainId in @($script:domainIds)) { + if ($script:environmentId) { + Invoke-Api -Method DELETE -Path ("Domain/{0}/Environment/{1}" -f $domainId, $script:environmentId) -BearerToken $script:token -AllowNotFound | Out-Null + } + + Invoke-Api -Method DELETE -Path ("Domain/{0}" -f $domainId) -BearerToken $script:token -AllowNotFound | Out-Null + } + if (@($script:domainIds).Count -gt 0) { + Write-TestInfo -Label 'Deleted domains' -Value @($script:domainIds).Count + } + + if ($script:environmentId) { + Invoke-Api -Method DELETE -Path ("Environment/{0}" -f $script:environmentId) -BearerToken $script:token -AllowNotFound | Out-Null + Write-TestInfo -Label 'Deleted environment' -Value $script:environmentId + } + } + } +} diff --git a/.tests/OnPremClientCredentials.Api.Tests.ps1 b/.tests/OnPremClientCredentials.Api.Tests.ps1 index a2213fe..bbb8bf0 100644 --- a/.tests/OnPremClientCredentials.Api.Tests.ps1 +++ b/.tests/OnPremClientCredentials.Api.Tests.ps1 @@ -66,25 +66,69 @@ function Invoke-TestApi { } } +function Invoke-TestApiExpectFailure { + param( + [ValidateSet('GET', 'POST', 'DELETE')] + [string]$Method, + + [string]$Path, + + [object]$Body, + + [string]$BearerToken + ) + + $uri = ('{0}/{1}' -f $ApiBaseUrl.TrimEnd('/'), $Path.TrimStart('/')) + $parameters = @{ + Method = $Method + Uri = $uri + TimeoutSec = $ApiTimeoutSec + ErrorAction = 'Stop' + } + + if ($Body) { + $parameters.Body = ($Body | ConvertTo-Json -Depth 10) + $parameters.ContentType = 'application/json' + } + + if ($BearerToken) { + $parameters.Headers = @{ + Authorization = "Bearer $BearerToken" + } + } + + try { + Invoke-RestMethod @parameters | Out-Null + throw "API request was expected to fail but succeeded. Method=[$Method], Uri=[$uri]." + } + catch { + if ($_.Exception.Response -and $_.Exception.Response.StatusCode) { + return [int]$_.Exception.Response.StatusCode + } + + throw + } +} + Describe 'On-prem client credentials API authentication' { It 'issues a bearer token for the seeded demo worker client' { $token = Invoke-TestApi -Method POST -Path 'auth/token' -Body @{ clientId = $ClientId clientSecret = $ClientSecret - scope = 'deployment.read template.read' + scope = 'configuration.read' } $token.accessToken | Should Not BeNullOrEmpty $token.tokenType | Should Be 'Bearer' $token.expiresIn | Should BeGreaterThan 0 - $token.scope | Should Be 'deployment.read template.read' + $token.scope | Should Be 'configuration.read' } It 'allows bearer-token API calls without Windows authentication' { $token = Invoke-TestApi -Method POST -Path 'auth/token' -Body @{ clientId = $ClientId clientSecret = $ClientSecret - scope = 'deployment.read template.read' + scope = 'configuration.read' } $definitions = @(Invoke-TestApi -Method GET -Path 'configuration-definitions?kind=Parameter' -BearerToken $token.accessToken) @@ -93,6 +137,18 @@ Describe 'On-prem client credentials API authentication' { @($definitions | Where-Object { $_.kind -ne 'Parameter' }).Count | Should Be 0 } + It 'rejects bearer-token API calls without the required scope' { + $token = Invoke-TestApi -Method POST -Path 'auth/token' -Body @{ + clientId = $ClientId + clientSecret = $ClientSecret + scope = 'deployment.read' + } + + $statusCode = Invoke-TestApiExpectFailure -Method GET -Path 'configuration-definitions?kind=Parameter' -BearerToken $token.accessToken + + @(401, 403) -contains $statusCode | Should Be $true + } + It 'creates, lists and revokes managed tokens through the token API' { $adminToken = Invoke-TestApi -Method POST -Path 'auth/token' -Body @{ clientId = $ClientId diff --git a/Authorization/ApiPolicies.cs b/Authorization/ApiPolicies.cs new file mode 100644 index 0000000..0c04aac --- /dev/null +++ b/Authorization/ApiPolicies.cs @@ -0,0 +1,19 @@ +namespace Microsoft.SelfService.Portal.Core.API.Authorization +{ + public static class ApiPolicies + { + public const string ConfigurationRead = "ConfigurationRead"; + public const string ConfigurationWrite = "ConfigurationWrite"; + public const string CredentialRead = "CredentialRead"; + public const string CredentialWrite = "CredentialWrite"; + public const string CredentialResolve = "CredentialResolve"; + public const string DeploymentRead = "DeploymentRead"; + public const string DeploymentWrite = "DeploymentWrite"; + public const string QueueRead = "QueueRead"; + public const string QueueProcess = "QueueProcess"; + public const string TemplateRead = "TemplateRead"; + public const string TemplateWrite = "TemplateWrite"; + public const string TokenManage = "TokenManage"; + public const string TokenAdmin = "TokenAdmin"; + } +} diff --git a/Authorization/ApiScopes.cs b/Authorization/ApiScopes.cs new file mode 100644 index 0000000..dc1688c --- /dev/null +++ b/Authorization/ApiScopes.cs @@ -0,0 +1,19 @@ +namespace Microsoft.SelfService.Portal.Core.API.Authorization +{ + public static class ApiScopes + { + public const string ConfigurationRead = "configuration.read"; + public const string ConfigurationWrite = "configuration.write"; + public const string CredentialRead = "credential.read"; + public const string CredentialWrite = "credential.write"; + public const string CredentialResolve = "credential.resolve"; + public const string DeploymentRead = "deployment.read"; + public const string DeploymentWrite = "deployment.write"; + public const string QueueRead = "queue.read"; + public const string QueueProcess = "queue.process"; + public const string TemplateRead = "template.read"; + public const string TemplateWrite = "template.write"; + public const string TokenManage = "token.manage"; + public const string TokenAdmin = "token.admin"; + } +} diff --git a/Authorization/AuthorizationServiceCollectionExtensions.cs b/Authorization/AuthorizationServiceCollectionExtensions.cs new file mode 100644 index 0000000..5b7af89 --- /dev/null +++ b/Authorization/AuthorizationServiceCollectionExtensions.cs @@ -0,0 +1,50 @@ +using Microsoft.AspNetCore.Authorization; + +namespace Microsoft.SelfService.Portal.Core.API.Authorization +{ + public static class AuthorizationServiceCollectionExtensions + { + public static IServiceCollection AddSelfServicePortalAuthorization(this IServiceCollection services) + { + services.AddAuthorization(options => + { + options.FallbackPolicy = options.DefaultPolicy; + + AddScopePolicy(options, ApiPolicies.ConfigurationRead, ApiScopes.ConfigurationRead, ApiScopes.ConfigurationWrite); + AddScopePolicy(options, ApiPolicies.ConfigurationWrite, ApiScopes.ConfigurationWrite); + AddScopePolicy(options, ApiPolicies.CredentialRead, ApiScopes.CredentialRead, ApiScopes.CredentialWrite, ApiScopes.CredentialResolve); + AddScopePolicy(options, ApiPolicies.CredentialWrite, ApiScopes.CredentialWrite); + AddScopePolicy(options, ApiPolicies.CredentialResolve, ApiScopes.CredentialResolve); + AddScopePolicy(options, ApiPolicies.DeploymentRead, ApiScopes.DeploymentRead, ApiScopes.DeploymentWrite); + AddScopePolicy(options, ApiPolicies.DeploymentWrite, ApiScopes.DeploymentWrite); + AddScopePolicy(options, ApiPolicies.QueueRead, ApiScopes.QueueRead, ApiScopes.QueueProcess); + AddScopePolicy(options, ApiPolicies.QueueProcess, ApiScopes.QueueProcess); + AddScopePolicy(options, ApiPolicies.TemplateRead, ApiScopes.TemplateRead, ApiScopes.TemplateWrite); + AddScopePolicy(options, ApiPolicies.TemplateWrite, ApiScopes.TemplateWrite); + AddScopePolicy(options, ApiPolicies.TokenManage, ApiScopes.TokenManage, ApiScopes.TokenAdmin); + AddScopePolicy(options, ApiPolicies.TokenAdmin, ApiScopes.TokenAdmin); + }); + + return services; + } + + private static void AddScopePolicy(AuthorizationOptions options, string policyName, params string[] acceptedScopes) + { + options.AddPolicy(policyName, policy => policy.RequireAssertion(context => + { + if (context.User.Identity?.IsAuthenticated != true) + { + return false; + } + + var tokenScopes = context.User.FindAll("scope").Select(claim => claim.Value).ToList(); + if (tokenScopes.Count == 0) + { + return true; + } + + return acceptedScopes.Any(scope => tokenScopes.Contains(scope, StringComparer.OrdinalIgnoreCase)); + })); + } + } +} diff --git a/Context/DemoData.cs b/Context/DemoData.cs index 55f31d6..13ec1e6 100644 --- a/Context/DemoData.cs +++ b/Context/DemoData.cs @@ -364,7 +364,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Context ClientId = "ssp-demo-worker", Name = "Demo Worker Client", SecretHash = ApiClientSecretHasher.HashSecretForDemoData("DemoOnly-DoNotUseInProduction!", "ssp-demo-worker"), - ScopesJson = "[\"deployment.read\",\"deployment.write\",\"queue.process\",\"template.read\",\"credential.resolve\",\"token.manage\",\"token.admin\"]", + ScopesJson = "[\"configuration.read\",\"configuration.write\",\"credential.read\",\"credential.write\",\"credential.resolve\",\"deployment.read\",\"deployment.write\",\"queue.read\",\"queue.process\",\"template.read\",\"template.write\",\"token.manage\",\"token.admin\"]", IsEnabled = true }) ]; diff --git a/Controllers/ApiTokenController.cs b/Controllers/ApiTokenController.cs index 4b1b325..3dc8012 100644 --- a/Controllers/ApiTokenController.cs +++ b/Controllers/ApiTokenController.cs @@ -1,6 +1,7 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; +using Microsoft.SelfService.Portal.Core.API.Authorization; using Microsoft.SelfService.Portal.Core.API.Context; using Microsoft.SelfService.Portal.Core.API.Dto.Auth; using Microsoft.SelfService.Portal.Core.API.Models; @@ -24,7 +25,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers } [HttpGet("my")] - [Authorize(Policy = "TokenManage")] + [Authorize(Policy = ApiPolicies.TokenManage)] [ProducesResponseType(200, Type = typeof(IEnumerable))] public IActionResult GetMyTokens() { @@ -41,7 +42,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers } [HttpPost("my")] - [Authorize(Policy = "TokenManage")] + [Authorize(Policy = ApiPolicies.TokenManage)] [ProducesResponseType(200, Type = typeof(CreateManagedTokenResponseDto))] [ProducesResponseType(400)] public IActionResult CreateMyToken([FromBody] CreateManagedTokenRequestDto request) @@ -111,7 +112,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers } [HttpDelete("my/{id}")] - [Authorize(Policy = "TokenManage")] + [Authorize(Policy = ApiPolicies.TokenManage)] [ProducesResponseType(200, Type = typeof(GetManagedTokenDto))] [ProducesResponseType(404)] public IActionResult RevokeMyToken(Guid id) @@ -135,7 +136,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers } [HttpGet("admin")] - [Authorize(Policy = "TokenAdmin")] + [Authorize(Policy = ApiPolicies.TokenAdmin)] [ProducesResponseType(200, Type = typeof(IEnumerable))] public IActionResult GetAllTokens() { @@ -148,7 +149,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers } [HttpDelete("admin/{id}")] - [Authorize(Policy = "TokenAdmin")] + [Authorize(Policy = ApiPolicies.TokenAdmin)] [ProducesResponseType(200, Type = typeof(GetManagedTokenDto))] [ProducesResponseType(404)] public IActionResult RevokeTokenAsAdmin(Guid id) @@ -166,7 +167,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers } [HttpGet("scopes")] - [Authorize(Policy = "TokenManage")] + [Authorize(Policy = ApiPolicies.TokenManage)] [ProducesResponseType(200, Type = typeof(IEnumerable))] public IActionResult GetAllowedScopes() { diff --git a/Controllers/ConfigurationDefinitionController.cs b/Controllers/ConfigurationDefinitionController.cs index 48b6b34..b5e8373 100644 --- a/Controllers/ConfigurationDefinitionController.cs +++ b/Controllers/ConfigurationDefinitionController.cs @@ -1,6 +1,8 @@ using AutoMapper; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; +using Microsoft.SelfService.Portal.Core.API.Authorization; using Microsoft.SelfService.Portal.Core.API.Context; using Microsoft.SelfService.Portal.Core.API.Dto.ConfigurationDefinition.Add; using Microsoft.SelfService.Portal.Core.API.Dto.ConfigurationDefinition.Edit; @@ -13,6 +15,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers { [Route("api/configuration-definitions")] [ApiController] + [Authorize(Policy = ApiPolicies.ConfigurationRead)] public class ConfigurationDefinitionController : Controller { private readonly DataContext _context; @@ -84,6 +87,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers } [HttpPost] + [Authorize(Policy = ApiPolicies.ConfigurationWrite)] [ProducesResponseType(200, Type = typeof(Guid))] [ProducesResponseType(400)] [ProducesResponseType(422)] @@ -126,6 +130,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers } [HttpPut("{id}")] + [Authorize(Policy = ApiPolicies.ConfigurationWrite)] [ProducesResponseType(204)] [ProducesResponseType(400)] [ProducesResponseType(404)] @@ -173,6 +178,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers } [HttpDelete("{id}")] + [Authorize(Policy = ApiPolicies.ConfigurationWrite)] [ProducesResponseType(204)] [ProducesResponseType(404)] [ProducesResponseType(409)] diff --git a/Controllers/ConfigurationValueController.cs b/Controllers/ConfigurationValueController.cs index fdea462..da6a19e 100644 --- a/Controllers/ConfigurationValueController.cs +++ b/Controllers/ConfigurationValueController.cs @@ -1,6 +1,8 @@ using AutoMapper; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; +using Microsoft.SelfService.Portal.Core.API.Authorization; using Microsoft.SelfService.Portal.Core.API.Context; using Microsoft.SelfService.Portal.Core.API.Dto.ConfigurationValue.Add; using Microsoft.SelfService.Portal.Core.API.Dto.ConfigurationValue.Get; @@ -11,6 +13,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers { [Route("api/configuration-values")] [ApiController] + [Authorize(Policy = ApiPolicies.ConfigurationRead)] public class ConfigurationValueController : Controller { private readonly DataContext _context; @@ -50,6 +53,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers } [HttpPost] + [Authorize(Policy = ApiPolicies.ConfigurationWrite)] [ProducesResponseType(200, Type = typeof(Guid))] [ProducesResponseType(400)] public IActionResult AddConfigurationValue([FromBody] AddConfigurationValueDto configurationValue) @@ -89,6 +93,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers } [HttpDelete("{id}")] + [Authorize(Policy = ApiPolicies.ConfigurationWrite)] [ProducesResponseType(204)] [ProducesResponseType(404)] public IActionResult DeleteConfigurationValue(Guid id) diff --git a/Controllers/CredentialSecretController.cs b/Controllers/CredentialSecretController.cs index 00a9b88..71656dd 100644 --- a/Controllers/CredentialSecretController.cs +++ b/Controllers/CredentialSecretController.cs @@ -1,6 +1,8 @@ using AutoMapper; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; +using Microsoft.SelfService.Portal.Core.API.Authorization; using Microsoft.SelfService.Portal.Core.API.Context; using Microsoft.SelfService.Portal.Core.API.Dto.CredentialSecret.Add; using Microsoft.SelfService.Portal.Core.API.Dto.CredentialSecret.Get; @@ -11,6 +13,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers { [Route("api/credential-secrets")] [ApiController] + [Authorize(Policy = ApiPolicies.CredentialRead)] public class CredentialSecretController : Controller { private readonly DataContext _context; @@ -50,6 +53,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers } [HttpGet("resolve")] + [Authorize(Policy = ApiPolicies.CredentialResolve)] [ProducesResponseType(200, Type = typeof(GetCredentialSecretValueDto))] [ProducesResponseType(404)] public IActionResult ResolveCredentialSecret([FromQuery] string name) @@ -65,6 +69,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers } [HttpPost] + [Authorize(Policy = ApiPolicies.CredentialWrite)] [ProducesResponseType(200, Type = typeof(Guid))] [ProducesResponseType(400)] public IActionResult AddCredentialSecret([FromBody] AddCredentialSecretDto credentialSecret) @@ -103,6 +108,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers } [HttpPut("{id}")] + [Authorize(Policy = ApiPolicies.CredentialWrite)] [ProducesResponseType(204)] [ProducesResponseType(404)] public IActionResult UpdateCredentialSecret(Guid id, [FromBody] AddCredentialSecretDto credentialSecret) @@ -126,6 +132,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers } [HttpDelete("{id}")] + [Authorize(Policy = ApiPolicies.CredentialWrite)] [ProducesResponseType(204)] [ProducesResponseType(404)] public IActionResult DeleteCredentialSecret(Guid id) diff --git a/Controllers/DeploymentArtifactController.cs b/Controllers/DeploymentArtifactController.cs index 7e4c861..2c6acd0 100644 --- a/Controllers/DeploymentArtifactController.cs +++ b/Controllers/DeploymentArtifactController.cs @@ -1,6 +1,8 @@ using AutoMapper; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; +using Microsoft.SelfService.Portal.Core.API.Authorization; using Microsoft.SelfService.Portal.Core.API.Context; using Microsoft.SelfService.Portal.Core.API.Dto.DeploymentArtifact.Add; using Microsoft.SelfService.Portal.Core.API.Dto.DeploymentArtifact.Get; @@ -12,6 +14,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers { [Route("api/deployment-artifacts")] [ApiController] + [Authorize(Policy = ApiPolicies.DeploymentRead)] public class DeploymentArtifactController : Controller { private readonly DataContext _context; @@ -60,6 +63,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers } [HttpPost] + [Authorize(Policy = ApiPolicies.DeploymentWrite)] [ProducesResponseType(200, Type = typeof(Guid))] [ProducesResponseType(400)] public IActionResult AddDeploymentArtifact([FromBody] AddDeploymentArtifactDto deploymentArtifact) @@ -120,6 +124,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers } [HttpPost("{id}/stale-check")] + [Authorize(Policy = ApiPolicies.DeploymentWrite)] [ProducesResponseType(200, Type = typeof(GetDeploymentArtifactDto))] [ProducesResponseType(404)] public IActionResult CheckDeploymentArtifactStale(Guid id) diff --git a/Controllers/DeploymentBatchController.cs b/Controllers/DeploymentBatchController.cs index 7b68a65..97b4387 100644 --- a/Controllers/DeploymentBatchController.cs +++ b/Controllers/DeploymentBatchController.cs @@ -1,6 +1,8 @@ using AutoMapper; using Microsoft.EntityFrameworkCore; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; +using Microsoft.SelfService.Portal.Core.API.Authorization; using Microsoft.SelfService.Portal.Core.API.Context; using Microsoft.SelfService.Portal.Core.API.Dto.DeploymentBatch.Add; using Microsoft.SelfService.Portal.Core.API.Dto.DeploymentBatch.Edit; @@ -15,6 +17,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers { [Route("api/deployment-batches")] [ApiController] + [Authorize(Policy = ApiPolicies.DeploymentRead)] public class DeploymentBatchController : Controller { private readonly IDeploymentBatchInterface _deploymentBatchInterface; @@ -82,6 +85,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers } [HttpPost] + [Authorize(Policy = ApiPolicies.DeploymentWrite)] [ProducesResponseType(204)] [ProducesResponseType(400)] public IActionResult AddDeploymentBatch([FromBody] AddDeploymentBatchDto deploymentBatch) @@ -118,6 +122,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers } [HttpDelete("{id}")] + [Authorize(Policy = ApiPolicies.DeploymentWrite)] [ProducesResponseType(204)] [ProducesResponseType(400)] [ProducesResponseType(404)] @@ -144,6 +149,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers } [HttpPut("{id}")] + [Authorize(Policy = ApiPolicies.DeploymentWrite)] [ProducesResponseType(204)] [ProducesResponseType(400)] [ProducesResponseType(404)] @@ -182,6 +188,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers } [HttpPost("{id}/template-selections")] + [Authorize(Policy = ApiPolicies.DeploymentWrite)] [ProducesResponseType(200, Type = typeof(Guid))] [ProducesResponseType(400)] [ProducesResponseType(404)] @@ -233,6 +240,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers } [HttpDelete("{id}/template-selections/{selectionId}")] + [Authorize(Policy = ApiPolicies.DeploymentWrite)] [ProducesResponseType(204)] [ProducesResponseType(404)] public IActionResult DeleteTemplateSelection(Guid id, Guid selectionId) @@ -250,6 +258,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers } [HttpPost("{id}/parameter-values")] + [Authorize(Policy = ApiPolicies.DeploymentWrite)] [ProducesResponseType(200, Type = typeof(Guid))] [ProducesResponseType(400)] [ProducesResponseType(404)] @@ -299,6 +308,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers } [HttpDelete("{id}/parameter-values/{parameterValueId}")] + [Authorize(Policy = ApiPolicies.DeploymentWrite)] [ProducesResponseType(204)] [ProducesResponseType(404)] public IActionResult DeleteParameterValue(Guid id, Guid parameterValueId) @@ -316,6 +326,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers } [HttpPost("{id}/target-assignments")] + [Authorize(Policy = ApiPolicies.DeploymentWrite)] [ProducesResponseType(200, Type = typeof(Guid))] [ProducesResponseType(400)] [ProducesResponseType(404)] @@ -367,6 +378,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers } [HttpDelete("{id}/target-assignments/{targetAssignmentId}")] + [Authorize(Policy = ApiPolicies.DeploymentWrite)] [ProducesResponseType(204)] [ProducesResponseType(404)] public IActionResult DeleteTargetAssignment(Guid id, Guid targetAssignmentId) diff --git a/Controllers/DeploymentController.cs b/Controllers/DeploymentController.cs index beffc81..604bc20 100644 --- a/Controllers/DeploymentController.cs +++ b/Controllers/DeploymentController.cs @@ -1,5 +1,7 @@ using AutoMapper; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; +using Microsoft.SelfService.Portal.Core.API.Authorization; using Microsoft.SelfService.Portal.Core.API.Dto.Deployment.Add; using Microsoft.SelfService.Portal.Core.API.Dto.Deployment.Get; using Microsoft.SelfService.Portal.Core.API.Dto.Deployment.Edit; @@ -13,6 +15,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers { [Route("api/[controller]")] [ApiController] + [Authorize(Policy = ApiPolicies.DeploymentRead)] public class DeploymentController : Controller { private readonly IDeploymentInterface _deploymentInterface; @@ -62,6 +65,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers } [HttpPost] + [Authorize(Policy = ApiPolicies.DeploymentWrite)] [ProducesResponseType(204)] [ProducesResponseType(400)] public IActionResult AddDeploymentById([FromBody] AddDeploymentDto deployment) @@ -93,6 +97,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers } [HttpPost("Request")] + [Authorize(Policy = ApiPolicies.DeploymentWrite)] [ProducesResponseType(200)] [ProducesResponseType(400)] public IActionResult AddDeploymentRequest([FromBody] AddDeploymentRequestDto request) @@ -234,6 +239,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers } [HttpPost("QueueJobs/{Id}/Retry")] + [Authorize(Policy = ApiPolicies.QueueProcess)] [ProducesResponseType(204)] [ProducesResponseType(404)] public IActionResult RetryQueueJob(Guid Id) @@ -245,6 +251,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers } [HttpPost("QueueJobs/Steps/{stepId}/Approve")] + [Authorize(Policy = ApiPolicies.QueueProcess)] [ProducesResponseType(204)] [ProducesResponseType(404)] public IActionResult ApproveQueueJobStep(Guid stepId, [FromBody] QueueJobStepApprovalDto? payload) @@ -257,6 +264,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers } [HttpPost("QueueJobs/Steps/{stepId}/Reject")] + [Authorize(Policy = ApiPolicies.QueueProcess)] [ProducesResponseType(204)] [ProducesResponseType(404)] public IActionResult RejectQueueJobStep(Guid stepId, [FromBody] QueueJobStepApprovalDto? payload) @@ -269,6 +277,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers } [HttpDelete("{Id}")] + [Authorize(Policy = ApiPolicies.DeploymentWrite)] [ProducesResponseType(204)] [ProducesResponseType(400)] [ProducesResponseType(404)] @@ -291,6 +300,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers } [HttpDelete("Batch/{deploymentBatchId}/Target/{targetId}")] + [Authorize(Policy = ApiPolicies.DeploymentWrite)] [ProducesResponseType(204)] [ProducesResponseType(400)] [ProducesResponseType(404)] @@ -317,6 +327,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers } [HttpPut("{Id}")] + [Authorize(Policy = ApiPolicies.DeploymentWrite)] [ProducesResponseType(204)] [ProducesResponseType(400)] [ProducesResponseType(404)] diff --git a/Controllers/DeploymentRuleController.cs b/Controllers/DeploymentRuleController.cs index 9603a08..59a99c4 100644 --- a/Controllers/DeploymentRuleController.cs +++ b/Controllers/DeploymentRuleController.cs @@ -1,5 +1,7 @@ -using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; +using Microsoft.SelfService.Portal.Core.API.Authorization; using Microsoft.SelfService.Portal.Core.API.Context; using Microsoft.SelfService.Portal.Core.API.Dto.DeploymentRule.Add; using Microsoft.SelfService.Portal.Core.API.Dto.DeploymentRule.Get; @@ -9,6 +11,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers { [Route("api/deployment-rules")] [ApiController] + [Authorize(Policy = ApiPolicies.DeploymentRead)] public class DeploymentRuleController : Controller { private readonly DataContext _context; @@ -49,6 +52,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers } [HttpPost] + [Authorize(Policy = ApiPolicies.DeploymentWrite)] [ProducesResponseType(200, Type = typeof(Guid))] [ProducesResponseType(400)] public IActionResult AddDeploymentRule([FromBody] AddDeploymentRuleDto deploymentRule) @@ -84,6 +88,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers } [HttpPut("{id}")] + [Authorize(Policy = ApiPolicies.DeploymentWrite)] [ProducesResponseType(204)] [ProducesResponseType(404)] public IActionResult EditDeploymentRule(Guid id, [FromBody] AddDeploymentRuleDto deploymentRule) @@ -123,6 +128,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers } [HttpDelete("{id}")] + [Authorize(Policy = ApiPolicies.DeploymentWrite)] [ProducesResponseType(204)] [ProducesResponseType(404)] public IActionResult DeleteDeploymentRule(Guid id) @@ -181,4 +187,3 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers } } } - diff --git a/Controllers/DomainController.cs b/Controllers/DomainController.cs index b4729b9..9e88eeb 100644 --- a/Controllers/DomainController.cs +++ b/Controllers/DomainController.cs @@ -1,5 +1,7 @@ using AutoMapper; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; +using Microsoft.SelfService.Portal.Core.API.Authorization; using Microsoft.SelfService.Portal.Core.API.Dto.Domain.Add; using Microsoft.SelfService.Portal.Core.API.Dto.Domain.Edit; using Microsoft.SelfService.Portal.Core.API.Dto.Domain.Get; @@ -10,6 +12,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers { [Route("api/[controller]")] [ApiController] + [Authorize(Policy = ApiPolicies.ConfigurationRead)] public class DomainController : Controller { private readonly IDomainInterface _domainInterface; @@ -53,6 +56,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers } [HttpPost] + [Authorize(Policy = ApiPolicies.ConfigurationWrite)] [ProducesResponseType(204)] [ProducesResponseType(400)] public IActionResult AddDomainById([FromBody] AddDomainDto domain) @@ -83,6 +87,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers } [HttpDelete("{Id}")] + [Authorize(Policy = ApiPolicies.ConfigurationWrite)] [ProducesResponseType(204)] [ProducesResponseType(400)] [ProducesResponseType(404)] @@ -105,6 +110,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers } [HttpPut("{Id}")] + [Authorize(Policy = ApiPolicies.ConfigurationWrite)] [ProducesResponseType(204)] [ProducesResponseType(400)] [ProducesResponseType(404)] @@ -149,6 +155,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers } [HttpPost("{DomainId}/Environment/{EnvironmentId}")] + [Authorize(Policy = ApiPolicies.ConfigurationWrite)] [ProducesResponseType(200, Type = typeof(EnvironmentDomainsModel))] [ProducesResponseType(400)] public IActionResult LinkDomainByIdToEnvironment(Guid DomainId, Guid EnvironmentId) @@ -183,6 +190,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers } [HttpDelete("{DomainId}/Environment/{EnvironmentId}")] + [Authorize(Policy = ApiPolicies.ConfigurationWrite)] [ProducesResponseType(200, Type = typeof(EnvironmentDomainsModel))] [ProducesResponseType(400)] public IActionResult UnlinkDomainByIdFromEnvironment(Guid DomainId, Guid EnvironmentId) diff --git a/Controllers/EnvironmentController.cs b/Controllers/EnvironmentController.cs index 5f29d81..edec6a8 100644 --- a/Controllers/EnvironmentController.cs +++ b/Controllers/EnvironmentController.cs @@ -1,5 +1,7 @@ using AutoMapper; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; +using Microsoft.SelfService.Portal.Core.API.Authorization; using Microsoft.SelfService.Portal.Core.API.Dto.Environment.Add; using Microsoft.SelfService.Portal.Core.API.Dto.Environment.Edit; using Microsoft.SelfService.Portal.Core.API.Dto.Environment.Get; @@ -12,6 +14,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers { [Route("api/[controller]")] [ApiController] + [Authorize(Policy = ApiPolicies.ConfigurationRead)] public class EnvironmentController : Controller { private readonly IEnvironmentInterface _environmentInterface; @@ -53,6 +56,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers } [HttpPost] + [Authorize(Policy = ApiPolicies.ConfigurationWrite)] [ProducesResponseType(204)] [ProducesResponseType(400)] public IActionResult AddEnvironmentById([FromBody] AddEnvironmentDto environment) @@ -88,6 +92,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers } [HttpDelete("{Id}")] + [Authorize(Policy = ApiPolicies.ConfigurationWrite)] [ProducesResponseType(204)] [ProducesResponseType(400)] [ProducesResponseType(404)] @@ -110,6 +115,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers } [HttpPut("{Id}")] + [Authorize(Policy = ApiPolicies.ConfigurationWrite)] [ProducesResponseType(204)] [ProducesResponseType(400)] [ProducesResponseType(404)] diff --git a/Controllers/ServiceController.cs b/Controllers/ServiceController.cs index b98d140..ccd4d5e 100644 --- a/Controllers/ServiceController.cs +++ b/Controllers/ServiceController.cs @@ -1,5 +1,7 @@ using AutoMapper; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; +using Microsoft.SelfService.Portal.Core.API.Authorization; using Microsoft.SelfService.Portal.Core.API.Dto.Service.Add; using Microsoft.SelfService.Portal.Core.API.Dto.Service.Edit; using Microsoft.SelfService.Portal.Core.API.Dto.Service.Get; @@ -11,6 +13,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers { [Route("api/[controller]")] [ApiController] + [Authorize(Policy = ApiPolicies.ConfigurationRead)] public class ServiceController : Controller { private readonly IMapper _mapper; @@ -51,6 +54,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers } [HttpPost] + [Authorize(Policy = ApiPolicies.ConfigurationWrite)] [ProducesResponseType(200)] [ProducesResponseType(400)] public IActionResult AddServiceById([FromBody] AddServiceDto service) @@ -79,6 +83,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers } [HttpPut("{Id}")] + [Authorize(Policy = ApiPolicies.ConfigurationWrite)] [ProducesResponseType(204)] [ProducesResponseType(400)] [ProducesResponseType(404)] @@ -106,6 +111,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers } [HttpDelete("{Id}")] + [Authorize(Policy = ApiPolicies.ConfigurationWrite)] [ProducesResponseType(204)] [ProducesResponseType(400)] [ProducesResponseType(404)] @@ -141,6 +147,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers } [HttpPost("{Id}/RoleDefinitions")] + [Authorize(Policy = ApiPolicies.ConfigurationWrite)] [ProducesResponseType(200)] [ProducesResponseType(400)] [ProducesResponseType(404)] @@ -177,6 +184,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers } [HttpPut("{Id}/RoleDefinitions/{RoleDefinitionId}")] + [Authorize(Policy = ApiPolicies.ConfigurationWrite)] [ProducesResponseType(204)] [ProducesResponseType(400)] [ProducesResponseType(404)] @@ -216,6 +224,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers } [HttpDelete("{Id}/RoleDefinitions/{RoleDefinitionId}")] + [Authorize(Policy = ApiPolicies.ConfigurationWrite)] [ProducesResponseType(204)] [ProducesResponseType(404)] public IActionResult DeleteRoleDefinition(Guid Id, Guid RoleDefinitionId) diff --git a/Controllers/TargetController.cs b/Controllers/TargetController.cs index 075b61b..06034ea 100644 --- a/Controllers/TargetController.cs +++ b/Controllers/TargetController.cs @@ -1,5 +1,7 @@ using AutoMapper; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; +using Microsoft.SelfService.Portal.Core.API.Authorization; using Microsoft.SelfService.Portal.Core.API.Dto.Target.Add; using Microsoft.SelfService.Portal.Core.API.Dto.Target.Edit; using Microsoft.SelfService.Portal.Core.API.Dto.Target.Get; @@ -10,6 +12,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers { [Route("api/[controller]")] [ApiController] + [Authorize(Policy = ApiPolicies.ConfigurationRead)] public class TargetController : Controller { private readonly ITargetInterface _targetInterface; @@ -52,6 +55,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers } [HttpPost] + [Authorize(Policy = ApiPolicies.ConfigurationWrite)] [ProducesResponseType(200)] [ProducesResponseType(400)] public IActionResult AddTargetById([FromBody] AddTargetDto target) @@ -86,6 +90,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers } [HttpPut("{Id}")] + [Authorize(Policy = ApiPolicies.ConfigurationWrite)] [ProducesResponseType(204)] [ProducesResponseType(400)] [ProducesResponseType(404)] @@ -120,6 +125,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers } [HttpPost("{Id}/Domain/{domainId}")] + [Authorize(Policy = ApiPolicies.ConfigurationWrite)] [ProducesResponseType(204)] [ProducesResponseType(400)] [ProducesResponseType(404)] @@ -151,6 +157,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers } [HttpDelete("{Id}/Domain")] + [Authorize(Policy = ApiPolicies.ConfigurationWrite)] [ProducesResponseType(204)] [ProducesResponseType(404)] public IActionResult UnlinkTargetFromDomain(Guid Id) @@ -177,6 +184,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers } [HttpDelete("{Id}")] + [Authorize(Policy = ApiPolicies.ConfigurationWrite)] [ProducesResponseType(204)] [ProducesResponseType(400)] [ProducesResponseType(404)] diff --git a/Controllers/TemplateCategoryController.cs b/Controllers/TemplateCategoryController.cs index 05b9083..452ba66 100644 --- a/Controllers/TemplateCategoryController.cs +++ b/Controllers/TemplateCategoryController.cs @@ -1,5 +1,7 @@ using AutoMapper; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; +using Microsoft.SelfService.Portal.Core.API.Authorization; using Microsoft.SelfService.Portal.Core.API.Dto.TemplateCategory.Add; using Microsoft.SelfService.Portal.Core.API.Dto.TemplateCategory.Edit; using Microsoft.SelfService.Portal.Core.API.Dto.TemplateCategory.Get; @@ -10,6 +12,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers { [Route("api/[controller]")] [ApiController] + [Authorize(Policy = ApiPolicies.TemplateRead)] public class TemplateCategoryController : Controller { private readonly IMapper _mapper; @@ -50,6 +53,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers } [HttpPost] + [Authorize(Policy = ApiPolicies.TemplateWrite)] [ProducesResponseType(200)] [ProducesResponseType(400)] public IActionResult AddTemplateCategoryById([FromBody] AddTemplateCategoryDto templateCategory) @@ -78,6 +82,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers } [HttpPut("{Id}")] + [Authorize(Policy = ApiPolicies.TemplateWrite)] [ProducesResponseType(204)] [ProducesResponseType(400)] [ProducesResponseType(404)] @@ -105,6 +110,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers } [HttpDelete("{Id}")] + [Authorize(Policy = ApiPolicies.TemplateWrite)] [ProducesResponseType(204)] [ProducesResponseType(400)] [ProducesResponseType(404)] diff --git a/Controllers/TemplateController.cs b/Controllers/TemplateController.cs index a5b246f..7ff4d9c 100644 --- a/Controllers/TemplateController.cs +++ b/Controllers/TemplateController.cs @@ -1,5 +1,7 @@ using AutoMapper; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; +using Microsoft.SelfService.Portal.Core.API.Authorization; using Microsoft.SelfService.Portal.Core.API.Dto.Template.Add; using Microsoft.SelfService.Portal.Core.API.Dto.Template.Edit; using Microsoft.SelfService.Portal.Core.API.Dto.Template.Get; @@ -16,6 +18,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers { [Route("api/[controller]")] [ApiController] + [Authorize(Policy = ApiPolicies.TemplateRead)] public class TemplateController : Controller { private readonly ITemplateInterface _templateInterface; @@ -61,6 +64,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers } [HttpPost] + [Authorize(Policy = ApiPolicies.TemplateWrite)] [ProducesResponseType(200)] [ProducesResponseType(400)] public IActionResult AddTemplateById([FromBody] AddTemplateDto template) @@ -97,6 +101,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers } [HttpPut("{Id}")] + [Authorize(Policy = ApiPolicies.TemplateWrite)] [ProducesResponseType(204)] [ProducesResponseType(400)] [ProducesResponseType(404)] @@ -139,6 +144,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers } [HttpDelete("{Id}")] + [Authorize(Policy = ApiPolicies.TemplateWrite)] [ProducesResponseType(204)] [ProducesResponseType(400)] [ProducesResponseType(404)] @@ -186,6 +192,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers } [HttpPost("{Id}/Versions")] + [Authorize(Policy = ApiPolicies.TemplateWrite)] [ProducesResponseType(200, Type = typeof(Guid))] [ProducesResponseType(400)] [ProducesResponseType(404)] @@ -262,6 +269,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers } [HttpPost("{Id}/Versions/{VersionId}/Revisions")] + [Authorize(Policy = ApiPolicies.TemplateWrite)] [ProducesResponseType(200, Type = typeof(Guid))] [ProducesResponseType(400)] [ProducesResponseType(404)] @@ -298,6 +306,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers } [HttpPost("{Id}/Versions/{VersionId}/Publish")] + [Authorize(Policy = ApiPolicies.TemplateWrite)] [ProducesResponseType(204)] [ProducesResponseType(404)] public IActionResult PublishTemplateVersion(Guid Id, Guid VersionId) diff --git a/Helper/MappingProfilesHelper.cs b/Helper/MappingProfilesHelper.cs index 62d748c..680b5ef 100644 --- a/Helper/MappingProfilesHelper.cs +++ b/Helper/MappingProfilesHelper.cs @@ -160,6 +160,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Helper /** Credential Secret Model **/ CreateMap(); + CreateMap(); CreateMap(); /** Service Model **/ diff --git a/Migrations/20260709171904_AddCentralizedAuthorizationScopes.Designer.cs b/Migrations/20260709171904_AddCentralizedAuthorizationScopes.Designer.cs new file mode 100644 index 0000000..85c9998 --- /dev/null +++ b/Migrations/20260709171904_AddCentralizedAuthorizationScopes.Designer.cs @@ -0,0 +1,4884 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Microsoft.SelfService.Portal.Core.API.Context; + +#nullable disable + +namespace Microsoft.SelfService.Portal.Core.API.Migrations +{ + [DbContext(typeof(DataContext))] + [Migration("20260709171904_AddCentralizedAuthorizationScopes")] + partial class AddCentralizedAuthorizationScopes + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "10.0.8") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("Microsoft.SelfService.Portal.Core.API.Models.ApiClientModel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier") + .HasColumnOrder(0) + .HasDefaultValueSql("NEWID()"); + + b.Property("ClientId") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)") + .HasColumnOrder(1); + + b.Property("Created") + .ValueGeneratedOnAdd() + .HasColumnType("datetime2") + .HasColumnOrder(52) + .HasDefaultValueSql("GETDATE()"); + + b.Property("CreatedBy") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(53); + + b.Property("ExpiresAt") + .HasColumnType("datetime2") + .HasColumnOrder(6); + + b.Property("IsEnabled") + .HasColumnType("bit") + .HasColumnOrder(5); + + b.Property("LastUsedAt") + .HasColumnType("datetime2") + .HasColumnOrder(7); + + b.Property("Modified") + .ValueGeneratedOnAdd() + .HasColumnType("datetime2") + .HasColumnOrder(50) + .HasDefaultValueSql("GETDATE()"); + + b.Property("ModifiedBy") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(51); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(2); + + b.Property("ScopesJson") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(4); + + b.Property("SecretHash") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(3); + + b.HasKey("Id"); + + b.HasIndex("ClientId") + .IsUnique(); + + b.ToTable("ApiClients", t => + { + t.HasCheckConstraint("CK_ApiClients_ScopesJson_IsJson", "ISJSON([ScopesJson]) = 1"); + }); + + b.HasData( + new + { + Id = new Guid("91000000-0000-0000-0000-000000000001"), + ClientId = "ssp-demo-worker", + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + IsEnabled = true, + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + Name = "Demo Worker Client", + ScopesJson = "[\"configuration.read\",\"configuration.write\",\"credential.read\",\"credential.write\",\"credential.resolve\",\"deployment.read\",\"deployment.write\",\"queue.read\",\"queue.process\",\"template.read\",\"template.write\",\"token.manage\",\"token.admin\"]", + SecretHash = "PBKDF2-SHA256.100000.c3NwLWRlbW8td29ya2VyAA==.xQxe7BHCn9pdkqHozdyspEmKnz95uCUuxVvU2vgCEbo=" + }); + }); + + modelBuilder.Entity("Microsoft.SelfService.Portal.Core.API.Models.ApiTokenModel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier") + .HasColumnOrder(0) + .HasDefaultValueSql("NEWID()"); + + b.Property("ApiClientId") + .HasColumnType("uniqueidentifier") + .HasColumnOrder(4); + + b.Property("Created") + .ValueGeneratedOnAdd() + .HasColumnType("datetime2") + .HasColumnOrder(52) + .HasDefaultValueSql("GETDATE()"); + + b.Property("CreatedBy") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(53); + + b.Property("ExpiresAt") + .HasColumnType("datetime2") + .HasColumnOrder(8); + + b.Property("IssuedAt") + .HasColumnType("datetime2") + .HasColumnOrder(7); + + b.Property("Jti") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)") + .HasColumnOrder(1); + + b.Property("LastUsedAt") + .HasColumnType("datetime2") + .HasColumnOrder(11); + + b.Property("Modified") + .ValueGeneratedOnAdd() + .HasColumnType("datetime2") + .HasColumnOrder(50) + .HasDefaultValueSql("GETDATE()"); + + b.Property("ModifiedBy") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(51); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(5); + + b.Property("RevokedAt") + .HasColumnType("datetime2") + .HasColumnOrder(9); + + b.Property("RevokedBy") + .HasColumnType("nvarchar(max)") + .HasColumnOrder(10); + + b.Property("ScopesJson") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(6); + + b.Property("Subject") + .IsRequired() + .HasColumnType("nvarchar(450)") + .HasColumnOrder(2); + + b.Property("SubjectType") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("nvarchar(32)") + .HasColumnOrder(3); + + b.HasKey("Id"); + + b.HasIndex("ApiClientId"); + + b.HasIndex("Jti") + .IsUnique(); + + b.HasIndex("SubjectType", "Subject"); + + b.ToTable("ApiTokens", t => + { + t.HasCheckConstraint("CK_ApiTokens_ScopesJson_IsJson", "ISJSON([ScopesJson]) = 1"); + }); + }); + + modelBuilder.Entity("Microsoft.SelfService.Portal.Core.API.Models.ConfigurationDefinitionModel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier") + .HasColumnOrder(0) + .HasDefaultValueSql("NEWID()"); + + b.Property("Created") + .ValueGeneratedOnAdd() + .HasColumnType("datetime2") + .HasColumnOrder(52) + .HasDefaultValueSql("GETDATE()"); + + b.Property("CreatedBy") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(53); + + b.Property("DefinitionHash") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)") + .HasColumnOrder(5); + + b.Property("Kind") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("nvarchar(32)") + .HasColumnOrder(2); + + b.Property("Modified") + .ValueGeneratedOnAdd() + .HasColumnType("datetime2") + .HasColumnOrder(50) + .HasDefaultValueSql("GETDATE()"); + + b.Property("ModifiedBy") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(51); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)") + .HasColumnOrder(3); + + b.Property("PropertiesJson") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(4); + + b.Property("TemplateRevisionId") + .HasColumnType("uniqueidentifier") + .HasColumnOrder(1); + + b.HasKey("Id"); + + b.HasIndex("TemplateRevisionId", "Kind", "Name") + .IsUnique() + .HasFilter("[TemplateRevisionId] IS NOT NULL"); + + b.ToTable("ConfigurationDefinitions", t => + { + t.HasCheckConstraint("CK_ConfigurationDefinitions_PropertiesJson_IsJson", "ISJSON([PropertiesJson]) = 1"); + }); + + b.HasData( + new + { + Id = new Guid("67ca0430-31c6-553d-1553-60401cf4015c"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + DefinitionHash = "5A4F2C381DC5EBA68A416A739E7DCF0179EA6FF84D884BAF3A554D488DA9F5CE", + Kind = "Parameter", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + Name = "DomainName", + PropertiesJson = "{ \"type\": \"string\", \"defaultValue\": \"corp.contoso.com\" }", + TemplateRevisionId = new Guid("72000000-0000-0000-0000-000000000001") + }, + new + { + Id = new Guid("971fc778-2e79-6408-aec3-1beeaf7fce8e"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + DefinitionHash = "DB3469AE0FFB2D1669BD5E8B3078C3FA04FF8DB4FA67998C9610BE9C1C96FB53", + Kind = "Parameter", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + Name = "NetBIOSName", + PropertiesJson = "{ \"type\": \"string\", \"defaultValue\": \"CONTOSO\" }", + TemplateRevisionId = new Guid("72000000-0000-0000-0000-000000000001") + }, + new + { + Id = new Guid("dc4af326-9a3d-c4a6-9462-669bcf16103a"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + DefinitionHash = "DDC6599447376095A217761107BAB8795DBDB6CD0D7418A8B1A2E49684E1EFB8", + Kind = "Variable", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + Name = "DefaultSiteName", + PropertiesJson = "{\"Expression\":\"[concat(parameters('DomainName'), '-DefaultSite')]\"}", + TemplateRevisionId = new Guid("72000000-0000-0000-0000-000000000001") + }, + new + { + Id = new Guid("72fbe523-8aba-6aed-0918-d3e96f12254f"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + DefinitionHash = "112452BFA4BC12A22D96FE3095743046C3BDFBEB7DDC17E473BB2D54E6134AF6", + Kind = "Parameter", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + Name = "InstanceName", + PropertiesJson = "{ \"type\": \"string\", \"defaultValue\": \"MSSQLSERVER\" }", + TemplateRevisionId = new Guid("72000000-0000-0000-0000-000000000002") + }, + new + { + Id = new Guid("eb2d6268-83d4-ecc7-1696-eff819ac5db5"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + DefinitionHash = "0975CC4EB86BE0F5D26FF2E44A7663ECDC550671F88270DE44E402AA36793609", + Kind = "Parameter", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + Name = "DatabasePrefix", + PropertiesJson = "{ \"type\": \"string\", \"defaultValue\": \"Contoso\" }", + TemplateRevisionId = new Guid("72000000-0000-0000-0000-000000000002") + }, + new + { + Id = new Guid("afa8d0b4-7fc7-d419-7f01-6fb1fd59be4d"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + DefinitionHash = "E61970B4774DA1EABE34D93AE56C4647008872A0E01B9F1862D67B7049E02CDB", + Kind = "Variable", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + Name = "ConfigDatabase", + PropertiesJson = "{\"Expression\":\"[concat(parameters('DatabasePrefix'), '_Config')]\"}", + TemplateRevisionId = new Guid("72000000-0000-0000-0000-000000000002") + }, + new + { + Id = new Guid("d7d653e4-d29b-b9be-d701-b4eae2b34d2e"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + DefinitionHash = "B259744A1EB2E69B9D7B2A4BA1B0A9B1930AD837872C7D4F4ABDEEFA2F61A868", + Kind = "Parameter", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + Name = "DatabasePrefix", + PropertiesJson = "{ \"type\": \"string\", \"defaultValue\": \"SharePoint_Contoso_Test\" }", + TemplateRevisionId = new Guid("72000000-0000-0000-0000-000000000003") + }, + new + { + Id = new Guid("8e334e04-0465-ca82-b4f0-fd01561cdb4a"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + DefinitionHash = "75224F964656A4CFD8BBB38F26767A098A327F35A986F0E63247B75B0CD0C834", + Kind = "Parameter", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + Name = "FarmAccount", + PropertiesJson = "{ \"type\": \"credential\", \"metadata\": { \"description\": \"Farm account resolved by the credential provider.\" } }", + TemplateRevisionId = new Guid("72000000-0000-0000-0000-000000000003") + }, + new + { + Id = new Guid("2b7b2531-54ed-e778-e547-f0b696591d0c"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + DefinitionHash = "8FF8AE6C17C434DEC71C889173C0AD3E1759B94F99C0ACAFECB657D3327708BA", + Kind = "Variable", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + Name = "ConfigDbName", + PropertiesJson = "{\"Expression\":\"[concat(parameters('DatabasePrefix'), '_Farm_Config')]\"}", + TemplateRevisionId = new Guid("72000000-0000-0000-0000-000000000003") + }, + new + { + Id = new Guid("50f73169-1bda-2644-6963-b7cfad914a6a"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + DefinitionHash = "00139B0DB8374A47087A5AE9114E53200D7B2FEF79163BC3E2D627159986141A", + Kind = "Variable", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + Name = "AdminContentDbName", + PropertiesJson = "{\"Expression\":\"[concat(parameters('DatabasePrefix'), '_AdminContent')]\"}", + TemplateRevisionId = new Guid("72000000-0000-0000-0000-000000000003") + }, + new + { + Id = new Guid("9c60f6a6-a0c8-9f27-d31e-030403f78cd9"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + DefinitionHash = "8BAB062E6AAAE0E29902434B02DDFEC4A79908E307530CC3177F081F587317BD", + Kind = "Parameter", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + Name = "CallingPolicyName", + PropertiesJson = "{ \"type\": \"string\", \"defaultValue\": \"Contoso-Standard-Calling\" }", + TemplateRevisionId = new Guid("72000000-0000-0000-0000-000000000004") + }, + new + { + Id = new Guid("64767ffc-812e-b48e-db29-f295a287258b"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + DefinitionHash = "5469237A902DBDD5D1D5365F83BC4369D466C6283B618D5EFFF18037B954D206", + Kind = "Parameter", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + Name = "MeetingPolicyName", + PropertiesJson = "{ \"type\": \"string\", \"defaultValue\": \"Contoso-Standard-Meetings\" }", + TemplateRevisionId = new Guid("72000000-0000-0000-0000-000000000004") + }, + new + { + Id = new Guid("1ee4b631-fc15-85dc-3057-a1ca26da7ba9"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + DefinitionHash = "48BB0B2F36F4CA5BA7A2326F64B19AFA55D58345E675540A806877A78F61F97D", + Kind = "Parameter", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + Name = "Landscape", + PropertiesJson = "{\r\n \"DefaultValue\": \"Prod\",\r\n \"Value\": \"Test\",\r\n \"Type\": \"string\",\r\n \"AllowedValues\": [\r\n \"Prod\",\r\n \"QA\",\r\n \"Test\"\r\n ]\r\n }", + TemplateRevisionId = new Guid("72000000-0000-0000-0000-000000000101") + }, + new + { + Id = new Guid("a9be4c68-f2c0-279f-6a98-92b5ac3c0e80"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + DefinitionHash = "AB14380C5D597E9B70A8F42F768BF86A71118D86A8B9E28237B70952CE0BEBBD", + Kind = "Variable", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + Name = "AdminDbName", + PropertiesJson = "{\"Expression\":\"[joinNotEmpty(\\u0027_\\u0027, variables(\\u0027DatabasePrefix\\u0027), \\u0027Farm_AdminContent\\u0027)]\"}", + TemplateRevisionId = new Guid("72000000-0000-0000-0000-000000000101") + }, + new + { + Id = new Guid("07333ab1-de72-442d-d91a-0bb2dd969443"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + DefinitionHash = "81D3F97A03D7745EEB15174781144CD222A27E71F28A08F0C7F03496B74A0C87", + Kind = "Variable", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + Name = "ContentDbPrefix", + PropertiesJson = "{\"Expression\":\"[joinNotEmpty(\\u0027_\\u0027, variables(\\u0027DatabasePrefix\\u0027), parameters(\\u0027ContentDatabaseSegment\\u0027))]\"}", + TemplateRevisionId = new Guid("72000000-0000-0000-0000-000000000101") + }, + new + { + Id = new Guid("5d326698-5daf-cf78-b44d-2bbe6625d506"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + DefinitionHash = "66CA01A01EE073BAD5B77E2ECC9F3CB54967A3F4AE820E317C24C35DB6AF5ED2", + Kind = "Variable", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + Name = "ServiceDbPrefix", + PropertiesJson = "{\"Expression\":\"[joinNotEmpty(\\u0027_\\u0027, variables(\\u0027DatabasePrefix\\u0027), parameters(\\u0027ServiceDatabaseSegment\\u0027))]\"}", + TemplateRevisionId = new Guid("72000000-0000-0000-0000-000000000101") + }, + new + { + Id = new Guid("62443ac9-c783-01b8-0cf4-21dc6bd57e44"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + DefinitionHash = "4F3A9ED930F155C1D23ACD9FD640C0D2253B250467200E68020E1BA9FF25CA15", + Kind = "Variable", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + Name = "DatabasePrefix", + PropertiesJson = "{\"Expression\":\"[joinNotEmpty(\\u0027_\\u0027, parameters(\\u0027DatabasePrefix\\u0027), parameters(\\u0027DomainLabel\\u0027), if(equals(parameters(\\u0027Landscape\\u0027), \\u0027Test\\u0027), \\u0027Test\\u0027, \\u0027\\u0027))]\"}", + TemplateRevisionId = new Guid("72000000-0000-0000-0000-000000000101") + }, + new + { + Id = new Guid("14bcd250-6d40-e1a6-5aed-e563c7a2d589"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + DefinitionHash = "B020AA02247152F414B03ACFB1281A6A955D4F48CA3CB26A5B42EB3A3169113A", + Kind = "Variable", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + Name = "ConfigDbName", + PropertiesJson = "{\"Expression\":\"[joinNotEmpty(\\u0027_\\u0027, variables(\\u0027DatabasePrefix\\u0027), \\u0027Farm_Config\\u0027)]\"}", + TemplateRevisionId = new Guid("72000000-0000-0000-0000-000000000101") + }, + new + { + Id = new Guid("75c6a433-0dfe-1e3e-d324-322a2fad0d71"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + DefinitionHash = "FE5E0E49AA2D785B2ECA765C15A57889372826684A465793C1A69B528406D7AB", + Kind = "Parameter", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + Name = "DomainFQDN", + PropertiesJson = "{\r\n \"DefaultValue\": \"\",\r\n \"Pattern\": \"^[A-Za-z0-9.-]+$\",\r\n \"Type\": \"string\",\r\n \"Value\": \"contoso.local\",\r\n \"Required\": true\r\n }", + TemplateRevisionId = new Guid("72000000-0000-0000-0000-000000000102") + }, + new + { + Id = new Guid("dfb00c19-363f-7518-47be-1ba0ec16abd7"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + DefinitionHash = "ECF2FC72BEF5492B23764A1316ABEE9652F23D5C02A569A6FF59D35AAB4DE603", + Kind = "Parameter", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + Name = "DomainLabel", + PropertiesJson = "{\r\n \"Type\": \"string\",\r\n \"MaxLength\": 32,\r\n \"Value\": \"Contoso\",\r\n \"DefaultValue\": \"\",\r\n \"Pattern\": \"^[A-Za-z][A-Za-z0-9_-]*$\",\r\n \"MinLength\": 2,\r\n \"Required\": false\r\n }", + TemplateRevisionId = new Guid("72000000-0000-0000-0000-000000000102") + }, + new + { + Id = new Guid("68c57a16-e728-4c39-f245-8a41d77d0aa7"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + DefinitionHash = "62DE452BEBAE7CC7332895F461CD648707B5434F1EC4D55FA01E6B10A0FC4F74", + Kind = "Parameter", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + Name = "DomainNetBIOS", + PropertiesJson = "{\r\n \"Type\": \"string\",\r\n \"MaxLength\": 15,\r\n \"Value\": \"CONTOSO\",\r\n \"DefaultValue\": \"\",\r\n \"Pattern\": \"^[A-Za-z0-9_-]+$\",\r\n \"MinLength\": 1,\r\n \"Required\": true\r\n }", + TemplateRevisionId = new Guid("72000000-0000-0000-0000-000000000102") + }, + new + { + Id = new Guid("efbb9cc6-ed11-105b-91e4-0d925c214e32"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + DefinitionHash = "8EF099B36AF59BC20F3FBB9D9CBBFAC9F1E32D52521A890F9510216D862DCDA2", + Kind = "Parameter", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + Name = "FarmCredential", + PropertiesJson = "{\r\n \"Sensitive\": true,\r\n \"Value\": {\r\n \"Provider\": \"SecretManagement\",\r\n \"Vault\": \"Test\",\r\n \"Name\": \"Windows/SharePoint/FarmAccount\"\r\n },\r\n \"Type\": \"credential\",\r\n \"Required\": true\r\n }", + TemplateRevisionId = new Guid("72000000-0000-0000-0000-000000000103") + }, + new + { + Id = new Guid("c32f0de1-59a8-ffb2-a421-92209185de89"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + DefinitionHash = "28AF3E6D01302114A9A83652445875D944E00AE5291CDC76F34BE5D412328B4D", + Kind = "Parameter", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + Name = "ContentDatabaseSegment", + PropertiesJson = "{\r\n \"DefaultValue\": \"Content\",\r\n \"Type\": \"string\",\r\n \"Metadata\": {\r\n \"Description\": {\r\n \"de-DE\": \"Namenssegment fuer SharePoint-Content-Datenbanken innerhalb des Datenbanknamens.\",\r\n \"en-US\": \"Name segment used for SharePoint content databases within the database name.\"\r\n }\r\n }\r\n }", + TemplateRevisionId = new Guid("72000000-0000-0000-0000-000000000103") + }, + new + { + Id = new Guid("753acf7d-8ef6-69ef-b710-d430bfef3a98"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + DefinitionHash = "F45D71DEA1E2C611B54BD9077A92D438B2DBA2866781ABF397AFA20C2E985E07", + Kind = "Parameter", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + Name = "ServiceApplicationPoolDefault", + PropertiesJson = "{\r\n \"DefaultValue\": \"SharePoint Service Applications\",\r\n \"Type\": \"string\",\r\n \"Metadata\": {\r\n \"Description\": {\r\n \"de-DE\": \"Anzeigename des Standard-Application-Pools fuer SharePoint-Serviceanwendungen.\",\r\n \"en-US\": \"Display name of the default application pool for SharePoint service applications.\"\r\n }\r\n }\r\n }", + TemplateRevisionId = new Guid("72000000-0000-0000-0000-000000000103") + }, + new + { + Id = new Guid("16fa79cc-52be-7ba0-56ad-051ce1879851"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + DefinitionHash = "8F7A22AEDBCA0CCC09451FBE6B969687E56042826C989B85CD3F02569837B761", + Kind = "Parameter", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + Name = "WebApplicationPoolDefault", + PropertiesJson = "{\r\n \"DefaultValue\": \"SharePoint Web Applications\",\r\n \"Type\": \"string\",\r\n \"Metadata\": {\r\n \"Description\": {\r\n \"de-DE\": \"Anzeigename des Standard-Application-Pools fuer SharePoint-Webanwendungen.\",\r\n \"en-US\": \"Display name of the default application pool for SharePoint web applications.\"\r\n }\r\n }\r\n }", + TemplateRevisionId = new Guid("72000000-0000-0000-0000-000000000103") + }, + new + { + Id = new Guid("1e409601-2e11-453e-09bc-ccc0e61a2eaf"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + DefinitionHash = "BCDC01B9105DB0D42D6E8CD49092E10713CF4CBB42178218F5B2450CCB1A359A", + Kind = "Parameter", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + Name = "DatabaseServerName", + PropertiesJson = "{\r\n \"DefaultValue\": \"SQL_Server\",\r\n \"Type\": \"string\",\r\n \"Value\": \"CL-SQL-01\"\r\n }", + TemplateRevisionId = new Guid("72000000-0000-0000-0000-000000000103") + }, + new + { + Id = new Guid("a1bbb850-c83a-f3ee-474c-dc9484456e2a"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + DefinitionHash = "21654CC3E82D2DE59E438E554C32F074BA88894F1F6825BC0154D6B127CDCDD8", + Kind = "Parameter", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + Name = "WebApplicationPoolDefaultAccount", + PropertiesJson = "{\r\n \"DefaultValue\": \"SVC_SHP_WAP\",\r\n \"Type\": \"string\",\r\n \"Metadata\": {\r\n \"Description\": {\r\n \"de-DE\": \"Kontoname fuer den Standard-Application-Pool der SharePoint-Webanwendungen.\",\r\n \"en-US\": \"Account name used by the default application pool for SharePoint web applications.\"\r\n }\r\n }\r\n }", + TemplateRevisionId = new Guid("72000000-0000-0000-0000-000000000103") + }, + new + { + Id = new Guid("80733c50-d68a-d8f9-bb5f-fb6fce6f66a1"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + DefinitionHash = "161F0B7F00446101C1C6CBFFAACC28EFE56418E7636DCCEC2C4EE57538ACC182", + Kind = "Parameter", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + Name = "ServiceDatabaseSegment", + PropertiesJson = "{\r\n \"DefaultValue\": \"Services\",\r\n \"Type\": \"string\",\r\n \"Metadata\": {\r\n \"Description\": {\r\n \"de-DE\": \"Namenssegment fuer SharePoint-Service-Datenbanken innerhalb des Datenbanknamens.\",\r\n \"en-US\": \"Name segment used for SharePoint service databases within the database name.\"\r\n }\r\n }\r\n }", + TemplateRevisionId = new Guid("72000000-0000-0000-0000-000000000103") + }, + new + { + Id = new Guid("de747816-08b8-faf8-d4ee-57b47222a7f4"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + DefinitionHash = "1E280B017D410A45BBF262CBED384ADA7AE42FB0D1390BDFF68909FD4389043A", + Kind = "Parameter", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + Name = "FarmPassphrase", + PropertiesJson = "{\r\n \"Sensitive\": true,\r\n \"Value\": {\r\n \"Provider\": \"SecretManagement\",\r\n \"Vault\": \"Test\",\r\n \"Name\": \"Windows/SharePoint/FarmPassphrase\"\r\n },\r\n \"Type\": \"credential\",\r\n \"Required\": true\r\n }", + TemplateRevisionId = new Guid("72000000-0000-0000-0000-000000000103") + }, + new + { + Id = new Guid("a7cc8607-ab28-8765-6fb3-87222c485f65"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + DefinitionHash = "2BFD19F4E9E81007EBA8B7EDE220316E042FF6B1471CF1C33AD47E8FEE083121", + Kind = "Parameter", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + Name = "DatabaseInstanceName", + PropertiesJson = "{\r\n \"DefaultValue\": \"SQL_Server\",\r\n \"Type\": \"string\",\r\n \"Value\": \"SQLServer\"\r\n }", + TemplateRevisionId = new Guid("72000000-0000-0000-0000-000000000103") + }, + new + { + Id = new Guid("dc6781e4-7ca7-7307-bf91-42078ba9dea1"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + DefinitionHash = "DED3F6C00C32BA6888DEFA172C837415D118388478A160D872AEA098B38C9298", + Kind = "Parameter", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + Name = "DatabaseTcpPort", + PropertiesJson = "{\r\n \"DefaultValue\": 1433,\r\n \"Type\": \"int\",\r\n \"Value\": 1433\r\n }", + TemplateRevisionId = new Guid("72000000-0000-0000-0000-000000000103") + }, + new + { + Id = new Guid("4b3283a0-f2df-1edd-fa3f-a90cacf2a7f1"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + DefinitionHash = "071CCD19384E43C652F0CF2E633702F12BBC1CE8A46472DCF1B7EBB9A500795E", + Kind = "Parameter", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + Name = "DefaultServiceApplicationPoolAccount", + PropertiesJson = "{\r\n \"Metadata\": {\r\n \"Description\": {\r\n \"de-DE\": \"Kontoname fuer den Standard-Application-Pool der SharePoint-Serviceanwendungen.\",\r\n \"en-US\": \"Account name used by the default application pool for SharePoint service applications.\"\r\n }\r\n },\r\n \"Sensitive\": true,\r\n \"Value\": {\r\n \"Provider\": \"SecretManagement\",\r\n \"Vault\": \"Test\",\r\n \"Name\": \"Windows/SharePoint/DefaultServiceAccount\"\r\n },\r\n \"Type\": \"credential\",\r\n \"Required\": true\r\n }", + TemplateRevisionId = new Guid("72000000-0000-0000-0000-000000000103") + }, + new + { + Id = new Guid("b5f3de9e-251e-ebb1-c6cc-b4a1a2afc987"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + DefinitionHash = "C16A8CDDCD81BAA020E26C1EC06AB229A4483E095A9259E1C471CC7322CCF011", + Kind = "Parameter", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + Name = "ProductKey", + PropertiesJson = "{\r\n \"DefaultValue\": \"0000-0000-0000-0000-0000\",\r\n \"Type\": \"string\",\r\n \"Metadata\": {\r\n \"Description\": {\r\n \"de-DE\": \"SharePoint-Produktlizenzschluessel.\",\r\n \"en-US\": \"SharePoint product license key.\"\r\n }\r\n }\r\n }", + TemplateRevisionId = new Guid("72000000-0000-0000-0000-000000000103") + }, + new + { + Id = new Guid("e9a93051-120a-00c2-c69d-794d3d3c6c86"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + DefinitionHash = "4A1AAAAA8D012E87FDFCB9C7B45C490E35B4FDD1341A6D8682591E25DE782A1F", + Kind = "Parameter", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + Name = "SetupCredential", + PropertiesJson = "{\r\n \"Sensitive\": true,\r\n \"Value\": {\r\n \"Provider\": \"SecretManagement\",\r\n \"Vault\": \"Test\",\r\n \"Name\": \"Windows/SharePoint/SetupAccount\"\r\n },\r\n \"Type\": \"credential\",\r\n \"Required\": true\r\n }", + TemplateRevisionId = new Guid("72000000-0000-0000-0000-000000000103") + }, + new + { + Id = new Guid("d0fbeeb9-628d-fa56-c106-6f54e3080b11"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + DefinitionHash = "4BE38B4AB1097AB42C79DA38FE0E6B6F4399319E22B23CCE5461BF7D1D1E586E", + Kind = "Parameter", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + Name = "DatabasePrefix", + PropertiesJson = "{\r\n \"DefaultValue\": \"SharePoint\",\r\n \"Type\": \"string\",\r\n \"Value\": \"SharePoint\"\r\n }", + TemplateRevisionId = new Guid("72000000-0000-0000-0000-000000000103") + }, + new + { + Id = new Guid("13f4b031-f8b8-1ef4-21b0-ab825dc54aee"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + DefinitionHash = "16F0D197D56D4E12B3BEB98AEA78A9D9C16DB35C1B09F3FA2298620504820B73", + Kind = "Parameter", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + Name = "SearchServiceApplicationPoolAccount", + PropertiesJson = "{\r\n \"Metadata\": {\r\n \"Description\": {\r\n \"de-DE\": \"Kontoname fuer den Search-Application-Pool der SharePoint-Serviceanwendungen.\",\r\n \"en-US\": \"Account name used by the search application pool for SharePoint service applications.\"\r\n }\r\n },\r\n \"Sensitive\": true,\r\n \"Value\": {\r\n \"Provider\": \"SecretManagement\",\r\n \"Vault\": \"Test\",\r\n \"Name\": \"Windows/SharePoint/SearchAccount\"\r\n },\r\n \"Type\": \"credential\",\r\n \"Required\": true\r\n }", + TemplateRevisionId = new Guid("72000000-0000-0000-0000-000000000103") + }, + new + { + Id = new Guid("1fc14a66-5b69-00da-e92c-a38e6d674b50"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + DefinitionHash = "50EDDD3C7853B59491CA782C3A45A9E33EE6709FF4B964D6E42FB2DC4D6D546D", + Kind = "Parameter", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + Name = "CentralAdminPort", + PropertiesJson = "{\r\n \"DefaultValue\": 443,\r\n \"Type\": \"int\",\r\n \"Value\": 4000\r\n }", + TemplateRevisionId = new Guid("72000000-0000-0000-0000-000000000103") + }, + new + { + Id = new Guid("f7ea1bce-9cf1-ddc4-320f-e26ef51a6108"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + DefinitionHash = "3932CF99DA0C5583F34A16C94762F0EA1E94A2D197E4E56D5F2226863686577E", + Kind = "Parameter", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + Name = "ServiceApplicationPoolSearch", + PropertiesJson = "{\r\n \"DefaultValue\": \"SharePoint Search Service Applications\",\r\n \"Type\": \"string\",\r\n \"Metadata\": {\r\n \"Description\": {\r\n \"de-DE\": \"Anzeigename des Application-Pools fuer SharePoint Search-Serviceanwendungen.\",\r\n \"en-US\": \"Display name of the application pool for SharePoint Search service applications.\"\r\n }\r\n }\r\n }", + TemplateRevisionId = new Guid("72000000-0000-0000-0000-000000000103") + }, + new + { + Id = new Guid("3bdcaa78-354c-487f-b0c5-6a3e0b20f8a1"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + DefinitionHash = "AB14380C5D597E9B70A8F42F768BF86A71118D86A8B9E28237B70952CE0BEBBD", + Kind = "Variable", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + Name = "AdminDbName", + PropertiesJson = "{\"Expression\":\"[joinNotEmpty(\\u0027_\\u0027, variables(\\u0027DatabasePrefix\\u0027), \\u0027Farm_AdminContent\\u0027)]\"}", + TemplateRevisionId = new Guid("72000000-0000-0000-0000-000000000103") + }, + new + { + Id = new Guid("57fe8654-dbf4-c6c1-3a99-ac68fe393731"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + DefinitionHash = "81D3F97A03D7745EEB15174781144CD222A27E71F28A08F0C7F03496B74A0C87", + Kind = "Variable", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + Name = "ContentDbPrefix", + PropertiesJson = "{\"Expression\":\"[joinNotEmpty(\\u0027_\\u0027, variables(\\u0027DatabasePrefix\\u0027), parameters(\\u0027ContentDatabaseSegment\\u0027))]\"}", + TemplateRevisionId = new Guid("72000000-0000-0000-0000-000000000103") + }, + new + { + Id = new Guid("04091788-4a0a-7911-b11d-b70335ad378a"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + DefinitionHash = "66CA01A01EE073BAD5B77E2ECC9F3CB54967A3F4AE820E317C24C35DB6AF5ED2", + Kind = "Variable", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + Name = "ServiceDbPrefix", + PropertiesJson = "{\"Expression\":\"[joinNotEmpty(\\u0027_\\u0027, variables(\\u0027DatabasePrefix\\u0027), parameters(\\u0027ServiceDatabaseSegment\\u0027))]\"}", + TemplateRevisionId = new Guid("72000000-0000-0000-0000-000000000103") + }, + new + { + Id = new Guid("7232ce0f-9f3e-e10b-9370-7aec1c610ecc"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + DefinitionHash = "4F3A9ED930F155C1D23ACD9FD640C0D2253B250467200E68020E1BA9FF25CA15", + Kind = "Variable", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + Name = "DatabasePrefix", + PropertiesJson = "{\"Expression\":\"[joinNotEmpty(\\u0027_\\u0027, parameters(\\u0027DatabasePrefix\\u0027), parameters(\\u0027DomainLabel\\u0027), if(equals(parameters(\\u0027Landscape\\u0027), \\u0027Test\\u0027), \\u0027Test\\u0027, \\u0027\\u0027))]\"}", + TemplateRevisionId = new Guid("72000000-0000-0000-0000-000000000103") + }, + new + { + Id = new Guid("73be057e-cd31-1658-186b-bcf4695a48f7"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + DefinitionHash = "B020AA02247152F414B03ACFB1281A6A955D4F48CA3CB26A5B42EB3A3169113A", + Kind = "Variable", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + Name = "ConfigDbName", + PropertiesJson = "{\"Expression\":\"[joinNotEmpty(\\u0027_\\u0027, variables(\\u0027DatabasePrefix\\u0027), \\u0027Farm_Config\\u0027)]\"}", + TemplateRevisionId = new Guid("72000000-0000-0000-0000-000000000103") + }); + }); + + modelBuilder.Entity("Microsoft.SelfService.Portal.Core.API.Models.ConfigurationValueModel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier") + .HasColumnOrder(0) + .HasDefaultValueSql("NEWID()"); + + b.Property("ConfigurationDefinitionId") + .HasColumnType("uniqueidentifier") + .HasColumnOrder(1); + + b.Property("Created") + .ValueGeneratedOnAdd() + .HasColumnType("datetime2") + .HasColumnOrder(52) + .HasDefaultValueSql("GETDATE()"); + + b.Property("CreatedBy") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(53); + + b.Property("Modified") + .ValueGeneratedOnAdd() + .HasColumnType("datetime2") + .HasColumnOrder(50) + .HasDefaultValueSql("GETDATE()"); + + b.Property("ModifiedBy") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(51); + + b.Property("ScopeId") + .HasColumnType("uniqueidentifier") + .HasColumnOrder(3); + + b.Property("ScopeType") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)") + .HasColumnOrder(2); + + b.Property("SortOrder") + .HasColumnType("int") + .HasColumnOrder(8); + + b.Property("SourcePath") + .HasColumnType("nvarchar(max)") + .HasColumnOrder(5); + + b.Property("ValueHash") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)") + .HasColumnOrder(7); + + b.Property("ValueJson") + .HasColumnType("nvarchar(max)") + .HasColumnOrder(6); + + b.Property("ValueSourceType") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)") + .HasColumnOrder(4); + + b.HasKey("Id"); + + b.HasIndex("ConfigurationDefinitionId", "ScopeType", "ScopeId", "SortOrder"); + + b.ToTable("ConfigurationValues", t => + { + t.HasCheckConstraint("CK_ConfigurationValues_ValueJson_IsJson", "[ValueJson] IS NULL OR ISJSON([ValueJson]) = 1"); + }); + + b.HasData( + new + { + Id = new Guid("4a2c7cf6-41f3-b20f-de61-6efaf96444f9"), + ConfigurationDefinitionId = new Guid("67ca0430-31c6-553d-1553-60401cf4015c"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + ScopeId = new Guid("72000000-0000-0000-0000-000000000001"), + ScopeType = "TemplateRevision", + SortOrder = 10, + ValueHash = "44136FA355B3678A1146AD16F7E8649E94FB4FC21FE77E8310C060F61CAAFF8A", + ValueJson = "{}", + ValueSourceType = "Static" + }, + new + { + Id = new Guid("b21cf5c3-284f-eca7-cf39-dd7451002ea4"), + ConfigurationDefinitionId = new Guid("971fc778-2e79-6408-aec3-1beeaf7fce8e"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + ScopeId = new Guid("72000000-0000-0000-0000-000000000001"), + ScopeType = "TemplateRevision", + SortOrder = 20, + ValueHash = "44136FA355B3678A1146AD16F7E8649E94FB4FC21FE77E8310C060F61CAAFF8A", + ValueJson = "{}", + ValueSourceType = "Static" + }, + new + { + Id = new Guid("eb107c2a-335d-5148-aecf-33ffd3ba51bc"), + ConfigurationDefinitionId = new Guid("dc4af326-9a3d-c4a6-9462-669bcf16103a"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + ScopeId = new Guid("72000000-0000-0000-0000-000000000001"), + ScopeType = "TemplateRevision", + SortOrder = 10, + ValueHash = "C02CA81E91040D74400B8E4D152614D790E8D741A993754383057E87A581AF09", + ValueJson = "{\"expression\":\"[concat(parameters('DomainName'), '-DefaultSite')]\"}", + ValueSourceType = "Expression" + }, + new + { + Id = new Guid("57913480-45b6-f13d-504d-b05d239a2366"), + ConfigurationDefinitionId = new Guid("72fbe523-8aba-6aed-0918-d3e96f12254f"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + ScopeId = new Guid("72000000-0000-0000-0000-000000000002"), + ScopeType = "TemplateRevision", + SortOrder = 10, + ValueHash = "44136FA355B3678A1146AD16F7E8649E94FB4FC21FE77E8310C060F61CAAFF8A", + ValueJson = "{}", + ValueSourceType = "Static" + }, + new + { + Id = new Guid("651d7a24-db44-f18e-2607-1da3a1afbd9c"), + ConfigurationDefinitionId = new Guid("eb2d6268-83d4-ecc7-1696-eff819ac5db5"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + ScopeId = new Guid("72000000-0000-0000-0000-000000000002"), + ScopeType = "TemplateRevision", + SortOrder = 20, + ValueHash = "44136FA355B3678A1146AD16F7E8649E94FB4FC21FE77E8310C060F61CAAFF8A", + ValueJson = "{}", + ValueSourceType = "Static" + }, + new + { + Id = new Guid("9550114f-755b-9512-b430-603954351fed"), + ConfigurationDefinitionId = new Guid("afa8d0b4-7fc7-d419-7f01-6fb1fd59be4d"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + ScopeId = new Guid("72000000-0000-0000-0000-000000000002"), + ScopeType = "TemplateRevision", + SortOrder = 10, + ValueHash = "6ED96528075B87998FDAF609CB1E2A95224A347D109435B05E4C40A0A2F5FC44", + ValueJson = "{\"expression\":\"[concat(parameters('DatabasePrefix'), '_Config')]\"}", + ValueSourceType = "Expression" + }, + new + { + Id = new Guid("146d60ab-37ba-8fbf-83f1-89a0976b70c7"), + ConfigurationDefinitionId = new Guid("d7d653e4-d29b-b9be-d701-b4eae2b34d2e"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + ScopeId = new Guid("72000000-0000-0000-0000-000000000003"), + ScopeType = "TemplateRevision", + SortOrder = 10, + ValueHash = "44136FA355B3678A1146AD16F7E8649E94FB4FC21FE77E8310C060F61CAAFF8A", + ValueJson = "{}", + ValueSourceType = "Static" + }, + new + { + Id = new Guid("7e85c8b9-3fd6-fef6-eea5-d8789601e7de"), + ConfigurationDefinitionId = new Guid("8e334e04-0465-ca82-b4f0-fd01561cdb4a"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + ScopeId = new Guid("72000000-0000-0000-0000-000000000003"), + ScopeType = "TemplateRevision", + SortOrder = 20, + ValueHash = "44136FA355B3678A1146AD16F7E8649E94FB4FC21FE77E8310C060F61CAAFF8A", + ValueJson = "{}", + ValueSourceType = "Static" + }, + new + { + Id = new Guid("e5c9e96a-c891-0854-60b0-b2246870d0c0"), + ConfigurationDefinitionId = new Guid("2b7b2531-54ed-e778-e547-f0b696591d0c"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + ScopeId = new Guid("72000000-0000-0000-0000-000000000003"), + ScopeType = "TemplateRevision", + SortOrder = 10, + ValueHash = "AB48409D8EC6C4009EFCDEE399B7DEED9BC132543EE5C2CF518A9201B6BEF41D", + ValueJson = "{\"expression\":\"[concat(parameters('DatabasePrefix'), '_Farm_Config')]\"}", + ValueSourceType = "Expression" + }, + new + { + Id = new Guid("e79ccc48-28ec-72d3-1331-6c825dc1b7c0"), + ConfigurationDefinitionId = new Guid("50f73169-1bda-2644-6963-b7cfad914a6a"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + ScopeId = new Guid("72000000-0000-0000-0000-000000000003"), + ScopeType = "TemplateRevision", + SortOrder = 20, + ValueHash = "7B7FA4E9CF1492587605741B7CEE29F579EC357030B794ED646A19C4474907A6", + ValueJson = "{\"expression\":\"[concat(parameters('DatabasePrefix'), '_AdminContent')]\"}", + ValueSourceType = "Expression" + }, + new + { + Id = new Guid("49c62e61-ae10-259f-188c-618cd50e22a4"), + ConfigurationDefinitionId = new Guid("9c60f6a6-a0c8-9f27-d31e-030403f78cd9"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + ScopeId = new Guid("72000000-0000-0000-0000-000000000004"), + ScopeType = "TemplateRevision", + SortOrder = 10, + ValueHash = "44136FA355B3678A1146AD16F7E8649E94FB4FC21FE77E8310C060F61CAAFF8A", + ValueJson = "{}", + ValueSourceType = "Static" + }, + new + { + Id = new Guid("6c056e2d-4714-80d0-905a-f49c62ea8d31"), + ConfigurationDefinitionId = new Guid("64767ffc-812e-b48e-db29-f295a287258b"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + ScopeId = new Guid("72000000-0000-0000-0000-000000000004"), + ScopeType = "TemplateRevision", + SortOrder = 20, + ValueHash = "44136FA355B3678A1146AD16F7E8649E94FB4FC21FE77E8310C060F61CAAFF8A", + ValueJson = "{}", + ValueSourceType = "Static" + }, + new + { + Id = new Guid("ea4bdba4-397b-d93a-fc6d-03ff3826d2c1"), + ConfigurationDefinitionId = new Guid("1ee4b631-fc15-85dc-3057-a1ca26da7ba9"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + ScopeId = new Guid("72000000-0000-0000-0000-000000000101"), + ScopeType = "TemplateRevision", + SortOrder = 10, + ValueHash = "94FA03DA6461D6142CFA6448B23D207BC7AFCC89E3CC4B9A507ADA54864A6B6F", + ValueJson = "{\"value\":\"Test\"}", + ValueSourceType = "Static" + }, + new + { + Id = new Guid("42f554e8-2d02-ce15-b5eb-e9344b3af1de"), + ConfigurationDefinitionId = new Guid("a9be4c68-f2c0-279f-6a98-92b5ac3c0e80"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + ScopeId = new Guid("72000000-0000-0000-0000-000000000101"), + ScopeType = "TemplateRevision", + SortOrder = 10, + ValueHash = "F1D875A6571735F22CA408E51F3793292BD9051C28443A107D3D3AE3E67CC18F", + ValueJson = "{\"expression\":\"[joinNotEmpty(\\u0027_\\u0027, variables(\\u0027DatabasePrefix\\u0027), \\u0027Farm_AdminContent\\u0027)]\"}", + ValueSourceType = "Expression" + }, + new + { + Id = new Guid("bfc73c02-2df3-916e-7f54-f432bab37613"), + ConfigurationDefinitionId = new Guid("07333ab1-de72-442d-d91a-0bb2dd969443"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + ScopeId = new Guid("72000000-0000-0000-0000-000000000101"), + ScopeType = "TemplateRevision", + SortOrder = 20, + ValueHash = "B00E74A711838E3C2D4D3779ED0DEAECCF66172565F88F8F9ACE644EEBFBCD91", + ValueJson = "{\"expression\":\"[joinNotEmpty(\\u0027_\\u0027, variables(\\u0027DatabasePrefix\\u0027), parameters(\\u0027ContentDatabaseSegment\\u0027))]\"}", + ValueSourceType = "Expression" + }, + new + { + Id = new Guid("bf6abd6f-d02c-55f4-a27d-b89c19bc9c35"), + ConfigurationDefinitionId = new Guid("5d326698-5daf-cf78-b44d-2bbe6625d506"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + ScopeId = new Guid("72000000-0000-0000-0000-000000000101"), + ScopeType = "TemplateRevision", + SortOrder = 30, + ValueHash = "4D54C78468AB68A528415889AC8B50B89E2F5AFD0B0C36D3F6B060036422009E", + ValueJson = "{\"expression\":\"[joinNotEmpty(\\u0027_\\u0027, variables(\\u0027DatabasePrefix\\u0027), parameters(\\u0027ServiceDatabaseSegment\\u0027))]\"}", + ValueSourceType = "Expression" + }, + new + { + Id = new Guid("7ac33a52-7ee3-6b42-78fb-c125f218fa2b"), + ConfigurationDefinitionId = new Guid("62443ac9-c783-01b8-0cf4-21dc6bd57e44"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + ScopeId = new Guid("72000000-0000-0000-0000-000000000101"), + ScopeType = "TemplateRevision", + SortOrder = 40, + ValueHash = "7EB8E130BDEA0111303714519A04B078E07970AEBD2C51EC0244F90D3E3DFC98", + ValueJson = "{\"expression\":\"[joinNotEmpty(\\u0027_\\u0027, parameters(\\u0027DatabasePrefix\\u0027), parameters(\\u0027DomainLabel\\u0027), if(equals(parameters(\\u0027Landscape\\u0027), \\u0027Test\\u0027), \\u0027Test\\u0027, \\u0027\\u0027))]\"}", + ValueSourceType = "Expression" + }, + new + { + Id = new Guid("ab4a8935-6d46-f6da-d17f-0e2abed7b413"), + ConfigurationDefinitionId = new Guid("14bcd250-6d40-e1a6-5aed-e563c7a2d589"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + ScopeId = new Guid("72000000-0000-0000-0000-000000000101"), + ScopeType = "TemplateRevision", + SortOrder = 50, + ValueHash = "261FCBE546960FDBA45B615045DC04AE5B717633C4368C87A25A81B31339BE96", + ValueJson = "{\"expression\":\"[joinNotEmpty(\\u0027_\\u0027, variables(\\u0027DatabasePrefix\\u0027), \\u0027Farm_Config\\u0027)]\"}", + ValueSourceType = "Expression" + }, + new + { + Id = new Guid("834efeb6-4b29-efa5-9856-465663c13458"), + ConfigurationDefinitionId = new Guid("75c6a433-0dfe-1e3e-d324-322a2fad0d71"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + ScopeId = new Guid("72000000-0000-0000-0000-000000000102"), + ScopeType = "TemplateRevision", + SortOrder = 10, + ValueHash = "9EA8921C32C58E37F911E22432BEC6E68686DE6D3B4732B3B08029D606F09FA5", + ValueJson = "{\"value\":\"contoso.local\"}", + ValueSourceType = "Static" + }, + new + { + Id = new Guid("534db414-821b-59d3-b082-3c57efff2bff"), + ConfigurationDefinitionId = new Guid("dfb00c19-363f-7518-47be-1ba0ec16abd7"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + ScopeId = new Guid("72000000-0000-0000-0000-000000000102"), + ScopeType = "TemplateRevision", + SortOrder = 20, + ValueHash = "03289E6E378FD3D96F2565E9A7B802E0D8AB301F7CAE63F1853CB4080B19EEDF", + ValueJson = "{\"value\":\"Contoso\"}", + ValueSourceType = "Static" + }, + new + { + Id = new Guid("4a01be5c-e40f-5a3e-e2af-548739f4d0ae"), + ConfigurationDefinitionId = new Guid("68c57a16-e728-4c39-f245-8a41d77d0aa7"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + ScopeId = new Guid("72000000-0000-0000-0000-000000000102"), + ScopeType = "TemplateRevision", + SortOrder = 30, + ValueHash = "41D77AE0AA9812940953F0E186514FBC3AF0E59F19573213C33A206FBE74C903", + ValueJson = "{\"value\":\"CONTOSO\"}", + ValueSourceType = "Static" + }, + new + { + Id = new Guid("d746cb22-0a95-7464-d693-aa5af56ae901"), + ConfigurationDefinitionId = new Guid("efbb9cc6-ed11-105b-91e4-0d925c214e32"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + ScopeId = new Guid("72000000-0000-0000-0000-000000000103"), + ScopeType = "TemplateRevision", + SortOrder = 10, + ValueHash = "D6BBF1B384A92232566CF22E32A5D99FC9AC6F92E70D86EC00BF1FD5876F6FFB", + ValueJson = "{\"value\":{\r\n \"Provider\": \"SecretManagement\",\r\n \"Vault\": \"Test\",\r\n \"Name\": \"Windows/SharePoint/FarmAccount\"\r\n }}", + ValueSourceType = "SecretReference" + }, + new + { + Id = new Guid("8175dee7-8e0a-c7e7-8e66-d4f12a4eb42c"), + ConfigurationDefinitionId = new Guid("c32f0de1-59a8-ffb2-a421-92209185de89"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + ScopeId = new Guid("72000000-0000-0000-0000-000000000103"), + ScopeType = "TemplateRevision", + SortOrder = 20, + ValueHash = "425625B9EBF4642A17AAEA773F1304A83FC7AA89A00BD4C934B7B63434AA605C", + ValueJson = "{\"value\":\"Content\"}", + ValueSourceType = "Static" + }, + new + { + Id = new Guid("851ce8ed-dc94-d437-4947-f1fbe53e5469"), + ConfigurationDefinitionId = new Guid("753acf7d-8ef6-69ef-b710-d430bfef3a98"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + ScopeId = new Guid("72000000-0000-0000-0000-000000000103"), + ScopeType = "TemplateRevision", + SortOrder = 30, + ValueHash = "6B1F221C6266934F56A72E241B1D8D3426B59088F46B12BF78291F75CDC8008C", + ValueJson = "{\"value\":\"SharePoint Service Applications\"}", + ValueSourceType = "Static" + }, + new + { + Id = new Guid("a1c445b1-e063-e267-8721-54c0cdb6b36c"), + ConfigurationDefinitionId = new Guid("16fa79cc-52be-7ba0-56ad-051ce1879851"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + ScopeId = new Guid("72000000-0000-0000-0000-000000000103"), + ScopeType = "TemplateRevision", + SortOrder = 40, + ValueHash = "0370D254CED4857D0DEEBF1E9E8D1061DB1503E1E3E12B7393EE534BBD5AF783", + ValueJson = "{\"value\":\"SharePoint Web Applications\"}", + ValueSourceType = "Static" + }, + new + { + Id = new Guid("b08bf2a8-6bd3-1ed9-bf9b-a4f20738a6eb"), + ConfigurationDefinitionId = new Guid("1e409601-2e11-453e-09bc-ccc0e61a2eaf"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + ScopeId = new Guid("72000000-0000-0000-0000-000000000103"), + ScopeType = "TemplateRevision", + SortOrder = 50, + ValueHash = "E3D4EFD336BE54EA0E9E1BFC14536244717CCCDF5291FAB78721936BA47673C4", + ValueJson = "{\"value\":\"CL-SQL-01\"}", + ValueSourceType = "Static" + }, + new + { + Id = new Guid("cd9e8e80-1975-10d8-8272-d95ba8275299"), + ConfigurationDefinitionId = new Guid("a1bbb850-c83a-f3ee-474c-dc9484456e2a"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + ScopeId = new Guid("72000000-0000-0000-0000-000000000103"), + ScopeType = "TemplateRevision", + SortOrder = 60, + ValueHash = "16EC9E2621F1BA6E974D9005EECC34771B1D6303EE73DCC86214BAD2F5E4CA81", + ValueJson = "{\"value\":\"SVC_SHP_WAP\"}", + ValueSourceType = "Static" + }, + new + { + Id = new Guid("27a2b22c-871b-a5e9-fda1-a862c1238f03"), + ConfigurationDefinitionId = new Guid("80733c50-d68a-d8f9-bb5f-fb6fce6f66a1"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + ScopeId = new Guid("72000000-0000-0000-0000-000000000103"), + ScopeType = "TemplateRevision", + SortOrder = 70, + ValueHash = "2E39290C9FFD6829B4EFE9004DF7D8236A17E02EE49D03EA79A0DAA936A1F249", + ValueJson = "{\"value\":\"Services\"}", + ValueSourceType = "Static" + }, + new + { + Id = new Guid("665a2e6b-80a7-f64d-85b8-7386c9366549"), + ConfigurationDefinitionId = new Guid("de747816-08b8-faf8-d4ee-57b47222a7f4"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + ScopeId = new Guid("72000000-0000-0000-0000-000000000103"), + ScopeType = "TemplateRevision", + SortOrder = 80, + ValueHash = "ED585C568AA8DAB5EEBB883F90FB02B5B31C614A290A806CFD44E451EC8303ED", + ValueJson = "{\"value\":{\r\n \"Provider\": \"SecretManagement\",\r\n \"Vault\": \"Test\",\r\n \"Name\": \"Windows/SharePoint/FarmPassphrase\"\r\n }}", + ValueSourceType = "SecretReference" + }, + new + { + Id = new Guid("e69c4719-077b-8ebc-bf06-708bbbca4052"), + ConfigurationDefinitionId = new Guid("a7cc8607-ab28-8765-6fb3-87222c485f65"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + ScopeId = new Guid("72000000-0000-0000-0000-000000000103"), + ScopeType = "TemplateRevision", + SortOrder = 90, + ValueHash = "794D1C1505B58390120A1BE2139A2056C5ED852D4653730DFD4A206060DD3155", + ValueJson = "{\"value\":\"SQLServer\"}", + ValueSourceType = "Static" + }, + new + { + Id = new Guid("2e2fe570-7204-6b79-d073-b62171e5c5ea"), + ConfigurationDefinitionId = new Guid("dc6781e4-7ca7-7307-bf91-42078ba9dea1"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + ScopeId = new Guid("72000000-0000-0000-0000-000000000103"), + ScopeType = "TemplateRevision", + SortOrder = 100, + ValueHash = "635B61BE7E1B2CF8197647383A166882478C6632F878068D383D1307C2678EC4", + ValueJson = "{\"value\":1433}", + ValueSourceType = "Static" + }, + new + { + Id = new Guid("a2c1e504-20be-aff3-bde2-bcd9ba98bbba"), + ConfigurationDefinitionId = new Guid("4b3283a0-f2df-1edd-fa3f-a90cacf2a7f1"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + ScopeId = new Guid("72000000-0000-0000-0000-000000000103"), + ScopeType = "TemplateRevision", + SortOrder = 110, + ValueHash = "1843C3695744571EDFEA9C4765EAC5AE430FC8C704AFE1FFDE02FF6E68D8BE45", + ValueJson = "{\"value\":{\r\n \"Provider\": \"SecretManagement\",\r\n \"Vault\": \"Test\",\r\n \"Name\": \"Windows/SharePoint/DefaultServiceAccount\"\r\n }}", + ValueSourceType = "SecretReference" + }, + new + { + Id = new Guid("cd120ede-010a-7433-d59c-13f90301b9e2"), + ConfigurationDefinitionId = new Guid("b5f3de9e-251e-ebb1-c6cc-b4a1a2afc987"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + ScopeId = new Guid("72000000-0000-0000-0000-000000000103"), + ScopeType = "TemplateRevision", + SortOrder = 120, + ValueHash = "09773BB7E26265A65AB115E500C4CD051F10FEAA92C43C4260004F920BFDFAA5", + ValueJson = "{\"value\":\"0000-0000-0000-0000-0000\"}", + ValueSourceType = "Static" + }, + new + { + Id = new Guid("1a37be2a-89b9-4784-e89e-604946b4a2a0"), + ConfigurationDefinitionId = new Guid("e9a93051-120a-00c2-c69d-794d3d3c6c86"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + ScopeId = new Guid("72000000-0000-0000-0000-000000000103"), + ScopeType = "TemplateRevision", + SortOrder = 130, + ValueHash = "178FED388ECABE98936E5F474887112583588BF34C39241AC452A48A3E1CEA11", + ValueJson = "{\"value\":{\r\n \"Provider\": \"SecretManagement\",\r\n \"Vault\": \"Test\",\r\n \"Name\": \"Windows/SharePoint/SetupAccount\"\r\n }}", + ValueSourceType = "SecretReference" + }, + new + { + Id = new Guid("aed99da4-e113-0a05-287e-5cca3abc1c7c"), + ConfigurationDefinitionId = new Guid("d0fbeeb9-628d-fa56-c106-6f54e3080b11"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + ScopeId = new Guid("72000000-0000-0000-0000-000000000103"), + ScopeType = "TemplateRevision", + SortOrder = 140, + ValueHash = "E062DA6C7583AEC7061A78C9650B5B9CE023DD629C9E6FC3184CF8D0EFCF5755", + ValueJson = "{\"value\":\"SharePoint\"}", + ValueSourceType = "Static" + }, + new + { + Id = new Guid("67204f36-a09b-233d-c022-9b4c713f40e1"), + ConfigurationDefinitionId = new Guid("13f4b031-f8b8-1ef4-21b0-ab825dc54aee"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + ScopeId = new Guid("72000000-0000-0000-0000-000000000103"), + ScopeType = "TemplateRevision", + SortOrder = 150, + ValueHash = "5B90965D61E7AD5163813A169214CA5CF9F2297487CEEBFE591487661CBFEBE1", + ValueJson = "{\"value\":{\r\n \"Provider\": \"SecretManagement\",\r\n \"Vault\": \"Test\",\r\n \"Name\": \"Windows/SharePoint/SearchAccount\"\r\n }}", + ValueSourceType = "SecretReference" + }, + new + { + Id = new Guid("680f4dac-c18b-0646-f036-478caf967a7a"), + ConfigurationDefinitionId = new Guid("1fc14a66-5b69-00da-e92c-a38e6d674b50"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + ScopeId = new Guid("72000000-0000-0000-0000-000000000103"), + ScopeType = "TemplateRevision", + SortOrder = 160, + ValueHash = "80473B1B926C839E59F1D74E99D16E1BBC9E57E96B87545421BA23E9BF9E2536", + ValueJson = "{\"value\":4000}", + ValueSourceType = "Static" + }, + new + { + Id = new Guid("93bcf261-facd-49b5-376a-fdbb046e46a3"), + ConfigurationDefinitionId = new Guid("f7ea1bce-9cf1-ddc4-320f-e26ef51a6108"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + ScopeId = new Guid("72000000-0000-0000-0000-000000000103"), + ScopeType = "TemplateRevision", + SortOrder = 170, + ValueHash = "7A32645CBAED087EDCAF78976456E695575F839D30D6F09986DDFA3B59E0AA75", + ValueJson = "{\"value\":\"SharePoint Search Service Applications\"}", + ValueSourceType = "Static" + }, + new + { + Id = new Guid("4d9d3f0a-dd2e-7f7a-4bbd-8e33526dcbce"), + ConfigurationDefinitionId = new Guid("3bdcaa78-354c-487f-b0c5-6a3e0b20f8a1"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + ScopeId = new Guid("72000000-0000-0000-0000-000000000103"), + ScopeType = "TemplateRevision", + SortOrder = 10, + ValueHash = "F1D875A6571735F22CA408E51F3793292BD9051C28443A107D3D3AE3E67CC18F", + ValueJson = "{\"expression\":\"[joinNotEmpty(\\u0027_\\u0027, variables(\\u0027DatabasePrefix\\u0027), \\u0027Farm_AdminContent\\u0027)]\"}", + ValueSourceType = "Expression" + }, + new + { + Id = new Guid("f1520907-d5c3-3e33-1daa-0fbdec706c57"), + ConfigurationDefinitionId = new Guid("57fe8654-dbf4-c6c1-3a99-ac68fe393731"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + ScopeId = new Guid("72000000-0000-0000-0000-000000000103"), + ScopeType = "TemplateRevision", + SortOrder = 20, + ValueHash = "B00E74A711838E3C2D4D3779ED0DEAECCF66172565F88F8F9ACE644EEBFBCD91", + ValueJson = "{\"expression\":\"[joinNotEmpty(\\u0027_\\u0027, variables(\\u0027DatabasePrefix\\u0027), parameters(\\u0027ContentDatabaseSegment\\u0027))]\"}", + ValueSourceType = "Expression" + }, + new + { + Id = new Guid("d336f688-57f4-4df1-a992-27e775a48440"), + ConfigurationDefinitionId = new Guid("04091788-4a0a-7911-b11d-b70335ad378a"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + ScopeId = new Guid("72000000-0000-0000-0000-000000000103"), + ScopeType = "TemplateRevision", + SortOrder = 30, + ValueHash = "4D54C78468AB68A528415889AC8B50B89E2F5AFD0B0C36D3F6B060036422009E", + ValueJson = "{\"expression\":\"[joinNotEmpty(\\u0027_\\u0027, variables(\\u0027DatabasePrefix\\u0027), parameters(\\u0027ServiceDatabaseSegment\\u0027))]\"}", + ValueSourceType = "Expression" + }, + new + { + Id = new Guid("fc6347da-d00e-db4c-5b5b-5a5e80c568ab"), + ConfigurationDefinitionId = new Guid("7232ce0f-9f3e-e10b-9370-7aec1c610ecc"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + ScopeId = new Guid("72000000-0000-0000-0000-000000000103"), + ScopeType = "TemplateRevision", + SortOrder = 40, + ValueHash = "7EB8E130BDEA0111303714519A04B078E07970AEBD2C51EC0244F90D3E3DFC98", + ValueJson = "{\"expression\":\"[joinNotEmpty(\\u0027_\\u0027, parameters(\\u0027DatabasePrefix\\u0027), parameters(\\u0027DomainLabel\\u0027), if(equals(parameters(\\u0027Landscape\\u0027), \\u0027Test\\u0027), \\u0027Test\\u0027, \\u0027\\u0027))]\"}", + ValueSourceType = "Expression" + }, + new + { + Id = new Guid("0d47df0b-4ae8-e379-42f7-660dbf80cff1"), + ConfigurationDefinitionId = new Guid("73be057e-cd31-1658-186b-bcf4695a48f7"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + ScopeId = new Guid("72000000-0000-0000-0000-000000000103"), + ScopeType = "TemplateRevision", + SortOrder = 50, + ValueHash = "261FCBE546960FDBA45B615045DC04AE5B717633C4368C87A25A81B31339BE96", + ValueJson = "{\"expression\":\"[joinNotEmpty(\\u0027_\\u0027, variables(\\u0027DatabasePrefix\\u0027), \\u0027Farm_Config\\u0027)]\"}", + ValueSourceType = "Expression" + }); + }); + + modelBuilder.Entity("Microsoft.SelfService.Portal.Core.API.Models.CredentialSecretModel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier") + .HasColumnOrder(0) + .HasDefaultValueSql("NEWID()"); + + b.Property("Created") + .ValueGeneratedOnAdd() + .HasColumnType("datetime2") + .HasColumnOrder(52) + .HasDefaultValueSql("GETDATE()"); + + b.Property("CreatedBy") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(53); + + b.Property("IsEnabled") + .HasColumnType("bit") + .HasColumnOrder(6); + + b.Property("MetadataJson") + .HasColumnType("nvarchar(max)") + .HasColumnOrder(5); + + b.Property("Modified") + .ValueGeneratedOnAdd() + .HasColumnType("datetime2") + .HasColumnOrder(50) + .HasDefaultValueSql("GETDATE()"); + + b.Property("ModifiedBy") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(51); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)") + .HasColumnOrder(1); + + b.Property("SecretType") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(4); + + b.Property("SecretValue") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(3); + + b.Property("UserName") + .HasColumnType("nvarchar(max)") + .HasColumnOrder(2); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("CredentialSecrets", t => + { + t.HasCheckConstraint("CK_CredentialSecrets_MetadataJson_IsJson", "[MetadataJson] IS NULL OR ISJSON([MetadataJson]) = 1"); + }); + + b.HasData( + new + { + Id = new Guid("90000000-0000-0000-0000-000000000001"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + IsEnabled = true, + MetadataJson = "{\"environment\":\"Demo\",\"plaintext\":true}", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + Name = "Windows/SharePoint/SetupAccount", + SecretType = "Credential", + SecretValue = "DemoOnly-DoNotUseInProduction!", + UserName = "CONTOSO\\svc_sp_setup" + }, + new + { + Id = new Guid("90000000-0000-0000-0000-000000000002"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + IsEnabled = true, + MetadataJson = "{\"environment\":\"Demo\",\"plaintext\":true}", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + Name = "Windows/SharePoint/FarmAccount", + SecretType = "Credential", + SecretValue = "DemoOnly-DoNotUseInProduction!", + UserName = "CONTOSO\\svc_sp_farm" + }, + new + { + Id = new Guid("90000000-0000-0000-0000-000000000003"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + IsEnabled = true, + MetadataJson = "{\"environment\":\"Demo\",\"plaintext\":true}", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + Name = "Windows/SharePoint/FarmPassphrase", + SecretType = "Secret", + SecretValue = "DemoOnly-DoNotUseInProduction!" + }, + new + { + Id = new Guid("90000000-0000-0000-0000-000000000004"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + IsEnabled = true, + MetadataJson = "{\"environment\":\"Demo\",\"plaintext\":true}", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + Name = "Windows/SharePoint/DefaultServiceAccount", + SecretType = "Credential", + SecretValue = "DemoOnly-DoNotUseInProduction!", + UserName = "CONTOSO\\svc_sp_service" + }, + new + { + Id = new Guid("90000000-0000-0000-0000-000000000005"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + IsEnabled = true, + MetadataJson = "{\"environment\":\"Demo\",\"plaintext\":true}", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + Name = "Windows/SharePoint/SearchAccount", + SecretType = "Credential", + SecretValue = "DemoOnly-DoNotUseInProduction!", + UserName = "CONTOSO\\svc_sp_search" + }); + }); + + modelBuilder.Entity("Microsoft.SelfService.Portal.Core.API.Models.DeploymentArtifactModel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier") + .HasColumnOrder(0) + .HasDefaultValueSql("NEWID()"); + + b.Property("ArtifactType") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)") + .HasColumnOrder(4); + + b.Property("Created") + .ValueGeneratedOnAdd() + .HasColumnType("datetime2") + .HasColumnOrder(52) + .HasDefaultValueSql("GETDATE()"); + + b.Property("CreatedBy") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(53); + + b.Property("DeploymentGroupId") + .HasColumnType("uniqueidentifier") + .HasColumnOrder(1); + + b.Property("DeploymentJson") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(6); + + b.Property("DeploymentTargetId") + .HasColumnType("uniqueidentifier") + .HasColumnOrder(2); + + b.Property("InputHash") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)") + .HasColumnOrder(10); + + b.Property("IsStale") + .HasColumnType("bit") + .HasColumnOrder(12); + + b.Property("Modified") + .ValueGeneratedOnAdd() + .HasColumnType("datetime2") + .HasColumnOrder(50) + .HasDefaultValueSql("GETDATE()"); + + b.Property("ModifiedBy") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(51); + + b.Property("OutputHash") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)") + .HasColumnOrder(11); + + b.Property("ResolvedJson") + .HasColumnType("nvarchar(max)") + .HasColumnOrder(8); + + b.Property("SourceJson") + .HasColumnType("nvarchar(max)") + .HasColumnOrder(7); + + b.Property("SourceSnapshotJson") + .HasColumnType("nvarchar(max)") + .HasColumnOrder(9); + + b.Property("StaleReasonJson") + .HasColumnType("nvarchar(max)") + .HasColumnOrder(13); + + b.Property("Status") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(5); + + b.Property("TargetId") + .HasColumnType("uniqueidentifier") + .HasColumnOrder(3); + + b.HasKey("Id"); + + b.HasIndex("DeploymentGroupId"); + + b.HasIndex("TargetId", "DeploymentGroupId"); + + b.ToTable("DeploymentArtifacts", t => + { + t.HasCheckConstraint("CK_DeploymentArtifacts_DeploymentJson_IsJson", "ISJSON([DeploymentJson]) = 1"); + + t.HasCheckConstraint("CK_DeploymentArtifacts_ResolvedJson_IsJson", "[ResolvedJson] IS NULL OR ISJSON([ResolvedJson]) = 1"); + + t.HasCheckConstraint("CK_DeploymentArtifacts_SourceJson_IsJson", "[SourceJson] IS NULL OR ISJSON([SourceJson]) = 1"); + + t.HasCheckConstraint("CK_DeploymentArtifacts_SourceSnapshotJson_IsJson", "[SourceSnapshotJson] IS NULL OR ISJSON([SourceSnapshotJson]) = 1"); + }); + + b.HasData( + new + { + Id = new Guid("85000000-0000-0000-0000-000000000101"), + ArtifactType = "ResolvedConfigurationData", + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + DeploymentGroupId = new Guid("80000000-0000-0000-0000-000000000101"), + DeploymentJson = "{\n \"metadata\": {\n \"name\": \"Contoso-Test-SharePoint\",\n \"deploymentId\": \"8f6c2c1a\",\n \"source\": \"DemoData\"\n },\n \"parameters\": {\n \"DatabasePrefix\": \"SharePoint_Contoso_Test\"\n },\n \"variables\": {\n \"DatabasePrefix\": \"SharePoint_Contoso_Test\",\n \"ServiceDbPrefix\": \"SharePoint_Contoso_Test_Services\",\n \"ConfigDbName\": \"SharePoint_Contoso_Test_Farm_Config\"\n },\n \"resources\": {\n \"AllNodes\": [\n { \"NodeName\": \"CLD-SHP-01\", \"RunCentralAdministration\": true },\n { \"NodeName\": \"CLD-SHP-02\", \"RunCentralAdministration\": false },\n { \"NodeName\": \"CLD-SHP-03\", \"RunCentralAdministration\": false }\n ],\n \"NonNodeData\": {\n \"LocalConfigurationManager\": {\n \"ConfigurationMode\": \"ApplyOnly\"\n }\n }\n }\n}", + InputHash = "F081B9BACB21534D9673317615B990CC3836D68416CD6C94E06045E524640020", + IsStale = false, + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + OutputHash = "8A49E86D9D571FDE9FE243849A5399A73750798F165B0D9DCE1318B8561CEF01", + ResolvedJson = "{\n \"metadata\": {\n \"name\": \"Contoso-Test-SharePoint\",\n \"deploymentId\": \"8f6c2c1a\",\n \"source\": \"DemoData\"\n },\n \"parameters\": {\n \"DatabasePrefix\": \"SharePoint_Contoso_Test\"\n },\n \"variables\": {\n \"DatabasePrefix\": \"SharePoint_Contoso_Test\",\n \"ServiceDbPrefix\": \"SharePoint_Contoso_Test_Services\",\n \"ConfigDbName\": \"SharePoint_Contoso_Test_Farm_Config\"\n },\n \"resources\": {\n \"AllNodes\": [\n { \"NodeName\": \"CLD-SHP-01\", \"RunCentralAdministration\": true },\n { \"NodeName\": \"CLD-SHP-02\", \"RunCentralAdministration\": false },\n { \"NodeName\": \"CLD-SHP-03\", \"RunCentralAdministration\": false }\n ],\n \"NonNodeData\": {\n \"LocalConfigurationManager\": {\n \"ConfigurationMode\": \"ApplyOnly\"\n }\n }\n }\n}", + SourceJson = "{\"source\":\"DemoData\",\"composition\":\"Test.Merge.ps1\"}", + SourceSnapshotJson = "{\n \"templateRevisions\": [\n {\n \"id\": \"72000000-0000-0000-0000-000000000101\",\n \"templateVersionId\": \"71000000-0000-0000-0000-000000000101\",\n \"role\": \"Environment\",\n \"alias\": \"Environment-Test\",\n \"hash\": \"58553C7A4E902B5E39D30272754FEF9EF805A7F36363D8316A9B37540C6D4646\"\n },\n {\n \"id\": \"72000000-0000-0000-0000-000000000102\",\n \"templateVersionId\": \"71000000-0000-0000-0000-000000000102\",\n \"role\": \"Domain\",\n \"alias\": \"Domain-Contoso\",\n \"hash\": \"B265C4D542826423BAAF50BF939F026CC67FF631FEC19F708067516BCE4C7667\"\n },\n {\n \"id\": \"72000000-0000-0000-0000-000000000103\",\n \"templateVersionId\": \"71000000-0000-0000-0000-000000000103\",\n \"role\": \"Service\",\n \"alias\": \"Service-SharePoint-Contoso\",\n \"hash\": \"E3B0E2A8E0C85CCD92AEA521ECD243E61E34C61D7078D6715E6317F5669A1D69\"\n },\n {\n \"id\": \"72000000-0000-0000-0000-000000000104\",\n \"templateVersionId\": \"71000000-0000-0000-0000-000000000104\",\n \"role\": \"Stage\",\n \"alias\": \"Stage-Install\",\n \"hash\": \"ACA23E44C9F625F080D2653646555A9DE5546D8DE7BB2166324E775BCF47F3C1\"\n }\n ],\n \"targets\": [\n { \"id\": \"30000000-0000-0000-0000-000000000101\", \"nodeName\": \"CLD-SHP-01\" },\n { \"id\": \"30000000-0000-0000-0000-000000000102\", \"nodeName\": \"CLD-SHP-02\" },\n { \"id\": \"30000000-0000-0000-0000-000000000103\", \"nodeName\": \"CLD-SHP-03\" }\n ]\n}", + Status = "Pending" + }); + }); + + modelBuilder.Entity("Microsoft.SelfService.Portal.Core.API.Models.DeploymentGroupModel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier") + .HasColumnOrder(0) + .HasDefaultValueSql("NEWID()"); + + b.Property("Created") + .ValueGeneratedOnAdd() + .HasColumnType("datetime2") + .HasColumnOrder(52) + .HasDefaultValueSql("GETDATE()"); + + b.Property("CreatedBy") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(53); + + b.Property("DeploymentRuleId") + .HasColumnType("uniqueidentifier") + .HasColumnOrder(3); + + b.Property("Modified") + .ValueGeneratedOnAdd() + .HasColumnType("datetime2") + .HasColumnOrder(50) + .HasDefaultValueSql("GETDATE()"); + + b.Property("ModifiedBy") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(51); + + b.Property("Status") + .IsRequired() + .ValueGeneratedOnAdd() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(4) + .HasDefaultValueSql("'New'"); + + b.Property("TemplateId") + .HasColumnType("uniqueidentifier") + .HasColumnOrder(2); + + b.HasKey("Id"); + + b.HasIndex("DeploymentRuleId"); + + b.HasIndex("TemplateId"); + + b.ToTable("DeploymentBatches", (string)null); + + b.HasData( + new + { + Id = new Guid("80000000-0000-0000-0000-000000000001"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + DeploymentRuleId = new Guid("60000000-0000-0000-0000-000000000001"), + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + Status = "Pending", + TemplateId = new Guid("70000000-0000-0000-0000-000000000003") + }, + new + { + Id = new Guid("80000000-0000-0000-0000-000000000101"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + DeploymentRuleId = new Guid("60000000-0000-0000-0000-000000000001"), + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + Status = "Pending", + TemplateId = new Guid("70000000-0000-0000-0000-000000000103") + }); + }); + + modelBuilder.Entity("Microsoft.SelfService.Portal.Core.API.Models.DeploymentModel", b => + { + b.Property("TargetId") + .HasColumnType("uniqueidentifier") + .HasColumnOrder(3); + + b.Property("DeploymentGroupId") + .HasColumnType("uniqueidentifier") + .HasColumnName("DeploymentBatchId") + .HasColumnOrder(2); + + b.Property("Created") + .ValueGeneratedOnAdd() + .HasColumnType("datetime2") + .HasColumnOrder(52) + .HasDefaultValueSql("GETDATE()"); + + b.Property("CreatedBy") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(53); + + b.Property("CurrentArtifactId") + .HasColumnType("uniqueidentifier") + .HasColumnOrder(5); + + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier") + .HasColumnOrder(0) + .HasDefaultValueSql("NEWID()"); + + b.Property("JSONData") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(7); + + b.Property("Modified") + .ValueGeneratedOnAdd() + .HasColumnType("datetime2") + .HasColumnOrder(50) + .HasDefaultValueSql("GETDATE()"); + + b.Property("ModifiedBy") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(51); + + b.Property("OverridesJson") + .HasColumnType("nvarchar(max)") + .HasColumnOrder(8); + + b.Property("SourceJson") + .HasColumnType("nvarchar(max)") + .HasColumnOrder(9); + + b.Property("Status") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(6); + + b.Property("TemplateRevisionId") + .HasColumnType("uniqueidentifier") + .HasColumnOrder(4); + + b.HasKey("TargetId", "DeploymentGroupId"); + + b.HasIndex("CurrentArtifactId"); + + b.HasIndex("DeploymentGroupId"); + + b.HasIndex("TemplateRevisionId"); + + b.ToTable("DeploymentExecutions", (string)null); + + b.HasData( + new + { + TargetId = new Guid("30000000-0000-0000-0000-000000000004"), + DeploymentGroupId = new Guid("80000000-0000-0000-0000-000000000001"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + Id = new Guid("81000000-0000-0000-0000-000000000001"), + JSONData = "{\"role\":\"WebFrontEnd\"}", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + Status = "Pending", + TemplateRevisionId = new Guid("72000000-0000-0000-0000-000000000003") + }, + new + { + TargetId = new Guid("30000000-0000-0000-0000-000000000005"), + DeploymentGroupId = new Guid("80000000-0000-0000-0000-000000000001"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + Id = new Guid("81000000-0000-0000-0000-000000000002"), + JSONData = "{\"role\":\"Application\"}", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + Status = "Pending", + TemplateRevisionId = new Guid("72000000-0000-0000-0000-000000000003") + }, + new + { + TargetId = new Guid("30000000-0000-0000-0000-000000000101"), + DeploymentGroupId = new Guid("80000000-0000-0000-0000-000000000101"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + Id = new Guid("81000000-0000-0000-0000-000000000101"), + JSONData = "{\"role\":\"Node\"}", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + Status = "Pending", + TemplateRevisionId = new Guid("72000000-0000-0000-0000-000000000103") + }, + new + { + TargetId = new Guid("30000000-0000-0000-0000-000000000102"), + DeploymentGroupId = new Guid("80000000-0000-0000-0000-000000000101"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + Id = new Guid("81000000-0000-0000-0000-000000000102"), + JSONData = "{\"role\":\"Node\"}", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + Status = "Pending", + TemplateRevisionId = new Guid("72000000-0000-0000-0000-000000000103") + }, + new + { + TargetId = new Guid("30000000-0000-0000-0000-000000000103"), + DeploymentGroupId = new Guid("80000000-0000-0000-0000-000000000101"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + Id = new Guid("81000000-0000-0000-0000-000000000103"), + JSONData = "{\"role\":\"Node\"}", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + Status = "Pending", + TemplateRevisionId = new Guid("72000000-0000-0000-0000-000000000103") + }); + }); + + modelBuilder.Entity("Microsoft.SelfService.Portal.Core.API.Models.DeploymentParameterValueModel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier") + .HasColumnOrder(0) + .HasDefaultValueSql("NEWID()"); + + b.Property("Created") + .ValueGeneratedOnAdd() + .HasColumnType("datetime2") + .HasColumnOrder(52) + .HasDefaultValueSql("GETDATE()"); + + b.Property("CreatedBy") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(53); + + b.Property("DeploymentGroupId") + .HasColumnType("uniqueidentifier") + .HasColumnOrder(1); + + b.Property("DeploymentTemplateSelectionId") + .HasColumnType("uniqueidentifier") + .HasColumnOrder(2); + + b.Property("IsOverride") + .HasColumnType("bit") + .HasColumnOrder(6); + + b.Property("IsSecretReference") + .HasColumnType("bit") + .HasColumnOrder(5); + + b.Property("Modified") + .ValueGeneratedOnAdd() + .HasColumnType("datetime2") + .HasColumnOrder(50) + .HasDefaultValueSql("GETDATE()"); + + b.Property("ModifiedBy") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(51); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)") + .HasColumnOrder(3); + + b.Property("ValueJson") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(4); + + b.HasKey("Id"); + + b.HasIndex("DeploymentTemplateSelectionId"); + + b.HasIndex("DeploymentGroupId", "Name") + .IsUnique() + .HasFilter("[DeploymentTemplateSelectionId] IS NULL"); + + b.HasIndex("DeploymentGroupId", "DeploymentTemplateSelectionId", "Name") + .IsUnique() + .HasFilter("[DeploymentTemplateSelectionId] IS NOT NULL"); + + b.ToTable("DeploymentParameterValues", t => + { + t.HasCheckConstraint("CK_DeploymentParameterValues_ValueJson_IsJson", "ISJSON([ValueJson]) = 1"); + }); + + b.HasData( + new + { + Id = new Guid("83000000-0000-0000-0000-000000000001"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + DeploymentGroupId = new Guid("80000000-0000-0000-0000-000000000001"), + DeploymentTemplateSelectionId = new Guid("82000000-0000-0000-0000-000000000001"), + IsOverride = true, + IsSecretReference = false, + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + Name = "DatabasePrefix", + ValueJson = "{\"value\":\"SharePoint_Contoso_Test\"}" + }, + new + { + Id = new Guid("83000000-0000-0000-0000-000000000002"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + DeploymentGroupId = new Guid("80000000-0000-0000-0000-000000000001"), + DeploymentTemplateSelectionId = new Guid("82000000-0000-0000-0000-000000000001"), + IsOverride = true, + IsSecretReference = true, + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + Name = "FarmAccount", + ValueJson = "{\"provider\":\"SecretManagement\",\"vault\":\"ContosoDemo\",\"name\":\"Windows/SharePoint/FarmAccount\"}" + }); + }); + + modelBuilder.Entity("Microsoft.SelfService.Portal.Core.API.Models.DeploymentRuleModel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier") + .HasColumnOrder(0) + .HasDefaultValueSql("NEWID()"); + + b.Property("Created") + .ValueGeneratedOnAdd() + .HasColumnType("datetime2") + .HasColumnOrder(52) + .HasDefaultValueSql("GETDATE()"); + + b.Property("CreatedBy") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(53); + + b.Property("Description") + .HasColumnType("nvarchar(max)") + .HasColumnOrder(2); + + b.Property("IsActive") + .HasColumnType("bit") + .HasColumnOrder(3); + + b.Property("Modified") + .ValueGeneratedOnAdd() + .HasColumnType("datetime2") + .HasColumnOrder(50) + .HasDefaultValueSql("GETDATE()"); + + b.Property("ModifiedBy") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(51); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(1); + + b.HasKey("Id"); + + b.ToTable("DeploymentRules"); + + b.HasData( + new + { + Id = new Guid("60000000-0000-0000-0000-000000000001"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + Description = "Validate input, wait for approval, then provision targets.", + IsActive = true, + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + Name = "Standard Provisioning" + }); + }); + + modelBuilder.Entity("Microsoft.SelfService.Portal.Core.API.Models.DeploymentRuleStepModel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier") + .HasColumnOrder(0) + .HasDefaultValueSql("NEWID()"); + + b.Property("Created") + .ValueGeneratedOnAdd() + .HasColumnType("datetime2") + .HasColumnOrder(52) + .HasDefaultValueSql("GETDATE()"); + + b.Property("CreatedBy") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(53); + + b.Property("DeploymentRuleId") + .HasColumnType("uniqueidentifier") + .HasColumnOrder(1); + + b.Property("MetadataJson") + .HasColumnType("nvarchar(max)") + .HasColumnOrder(6); + + b.Property("Modified") + .ValueGeneratedOnAdd() + .HasColumnType("datetime2") + .HasColumnOrder(50) + .HasDefaultValueSql("GETDATE()"); + + b.Property("ModifiedBy") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(51); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(3); + + b.Property("RequiresApproval") + .HasColumnType("bit") + .HasColumnOrder(5); + + b.Property("SortOrder") + .HasColumnType("int") + .HasColumnOrder(2); + + b.Property("StepType") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(4); + + b.HasKey("Id"); + + b.HasIndex("DeploymentRuleId"); + + b.ToTable("DeploymentRuleSteps"); + + b.HasData( + new + { + Id = new Guid("60000000-0000-0000-0000-000000000101"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + DeploymentRuleId = new Guid("60000000-0000-0000-0000-000000000001"), + MetadataJson = "{\"action\":\"validate\"}", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + Name = "Validate configuration", + RequiresApproval = false, + SortOrder = 10, + StepType = "Provision" + }, + new + { + Id = new Guid("60000000-0000-0000-0000-000000000102"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + DeploymentRuleId = new Guid("60000000-0000-0000-0000-000000000001"), + MetadataJson = "{\"approverGroup\":\"Platform Owners\"}", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + Name = "Approve deployment", + RequiresApproval = true, + SortOrder = 20, + StepType = "Approval" + }, + new + { + Id = new Guid("60000000-0000-0000-0000-000000000103"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + DeploymentRuleId = new Guid("60000000-0000-0000-0000-000000000001"), + MetadataJson = "{\"action\":\"deploy\"}", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + Name = "Provision workload", + RequiresApproval = false, + SortOrder = 30, + StepType = "Provision" + }); + }); + + modelBuilder.Entity("Microsoft.SelfService.Portal.Core.API.Models.DeploymentTargetAssignmentModel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier") + .HasColumnOrder(0) + .HasDefaultValueSql("NEWID()"); + + b.Property("Created") + .ValueGeneratedOnAdd() + .HasColumnType("datetime2") + .HasColumnOrder(52) + .HasDefaultValueSql("GETDATE()"); + + b.Property("CreatedBy") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(53); + + b.Property("DeploymentGroupId") + .HasColumnType("uniqueidentifier") + .HasColumnOrder(1); + + b.Property("Modified") + .ValueGeneratedOnAdd() + .HasColumnType("datetime2") + .HasColumnOrder(50) + .HasDefaultValueSql("GETDATE()"); + + b.Property("ModifiedBy") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(51); + + b.Property("NodeDataJson") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(5); + + b.Property("RoleKey") + .IsRequired() + .HasColumnType("nvarchar(450)") + .HasColumnOrder(3); + + b.Property("SortOrder") + .HasColumnType("int") + .HasColumnOrder(4); + + b.Property("TargetId") + .HasColumnType("uniqueidentifier") + .HasColumnOrder(2); + + b.HasKey("Id"); + + b.HasIndex("TargetId"); + + b.HasIndex("DeploymentGroupId", "TargetId", "RoleKey") + .IsUnique(); + + b.ToTable("DeploymentTargetAssignments", t => + { + t.HasCheckConstraint("CK_DeploymentTargetAssignments_NodeDataJson_IsJson", "ISJSON([NodeDataJson]) = 1"); + }); + + b.HasData( + new + { + Id = new Guid("84000000-0000-0000-0000-000000000001"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + DeploymentGroupId = new Guid("80000000-0000-0000-0000-000000000001"), + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + NodeDataJson = "{\"nodeName\":\"CT-SHP-01\"}", + RoleKey = "WebFrontEnd", + SortOrder = 10, + TargetId = new Guid("30000000-0000-0000-0000-000000000004") + }, + new + { + Id = new Guid("84000000-0000-0000-0000-000000000002"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + DeploymentGroupId = new Guid("80000000-0000-0000-0000-000000000001"), + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + NodeDataJson = "{\"nodeName\":\"CT-SHP-02\"}", + RoleKey = "Application", + SortOrder = 20, + TargetId = new Guid("30000000-0000-0000-0000-000000000005") + }, + new + { + Id = new Guid("84000000-0000-0000-0000-000000000101"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + DeploymentGroupId = new Guid("80000000-0000-0000-0000-000000000101"), + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + NodeDataJson = "{\"nodeName\":\"CLD-SHP-01\",\"RunCentralAdministration\":true}", + RoleKey = "Node", + SortOrder = 10, + TargetId = new Guid("30000000-0000-0000-0000-000000000101") + }, + new + { + Id = new Guid("84000000-0000-0000-0000-000000000102"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + DeploymentGroupId = new Guid("80000000-0000-0000-0000-000000000101"), + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + NodeDataJson = "{\"nodeName\":\"CLD-SHP-02\",\"RunCentralAdministration\":false}", + RoleKey = "Node", + SortOrder = 20, + TargetId = new Guid("30000000-0000-0000-0000-000000000102") + }, + new + { + Id = new Guid("84000000-0000-0000-0000-000000000103"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + DeploymentGroupId = new Guid("80000000-0000-0000-0000-000000000101"), + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + NodeDataJson = "{\"nodeName\":\"CLD-SHP-03\",\"RunCentralAdministration\":false}", + RoleKey = "Node", + SortOrder = 30, + TargetId = new Guid("30000000-0000-0000-0000-000000000103") + }); + }); + + modelBuilder.Entity("Microsoft.SelfService.Portal.Core.API.Models.DeploymentTemplateSelectionModel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier") + .HasColumnOrder(0) + .HasDefaultValueSql("NEWID()"); + + b.Property("Alias") + .HasColumnType("nvarchar(max)") + .HasColumnOrder(6); + + b.Property("Created") + .ValueGeneratedOnAdd() + .HasColumnType("datetime2") + .HasColumnOrder(52) + .HasDefaultValueSql("GETDATE()"); + + b.Property("CreatedBy") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(53); + + b.Property("DeploymentGroupId") + .HasColumnType("uniqueidentifier") + .HasColumnOrder(1); + + b.Property("Modified") + .ValueGeneratedOnAdd() + .HasColumnType("datetime2") + .HasColumnOrder(50) + .HasDefaultValueSql("GETDATE()"); + + b.Property("ModifiedBy") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(51); + + b.Property("SortOrder") + .HasColumnType("int") + .HasColumnOrder(5); + + b.Property("TemplateRevisionId") + .HasColumnType("uniqueidentifier") + .HasColumnOrder(3); + + b.Property("TemplateRole") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(4); + + b.Property("TemplateVersionId") + .HasColumnType("uniqueidentifier") + .HasColumnOrder(2); + + b.HasKey("Id"); + + b.HasIndex("TemplateRevisionId"); + + b.HasIndex("TemplateVersionId"); + + b.HasIndex("DeploymentGroupId", "SortOrder") + .IsUnique(); + + b.ToTable("DeploymentTemplateSelections"); + + b.HasData( + new + { + Id = new Guid("82000000-0000-0000-0000-000000000001"), + Alias = "SharePoint", + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + DeploymentGroupId = new Guid("80000000-0000-0000-0000-000000000001"), + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + SortOrder = 10, + TemplateRevisionId = new Guid("72000000-0000-0000-0000-000000000003"), + TemplateRole = "Service", + TemplateVersionId = new Guid("71000000-0000-0000-0000-000000000003") + }, + new + { + Id = new Guid("82000000-0000-0000-0000-000000000101"), + Alias = "Environment-Test", + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + DeploymentGroupId = new Guid("80000000-0000-0000-0000-000000000101"), + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + SortOrder = 10, + TemplateRevisionId = new Guid("72000000-0000-0000-0000-000000000101"), + TemplateRole = "Environment", + TemplateVersionId = new Guid("71000000-0000-0000-0000-000000000101") + }, + new + { + Id = new Guid("82000000-0000-0000-0000-000000000102"), + Alias = "Domain-Contoso", + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + DeploymentGroupId = new Guid("80000000-0000-0000-0000-000000000101"), + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + SortOrder = 20, + TemplateRevisionId = new Guid("72000000-0000-0000-0000-000000000102"), + TemplateRole = "Domain", + TemplateVersionId = new Guid("71000000-0000-0000-0000-000000000102") + }, + new + { + Id = new Guid("82000000-0000-0000-0000-000000000103"), + Alias = "Service-SharePoint-Contoso", + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + DeploymentGroupId = new Guid("80000000-0000-0000-0000-000000000101"), + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + SortOrder = 30, + TemplateRevisionId = new Guid("72000000-0000-0000-0000-000000000103"), + TemplateRole = "Service", + TemplateVersionId = new Guid("71000000-0000-0000-0000-000000000103") + }, + new + { + Id = new Guid("82000000-0000-0000-0000-000000000104"), + Alias = "Stage-Install", + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + DeploymentGroupId = new Guid("80000000-0000-0000-0000-000000000101"), + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + SortOrder = 40, + TemplateRevisionId = new Guid("72000000-0000-0000-0000-000000000104"), + TemplateRole = "Stage", + TemplateVersionId = new Guid("71000000-0000-0000-0000-000000000104") + }); + }); + + modelBuilder.Entity("Microsoft.SelfService.Portal.Core.API.Models.DomainModel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier") + .HasColumnOrder(0) + .HasDefaultValueSql("NEWID()"); + + b.Property("Created") + .ValueGeneratedOnAdd() + .HasColumnType("datetime2") + .HasColumnOrder(52) + .HasDefaultValueSql("GETDATE()"); + + b.Property("CreatedBy") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(53); + + b.Property("FQDN") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(2); + + b.Property("Modified") + .ValueGeneratedOnAdd() + .HasColumnType("datetime2") + .HasColumnOrder(50) + .HasDefaultValueSql("GETDATE()"); + + b.Property("ModifiedBy") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(51); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(1); + + b.Property("NetBIOS") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(3); + + b.HasKey("Id"); + + b.ToTable("Domains"); + + b.HasData( + new + { + Id = new Guid("20000000-0000-0000-0000-000000000001"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + FQDN = "corp.contoso.com", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + Name = "Central Management", + NetBIOS = "CONTOSO" + }, + new + { + Id = new Guid("20000000-0000-0000-0000-000000000002"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + FQDN = "resource.contoso.com", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + Name = "Resource Domain", + NetBIOS = "RESOURCE" + }); + }); + + modelBuilder.Entity("Microsoft.SelfService.Portal.Core.API.Models.EnvironmentDomainsModel", b => + { + b.Property("EnvironmentId") + .HasColumnType("uniqueidentifier") + .HasColumnOrder(0); + + b.Property("DomainId") + .HasColumnType("uniqueidentifier") + .HasColumnOrder(1); + + b.Property("Created") + .HasColumnType("datetime2") + .HasColumnOrder(52); + + b.Property("CreatedBy") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(53); + + b.Property("Modified") + .HasColumnType("datetime2") + .HasColumnOrder(50); + + b.Property("ModifiedBy") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(51); + + b.HasKey("EnvironmentId", "DomainId"); + + b.HasIndex("DomainId"); + + b.ToTable("EnvironmentDomains"); + + b.HasData( + new + { + EnvironmentId = new Guid("10000000-0000-0000-0000-000000000001"), + DomainId = new Guid("20000000-0000-0000-0000-000000000001"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed" + }, + new + { + EnvironmentId = new Guid("10000000-0000-0000-0000-000000000002"), + DomainId = new Guid("20000000-0000-0000-0000-000000000001"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed" + }, + new + { + EnvironmentId = new Guid("10000000-0000-0000-0000-000000000002"), + DomainId = new Guid("20000000-0000-0000-0000-000000000002"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed" + }); + }); + + modelBuilder.Entity("Microsoft.SelfService.Portal.Core.API.Models.EnvironmentModel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier") + .HasColumnOrder(0) + .HasDefaultValueSql("NEWID()"); + + b.Property("Created") + .ValueGeneratedOnAdd() + .HasColumnType("datetime2") + .HasColumnOrder(52) + .HasDefaultValueSql("GETDATE()"); + + b.Property("CreatedBy") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(53); + + b.Property("EnvironmentType") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(2); + + b.Property("HostingType") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(3); + + b.Property("MetadataJson") + .HasColumnType("nvarchar(max)") + .HasColumnOrder(7); + + b.Property("Modified") + .ValueGeneratedOnAdd() + .HasColumnType("datetime2") + .HasColumnOrder(50) + .HasDefaultValueSql("GETDATE()"); + + b.Property("ModifiedBy") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(51); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(1); + + b.Property("ProviderType") + .HasColumnType("nvarchar(max)") + .HasColumnOrder(4); + + b.Property("SubscriptionId") + .HasColumnType("nvarchar(max)") + .HasColumnOrder(6); + + b.Property("TenantId") + .HasColumnType("nvarchar(max)") + .HasColumnOrder(5); + + b.HasKey("Id"); + + b.ToTable("Environments"); + + b.HasData( + new + { + Id = new Guid("10000000-0000-0000-0000-000000000001"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + EnvironmentType = "Test", + HostingType = "OnPrem", + MetadataJson = "{\"location\":\"Datacenter A\"}", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + Name = "Contoso Test" + }, + new + { + Id = new Guid("10000000-0000-0000-0000-000000000002"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + EnvironmentType = "Production", + HostingType = "OnPrem", + MetadataJson = "{\"location\":\"Datacenter A\"}", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + Name = "Contoso Production" + }, + new + { + Id = new Guid("10000000-0000-0000-0000-000000000003"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + EnvironmentType = "Production", + HostingType = "M365Tenant", + MetadataJson = "{\"tenant\":\"contoso.onmicrosoft.com\"}", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + Name = "Contoso M365", + ProviderType = "Microsoft365", + TenantId = "11111111-1111-1111-1111-111111111111" + }); + }); + + modelBuilder.Entity("Microsoft.SelfService.Portal.Core.API.Models.OptionCategoryModel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier") + .HasColumnOrder(0) + .HasDefaultValueSql("NEWID()"); + + b.Property("Created") + .ValueGeneratedOnAdd() + .HasColumnType("datetime2") + .HasColumnOrder(52) + .HasDefaultValueSql("GETDATE()"); + + b.Property("CreatedBy") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(53); + + b.Property("Modified") + .ValueGeneratedOnAdd() + .HasColumnType("datetime2") + .HasColumnOrder(50) + .HasDefaultValueSql("GETDATE()"); + + b.Property("ModifiedBy") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(51); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(1); + + b.Property("ParentCategoryName") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(2); + + b.Property("showOrder") + .HasColumnType("int") + .HasColumnOrder(3); + + b.HasKey("Id"); + + b.ToTable("OptionCategories"); + }); + + modelBuilder.Entity("Microsoft.SelfService.Portal.Core.API.Models.OptionModel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier") + .HasColumnOrder(0) + .HasDefaultValueSql("NEWID()"); + + b.Property("Created") + .ValueGeneratedOnAdd() + .HasColumnType("datetime2") + .HasColumnOrder(52) + .HasDefaultValueSql("GETDATE()"); + + b.Property("CreatedBy") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(53); + + b.Property("Modified") + .ValueGeneratedOnAdd() + .HasColumnType("datetime2") + .HasColumnOrder(50) + .HasDefaultValueSql("GETDATE()"); + + b.Property("ModifiedBy") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(51); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(1); + + b.Property("OptionCategoryId") + .HasColumnType("uniqueidentifier"); + + b.Property("OptionType") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(2); + + b.Property("OptionValue") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(3); + + b.HasKey("Id"); + + b.HasIndex("OptionCategoryId"); + + b.ToTable("Options"); + }); + + modelBuilder.Entity("Microsoft.SelfService.Portal.Core.API.Models.QueueJobModel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier") + .HasColumnOrder(0) + .HasDefaultValueSql("NEWID()"); + + b.Property("Attempts") + .HasColumnType("int") + .HasColumnOrder(4); + + b.Property("CorrelationId") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier") + .HasColumnOrder(13) + .HasDefaultValueSql("NEWID()"); + + b.Property("Created") + .ValueGeneratedOnAdd() + .HasColumnType("datetime2") + .HasColumnOrder(52) + .HasDefaultValueSql("GETDATE()"); + + b.Property("CreatedBy") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(53); + + b.Property("ErrorMessage") + .HasColumnType("nvarchar(max)") + .HasColumnOrder(10); + + b.Property("Finished") + .HasColumnType("datetime2") + .HasColumnOrder(7); + + b.Property("HeartbeatAt") + .HasColumnType("datetime2") + .HasColumnOrder(16); + + b.Property("LockedBy") + .HasColumnType("nvarchar(max)") + .HasColumnOrder(9); + + b.Property("LockedUntil") + .HasColumnType("datetime2") + .HasColumnOrder(8); + + b.Property("MaxAttempts") + .HasColumnType("int") + .HasColumnOrder(5); + + b.Property("MetadataJson") + .HasColumnType("nvarchar(max)") + .HasColumnOrder(11); + + b.Property("Modified") + .ValueGeneratedOnAdd() + .HasColumnType("datetime2") + .HasColumnOrder(50) + .HasDefaultValueSql("GETDATE()"); + + b.Property("ModifiedBy") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(51); + + b.Property("PayloadJson") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(3); + + b.Property("Priority") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasDefaultValue(100) + .HasColumnOrder(14); + + b.Property("RowVersion") + .IsConcurrencyToken() + .IsRequired() + .ValueGeneratedOnAddOrUpdate() + .HasColumnType("rowversion"); + + b.Property("RuleSnapshotJson") + .HasColumnType("nvarchar(max)") + .HasColumnOrder(12); + + b.Property("ScheduledAt") + .HasColumnType("datetime2") + .HasColumnOrder(15); + + b.Property("Started") + .HasColumnType("datetime2") + .HasColumnOrder(6); + + b.Property("Status") + .IsRequired() + .HasColumnType("nvarchar(450)") + .HasColumnOrder(2); + + b.Property("Type") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(1); + + b.Property("WorkerName") + .HasColumnType("nvarchar(450)") + .HasColumnOrder(17); + + b.HasKey("Id"); + + b.HasIndex("CorrelationId"); + + b.HasIndex("WorkerName"); + + b.HasIndex("Status", "ScheduledAt", "LockedUntil", "Priority", "Created"); + + b.ToTable("DeploymentJobs", (string)null); + }); + + modelBuilder.Entity("Microsoft.SelfService.Portal.Core.API.Models.QueueJobStepModel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier") + .HasColumnOrder(0) + .HasDefaultValueSql("NEWID()"); + + b.Property("ApprovalComment") + .HasColumnType("nvarchar(max)") + .HasColumnOrder(10); + + b.Property("ApprovedAt") + .HasColumnType("datetime2") + .HasColumnOrder(8); + + b.Property("ApprovedBy") + .HasColumnType("nvarchar(max)") + .HasColumnOrder(9); + + b.Property("Created") + .ValueGeneratedOnAdd() + .HasColumnType("datetime2") + .HasColumnOrder(52) + .HasDefaultValueSql("GETDATE()"); + + b.Property("CreatedBy") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(53); + + b.Property("DependsOnQueueJobStepId") + .HasColumnType("uniqueidentifier") + .HasColumnName("DependsOnDeploymentJobStepId") + .HasColumnOrder(2); + + b.Property("ErrorMessage") + .HasColumnType("nvarchar(max)") + .HasColumnOrder(14); + + b.Property("Finished") + .HasColumnType("datetime2") + .HasColumnOrder(12); + + b.Property("MetadataJson") + .HasColumnType("nvarchar(max)") + .HasColumnOrder(7); + + b.Property("Modified") + .ValueGeneratedOnAdd() + .HasColumnType("datetime2") + .HasColumnOrder(50) + .HasDefaultValueSql("GETDATE()"); + + b.Property("ModifiedBy") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(51); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(4); + + b.Property("OutputMetadataJson") + .HasColumnType("nvarchar(max)") + .HasColumnOrder(13); + + b.Property("QueueJobId") + .HasColumnType("uniqueidentifier") + .HasColumnName("DeploymentJobId") + .HasColumnOrder(1); + + b.Property("SortOrder") + .HasColumnType("int") + .HasColumnOrder(3); + + b.Property("Started") + .HasColumnType("datetime2") + .HasColumnOrder(11); + + b.Property("Status") + .IsRequired() + .HasColumnType("nvarchar(450)") + .HasColumnOrder(6); + + b.Property("StepType") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(5); + + b.HasKey("Id"); + + b.HasIndex("DependsOnQueueJobStepId"); + + b.HasIndex("QueueJobId", "Status", "SortOrder"); + + b.ToTable("DeploymentJobSteps", null, t => + { + t.HasCheckConstraint("CK_DeploymentJobSteps_OutputMetadataJson_IsJson", "[OutputMetadataJson] IS NULL OR ISJSON([OutputMetadataJson]) = 1"); + }); + }); + + modelBuilder.Entity("Microsoft.SelfService.Portal.Core.API.Models.QueueJobTargetModel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier") + .HasColumnOrder(0) + .HasDefaultValueSql("NEWID()"); + + b.Property("Attempts") + .HasColumnType("int") + .HasColumnOrder(6); + + b.Property("Created") + .ValueGeneratedOnAdd() + .HasColumnType("datetime2") + .HasColumnOrder(52) + .HasDefaultValueSql("GETDATE()"); + + b.Property("CreatedBy") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(53); + + b.Property("DeploymentGroupId") + .HasColumnType("uniqueidentifier") + .HasColumnName("DeploymentBatchId") + .HasColumnOrder(3); + + b.Property("ErrorMessage") + .HasColumnType("nvarchar(max)") + .HasColumnOrder(7); + + b.Property("Finished") + .HasColumnType("datetime2") + .HasColumnOrder(9); + + b.Property("Modified") + .ValueGeneratedOnAdd() + .HasColumnType("datetime2") + .HasColumnOrder(50) + .HasDefaultValueSql("GETDATE()"); + + b.Property("ModifiedBy") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(51); + + b.Property("OutputMetadataJson") + .HasColumnType("nvarchar(max)") + .HasColumnOrder(10); + + b.Property("QueueJobId") + .HasColumnType("uniqueidentifier") + .HasColumnName("DeploymentJobId") + .HasColumnOrder(1); + + b.Property("Started") + .HasColumnType("datetime2") + .HasColumnOrder(8); + + b.Property("Status") + .IsRequired() + .HasColumnType("nvarchar(450)") + .HasColumnOrder(5); + + b.Property("TargetId") + .HasColumnType("uniqueidentifier") + .HasColumnOrder(2); + + b.Property("TemplateId") + .HasColumnType("uniqueidentifier") + .HasColumnOrder(4); + + b.HasKey("Id"); + + b.HasIndex("QueueJobId", "Status"); + + b.ToTable("DeploymentJobTargets", null, t => + { + t.HasCheckConstraint("CK_DeploymentJobTargets_OutputMetadataJson_IsJson", "[OutputMetadataJson] IS NULL OR ISJSON([OutputMetadataJson]) = 1"); + }); + }); + + modelBuilder.Entity("Microsoft.SelfService.Portal.Core.API.Models.ServiceModel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier") + .HasColumnOrder(0) + .HasDefaultValueSql("NEWID()"); + + b.Property("Created") + .ValueGeneratedOnAdd() + .HasColumnType("datetime2") + .HasColumnOrder(52) + .HasDefaultValueSql("GETDATE()"); + + b.Property("CreatedBy") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(53); + + b.Property("Description") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(2); + + b.Property("IconKey") + .HasColumnType("nvarchar(max)") + .HasColumnOrder(4); + + b.Property("IsCloudService") + .HasColumnType("bit") + .HasColumnOrder(3); + + b.Property("Modified") + .ValueGeneratedOnAdd() + .HasColumnType("datetime2") + .HasColumnOrder(50) + .HasDefaultValueSql("GETDATE()"); + + b.Property("ModifiedBy") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(51); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(1); + + b.HasKey("Id"); + + b.ToTable("Services"); + + b.HasData( + new + { + Id = new Guid("40000000-0000-0000-0000-000000000001"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + Description = "On-premises directory and identity service.", + IconKey = "network", + IsCloudService = false, + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + Name = "Active Directory" + }, + new + { + Id = new Guid("40000000-0000-0000-0000-000000000002"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + Description = "Database platform for application workloads.", + IconKey = "database", + IsCloudService = false, + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + Name = "SQL Server" + }, + new + { + Id = new Guid("40000000-0000-0000-0000-000000000003"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + Description = "Collaboration platform for on-premises workloads.", + IconKey = "sharepoint", + IsCloudService = false, + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + Name = "SharePoint Server" + }, + new + { + Id = new Guid("40000000-0000-0000-0000-000000000004"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + Description = "Cloud collaboration workload in Microsoft 365.", + IconKey = "messages-square", + IsCloudService = true, + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + Name = "Microsoft Teams" + }, + new + { + Id = new Guid("40000000-0000-0000-0000-000000000101"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + Description = "Reusable configuration-data template building blocks for deployment composition.", + IconKey = "braces", + IsCloudService = false, + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + Name = "DSC Configuration Data" + }); + }); + + modelBuilder.Entity("Microsoft.SelfService.Portal.Core.API.Models.ServiceRoleDefinitionModel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier") + .HasColumnOrder(0) + .HasDefaultValueSql("NEWID()"); + + b.Property("Created") + .ValueGeneratedOnAdd() + .HasColumnType("datetime2") + .HasColumnOrder(52) + .HasDefaultValueSql("GETDATE()"); + + b.Property("CreatedBy") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(53); + + b.Property("Description") + .HasColumnType("nvarchar(max)") + .HasColumnOrder(4); + + b.Property("Key") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(2); + + b.Property("Modified") + .ValueGeneratedOnAdd() + .HasColumnType("datetime2") + .HasColumnOrder(50) + .HasDefaultValueSql("GETDATE()"); + + b.Property("ModifiedBy") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(51); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(3); + + b.Property("ServiceId") + .HasColumnType("uniqueidentifier") + .HasColumnOrder(1); + + b.HasKey("Id"); + + b.HasIndex("ServiceId"); + + b.ToTable("ServiceRoleDefinitions"); + + b.HasData( + new + { + Id = new Guid("41000000-0000-0000-0000-000000000001"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + Description = "SharePoint farm role.", + Key = "Farm", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + Name = "Farm", + ServiceId = new Guid("40000000-0000-0000-0000-000000000003") + }, + new + { + Id = new Guid("41000000-0000-0000-0000-000000000002"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + Description = "SharePoint web front-end role.", + Key = "WebFrontEnd", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + Name = "Web Front End", + ServiceId = new Guid("40000000-0000-0000-0000-000000000003") + }, + new + { + Id = new Guid("41000000-0000-0000-0000-000000000003"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + Description = "SharePoint service application role.", + Key = "Application", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + Name = "Application", + ServiceId = new Guid("40000000-0000-0000-0000-000000000003") + }, + new + { + Id = new Guid("41000000-0000-0000-0000-000000000004"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + Description = "SQL Server database role.", + Key = "Database", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + Name = "Database", + ServiceId = new Guid("40000000-0000-0000-0000-000000000002") + }); + }); + + modelBuilder.Entity("Microsoft.SelfService.Portal.Core.API.Models.TargetModel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier") + .HasColumnOrder(0) + .HasDefaultValueSql("NEWID()"); + + b.Property("Created") + .ValueGeneratedOnAdd() + .HasColumnType("datetime2") + .HasColumnOrder(52) + .HasDefaultValueSql("GETDATE()"); + + b.Property("CreatedBy") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(53); + + b.Property("DomainID") + .HasColumnType("uniqueidentifier") + .HasColumnOrder(1); + + b.Property("ExternalId") + .HasColumnType("nvarchar(max)") + .HasColumnOrder(5); + + b.Property("MetadataJson") + .HasColumnType("nvarchar(max)") + .HasColumnOrder(6); + + b.Property("Modified") + .ValueGeneratedOnAdd() + .HasColumnType("datetime2") + .HasColumnOrder(50) + .HasDefaultValueSql("GETDATE()"); + + b.Property("ModifiedBy") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(51); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(2); + + b.Property("ProviderType") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)") + .HasColumnOrder(4); + + b.Property("TargetType") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)") + .HasColumnOrder(3); + + b.HasKey("Id"); + + b.HasIndex("DomainID"); + + b.ToTable("Targets"); + + b.HasData( + new + { + Id = new Guid("30000000-0000-0000-0000-000000000001"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + DomainID = new Guid("20000000-0000-0000-0000-000000000001"), + MetadataJson = "{\"role\":\"DomainController\",\"environment\":\"Test\"}", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + Name = "CT-DC-01", + ProviderType = "OnPrem", + TargetType = "VirtualMachine" + }, + new + { + Id = new Guid("30000000-0000-0000-0000-000000000002"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + DomainID = new Guid("20000000-0000-0000-0000-000000000001"), + MetadataJson = "{\"role\":\"DomainController\",\"environment\":\"Production\"}", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + Name = "CT-DC-02", + ProviderType = "OnPrem", + TargetType = "VirtualMachine" + }, + new + { + Id = new Guid("30000000-0000-0000-0000-000000000003"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + DomainID = new Guid("20000000-0000-0000-0000-000000000001"), + MetadataJson = "{\"role\":\"SqlServer\",\"environment\":\"Test\"}", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + Name = "CT-SQL-01", + ProviderType = "OnPrem", + TargetType = "VirtualMachine" + }, + new + { + Id = new Guid("30000000-0000-0000-0000-000000000004"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + DomainID = new Guid("20000000-0000-0000-0000-000000000001"), + MetadataJson = "{\"role\":\"SharePoint\",\"environment\":\"Test\"}", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + Name = "CT-SHP-01", + ProviderType = "OnPrem", + TargetType = "VirtualMachine" + }, + new + { + Id = new Guid("30000000-0000-0000-0000-000000000005"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + DomainID = new Guid("20000000-0000-0000-0000-000000000001"), + MetadataJson = "{\"role\":\"SharePoint\",\"environment\":\"Test\"}", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + Name = "CT-SHP-02", + ProviderType = "OnPrem", + TargetType = "VirtualMachine" + }, + new + { + Id = new Guid("30000000-0000-0000-0000-000000000006"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + ExternalId = "11111111-1111-1111-1111-111111111111", + MetadataJson = "{\"environment\":\"Production\",\"workload\":\"M365\"}", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + Name = "contoso.onmicrosoft.com", + ProviderType = "Microsoft365", + TargetType = "Tenant" + }, + new + { + Id = new Guid("30000000-0000-0000-0000-000000000007"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + ExternalId = "Teams.StandardUsers", + MetadataJson = "{\"workload\":\"Teams\",\"scope\":\"StandardUsers\"}", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + Name = "Teams - Standard Users", + ProviderType = "Microsoft365", + TargetType = "PolicyScope" + }, + new + { + Id = new Guid("30000000-0000-0000-0000-000000000101"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + DomainID = new Guid("20000000-0000-0000-0000-000000000001"), + MetadataJson = "{\"role\":\"SharePoint\",\"environment\":\"Test\",\"source\":\"Test.Merge.ps1\"}", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + Name = "CLD-SHP-01", + ProviderType = "OnPrem", + TargetType = "VirtualMachine" + }, + new + { + Id = new Guid("30000000-0000-0000-0000-000000000102"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + DomainID = new Guid("20000000-0000-0000-0000-000000000001"), + MetadataJson = "{\"role\":\"SharePoint\",\"environment\":\"Test\",\"source\":\"Test.Merge.ps1\"}", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + Name = "CLD-SHP-02", + ProviderType = "OnPrem", + TargetType = "VirtualMachine" + }, + new + { + Id = new Guid("30000000-0000-0000-0000-000000000103"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + DomainID = new Guid("20000000-0000-0000-0000-000000000001"), + MetadataJson = "{\"role\":\"SharePoint\",\"environment\":\"Test\",\"source\":\"Test.Merge.ps1\"}", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + Name = "CLD-SHP-03", + ProviderType = "OnPrem", + TargetType = "VirtualMachine" + }); + }); + + modelBuilder.Entity("Microsoft.SelfService.Portal.Core.API.Models.TemplateCategoryModel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier") + .HasColumnOrder(0) + .HasDefaultValueSql("NEWID()"); + + b.Property("Color") + .HasColumnType("nvarchar(max)") + .HasColumnOrder(5); + + b.Property("Created") + .ValueGeneratedOnAdd() + .HasColumnType("datetime2") + .HasColumnOrder(52) + .HasDefaultValueSql("GETDATE()"); + + b.Property("CreatedBy") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(53); + + b.Property("Description") + .HasColumnType("nvarchar(max)") + .HasColumnOrder(3); + + b.Property("IsActive") + .HasColumnType("bit") + .HasColumnOrder(4); + + b.Property("Modified") + .ValueGeneratedOnAdd() + .HasColumnType("datetime2") + .HasColumnOrder(50) + .HasDefaultValueSql("GETDATE()"); + + b.Property("ModifiedBy") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(51); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(2); + + b.Property("ServiceId") + .HasColumnType("uniqueidentifier") + .HasColumnOrder(1); + + b.HasKey("Id"); + + b.HasIndex("ServiceId"); + + b.ToTable("TemplateCategories"); + + b.HasData( + new + { + Id = new Guid("50000000-0000-0000-0000-000000000001"), + Color = "#2563EB", + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + Description = "Templates for domain controller and domain configuration.", + IsActive = true, + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + Name = "Domain Services", + ServiceId = new Guid("40000000-0000-0000-0000-000000000001") + }, + new + { + Id = new Guid("50000000-0000-0000-0000-000000000002"), + Color = "#16A34A", + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + Description = "Templates for SQL Server workloads.", + IsActive = true, + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + Name = "Database Platform", + ServiceId = new Guid("40000000-0000-0000-0000-000000000002") + }, + new + { + Id = new Guid("50000000-0000-0000-0000-000000000003"), + Color = "#0F766E", + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + Description = "Templates for SharePoint Server farms.", + IsActive = true, + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + Name = "Collaboration Farm", + ServiceId = new Guid("40000000-0000-0000-0000-000000000003") + }, + new + { + Id = new Guid("50000000-0000-0000-0000-000000000004"), + Color = "#7C3AED", + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + Description = "Templates for Teams policy configuration.", + IsActive = true, + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + Name = "Teams Policies", + ServiceId = new Guid("40000000-0000-0000-0000-000000000004") + }, + new + { + Id = new Guid("50000000-0000-0000-0000-000000000101"), + Color = "#2563EB", + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + Description = "Materialized template building blocks from the BGW Test.Merge.ps1 scenario.", + IsActive = true, + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + Name = "Test.Merge.ps1 Templates", + ServiceId = new Guid("40000000-0000-0000-0000-000000000101") + }); + }); + + modelBuilder.Entity("Microsoft.SelfService.Portal.Core.API.Models.TemplateModel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier") + .HasColumnOrder(0) + .HasDefaultValueSql("NEWID()"); + + b.Property("Created") + .ValueGeneratedOnAdd() + .HasColumnType("datetime2") + .HasColumnOrder(52) + .HasDefaultValueSql("GETDATE()"); + + b.Property("CreatedBy") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(53); + + b.Property("DeploymentRuleId") + .HasColumnType("uniqueidentifier") + .HasColumnOrder(6); + + b.Property("Description") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(3); + + b.Property("JSONData") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(4); + + b.Property("Modified") + .ValueGeneratedOnAdd() + .HasColumnType("datetime2") + .HasColumnOrder(50) + .HasDefaultValueSql("GETDATE()"); + + b.Property("ModifiedBy") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(51); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(1); + + b.Property("TemplateCategoryId") + .HasColumnType("uniqueidentifier") + .HasColumnOrder(5); + + b.Property("Version") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(2); + + b.HasKey("Id"); + + b.HasIndex("DeploymentRuleId"); + + b.HasIndex("TemplateCategoryId"); + + b.ToTable("Templates"); + + b.HasData( + new + { + Id = new Guid("70000000-0000-0000-0000-000000000001"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + DeploymentRuleId = new Guid("60000000-0000-0000-0000-000000000001"), + Description = "Creates a reusable Active Directory domain baseline.", + JSONData = "{\n \"schemaVersion\": \"1.0\",\n \"templateType\": \"Service\",\n \"parameters\": {\n \"DomainName\": { \"type\": \"string\", \"defaultValue\": \"corp.contoso.com\" },\n \"NetBIOSName\": { \"type\": \"string\", \"defaultValue\": \"CONTOSO\" }\n },\n \"variables\": {\n \"DefaultSiteName\": \"[concat(parameters('DomainName'), '-DefaultSite')]\"\n },\n \"resources\": {\n \"AllNodes\": [\n { \"NodeName\": \"*\", \"PSDscAllowPlainTextPassword\": true }\n ],\n \"NonNodeData\": {\n \"Services\": {\n \"ActiveDirectory\": {\n \"DomainName\": \"[parameters('DomainName')]\",\n \"NetBIOSName\": \"[parameters('NetBIOSName')]\"\n }\n }\n }\n }\n}", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + Name = "Contoso Active Directory Domain", + TemplateCategoryId = new Guid("50000000-0000-0000-0000-000000000001"), + Version = "1.0.0" + }, + new + { + Id = new Guid("70000000-0000-0000-0000-000000000002"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + DeploymentRuleId = new Guid("60000000-0000-0000-0000-000000000001"), + Description = "Creates a SQL Server baseline for application workloads.", + JSONData = "{\n \"schemaVersion\": \"1.0\",\n \"templateType\": \"Service\",\n \"parameters\": {\n \"InstanceName\": { \"type\": \"string\", \"defaultValue\": \"MSSQLSERVER\" },\n \"DatabasePrefix\": { \"type\": \"string\", \"defaultValue\": \"Contoso\" }\n },\n \"variables\": {\n \"ConfigDatabase\": \"[concat(parameters('DatabasePrefix'), '_Config')]\"\n },\n \"resources\": {\n \"NonNodeData\": {\n \"Services\": {\n \"SqlServer\": {\n \"InstanceName\": \"[parameters('InstanceName')]\",\n \"ConfigDatabase\": \"[variables('ConfigDatabase')]\"\n }\n }\n }\n }\n}", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + Name = "Contoso SQL Server", + TemplateCategoryId = new Guid("50000000-0000-0000-0000-000000000002"), + Version = "1.0.0" + }, + new + { + Id = new Guid("70000000-0000-0000-0000-000000000003"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + DeploymentRuleId = new Guid("60000000-0000-0000-0000-000000000001"), + Description = "Creates a SharePoint Server farm baseline.", + JSONData = "{\n \"schemaVersion\": \"1.0\",\n \"templateType\": \"Service\",\n \"parameters\": {\n \"DatabasePrefix\": { \"type\": \"string\", \"defaultValue\": \"SharePoint_Contoso_Test\" },\n \"FarmAccount\": { \"type\": \"credential\", \"metadata\": { \"description\": \"Farm account resolved by the credential provider.\" } }\n },\n \"variables\": {\n \"ConfigDbName\": \"[concat(parameters('DatabasePrefix'), '_Farm_Config')]\",\n \"AdminContentDbName\": \"[concat(parameters('DatabasePrefix'), '_AdminContent')]\"\n },\n \"resources\": {\n \"NonNodeData\": {\n \"Services\": {\n \"SharePoint\": {\n \"Farm\": {\n \"ConfigDatabase\": \"[variables('ConfigDbName')]\",\n \"AdminContentDatabase\": \"[variables('AdminContentDbName')]\",\n \"ManagedAccounts\": {\n \"FarmAccount\": \"[parameters('FarmAccount')]\"\n }\n }\n }\n }\n }\n }\n}", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + Name = "Contoso SharePoint Server", + TemplateCategoryId = new Guid("50000000-0000-0000-0000-000000000003"), + Version = "1.0.0" + }, + new + { + Id = new Guid("70000000-0000-0000-0000-000000000004"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + DeploymentRuleId = new Guid("60000000-0000-0000-0000-000000000001"), + Description = "Creates a Microsoft Teams policy baseline.", + JSONData = "{\n \"schemaVersion\": \"1.0\",\n \"templateType\": \"Service\",\n \"parameters\": {\n \"CallingPolicyName\": { \"type\": \"string\", \"defaultValue\": \"Contoso-Standard-Calling\" },\n \"MeetingPolicyName\": { \"type\": \"string\", \"defaultValue\": \"Contoso-Standard-Meetings\" }\n },\n \"variables\": {},\n \"resources\": {\n \"NonNodeData\": {\n \"Services\": {\n \"Teams\": {\n \"CallingPolicy\": \"[parameters('CallingPolicyName')]\",\n \"MeetingPolicy\": \"[parameters('MeetingPolicyName')]\"\n }\n }\n }\n }\n}", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + Name = "Contoso Teams Policies", + TemplateCategoryId = new Guid("50000000-0000-0000-0000-000000000004"), + Version = "1.0.0" + }, + new + { + Id = new Guid("70000000-0000-0000-0000-000000000101"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + DeploymentRuleId = new Guid("60000000-0000-0000-0000-000000000001"), + Description = "Materialized Environment/Test.psd1 template from Test.Merge.ps1.", + JSONData = "{\r\n \"schemaVersion\": \"1.0\",\r\n \"templateType\": \"Environment\",\r\n \"metadata\": {\r\n \"TemplateType\": \"Environment\",\r\n \"Name\": \"Test\"\r\n },\r\n \"parameters\": {\r\n \"Landscape\": {\r\n \"DefaultValue\": \"Prod\",\r\n \"Value\": \"Test\",\r\n \"Type\": \"string\",\r\n \"AllowedValues\": [\r\n \"Prod\",\r\n \"QA\",\r\n \"Test\"\r\n ]\r\n }\r\n },\r\n \"variables\": {\r\n \"AdminDbName\": \"[joinNotEmpty(\\u0027_\\u0027, variables(\\u0027DatabasePrefix\\u0027), \\u0027Farm_AdminContent\\u0027)]\",\r\n \"ContentDbPrefix\": \"[joinNotEmpty(\\u0027_\\u0027, variables(\\u0027DatabasePrefix\\u0027), parameters(\\u0027ContentDatabaseSegment\\u0027))]\",\r\n \"ServiceDbPrefix\": \"[joinNotEmpty(\\u0027_\\u0027, variables(\\u0027DatabasePrefix\\u0027), parameters(\\u0027ServiceDatabaseSegment\\u0027))]\",\r\n \"DatabasePrefix\": \"[joinNotEmpty(\\u0027_\\u0027, parameters(\\u0027DatabasePrefix\\u0027), parameters(\\u0027DomainLabel\\u0027), if(equals(parameters(\\u0027Landscape\\u0027), \\u0027Test\\u0027), \\u0027Test\\u0027, \\u0027\\u0027))]\",\r\n \"ConfigDbName\": \"[joinNotEmpty(\\u0027_\\u0027, variables(\\u0027DatabasePrefix\\u0027), \\u0027Farm_Config\\u0027)]\"\r\n },\r\n \"resources\": {\r\n\r\n }\r\n}", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + Name = "BGW Environment Test", + TemplateCategoryId = new Guid("50000000-0000-0000-0000-000000000101"), + Version = "1.0.0" + }, + new + { + Id = new Guid("70000000-0000-0000-0000-000000000102"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + DeploymentRuleId = new Guid("60000000-0000-0000-0000-000000000001"), + Description = "Materialized Domain/Contoso.psd1 template from Test.Merge.ps1.", + JSONData = "{\r\n \"schemaVersion\": \"1.0\",\r\n \"templateType\": \"Domain\",\r\n \"metadata\": {\r\n \"TemplateType\": \"Domain\",\r\n \"Name\": \"Contoso\"\r\n },\r\n \"parameters\": {\r\n \"DomainFQDN\": {\r\n \"DefaultValue\": \"\",\r\n \"Pattern\": \"^[A-Za-z0-9.-]+$\",\r\n \"Type\": \"string\",\r\n \"Value\": \"contoso.local\",\r\n \"Required\": true\r\n },\r\n \"DomainLabel\": {\r\n \"Type\": \"string\",\r\n \"MaxLength\": 32,\r\n \"Value\": \"Contoso\",\r\n \"DefaultValue\": \"\",\r\n \"Pattern\": \"^[A-Za-z][A-Za-z0-9_-]*$\",\r\n \"MinLength\": 2,\r\n \"Required\": false\r\n },\r\n \"DomainNetBIOS\": {\r\n \"Type\": \"string\",\r\n \"MaxLength\": 15,\r\n \"Value\": \"CONTOSO\",\r\n \"DefaultValue\": \"\",\r\n \"Pattern\": \"^[A-Za-z0-9_-]+$\",\r\n \"MinLength\": 1,\r\n \"Required\": true\r\n }\r\n },\r\n \"variables\": {\r\n\r\n },\r\n \"resources\": {\r\n \"NonNodeData\": {\r\n \"Services\": {\r\n \"ActiveDirectory\": {\r\n \"NetBIOSName\": \"[parameters(\\u0027DomainNetBIOS\\u0027)]\",\r\n \"DomainName\": \"[parameters(\\u0027DomainFQDN\\u0027)]\"\r\n }\r\n }\r\n }\r\n }\r\n}", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + Name = "BGW Domain Contoso", + TemplateCategoryId = new Guid("50000000-0000-0000-0000-000000000101"), + Version = "1.0.0" + }, + new + { + Id = new Guid("70000000-0000-0000-0000-000000000103"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + DeploymentRuleId = new Guid("60000000-0000-0000-0000-000000000001"), + Description = "Materialized Service/SharePoint/Contoso.psd1 template from Test.Merge.ps1.", + JSONData = "{\r\n \"schemaVersion\": \"1.0\",\r\n \"templateType\": \"Service\",\r\n \"metadata\": {\r\n \"TemplateType\": \"Service\",\r\n \"Name\": \"SharePoint.Contoso\"\r\n },\r\n \"parameters\": {\r\n \"FarmCredential\": {\r\n \"Sensitive\": true,\r\n \"Value\": {\r\n \"Provider\": \"SecretManagement\",\r\n \"Vault\": \"Test\",\r\n \"Name\": \"Windows/SharePoint/FarmAccount\"\r\n },\r\n \"Type\": \"credential\",\r\n \"Required\": true\r\n },\r\n \"ContentDatabaseSegment\": {\r\n \"DefaultValue\": \"Content\",\r\n \"Type\": \"string\",\r\n \"Metadata\": {\r\n \"Description\": {\r\n \"de-DE\": \"Namenssegment fuer SharePoint-Content-Datenbanken innerhalb des Datenbanknamens.\",\r\n \"en-US\": \"Name segment used for SharePoint content databases within the database name.\"\r\n }\r\n }\r\n },\r\n \"ServiceApplicationPoolDefault\": {\r\n \"DefaultValue\": \"SharePoint Service Applications\",\r\n \"Type\": \"string\",\r\n \"Metadata\": {\r\n \"Description\": {\r\n \"de-DE\": \"Anzeigename des Standard-Application-Pools fuer SharePoint-Serviceanwendungen.\",\r\n \"en-US\": \"Display name of the default application pool for SharePoint service applications.\"\r\n }\r\n }\r\n },\r\n \"WebApplicationPoolDefault\": {\r\n \"DefaultValue\": \"SharePoint Web Applications\",\r\n \"Type\": \"string\",\r\n \"Metadata\": {\r\n \"Description\": {\r\n \"de-DE\": \"Anzeigename des Standard-Application-Pools fuer SharePoint-Webanwendungen.\",\r\n \"en-US\": \"Display name of the default application pool for SharePoint web applications.\"\r\n }\r\n }\r\n },\r\n \"DatabaseServerName\": {\r\n \"DefaultValue\": \"SQL_Server\",\r\n \"Type\": \"string\",\r\n \"Value\": \"CL-SQL-01\"\r\n },\r\n \"WebApplicationPoolDefaultAccount\": {\r\n \"DefaultValue\": \"SVC_SHP_WAP\",\r\n \"Type\": \"string\",\r\n \"Metadata\": {\r\n \"Description\": {\r\n \"de-DE\": \"Kontoname fuer den Standard-Application-Pool der SharePoint-Webanwendungen.\",\r\n \"en-US\": \"Account name used by the default application pool for SharePoint web applications.\"\r\n }\r\n }\r\n },\r\n \"ServiceDatabaseSegment\": {\r\n \"DefaultValue\": \"Services\",\r\n \"Type\": \"string\",\r\n \"Metadata\": {\r\n \"Description\": {\r\n \"de-DE\": \"Namenssegment fuer SharePoint-Service-Datenbanken innerhalb des Datenbanknamens.\",\r\n \"en-US\": \"Name segment used for SharePoint service databases within the database name.\"\r\n }\r\n }\r\n },\r\n \"FarmPassphrase\": {\r\n \"Sensitive\": true,\r\n \"Value\": {\r\n \"Provider\": \"SecretManagement\",\r\n \"Vault\": \"Test\",\r\n \"Name\": \"Windows/SharePoint/FarmPassphrase\"\r\n },\r\n \"Type\": \"credential\",\r\n \"Required\": true\r\n },\r\n \"DatabaseInstanceName\": {\r\n \"DefaultValue\": \"SQL_Server\",\r\n \"Type\": \"string\",\r\n \"Value\": \"SQLServer\"\r\n },\r\n \"DatabaseTcpPort\": {\r\n \"DefaultValue\": 1433,\r\n \"Type\": \"int\",\r\n \"Value\": 1433\r\n },\r\n \"DefaultServiceApplicationPoolAccount\": {\r\n \"Metadata\": {\r\n \"Description\": {\r\n \"de-DE\": \"Kontoname fuer den Standard-Application-Pool der SharePoint-Serviceanwendungen.\",\r\n \"en-US\": \"Account name used by the default application pool for SharePoint service applications.\"\r\n }\r\n },\r\n \"Sensitive\": true,\r\n \"Value\": {\r\n \"Provider\": \"SecretManagement\",\r\n \"Vault\": \"Test\",\r\n \"Name\": \"Windows/SharePoint/DefaultServiceAccount\"\r\n },\r\n \"Type\": \"credential\",\r\n \"Required\": true\r\n },\r\n \"ProductKey\": {\r\n \"DefaultValue\": \"0000-0000-0000-0000-0000\",\r\n \"Type\": \"string\",\r\n \"Metadata\": {\r\n \"Description\": {\r\n \"de-DE\": \"SharePoint-Produktlizenzschluessel.\",\r\n \"en-US\": \"SharePoint product license key.\"\r\n }\r\n }\r\n },\r\n \"SetupCredential\": {\r\n \"Sensitive\": true,\r\n \"Value\": {\r\n \"Provider\": \"SecretManagement\",\r\n \"Vault\": \"Test\",\r\n \"Name\": \"Windows/SharePoint/SetupAccount\"\r\n },\r\n \"Type\": \"credential\",\r\n \"Required\": true\r\n },\r\n \"DatabasePrefix\": {\r\n \"DefaultValue\": \"SharePoint\",\r\n \"Type\": \"string\",\r\n \"Value\": \"SharePoint\"\r\n },\r\n \"SearchServiceApplicationPoolAccount\": {\r\n \"Metadata\": {\r\n \"Description\": {\r\n \"de-DE\": \"Kontoname fuer den Search-Application-Pool der SharePoint-Serviceanwendungen.\",\r\n \"en-US\": \"Account name used by the search application pool for SharePoint service applications.\"\r\n }\r\n },\r\n \"Sensitive\": true,\r\n \"Value\": {\r\n \"Provider\": \"SecretManagement\",\r\n \"Vault\": \"Test\",\r\n \"Name\": \"Windows/SharePoint/SearchAccount\"\r\n },\r\n \"Type\": \"credential\",\r\n \"Required\": true\r\n },\r\n \"CentralAdminPort\": {\r\n \"DefaultValue\": 443,\r\n \"Type\": \"int\",\r\n \"Value\": 4000\r\n },\r\n \"ServiceApplicationPoolSearch\": {\r\n \"DefaultValue\": \"SharePoint Search Service Applications\",\r\n \"Type\": \"string\",\r\n \"Metadata\": {\r\n \"Description\": {\r\n \"de-DE\": \"Anzeigename des Application-Pools fuer SharePoint Search-Serviceanwendungen.\",\r\n \"en-US\": \"Display name of the application pool for SharePoint Search service applications.\"\r\n }\r\n }\r\n }\r\n },\r\n \"variables\": {\r\n \"AdminDbName\": \"[joinNotEmpty(\\u0027_\\u0027, variables(\\u0027DatabasePrefix\\u0027), \\u0027Farm_AdminContent\\u0027)]\",\r\n \"ContentDbPrefix\": \"[joinNotEmpty(\\u0027_\\u0027, variables(\\u0027DatabasePrefix\\u0027), parameters(\\u0027ContentDatabaseSegment\\u0027))]\",\r\n \"ServiceDbPrefix\": \"[joinNotEmpty(\\u0027_\\u0027, variables(\\u0027DatabasePrefix\\u0027), parameters(\\u0027ServiceDatabaseSegment\\u0027))]\",\r\n \"DatabasePrefix\": \"[joinNotEmpty(\\u0027_\\u0027, parameters(\\u0027DatabasePrefix\\u0027), parameters(\\u0027DomainLabel\\u0027), if(equals(parameters(\\u0027Landscape\\u0027), \\u0027Test\\u0027), \\u0027Test\\u0027, \\u0027\\u0027))]\",\r\n \"ConfigDbName\": \"[joinNotEmpty(\\u0027_\\u0027, variables(\\u0027DatabasePrefix\\u0027), \\u0027Farm_Config\\u0027)]\"\r\n },\r\n \"resources\": {\r\n \"AllNodes\": [\r\n {\r\n \"PSDscAllowDomainUser\": true,\r\n \"PSDSCAllowPlainTextPassword\": true,\r\n \"NodeName\": \"*\",\r\n \"RunCentralAdministration\": false\r\n }\r\n ],\r\n \"NonNodeData\": {\r\n \"Services\": {\r\n \"SharePoint\": {\r\n \"Farm\": {\r\n \"ManagedAccounts\": {\r\n \"DefaultServiceApplicationPoolAccount\": \"[parameters(\\u0027DefaultServiceApplicationPoolAccount\\u0027)]\",\r\n \"FarmAccount\": \"[parameters(\\u0027FarmCredential\\u0027)]\",\r\n \"SearchServiceApplicationPoolAccount\": \"[parameters(\\u0027SearchServiceApplicationPoolAccount\\u0027)]\"\r\n },\r\n \"Passphrase\": \"[parameters(\\u0027FarmPassphrase\\u0027)]\",\r\n \"ServiceApplications\": {\r\n \"AppManagementService\": {\r\n \"DatabaseName\": \"[concat(variables(\\u0027ServiceDbPrefix\\u0027),\\u0027AppManagement\\u0027)]\",\r\n \"ApplicationPool\": \"[reference(\\u0027Resources.NonNodeData.Services.SharePoint.Farm.ServiceApplicationPools.DefaultServiceApplicationPool\\u0027, \\u0027Name\\u0027)]\",\r\n \"Provision\": true\r\n },\r\n \"StateService\": {\r\n \"DatabaseName\": \"[concat(variables(\\u0027ServiceDbPrefix\\u0027),\\u0027StateService\\u0027)]\",\r\n \"Provision\": true\r\n },\r\n \"SubscriptionSettingsService\": {\r\n \"DatabaseName\": \"[concat(variables(\\u0027ServiceDbPrefix\\u0027),\\u0027SubscriptionSettings\\u0027)]\",\r\n \"ApplicationPool\": \"[reference(\\u0027Resources.NonNodeData.Services.SharePoint.Farm.ServiceApplicationPools.DefaultServiceApplicationPool\\u0027, \\u0027Name\\u0027)]\",\r\n \"Provision\": true\r\n },\r\n \"ManagedMetadataService\": {\r\n \"Name\": \"Managed Metadata Service\",\r\n \"DatabaseName\": \"[concat(variables(\\u0027ServiceDbPrefix\\u0027), \\u0027ManagedMetadata\\u0027)]\",\r\n \"ApplicationPool\": \"[reference(\\u0027Resources.NonNodeData.Services.SharePoint.Farm.ServiceApplicationPools.DefaultServiceApplicationPool\\u0027, \\u0027Name\\u0027)]\",\r\n \"Provision\": true\r\n },\r\n \"SearchService\": {\r\n \"Name\": \"Search Service Application\",\r\n \"DatabaseName\": \"[concat(variables(\\u0027ServiceDbPrefix\\u0027),\\u0027Search\\u0027)]\",\r\n \"ApplicationPool\": \"[reference(\\u0027Resources.NonNodeData.Services.SharePoint.Farm.ServiceApplicationPools.SearchServiceApplicationPool\\u0027, \\u0027Name\\u0027)]\",\r\n \"Provision\": true\r\n },\r\n \"UsageAndHealthService\": {\r\n \"DatabaseName\": \"[concat(variables(\\u0027ServiceDbPrefix\\u0027),\\u0027UsageAndHealth\\u0027)]\",\r\n \"Provision\": true\r\n },\r\n \"SecureStoreService\": {\r\n \"Name\": \"Secure Store Service\",\r\n \"DatabaseName\": \"[concat(variables(\\u0027ServiceDbPrefix\\u0027),\\u0027SecureStore\\u0027)]\",\r\n \"ApplicationPool\": \"[reference(\\u0027Resources.NonNodeData.Services.SharePoint.Farm.ServiceApplicationPools.DefaultServiceApplicationPool\\u0027, \\u0027Name\\u0027)]\",\r\n \"Provision\": true,\r\n \"AuditingEnabled\": true\r\n },\r\n \"UserProfileService\": {\r\n \"SyncDBName\": \"[concat(variables(\\u0027ServiceDbPrefix\\u0027), \\u0027UserProfile_Sync\\u0027)]\",\r\n \"ApplicationPool\": \"[reference(\\u0027Resources.NonNodeData.Services.SharePoint.Farm.ServiceApplicationPools.DefaultServiceApplicationPool\\u0027, \\u0027Name\\u0027)]\",\r\n \"Provision\": true,\r\n \"Name\": \"User Profile Service\",\r\n \"SocialDBName\": \"[concat(variables(\\u0027ServiceDbPrefix\\u0027), \\u0027UserProfile_Social\\u0027)]\",\r\n \"ProfileDBName\": \"[concat(variables(\\u0027ServiceDbPrefix\\u0027), \\u0027UserProfile_Profile\\u0027)]\"\r\n }\r\n },\r\n \"CentralAdminAuth\": \"NTLM\",\r\n \"ConfigDatabaseName\": \"[variables(\\u0027ConfigDbName\\u0027)]\",\r\n \"Accounts\": {\r\n \"SetupAccount\": \"[parameters(\\u0027SetupCredential\\u0027)]\"\r\n },\r\n \"CentralAdminPort\": \"[parameters(\\u0027CentralAdminPort\\u0027)]\",\r\n \"AdminContentDatabase\": \"[variables(\\u0027AdminDbName\\u0027)]\",\r\n \"ServiceApplicationPools\": {\r\n \"SearchServiceApplicationPool\": {\r\n \"Account\": \"[reference(\\u0027Resources.NonNodeData.Services.SharePoint.Farm.ManagedAccounts.SearchServiceApplicationPoolAccount\\u0027, \\u0027UserName\\u0027)]\",\r\n \"Name\": \"[parameters(\\u0027ServiceApplicationPoolSearch\\u0027)]\"\r\n },\r\n \"DefaultServiceApplicationPool\": {\r\n \"Account\": \"[reference(\\u0027Resources.NonNodeData.Services.SharePoint.Farm.ManagedAccounts.DefaultServiceApplicationPoolAccount\\u0027, \\u0027UserName\\u0027)]\",\r\n \"Name\": \"[parameters(\\u0027ServiceApplicationPoolDefault\\u0027)]\"\r\n }\r\n }\r\n },\r\n \"Database\": {\r\n \"Targets\": {\r\n \"Farm\": {\r\n \"Server\": \"SQLServer\",\r\n \"DependsOnAlias\": \"SQLServer\"\r\n },\r\n \"Content\": {\r\n \"Server\": \"SQLServer\",\r\n \"DependsOnAlias\": \"SQLServer\"\r\n },\r\n \"Service\": {\r\n \"Server\": \"SQLServer\",\r\n \"DependsOnAlias\": \"SQLServer\"\r\n }\r\n },\r\n \"SQLAlias\": {\r\n \"SQLServer\": {\r\n \"InstanceName\": \"[parameters(\\u0027DatabaseInstanceName\\u0027)]\",\r\n \"ServerName\": \"[parameters(\\u0027DatabaseServerName\\u0027)]\",\r\n \"Protocol\": \"TCP\",\r\n \"TcpPort\": \"[parameters(\\u0027DatabaseTcpPort\\u0027)]\"\r\n }\r\n }\r\n },\r\n \"General\": {\r\n \"ProductKey\": \"[parameters(\\u0027ProductKey\\u0027)]\"\r\n },\r\n \"Windows\": {\r\n \"Registry\": {\r\n \"DisableLoopbackCheck\": {\r\n \"Path\": \"HKLM:\\\\SYSTEM\\\\CurrentControlSet\\\\Control\\\\Lsa\",\r\n \"Name\": \"DisableLoopbackCheck\",\r\n \"Value\": 1,\r\n \"Type\": \"DWord\"\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n}", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + Name = "BGW SharePoint Contoso", + TemplateCategoryId = new Guid("50000000-0000-0000-0000-000000000101"), + Version = "1.0.0" + }, + new + { + Id = new Guid("70000000-0000-0000-0000-000000000104"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + DeploymentRuleId = new Guid("60000000-0000-0000-0000-000000000001"), + Description = "Materialized Stage/Install.psd1 template from Test.Merge.ps1.", + JSONData = "{\r\n \"schemaVersion\": \"1.0\",\r\n \"templateType\": \"Stage\",\r\n \"metadata\": {\r\n \"TemplateType\": \"Stage\",\r\n \"Name\": \"Install\"\r\n },\r\n \"parameters\": {\r\n\r\n },\r\n \"variables\": {\r\n\r\n },\r\n \"resources\": {\r\n \"NonNodeData\": {\r\n \"LocalConfigurationManager\": {\r\n \"RefreshFrequencyMins\": \"30\",\r\n \"RefreshMode\": \"PUSH\",\r\n \"ConfigurationModeFrequencyMins\": \"120\",\r\n \"ConfigurationMode\": \"ApplyOnly\"\r\n }\r\n }\r\n }\r\n}", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + Name = "BGW Stage Install", + TemplateCategoryId = new Guid("50000000-0000-0000-0000-000000000101"), + Version = "1.0.0" + }); + }); + + modelBuilder.Entity("Microsoft.SelfService.Portal.Core.API.Models.TemplateOptionModel", b => + { + b.Property("OptionId") + .HasColumnType("uniqueidentifier") + .HasColumnOrder(1); + + b.Property("TemplateId") + .HasColumnType("uniqueidentifier") + .HasColumnOrder(0); + + b.Property("Created") + .HasColumnType("datetime2") + .HasColumnOrder(52); + + b.Property("CreatedBy") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(53); + + b.Property("Modified") + .HasColumnType("datetime2") + .HasColumnOrder(50); + + b.Property("ModifiedBy") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(51); + + b.Property("Value") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(2); + + b.HasKey("OptionId", "TemplateId"); + + b.HasIndex("TemplateId"); + + b.ToTable("TemplateOptions"); + }); + + modelBuilder.Entity("Microsoft.SelfService.Portal.Core.API.Models.TemplateRevisionModel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier") + .HasColumnOrder(0) + .HasDefaultValueSql("NEWID()"); + + b.Property("Created") + .ValueGeneratedOnAdd() + .HasColumnType("datetime2") + .HasColumnOrder(52) + .HasDefaultValueSql("GETDATE()"); + + b.Property("CreatedBy") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(53); + + b.Property("IsCurrent") + .HasColumnType("bit") + .HasColumnOrder(6); + + b.Property("IsPublished") + .HasColumnType("bit") + .HasColumnOrder(7); + + b.Property("JsonData") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(3); + + b.Property("JsonHash") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)") + .HasColumnOrder(4); + + b.Property("Modified") + .ValueGeneratedOnAdd() + .HasColumnType("datetime2") + .HasColumnOrder(50) + .HasDefaultValueSql("GETDATE()"); + + b.Property("ModifiedBy") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(51); + + b.Property("PublishedAt") + .HasColumnType("datetime2") + .HasColumnOrder(8); + + b.Property("PublishedBy") + .HasColumnType("nvarchar(max)") + .HasColumnOrder(9); + + b.Property("RevisionNumber") + .HasColumnType("int") + .HasColumnOrder(2); + + b.Property("SchemaVersion") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("nvarchar(32)") + .HasColumnOrder(5); + + b.Property("TemplateVersionId") + .HasColumnType("uniqueidentifier") + .HasColumnOrder(1); + + b.HasKey("Id"); + + b.HasIndex("TemplateVersionId") + .IsUnique() + .HasFilter("[IsCurrent] = 1"); + + b.HasIndex("TemplateVersionId", "RevisionNumber") + .IsUnique(); + + b.ToTable("TemplateRevisions", t => + { + t.HasCheckConstraint("CK_TemplateRevisions_JsonData_IsJson", "ISJSON([JsonData]) = 1"); + }); + + b.HasData( + new + { + Id = new Guid("72000000-0000-0000-0000-000000000001"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + IsCurrent = true, + IsPublished = true, + JsonData = "{\n \"schemaVersion\": \"1.0\",\n \"templateType\": \"Service\",\n \"parameters\": {\n \"DomainName\": { \"type\": \"string\", \"defaultValue\": \"corp.contoso.com\" },\n \"NetBIOSName\": { \"type\": \"string\", \"defaultValue\": \"CONTOSO\" }\n },\n \"variables\": {\n \"DefaultSiteName\": \"[concat(parameters('DomainName'), '-DefaultSite')]\"\n },\n \"resources\": {\n \"AllNodes\": [\n { \"NodeName\": \"*\", \"PSDscAllowPlainTextPassword\": true }\n ],\n \"NonNodeData\": {\n \"Services\": {\n \"ActiveDirectory\": {\n \"DomainName\": \"[parameters('DomainName')]\",\n \"NetBIOSName\": \"[parameters('NetBIOSName')]\"\n }\n }\n }\n }\n}", + JsonHash = "C05CBEF91131C75DE53B9609D9C2709D680AFC9559EE8D998318A132490F79A7", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + PublishedAt = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + PublishedBy = "DemoSeed", + RevisionNumber = 1, + SchemaVersion = "1.0", + TemplateVersionId = new Guid("71000000-0000-0000-0000-000000000001") + }, + new + { + Id = new Guid("72000000-0000-0000-0000-000000000002"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + IsCurrent = true, + IsPublished = true, + JsonData = "{\n \"schemaVersion\": \"1.0\",\n \"templateType\": \"Service\",\n \"parameters\": {\n \"InstanceName\": { \"type\": \"string\", \"defaultValue\": \"MSSQLSERVER\" },\n \"DatabasePrefix\": { \"type\": \"string\", \"defaultValue\": \"Contoso\" }\n },\n \"variables\": {\n \"ConfigDatabase\": \"[concat(parameters('DatabasePrefix'), '_Config')]\"\n },\n \"resources\": {\n \"NonNodeData\": {\n \"Services\": {\n \"SqlServer\": {\n \"InstanceName\": \"[parameters('InstanceName')]\",\n \"ConfigDatabase\": \"[variables('ConfigDatabase')]\"\n }\n }\n }\n }\n}", + JsonHash = "F376737E82CB6B729F7B9960CB9988897C16D90A1C454ED2F594B28EB86ECA11", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + PublishedAt = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + PublishedBy = "DemoSeed", + RevisionNumber = 1, + SchemaVersion = "1.0", + TemplateVersionId = new Guid("71000000-0000-0000-0000-000000000002") + }, + new + { + Id = new Guid("72000000-0000-0000-0000-000000000003"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + IsCurrent = true, + IsPublished = true, + JsonData = "{\n \"schemaVersion\": \"1.0\",\n \"templateType\": \"Service\",\n \"parameters\": {\n \"DatabasePrefix\": { \"type\": \"string\", \"defaultValue\": \"SharePoint_Contoso_Test\" },\n \"FarmAccount\": { \"type\": \"credential\", \"metadata\": { \"description\": \"Farm account resolved by the credential provider.\" } }\n },\n \"variables\": {\n \"ConfigDbName\": \"[concat(parameters('DatabasePrefix'), '_Farm_Config')]\",\n \"AdminContentDbName\": \"[concat(parameters('DatabasePrefix'), '_AdminContent')]\"\n },\n \"resources\": {\n \"NonNodeData\": {\n \"Services\": {\n \"SharePoint\": {\n \"Farm\": {\n \"ConfigDatabase\": \"[variables('ConfigDbName')]\",\n \"AdminContentDatabase\": \"[variables('AdminContentDbName')]\",\n \"ManagedAccounts\": {\n \"FarmAccount\": \"[parameters('FarmAccount')]\"\n }\n }\n }\n }\n }\n }\n}", + JsonHash = "FD5F0FD3C13538FAC70646972DC364DFCEAAF85BBE91B0F50FDFF9FD3A3748B4", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + PublishedAt = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + PublishedBy = "DemoSeed", + RevisionNumber = 1, + SchemaVersion = "1.0", + TemplateVersionId = new Guid("71000000-0000-0000-0000-000000000003") + }, + new + { + Id = new Guid("72000000-0000-0000-0000-000000000004"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + IsCurrent = true, + IsPublished = true, + JsonData = "{\n \"schemaVersion\": \"1.0\",\n \"templateType\": \"Service\",\n \"parameters\": {\n \"CallingPolicyName\": { \"type\": \"string\", \"defaultValue\": \"Contoso-Standard-Calling\" },\n \"MeetingPolicyName\": { \"type\": \"string\", \"defaultValue\": \"Contoso-Standard-Meetings\" }\n },\n \"variables\": {},\n \"resources\": {\n \"NonNodeData\": {\n \"Services\": {\n \"Teams\": {\n \"CallingPolicy\": \"[parameters('CallingPolicyName')]\",\n \"MeetingPolicy\": \"[parameters('MeetingPolicyName')]\"\n }\n }\n }\n }\n}", + JsonHash = "32A902FE1A871D4CE2C877EBC5542F7562856532F09BA7F53597B21270586241", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + PublishedAt = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + PublishedBy = "DemoSeed", + RevisionNumber = 1, + SchemaVersion = "1.0", + TemplateVersionId = new Guid("71000000-0000-0000-0000-000000000004") + }, + new + { + Id = new Guid("72000000-0000-0000-0000-000000000101"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + IsCurrent = true, + IsPublished = true, + JsonData = "{\r\n \"schemaVersion\": \"1.0\",\r\n \"templateType\": \"Environment\",\r\n \"metadata\": {\r\n \"TemplateType\": \"Environment\",\r\n \"Name\": \"Test\"\r\n },\r\n \"parameters\": {\r\n \"Landscape\": {\r\n \"DefaultValue\": \"Prod\",\r\n \"Value\": \"Test\",\r\n \"Type\": \"string\",\r\n \"AllowedValues\": [\r\n \"Prod\",\r\n \"QA\",\r\n \"Test\"\r\n ]\r\n }\r\n },\r\n \"variables\": {\r\n \"AdminDbName\": \"[joinNotEmpty(\\u0027_\\u0027, variables(\\u0027DatabasePrefix\\u0027), \\u0027Farm_AdminContent\\u0027)]\",\r\n \"ContentDbPrefix\": \"[joinNotEmpty(\\u0027_\\u0027, variables(\\u0027DatabasePrefix\\u0027), parameters(\\u0027ContentDatabaseSegment\\u0027))]\",\r\n \"ServiceDbPrefix\": \"[joinNotEmpty(\\u0027_\\u0027, variables(\\u0027DatabasePrefix\\u0027), parameters(\\u0027ServiceDatabaseSegment\\u0027))]\",\r\n \"DatabasePrefix\": \"[joinNotEmpty(\\u0027_\\u0027, parameters(\\u0027DatabasePrefix\\u0027), parameters(\\u0027DomainLabel\\u0027), if(equals(parameters(\\u0027Landscape\\u0027), \\u0027Test\\u0027), \\u0027Test\\u0027, \\u0027\\u0027))]\",\r\n \"ConfigDbName\": \"[joinNotEmpty(\\u0027_\\u0027, variables(\\u0027DatabasePrefix\\u0027), \\u0027Farm_Config\\u0027)]\"\r\n },\r\n \"resources\": {\r\n\r\n }\r\n}", + JsonHash = "58553C7A4E902B5E39D30272754FEF9EF805A7F36363D8316A9B37540C6D4646", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + PublishedAt = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + PublishedBy = "DemoSeed", + RevisionNumber = 1, + SchemaVersion = "1.0", + TemplateVersionId = new Guid("71000000-0000-0000-0000-000000000101") + }, + new + { + Id = new Guid("72000000-0000-0000-0000-000000000102"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + IsCurrent = true, + IsPublished = true, + JsonData = "{\r\n \"schemaVersion\": \"1.0\",\r\n \"templateType\": \"Domain\",\r\n \"metadata\": {\r\n \"TemplateType\": \"Domain\",\r\n \"Name\": \"Contoso\"\r\n },\r\n \"parameters\": {\r\n \"DomainFQDN\": {\r\n \"DefaultValue\": \"\",\r\n \"Pattern\": \"^[A-Za-z0-9.-]+$\",\r\n \"Type\": \"string\",\r\n \"Value\": \"contoso.local\",\r\n \"Required\": true\r\n },\r\n \"DomainLabel\": {\r\n \"Type\": \"string\",\r\n \"MaxLength\": 32,\r\n \"Value\": \"Contoso\",\r\n \"DefaultValue\": \"\",\r\n \"Pattern\": \"^[A-Za-z][A-Za-z0-9_-]*$\",\r\n \"MinLength\": 2,\r\n \"Required\": false\r\n },\r\n \"DomainNetBIOS\": {\r\n \"Type\": \"string\",\r\n \"MaxLength\": 15,\r\n \"Value\": \"CONTOSO\",\r\n \"DefaultValue\": \"\",\r\n \"Pattern\": \"^[A-Za-z0-9_-]+$\",\r\n \"MinLength\": 1,\r\n \"Required\": true\r\n }\r\n },\r\n \"variables\": {\r\n\r\n },\r\n \"resources\": {\r\n \"NonNodeData\": {\r\n \"Services\": {\r\n \"ActiveDirectory\": {\r\n \"NetBIOSName\": \"[parameters(\\u0027DomainNetBIOS\\u0027)]\",\r\n \"DomainName\": \"[parameters(\\u0027DomainFQDN\\u0027)]\"\r\n }\r\n }\r\n }\r\n }\r\n}", + JsonHash = "B265C4D542826423BAAF50BF939F026CC67FF631FEC19F708067516BCE4C7667", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + PublishedAt = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + PublishedBy = "DemoSeed", + RevisionNumber = 1, + SchemaVersion = "1.0", + TemplateVersionId = new Guid("71000000-0000-0000-0000-000000000102") + }, + new + { + Id = new Guid("72000000-0000-0000-0000-000000000103"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + IsCurrent = true, + IsPublished = true, + JsonData = "{\r\n \"schemaVersion\": \"1.0\",\r\n \"templateType\": \"Service\",\r\n \"metadata\": {\r\n \"TemplateType\": \"Service\",\r\n \"Name\": \"SharePoint.Contoso\"\r\n },\r\n \"parameters\": {\r\n \"FarmCredential\": {\r\n \"Sensitive\": true,\r\n \"Value\": {\r\n \"Provider\": \"SecretManagement\",\r\n \"Vault\": \"Test\",\r\n \"Name\": \"Windows/SharePoint/FarmAccount\"\r\n },\r\n \"Type\": \"credential\",\r\n \"Required\": true\r\n },\r\n \"ContentDatabaseSegment\": {\r\n \"DefaultValue\": \"Content\",\r\n \"Type\": \"string\",\r\n \"Metadata\": {\r\n \"Description\": {\r\n \"de-DE\": \"Namenssegment fuer SharePoint-Content-Datenbanken innerhalb des Datenbanknamens.\",\r\n \"en-US\": \"Name segment used for SharePoint content databases within the database name.\"\r\n }\r\n }\r\n },\r\n \"ServiceApplicationPoolDefault\": {\r\n \"DefaultValue\": \"SharePoint Service Applications\",\r\n \"Type\": \"string\",\r\n \"Metadata\": {\r\n \"Description\": {\r\n \"de-DE\": \"Anzeigename des Standard-Application-Pools fuer SharePoint-Serviceanwendungen.\",\r\n \"en-US\": \"Display name of the default application pool for SharePoint service applications.\"\r\n }\r\n }\r\n },\r\n \"WebApplicationPoolDefault\": {\r\n \"DefaultValue\": \"SharePoint Web Applications\",\r\n \"Type\": \"string\",\r\n \"Metadata\": {\r\n \"Description\": {\r\n \"de-DE\": \"Anzeigename des Standard-Application-Pools fuer SharePoint-Webanwendungen.\",\r\n \"en-US\": \"Display name of the default application pool for SharePoint web applications.\"\r\n }\r\n }\r\n },\r\n \"DatabaseServerName\": {\r\n \"DefaultValue\": \"SQL_Server\",\r\n \"Type\": \"string\",\r\n \"Value\": \"CL-SQL-01\"\r\n },\r\n \"WebApplicationPoolDefaultAccount\": {\r\n \"DefaultValue\": \"SVC_SHP_WAP\",\r\n \"Type\": \"string\",\r\n \"Metadata\": {\r\n \"Description\": {\r\n \"de-DE\": \"Kontoname fuer den Standard-Application-Pool der SharePoint-Webanwendungen.\",\r\n \"en-US\": \"Account name used by the default application pool for SharePoint web applications.\"\r\n }\r\n }\r\n },\r\n \"ServiceDatabaseSegment\": {\r\n \"DefaultValue\": \"Services\",\r\n \"Type\": \"string\",\r\n \"Metadata\": {\r\n \"Description\": {\r\n \"de-DE\": \"Namenssegment fuer SharePoint-Service-Datenbanken innerhalb des Datenbanknamens.\",\r\n \"en-US\": \"Name segment used for SharePoint service databases within the database name.\"\r\n }\r\n }\r\n },\r\n \"FarmPassphrase\": {\r\n \"Sensitive\": true,\r\n \"Value\": {\r\n \"Provider\": \"SecretManagement\",\r\n \"Vault\": \"Test\",\r\n \"Name\": \"Windows/SharePoint/FarmPassphrase\"\r\n },\r\n \"Type\": \"credential\",\r\n \"Required\": true\r\n },\r\n \"DatabaseInstanceName\": {\r\n \"DefaultValue\": \"SQL_Server\",\r\n \"Type\": \"string\",\r\n \"Value\": \"SQLServer\"\r\n },\r\n \"DatabaseTcpPort\": {\r\n \"DefaultValue\": 1433,\r\n \"Type\": \"int\",\r\n \"Value\": 1433\r\n },\r\n \"DefaultServiceApplicationPoolAccount\": {\r\n \"Metadata\": {\r\n \"Description\": {\r\n \"de-DE\": \"Kontoname fuer den Standard-Application-Pool der SharePoint-Serviceanwendungen.\",\r\n \"en-US\": \"Account name used by the default application pool for SharePoint service applications.\"\r\n }\r\n },\r\n \"Sensitive\": true,\r\n \"Value\": {\r\n \"Provider\": \"SecretManagement\",\r\n \"Vault\": \"Test\",\r\n \"Name\": \"Windows/SharePoint/DefaultServiceAccount\"\r\n },\r\n \"Type\": \"credential\",\r\n \"Required\": true\r\n },\r\n \"ProductKey\": {\r\n \"DefaultValue\": \"0000-0000-0000-0000-0000\",\r\n \"Type\": \"string\",\r\n \"Metadata\": {\r\n \"Description\": {\r\n \"de-DE\": \"SharePoint-Produktlizenzschluessel.\",\r\n \"en-US\": \"SharePoint product license key.\"\r\n }\r\n }\r\n },\r\n \"SetupCredential\": {\r\n \"Sensitive\": true,\r\n \"Value\": {\r\n \"Provider\": \"SecretManagement\",\r\n \"Vault\": \"Test\",\r\n \"Name\": \"Windows/SharePoint/SetupAccount\"\r\n },\r\n \"Type\": \"credential\",\r\n \"Required\": true\r\n },\r\n \"DatabasePrefix\": {\r\n \"DefaultValue\": \"SharePoint\",\r\n \"Type\": \"string\",\r\n \"Value\": \"SharePoint\"\r\n },\r\n \"SearchServiceApplicationPoolAccount\": {\r\n \"Metadata\": {\r\n \"Description\": {\r\n \"de-DE\": \"Kontoname fuer den Search-Application-Pool der SharePoint-Serviceanwendungen.\",\r\n \"en-US\": \"Account name used by the search application pool for SharePoint service applications.\"\r\n }\r\n },\r\n \"Sensitive\": true,\r\n \"Value\": {\r\n \"Provider\": \"SecretManagement\",\r\n \"Vault\": \"Test\",\r\n \"Name\": \"Windows/SharePoint/SearchAccount\"\r\n },\r\n \"Type\": \"credential\",\r\n \"Required\": true\r\n },\r\n \"CentralAdminPort\": {\r\n \"DefaultValue\": 443,\r\n \"Type\": \"int\",\r\n \"Value\": 4000\r\n },\r\n \"ServiceApplicationPoolSearch\": {\r\n \"DefaultValue\": \"SharePoint Search Service Applications\",\r\n \"Type\": \"string\",\r\n \"Metadata\": {\r\n \"Description\": {\r\n \"de-DE\": \"Anzeigename des Application-Pools fuer SharePoint Search-Serviceanwendungen.\",\r\n \"en-US\": \"Display name of the application pool for SharePoint Search service applications.\"\r\n }\r\n }\r\n }\r\n },\r\n \"variables\": {\r\n \"AdminDbName\": \"[joinNotEmpty(\\u0027_\\u0027, variables(\\u0027DatabasePrefix\\u0027), \\u0027Farm_AdminContent\\u0027)]\",\r\n \"ContentDbPrefix\": \"[joinNotEmpty(\\u0027_\\u0027, variables(\\u0027DatabasePrefix\\u0027), parameters(\\u0027ContentDatabaseSegment\\u0027))]\",\r\n \"ServiceDbPrefix\": \"[joinNotEmpty(\\u0027_\\u0027, variables(\\u0027DatabasePrefix\\u0027), parameters(\\u0027ServiceDatabaseSegment\\u0027))]\",\r\n \"DatabasePrefix\": \"[joinNotEmpty(\\u0027_\\u0027, parameters(\\u0027DatabasePrefix\\u0027), parameters(\\u0027DomainLabel\\u0027), if(equals(parameters(\\u0027Landscape\\u0027), \\u0027Test\\u0027), \\u0027Test\\u0027, \\u0027\\u0027))]\",\r\n \"ConfigDbName\": \"[joinNotEmpty(\\u0027_\\u0027, variables(\\u0027DatabasePrefix\\u0027), \\u0027Farm_Config\\u0027)]\"\r\n },\r\n \"resources\": {\r\n \"AllNodes\": [\r\n {\r\n \"PSDscAllowDomainUser\": true,\r\n \"PSDSCAllowPlainTextPassword\": true,\r\n \"NodeName\": \"*\",\r\n \"RunCentralAdministration\": false\r\n }\r\n ],\r\n \"NonNodeData\": {\r\n \"Services\": {\r\n \"SharePoint\": {\r\n \"Farm\": {\r\n \"ManagedAccounts\": {\r\n \"DefaultServiceApplicationPoolAccount\": \"[parameters(\\u0027DefaultServiceApplicationPoolAccount\\u0027)]\",\r\n \"FarmAccount\": \"[parameters(\\u0027FarmCredential\\u0027)]\",\r\n \"SearchServiceApplicationPoolAccount\": \"[parameters(\\u0027SearchServiceApplicationPoolAccount\\u0027)]\"\r\n },\r\n \"Passphrase\": \"[parameters(\\u0027FarmPassphrase\\u0027)]\",\r\n \"ServiceApplications\": {\r\n \"AppManagementService\": {\r\n \"DatabaseName\": \"[concat(variables(\\u0027ServiceDbPrefix\\u0027),\\u0027AppManagement\\u0027)]\",\r\n \"ApplicationPool\": \"[reference(\\u0027Resources.NonNodeData.Services.SharePoint.Farm.ServiceApplicationPools.DefaultServiceApplicationPool\\u0027, \\u0027Name\\u0027)]\",\r\n \"Provision\": true\r\n },\r\n \"StateService\": {\r\n \"DatabaseName\": \"[concat(variables(\\u0027ServiceDbPrefix\\u0027),\\u0027StateService\\u0027)]\",\r\n \"Provision\": true\r\n },\r\n \"SubscriptionSettingsService\": {\r\n \"DatabaseName\": \"[concat(variables(\\u0027ServiceDbPrefix\\u0027),\\u0027SubscriptionSettings\\u0027)]\",\r\n \"ApplicationPool\": \"[reference(\\u0027Resources.NonNodeData.Services.SharePoint.Farm.ServiceApplicationPools.DefaultServiceApplicationPool\\u0027, \\u0027Name\\u0027)]\",\r\n \"Provision\": true\r\n },\r\n \"ManagedMetadataService\": {\r\n \"Name\": \"Managed Metadata Service\",\r\n \"DatabaseName\": \"[concat(variables(\\u0027ServiceDbPrefix\\u0027), \\u0027ManagedMetadata\\u0027)]\",\r\n \"ApplicationPool\": \"[reference(\\u0027Resources.NonNodeData.Services.SharePoint.Farm.ServiceApplicationPools.DefaultServiceApplicationPool\\u0027, \\u0027Name\\u0027)]\",\r\n \"Provision\": true\r\n },\r\n \"SearchService\": {\r\n \"Name\": \"Search Service Application\",\r\n \"DatabaseName\": \"[concat(variables(\\u0027ServiceDbPrefix\\u0027),\\u0027Search\\u0027)]\",\r\n \"ApplicationPool\": \"[reference(\\u0027Resources.NonNodeData.Services.SharePoint.Farm.ServiceApplicationPools.SearchServiceApplicationPool\\u0027, \\u0027Name\\u0027)]\",\r\n \"Provision\": true\r\n },\r\n \"UsageAndHealthService\": {\r\n \"DatabaseName\": \"[concat(variables(\\u0027ServiceDbPrefix\\u0027),\\u0027UsageAndHealth\\u0027)]\",\r\n \"Provision\": true\r\n },\r\n \"SecureStoreService\": {\r\n \"Name\": \"Secure Store Service\",\r\n \"DatabaseName\": \"[concat(variables(\\u0027ServiceDbPrefix\\u0027),\\u0027SecureStore\\u0027)]\",\r\n \"ApplicationPool\": \"[reference(\\u0027Resources.NonNodeData.Services.SharePoint.Farm.ServiceApplicationPools.DefaultServiceApplicationPool\\u0027, \\u0027Name\\u0027)]\",\r\n \"Provision\": true,\r\n \"AuditingEnabled\": true\r\n },\r\n \"UserProfileService\": {\r\n \"SyncDBName\": \"[concat(variables(\\u0027ServiceDbPrefix\\u0027), \\u0027UserProfile_Sync\\u0027)]\",\r\n \"ApplicationPool\": \"[reference(\\u0027Resources.NonNodeData.Services.SharePoint.Farm.ServiceApplicationPools.DefaultServiceApplicationPool\\u0027, \\u0027Name\\u0027)]\",\r\n \"Provision\": true,\r\n \"Name\": \"User Profile Service\",\r\n \"SocialDBName\": \"[concat(variables(\\u0027ServiceDbPrefix\\u0027), \\u0027UserProfile_Social\\u0027)]\",\r\n \"ProfileDBName\": \"[concat(variables(\\u0027ServiceDbPrefix\\u0027), \\u0027UserProfile_Profile\\u0027)]\"\r\n }\r\n },\r\n \"CentralAdminAuth\": \"NTLM\",\r\n \"ConfigDatabaseName\": \"[variables(\\u0027ConfigDbName\\u0027)]\",\r\n \"Accounts\": {\r\n \"SetupAccount\": \"[parameters(\\u0027SetupCredential\\u0027)]\"\r\n },\r\n \"CentralAdminPort\": \"[parameters(\\u0027CentralAdminPort\\u0027)]\",\r\n \"AdminContentDatabase\": \"[variables(\\u0027AdminDbName\\u0027)]\",\r\n \"ServiceApplicationPools\": {\r\n \"SearchServiceApplicationPool\": {\r\n \"Account\": \"[reference(\\u0027Resources.NonNodeData.Services.SharePoint.Farm.ManagedAccounts.SearchServiceApplicationPoolAccount\\u0027, \\u0027UserName\\u0027)]\",\r\n \"Name\": \"[parameters(\\u0027ServiceApplicationPoolSearch\\u0027)]\"\r\n },\r\n \"DefaultServiceApplicationPool\": {\r\n \"Account\": \"[reference(\\u0027Resources.NonNodeData.Services.SharePoint.Farm.ManagedAccounts.DefaultServiceApplicationPoolAccount\\u0027, \\u0027UserName\\u0027)]\",\r\n \"Name\": \"[parameters(\\u0027ServiceApplicationPoolDefault\\u0027)]\"\r\n }\r\n }\r\n },\r\n \"Database\": {\r\n \"Targets\": {\r\n \"Farm\": {\r\n \"Server\": \"SQLServer\",\r\n \"DependsOnAlias\": \"SQLServer\"\r\n },\r\n \"Content\": {\r\n \"Server\": \"SQLServer\",\r\n \"DependsOnAlias\": \"SQLServer\"\r\n },\r\n \"Service\": {\r\n \"Server\": \"SQLServer\",\r\n \"DependsOnAlias\": \"SQLServer\"\r\n }\r\n },\r\n \"SQLAlias\": {\r\n \"SQLServer\": {\r\n \"InstanceName\": \"[parameters(\\u0027DatabaseInstanceName\\u0027)]\",\r\n \"ServerName\": \"[parameters(\\u0027DatabaseServerName\\u0027)]\",\r\n \"Protocol\": \"TCP\",\r\n \"TcpPort\": \"[parameters(\\u0027DatabaseTcpPort\\u0027)]\"\r\n }\r\n }\r\n },\r\n \"General\": {\r\n \"ProductKey\": \"[parameters(\\u0027ProductKey\\u0027)]\"\r\n },\r\n \"Windows\": {\r\n \"Registry\": {\r\n \"DisableLoopbackCheck\": {\r\n \"Path\": \"HKLM:\\\\SYSTEM\\\\CurrentControlSet\\\\Control\\\\Lsa\",\r\n \"Name\": \"DisableLoopbackCheck\",\r\n \"Value\": 1,\r\n \"Type\": \"DWord\"\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n}", + JsonHash = "E3B0E2A8E0C85CCD92AEA521ECD243E61E34C61D7078D6715E6317F5669A1D69", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + PublishedAt = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + PublishedBy = "DemoSeed", + RevisionNumber = 1, + SchemaVersion = "1.0", + TemplateVersionId = new Guid("71000000-0000-0000-0000-000000000103") + }, + new + { + Id = new Guid("72000000-0000-0000-0000-000000000104"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + IsCurrent = true, + IsPublished = true, + JsonData = "{\r\n \"schemaVersion\": \"1.0\",\r\n \"templateType\": \"Stage\",\r\n \"metadata\": {\r\n \"TemplateType\": \"Stage\",\r\n \"Name\": \"Install\"\r\n },\r\n \"parameters\": {\r\n\r\n },\r\n \"variables\": {\r\n\r\n },\r\n \"resources\": {\r\n \"NonNodeData\": {\r\n \"LocalConfigurationManager\": {\r\n \"RefreshFrequencyMins\": \"30\",\r\n \"RefreshMode\": \"PUSH\",\r\n \"ConfigurationModeFrequencyMins\": \"120\",\r\n \"ConfigurationMode\": \"ApplyOnly\"\r\n }\r\n }\r\n }\r\n}", + JsonHash = "ACA23E44C9F625F080D2653646555A9DE5546D8DE7BB2166324E775BCF47F3C1", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + PublishedAt = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + PublishedBy = "DemoSeed", + RevisionNumber = 1, + SchemaVersion = "1.0", + TemplateVersionId = new Guid("71000000-0000-0000-0000-000000000104") + }); + }); + + modelBuilder.Entity("Microsoft.SelfService.Portal.Core.API.Models.TemplateVersionModel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier") + .HasColumnOrder(0) + .HasDefaultValueSql("NEWID()"); + + b.Property("Created") + .ValueGeneratedOnAdd() + .HasColumnType("datetime2") + .HasColumnOrder(52) + .HasDefaultValueSql("GETDATE()"); + + b.Property("CreatedBy") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(53); + + b.Property("IsPublished") + .HasColumnType("bit") + .HasColumnOrder(6); + + b.Property("JsonData") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(3); + + b.Property("JsonHash") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)") + .HasColumnOrder(4); + + b.Property("Modified") + .ValueGeneratedOnAdd() + .HasColumnType("datetime2") + .HasColumnOrder(50) + .HasDefaultValueSql("GETDATE()"); + + b.Property("ModifiedBy") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnOrder(51); + + b.Property("PublishedAt") + .HasColumnType("datetime2") + .HasColumnOrder(7); + + b.Property("PublishedBy") + .HasColumnType("nvarchar(max)") + .HasColumnOrder(8); + + b.Property("SchemaVersion") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("nvarchar(32)") + .HasColumnOrder(5); + + b.Property("TemplateId") + .HasColumnType("uniqueidentifier") + .HasColumnOrder(1); + + b.Property("Version") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)") + .HasColumnOrder(2); + + b.HasKey("Id"); + + b.HasIndex("TemplateId") + .IsUnique() + .HasFilter("[IsPublished] = 1"); + + b.HasIndex("TemplateId", "Version") + .IsUnique(); + + b.ToTable("TemplateVersions", t => + { + t.HasCheckConstraint("CK_TemplateVersions_JsonData_IsJson", "ISJSON([JsonData]) = 1"); + }); + + b.HasData( + new + { + Id = new Guid("71000000-0000-0000-0000-000000000001"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + IsPublished = true, + JsonData = "{\n \"schemaVersion\": \"1.0\",\n \"templateType\": \"Service\",\n \"parameters\": {\n \"DomainName\": { \"type\": \"string\", \"defaultValue\": \"corp.contoso.com\" },\n \"NetBIOSName\": { \"type\": \"string\", \"defaultValue\": \"CONTOSO\" }\n },\n \"variables\": {\n \"DefaultSiteName\": \"[concat(parameters('DomainName'), '-DefaultSite')]\"\n },\n \"resources\": {\n \"AllNodes\": [\n { \"NodeName\": \"*\", \"PSDscAllowPlainTextPassword\": true }\n ],\n \"NonNodeData\": {\n \"Services\": {\n \"ActiveDirectory\": {\n \"DomainName\": \"[parameters('DomainName')]\",\n \"NetBIOSName\": \"[parameters('NetBIOSName')]\"\n }\n }\n }\n }\n}", + JsonHash = "C05CBEF91131C75DE53B9609D9C2709D680AFC9559EE8D998318A132490F79A7", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + PublishedAt = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + PublishedBy = "DemoSeed", + SchemaVersion = "1.0", + TemplateId = new Guid("70000000-0000-0000-0000-000000000001"), + Version = "1.0.0" + }, + new + { + Id = new Guid("71000000-0000-0000-0000-000000000002"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + IsPublished = true, + JsonData = "{\n \"schemaVersion\": \"1.0\",\n \"templateType\": \"Service\",\n \"parameters\": {\n \"InstanceName\": { \"type\": \"string\", \"defaultValue\": \"MSSQLSERVER\" },\n \"DatabasePrefix\": { \"type\": \"string\", \"defaultValue\": \"Contoso\" }\n },\n \"variables\": {\n \"ConfigDatabase\": \"[concat(parameters('DatabasePrefix'), '_Config')]\"\n },\n \"resources\": {\n \"NonNodeData\": {\n \"Services\": {\n \"SqlServer\": {\n \"InstanceName\": \"[parameters('InstanceName')]\",\n \"ConfigDatabase\": \"[variables('ConfigDatabase')]\"\n }\n }\n }\n }\n}", + JsonHash = "F376737E82CB6B729F7B9960CB9988897C16D90A1C454ED2F594B28EB86ECA11", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + PublishedAt = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + PublishedBy = "DemoSeed", + SchemaVersion = "1.0", + TemplateId = new Guid("70000000-0000-0000-0000-000000000002"), + Version = "1.0.0" + }, + new + { + Id = new Guid("71000000-0000-0000-0000-000000000003"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + IsPublished = true, + JsonData = "{\n \"schemaVersion\": \"1.0\",\n \"templateType\": \"Service\",\n \"parameters\": {\n \"DatabasePrefix\": { \"type\": \"string\", \"defaultValue\": \"SharePoint_Contoso_Test\" },\n \"FarmAccount\": { \"type\": \"credential\", \"metadata\": { \"description\": \"Farm account resolved by the credential provider.\" } }\n },\n \"variables\": {\n \"ConfigDbName\": \"[concat(parameters('DatabasePrefix'), '_Farm_Config')]\",\n \"AdminContentDbName\": \"[concat(parameters('DatabasePrefix'), '_AdminContent')]\"\n },\n \"resources\": {\n \"NonNodeData\": {\n \"Services\": {\n \"SharePoint\": {\n \"Farm\": {\n \"ConfigDatabase\": \"[variables('ConfigDbName')]\",\n \"AdminContentDatabase\": \"[variables('AdminContentDbName')]\",\n \"ManagedAccounts\": {\n \"FarmAccount\": \"[parameters('FarmAccount')]\"\n }\n }\n }\n }\n }\n }\n}", + JsonHash = "FD5F0FD3C13538FAC70646972DC364DFCEAAF85BBE91B0F50FDFF9FD3A3748B4", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + PublishedAt = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + PublishedBy = "DemoSeed", + SchemaVersion = "1.0", + TemplateId = new Guid("70000000-0000-0000-0000-000000000003"), + Version = "1.0.0" + }, + new + { + Id = new Guid("71000000-0000-0000-0000-000000000004"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + IsPublished = true, + JsonData = "{\n \"schemaVersion\": \"1.0\",\n \"templateType\": \"Service\",\n \"parameters\": {\n \"CallingPolicyName\": { \"type\": \"string\", \"defaultValue\": \"Contoso-Standard-Calling\" },\n \"MeetingPolicyName\": { \"type\": \"string\", \"defaultValue\": \"Contoso-Standard-Meetings\" }\n },\n \"variables\": {},\n \"resources\": {\n \"NonNodeData\": {\n \"Services\": {\n \"Teams\": {\n \"CallingPolicy\": \"[parameters('CallingPolicyName')]\",\n \"MeetingPolicy\": \"[parameters('MeetingPolicyName')]\"\n }\n }\n }\n }\n}", + JsonHash = "32A902FE1A871D4CE2C877EBC5542F7562856532F09BA7F53597B21270586241", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + PublishedAt = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + PublishedBy = "DemoSeed", + SchemaVersion = "1.0", + TemplateId = new Guid("70000000-0000-0000-0000-000000000004"), + Version = "1.0.0" + }, + new + { + Id = new Guid("71000000-0000-0000-0000-000000000101"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + IsPublished = true, + JsonData = "{\r\n \"schemaVersion\": \"1.0\",\r\n \"templateType\": \"Environment\",\r\n \"metadata\": {\r\n \"TemplateType\": \"Environment\",\r\n \"Name\": \"Test\"\r\n },\r\n \"parameters\": {\r\n \"Landscape\": {\r\n \"DefaultValue\": \"Prod\",\r\n \"Value\": \"Test\",\r\n \"Type\": \"string\",\r\n \"AllowedValues\": [\r\n \"Prod\",\r\n \"QA\",\r\n \"Test\"\r\n ]\r\n }\r\n },\r\n \"variables\": {\r\n \"AdminDbName\": \"[joinNotEmpty(\\u0027_\\u0027, variables(\\u0027DatabasePrefix\\u0027), \\u0027Farm_AdminContent\\u0027)]\",\r\n \"ContentDbPrefix\": \"[joinNotEmpty(\\u0027_\\u0027, variables(\\u0027DatabasePrefix\\u0027), parameters(\\u0027ContentDatabaseSegment\\u0027))]\",\r\n \"ServiceDbPrefix\": \"[joinNotEmpty(\\u0027_\\u0027, variables(\\u0027DatabasePrefix\\u0027), parameters(\\u0027ServiceDatabaseSegment\\u0027))]\",\r\n \"DatabasePrefix\": \"[joinNotEmpty(\\u0027_\\u0027, parameters(\\u0027DatabasePrefix\\u0027), parameters(\\u0027DomainLabel\\u0027), if(equals(parameters(\\u0027Landscape\\u0027), \\u0027Test\\u0027), \\u0027Test\\u0027, \\u0027\\u0027))]\",\r\n \"ConfigDbName\": \"[joinNotEmpty(\\u0027_\\u0027, variables(\\u0027DatabasePrefix\\u0027), \\u0027Farm_Config\\u0027)]\"\r\n },\r\n \"resources\": {\r\n\r\n }\r\n}", + JsonHash = "58553C7A4E902B5E39D30272754FEF9EF805A7F36363D8316A9B37540C6D4646", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + PublishedAt = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + PublishedBy = "DemoSeed", + SchemaVersion = "1.0", + TemplateId = new Guid("70000000-0000-0000-0000-000000000101"), + Version = "1.0.0" + }, + new + { + Id = new Guid("71000000-0000-0000-0000-000000000102"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + IsPublished = true, + JsonData = "{\r\n \"schemaVersion\": \"1.0\",\r\n \"templateType\": \"Domain\",\r\n \"metadata\": {\r\n \"TemplateType\": \"Domain\",\r\n \"Name\": \"Contoso\"\r\n },\r\n \"parameters\": {\r\n \"DomainFQDN\": {\r\n \"DefaultValue\": \"\",\r\n \"Pattern\": \"^[A-Za-z0-9.-]+$\",\r\n \"Type\": \"string\",\r\n \"Value\": \"contoso.local\",\r\n \"Required\": true\r\n },\r\n \"DomainLabel\": {\r\n \"Type\": \"string\",\r\n \"MaxLength\": 32,\r\n \"Value\": \"Contoso\",\r\n \"DefaultValue\": \"\",\r\n \"Pattern\": \"^[A-Za-z][A-Za-z0-9_-]*$\",\r\n \"MinLength\": 2,\r\n \"Required\": false\r\n },\r\n \"DomainNetBIOS\": {\r\n \"Type\": \"string\",\r\n \"MaxLength\": 15,\r\n \"Value\": \"CONTOSO\",\r\n \"DefaultValue\": \"\",\r\n \"Pattern\": \"^[A-Za-z0-9_-]+$\",\r\n \"MinLength\": 1,\r\n \"Required\": true\r\n }\r\n },\r\n \"variables\": {\r\n\r\n },\r\n \"resources\": {\r\n \"NonNodeData\": {\r\n \"Services\": {\r\n \"ActiveDirectory\": {\r\n \"NetBIOSName\": \"[parameters(\\u0027DomainNetBIOS\\u0027)]\",\r\n \"DomainName\": \"[parameters(\\u0027DomainFQDN\\u0027)]\"\r\n }\r\n }\r\n }\r\n }\r\n}", + JsonHash = "B265C4D542826423BAAF50BF939F026CC67FF631FEC19F708067516BCE4C7667", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + PublishedAt = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + PublishedBy = "DemoSeed", + SchemaVersion = "1.0", + TemplateId = new Guid("70000000-0000-0000-0000-000000000102"), + Version = "1.0.0" + }, + new + { + Id = new Guid("71000000-0000-0000-0000-000000000103"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + IsPublished = true, + JsonData = "{\r\n \"schemaVersion\": \"1.0\",\r\n \"templateType\": \"Service\",\r\n \"metadata\": {\r\n \"TemplateType\": \"Service\",\r\n \"Name\": \"SharePoint.Contoso\"\r\n },\r\n \"parameters\": {\r\n \"FarmCredential\": {\r\n \"Sensitive\": true,\r\n \"Value\": {\r\n \"Provider\": \"SecretManagement\",\r\n \"Vault\": \"Test\",\r\n \"Name\": \"Windows/SharePoint/FarmAccount\"\r\n },\r\n \"Type\": \"credential\",\r\n \"Required\": true\r\n },\r\n \"ContentDatabaseSegment\": {\r\n \"DefaultValue\": \"Content\",\r\n \"Type\": \"string\",\r\n \"Metadata\": {\r\n \"Description\": {\r\n \"de-DE\": \"Namenssegment fuer SharePoint-Content-Datenbanken innerhalb des Datenbanknamens.\",\r\n \"en-US\": \"Name segment used for SharePoint content databases within the database name.\"\r\n }\r\n }\r\n },\r\n \"ServiceApplicationPoolDefault\": {\r\n \"DefaultValue\": \"SharePoint Service Applications\",\r\n \"Type\": \"string\",\r\n \"Metadata\": {\r\n \"Description\": {\r\n \"de-DE\": \"Anzeigename des Standard-Application-Pools fuer SharePoint-Serviceanwendungen.\",\r\n \"en-US\": \"Display name of the default application pool for SharePoint service applications.\"\r\n }\r\n }\r\n },\r\n \"WebApplicationPoolDefault\": {\r\n \"DefaultValue\": \"SharePoint Web Applications\",\r\n \"Type\": \"string\",\r\n \"Metadata\": {\r\n \"Description\": {\r\n \"de-DE\": \"Anzeigename des Standard-Application-Pools fuer SharePoint-Webanwendungen.\",\r\n \"en-US\": \"Display name of the default application pool for SharePoint web applications.\"\r\n }\r\n }\r\n },\r\n \"DatabaseServerName\": {\r\n \"DefaultValue\": \"SQL_Server\",\r\n \"Type\": \"string\",\r\n \"Value\": \"CL-SQL-01\"\r\n },\r\n \"WebApplicationPoolDefaultAccount\": {\r\n \"DefaultValue\": \"SVC_SHP_WAP\",\r\n \"Type\": \"string\",\r\n \"Metadata\": {\r\n \"Description\": {\r\n \"de-DE\": \"Kontoname fuer den Standard-Application-Pool der SharePoint-Webanwendungen.\",\r\n \"en-US\": \"Account name used by the default application pool for SharePoint web applications.\"\r\n }\r\n }\r\n },\r\n \"ServiceDatabaseSegment\": {\r\n \"DefaultValue\": \"Services\",\r\n \"Type\": \"string\",\r\n \"Metadata\": {\r\n \"Description\": {\r\n \"de-DE\": \"Namenssegment fuer SharePoint-Service-Datenbanken innerhalb des Datenbanknamens.\",\r\n \"en-US\": \"Name segment used for SharePoint service databases within the database name.\"\r\n }\r\n }\r\n },\r\n \"FarmPassphrase\": {\r\n \"Sensitive\": true,\r\n \"Value\": {\r\n \"Provider\": \"SecretManagement\",\r\n \"Vault\": \"Test\",\r\n \"Name\": \"Windows/SharePoint/FarmPassphrase\"\r\n },\r\n \"Type\": \"credential\",\r\n \"Required\": true\r\n },\r\n \"DatabaseInstanceName\": {\r\n \"DefaultValue\": \"SQL_Server\",\r\n \"Type\": \"string\",\r\n \"Value\": \"SQLServer\"\r\n },\r\n \"DatabaseTcpPort\": {\r\n \"DefaultValue\": 1433,\r\n \"Type\": \"int\",\r\n \"Value\": 1433\r\n },\r\n \"DefaultServiceApplicationPoolAccount\": {\r\n \"Metadata\": {\r\n \"Description\": {\r\n \"de-DE\": \"Kontoname fuer den Standard-Application-Pool der SharePoint-Serviceanwendungen.\",\r\n \"en-US\": \"Account name used by the default application pool for SharePoint service applications.\"\r\n }\r\n },\r\n \"Sensitive\": true,\r\n \"Value\": {\r\n \"Provider\": \"SecretManagement\",\r\n \"Vault\": \"Test\",\r\n \"Name\": \"Windows/SharePoint/DefaultServiceAccount\"\r\n },\r\n \"Type\": \"credential\",\r\n \"Required\": true\r\n },\r\n \"ProductKey\": {\r\n \"DefaultValue\": \"0000-0000-0000-0000-0000\",\r\n \"Type\": \"string\",\r\n \"Metadata\": {\r\n \"Description\": {\r\n \"de-DE\": \"SharePoint-Produktlizenzschluessel.\",\r\n \"en-US\": \"SharePoint product license key.\"\r\n }\r\n }\r\n },\r\n \"SetupCredential\": {\r\n \"Sensitive\": true,\r\n \"Value\": {\r\n \"Provider\": \"SecretManagement\",\r\n \"Vault\": \"Test\",\r\n \"Name\": \"Windows/SharePoint/SetupAccount\"\r\n },\r\n \"Type\": \"credential\",\r\n \"Required\": true\r\n },\r\n \"DatabasePrefix\": {\r\n \"DefaultValue\": \"SharePoint\",\r\n \"Type\": \"string\",\r\n \"Value\": \"SharePoint\"\r\n },\r\n \"SearchServiceApplicationPoolAccount\": {\r\n \"Metadata\": {\r\n \"Description\": {\r\n \"de-DE\": \"Kontoname fuer den Search-Application-Pool der SharePoint-Serviceanwendungen.\",\r\n \"en-US\": \"Account name used by the search application pool for SharePoint service applications.\"\r\n }\r\n },\r\n \"Sensitive\": true,\r\n \"Value\": {\r\n \"Provider\": \"SecretManagement\",\r\n \"Vault\": \"Test\",\r\n \"Name\": \"Windows/SharePoint/SearchAccount\"\r\n },\r\n \"Type\": \"credential\",\r\n \"Required\": true\r\n },\r\n \"CentralAdminPort\": {\r\n \"DefaultValue\": 443,\r\n \"Type\": \"int\",\r\n \"Value\": 4000\r\n },\r\n \"ServiceApplicationPoolSearch\": {\r\n \"DefaultValue\": \"SharePoint Search Service Applications\",\r\n \"Type\": \"string\",\r\n \"Metadata\": {\r\n \"Description\": {\r\n \"de-DE\": \"Anzeigename des Application-Pools fuer SharePoint Search-Serviceanwendungen.\",\r\n \"en-US\": \"Display name of the application pool for SharePoint Search service applications.\"\r\n }\r\n }\r\n }\r\n },\r\n \"variables\": {\r\n \"AdminDbName\": \"[joinNotEmpty(\\u0027_\\u0027, variables(\\u0027DatabasePrefix\\u0027), \\u0027Farm_AdminContent\\u0027)]\",\r\n \"ContentDbPrefix\": \"[joinNotEmpty(\\u0027_\\u0027, variables(\\u0027DatabasePrefix\\u0027), parameters(\\u0027ContentDatabaseSegment\\u0027))]\",\r\n \"ServiceDbPrefix\": \"[joinNotEmpty(\\u0027_\\u0027, variables(\\u0027DatabasePrefix\\u0027), parameters(\\u0027ServiceDatabaseSegment\\u0027))]\",\r\n \"DatabasePrefix\": \"[joinNotEmpty(\\u0027_\\u0027, parameters(\\u0027DatabasePrefix\\u0027), parameters(\\u0027DomainLabel\\u0027), if(equals(parameters(\\u0027Landscape\\u0027), \\u0027Test\\u0027), \\u0027Test\\u0027, \\u0027\\u0027))]\",\r\n \"ConfigDbName\": \"[joinNotEmpty(\\u0027_\\u0027, variables(\\u0027DatabasePrefix\\u0027), \\u0027Farm_Config\\u0027)]\"\r\n },\r\n \"resources\": {\r\n \"AllNodes\": [\r\n {\r\n \"PSDscAllowDomainUser\": true,\r\n \"PSDSCAllowPlainTextPassword\": true,\r\n \"NodeName\": \"*\",\r\n \"RunCentralAdministration\": false\r\n }\r\n ],\r\n \"NonNodeData\": {\r\n \"Services\": {\r\n \"SharePoint\": {\r\n \"Farm\": {\r\n \"ManagedAccounts\": {\r\n \"DefaultServiceApplicationPoolAccount\": \"[parameters(\\u0027DefaultServiceApplicationPoolAccount\\u0027)]\",\r\n \"FarmAccount\": \"[parameters(\\u0027FarmCredential\\u0027)]\",\r\n \"SearchServiceApplicationPoolAccount\": \"[parameters(\\u0027SearchServiceApplicationPoolAccount\\u0027)]\"\r\n },\r\n \"Passphrase\": \"[parameters(\\u0027FarmPassphrase\\u0027)]\",\r\n \"ServiceApplications\": {\r\n \"AppManagementService\": {\r\n \"DatabaseName\": \"[concat(variables(\\u0027ServiceDbPrefix\\u0027),\\u0027AppManagement\\u0027)]\",\r\n \"ApplicationPool\": \"[reference(\\u0027Resources.NonNodeData.Services.SharePoint.Farm.ServiceApplicationPools.DefaultServiceApplicationPool\\u0027, \\u0027Name\\u0027)]\",\r\n \"Provision\": true\r\n },\r\n \"StateService\": {\r\n \"DatabaseName\": \"[concat(variables(\\u0027ServiceDbPrefix\\u0027),\\u0027StateService\\u0027)]\",\r\n \"Provision\": true\r\n },\r\n \"SubscriptionSettingsService\": {\r\n \"DatabaseName\": \"[concat(variables(\\u0027ServiceDbPrefix\\u0027),\\u0027SubscriptionSettings\\u0027)]\",\r\n \"ApplicationPool\": \"[reference(\\u0027Resources.NonNodeData.Services.SharePoint.Farm.ServiceApplicationPools.DefaultServiceApplicationPool\\u0027, \\u0027Name\\u0027)]\",\r\n \"Provision\": true\r\n },\r\n \"ManagedMetadataService\": {\r\n \"Name\": \"Managed Metadata Service\",\r\n \"DatabaseName\": \"[concat(variables(\\u0027ServiceDbPrefix\\u0027), \\u0027ManagedMetadata\\u0027)]\",\r\n \"ApplicationPool\": \"[reference(\\u0027Resources.NonNodeData.Services.SharePoint.Farm.ServiceApplicationPools.DefaultServiceApplicationPool\\u0027, \\u0027Name\\u0027)]\",\r\n \"Provision\": true\r\n },\r\n \"SearchService\": {\r\n \"Name\": \"Search Service Application\",\r\n \"DatabaseName\": \"[concat(variables(\\u0027ServiceDbPrefix\\u0027),\\u0027Search\\u0027)]\",\r\n \"ApplicationPool\": \"[reference(\\u0027Resources.NonNodeData.Services.SharePoint.Farm.ServiceApplicationPools.SearchServiceApplicationPool\\u0027, \\u0027Name\\u0027)]\",\r\n \"Provision\": true\r\n },\r\n \"UsageAndHealthService\": {\r\n \"DatabaseName\": \"[concat(variables(\\u0027ServiceDbPrefix\\u0027),\\u0027UsageAndHealth\\u0027)]\",\r\n \"Provision\": true\r\n },\r\n \"SecureStoreService\": {\r\n \"Name\": \"Secure Store Service\",\r\n \"DatabaseName\": \"[concat(variables(\\u0027ServiceDbPrefix\\u0027),\\u0027SecureStore\\u0027)]\",\r\n \"ApplicationPool\": \"[reference(\\u0027Resources.NonNodeData.Services.SharePoint.Farm.ServiceApplicationPools.DefaultServiceApplicationPool\\u0027, \\u0027Name\\u0027)]\",\r\n \"Provision\": true,\r\n \"AuditingEnabled\": true\r\n },\r\n \"UserProfileService\": {\r\n \"SyncDBName\": \"[concat(variables(\\u0027ServiceDbPrefix\\u0027), \\u0027UserProfile_Sync\\u0027)]\",\r\n \"ApplicationPool\": \"[reference(\\u0027Resources.NonNodeData.Services.SharePoint.Farm.ServiceApplicationPools.DefaultServiceApplicationPool\\u0027, \\u0027Name\\u0027)]\",\r\n \"Provision\": true,\r\n \"Name\": \"User Profile Service\",\r\n \"SocialDBName\": \"[concat(variables(\\u0027ServiceDbPrefix\\u0027), \\u0027UserProfile_Social\\u0027)]\",\r\n \"ProfileDBName\": \"[concat(variables(\\u0027ServiceDbPrefix\\u0027), \\u0027UserProfile_Profile\\u0027)]\"\r\n }\r\n },\r\n \"CentralAdminAuth\": \"NTLM\",\r\n \"ConfigDatabaseName\": \"[variables(\\u0027ConfigDbName\\u0027)]\",\r\n \"Accounts\": {\r\n \"SetupAccount\": \"[parameters(\\u0027SetupCredential\\u0027)]\"\r\n },\r\n \"CentralAdminPort\": \"[parameters(\\u0027CentralAdminPort\\u0027)]\",\r\n \"AdminContentDatabase\": \"[variables(\\u0027AdminDbName\\u0027)]\",\r\n \"ServiceApplicationPools\": {\r\n \"SearchServiceApplicationPool\": {\r\n \"Account\": \"[reference(\\u0027Resources.NonNodeData.Services.SharePoint.Farm.ManagedAccounts.SearchServiceApplicationPoolAccount\\u0027, \\u0027UserName\\u0027)]\",\r\n \"Name\": \"[parameters(\\u0027ServiceApplicationPoolSearch\\u0027)]\"\r\n },\r\n \"DefaultServiceApplicationPool\": {\r\n \"Account\": \"[reference(\\u0027Resources.NonNodeData.Services.SharePoint.Farm.ManagedAccounts.DefaultServiceApplicationPoolAccount\\u0027, \\u0027UserName\\u0027)]\",\r\n \"Name\": \"[parameters(\\u0027ServiceApplicationPoolDefault\\u0027)]\"\r\n }\r\n }\r\n },\r\n \"Database\": {\r\n \"Targets\": {\r\n \"Farm\": {\r\n \"Server\": \"SQLServer\",\r\n \"DependsOnAlias\": \"SQLServer\"\r\n },\r\n \"Content\": {\r\n \"Server\": \"SQLServer\",\r\n \"DependsOnAlias\": \"SQLServer\"\r\n },\r\n \"Service\": {\r\n \"Server\": \"SQLServer\",\r\n \"DependsOnAlias\": \"SQLServer\"\r\n }\r\n },\r\n \"SQLAlias\": {\r\n \"SQLServer\": {\r\n \"InstanceName\": \"[parameters(\\u0027DatabaseInstanceName\\u0027)]\",\r\n \"ServerName\": \"[parameters(\\u0027DatabaseServerName\\u0027)]\",\r\n \"Protocol\": \"TCP\",\r\n \"TcpPort\": \"[parameters(\\u0027DatabaseTcpPort\\u0027)]\"\r\n }\r\n }\r\n },\r\n \"General\": {\r\n \"ProductKey\": \"[parameters(\\u0027ProductKey\\u0027)]\"\r\n },\r\n \"Windows\": {\r\n \"Registry\": {\r\n \"DisableLoopbackCheck\": {\r\n \"Path\": \"HKLM:\\\\SYSTEM\\\\CurrentControlSet\\\\Control\\\\Lsa\",\r\n \"Name\": \"DisableLoopbackCheck\",\r\n \"Value\": 1,\r\n \"Type\": \"DWord\"\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n}", + JsonHash = "E3B0E2A8E0C85CCD92AEA521ECD243E61E34C61D7078D6715E6317F5669A1D69", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + PublishedAt = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + PublishedBy = "DemoSeed", + SchemaVersion = "1.0", + TemplateId = new Guid("70000000-0000-0000-0000-000000000103"), + Version = "1.0.0" + }, + new + { + Id = new Guid("71000000-0000-0000-0000-000000000104"), + Created = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + CreatedBy = "DemoSeed", + IsPublished = true, + JsonData = "{\r\n \"schemaVersion\": \"1.0\",\r\n \"templateType\": \"Stage\",\r\n \"metadata\": {\r\n \"TemplateType\": \"Stage\",\r\n \"Name\": \"Install\"\r\n },\r\n \"parameters\": {\r\n\r\n },\r\n \"variables\": {\r\n\r\n },\r\n \"resources\": {\r\n \"NonNodeData\": {\r\n \"LocalConfigurationManager\": {\r\n \"RefreshFrequencyMins\": \"30\",\r\n \"RefreshMode\": \"PUSH\",\r\n \"ConfigurationModeFrequencyMins\": \"120\",\r\n \"ConfigurationMode\": \"ApplyOnly\"\r\n }\r\n }\r\n }\r\n}", + JsonHash = "ACA23E44C9F625F080D2653646555A9DE5546D8DE7BB2166324E775BCF47F3C1", + Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + ModifiedBy = "DemoSeed", + PublishedAt = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), + PublishedBy = "DemoSeed", + SchemaVersion = "1.0", + TemplateId = new Guid("70000000-0000-0000-0000-000000000104"), + Version = "1.0.0" + }); + }); + + modelBuilder.Entity("Microsoft.SelfService.Portal.Core.API.Models.ApiTokenModel", b => + { + b.HasOne("Microsoft.SelfService.Portal.Core.API.Models.ApiClientModel", "ApiClient") + .WithMany() + .HasForeignKey("ApiClientId") + .OnDelete(DeleteBehavior.SetNull); + + b.Navigation("ApiClient"); + }); + + modelBuilder.Entity("Microsoft.SelfService.Portal.Core.API.Models.ConfigurationDefinitionModel", b => + { + b.HasOne("Microsoft.SelfService.Portal.Core.API.Models.TemplateRevisionModel", "TemplateRevision") + .WithMany("ConfigurationDefinitions") + .HasForeignKey("TemplateRevisionId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("TemplateRevision"); + }); + + modelBuilder.Entity("Microsoft.SelfService.Portal.Core.API.Models.ConfigurationValueModel", b => + { + b.HasOne("Microsoft.SelfService.Portal.Core.API.Models.ConfigurationDefinitionModel", "ConfigurationDefinition") + .WithMany("Values") + .HasForeignKey("ConfigurationDefinitionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ConfigurationDefinition"); + }); + + modelBuilder.Entity("Microsoft.SelfService.Portal.Core.API.Models.DeploymentArtifactModel", b => + { + b.HasOne("Microsoft.SelfService.Portal.Core.API.Models.DeploymentGroupModel", "DeploymentGroup") + .WithMany("Artifacts") + .HasForeignKey("DeploymentGroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Microsoft.SelfService.Portal.Core.API.Models.TargetModel", "Target") + .WithMany() + .HasForeignKey("TargetId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("Microsoft.SelfService.Portal.Core.API.Models.DeploymentModel", "Deployment") + .WithMany("Artifacts") + .HasForeignKey("TargetId", "DeploymentGroupId") + .OnDelete(DeleteBehavior.NoAction); + + b.Navigation("Deployment"); + + b.Navigation("DeploymentGroup"); + + b.Navigation("Target"); + }); + + modelBuilder.Entity("Microsoft.SelfService.Portal.Core.API.Models.DeploymentGroupModel", b => + { + b.HasOne("Microsoft.SelfService.Portal.Core.API.Models.DeploymentRuleModel", "DeploymentRule") + .WithMany() + .HasForeignKey("DeploymentRuleId") + .OnDelete(DeleteBehavior.SetNull); + + b.HasOne("Microsoft.SelfService.Portal.Core.API.Models.TemplateModel", "Template") + .WithMany("DeploymentGroups") + .HasForeignKey("TemplateId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("DeploymentRule"); + + b.Navigation("Template"); + }); + + modelBuilder.Entity("Microsoft.SelfService.Portal.Core.API.Models.DeploymentModel", b => + { + b.HasOne("Microsoft.SelfService.Portal.Core.API.Models.DeploymentArtifactModel", "CurrentArtifact") + .WithMany() + .HasForeignKey("CurrentArtifactId") + .OnDelete(DeleteBehavior.NoAction); + + b.HasOne("Microsoft.SelfService.Portal.Core.API.Models.DeploymentGroupModel", "DeploymentGroup") + .WithMany("Deployments") + .HasForeignKey("DeploymentGroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Microsoft.SelfService.Portal.Core.API.Models.TargetModel", "Target") + .WithMany("Deployments") + .HasForeignKey("TargetId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Microsoft.SelfService.Portal.Core.API.Models.TemplateRevisionModel", "TemplateRevision") + .WithMany("Deployments") + .HasForeignKey("TemplateRevisionId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("CurrentArtifact"); + + b.Navigation("DeploymentGroup"); + + b.Navigation("Target"); + + b.Navigation("TemplateRevision"); + }); + + modelBuilder.Entity("Microsoft.SelfService.Portal.Core.API.Models.DeploymentParameterValueModel", b => + { + b.HasOne("Microsoft.SelfService.Portal.Core.API.Models.DeploymentGroupModel", "DeploymentGroup") + .WithMany("ParameterValues") + .HasForeignKey("DeploymentGroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Microsoft.SelfService.Portal.Core.API.Models.DeploymentTemplateSelectionModel", "DeploymentTemplateSelection") + .WithMany() + .HasForeignKey("DeploymentTemplateSelectionId") + .OnDelete(DeleteBehavior.NoAction); + + b.Navigation("DeploymentGroup"); + + b.Navigation("DeploymentTemplateSelection"); + }); + + modelBuilder.Entity("Microsoft.SelfService.Portal.Core.API.Models.DeploymentRuleStepModel", b => + { + b.HasOne("Microsoft.SelfService.Portal.Core.API.Models.DeploymentRuleModel", "DeploymentRule") + .WithMany("Steps") + .HasForeignKey("DeploymentRuleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("DeploymentRule"); + }); + + modelBuilder.Entity("Microsoft.SelfService.Portal.Core.API.Models.DeploymentTargetAssignmentModel", b => + { + b.HasOne("Microsoft.SelfService.Portal.Core.API.Models.DeploymentGroupModel", "DeploymentGroup") + .WithMany("TargetAssignments") + .HasForeignKey("DeploymentGroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Microsoft.SelfService.Portal.Core.API.Models.TargetModel", "Target") + .WithMany() + .HasForeignKey("TargetId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("DeploymentGroup"); + + b.Navigation("Target"); + }); + + modelBuilder.Entity("Microsoft.SelfService.Portal.Core.API.Models.DeploymentTemplateSelectionModel", b => + { + b.HasOne("Microsoft.SelfService.Portal.Core.API.Models.DeploymentGroupModel", "DeploymentGroup") + .WithMany("TemplateSelections") + .HasForeignKey("DeploymentGroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Microsoft.SelfService.Portal.Core.API.Models.TemplateRevisionModel", "TemplateRevision") + .WithMany("DeploymentTemplateSelections") + .HasForeignKey("TemplateRevisionId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("Microsoft.SelfService.Portal.Core.API.Models.TemplateVersionModel", "TemplateVersion") + .WithMany() + .HasForeignKey("TemplateVersionId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("DeploymentGroup"); + + b.Navigation("TemplateRevision"); + + b.Navigation("TemplateVersion"); + }); + + modelBuilder.Entity("Microsoft.SelfService.Portal.Core.API.Models.EnvironmentDomainsModel", b => + { + b.HasOne("Microsoft.SelfService.Portal.Core.API.Models.DomainModel", "Domain") + .WithMany("EnvironmentDomains") + .HasForeignKey("DomainId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Microsoft.SelfService.Portal.Core.API.Models.EnvironmentModel", "Environment") + .WithMany("EnvironmentDomains") + .HasForeignKey("EnvironmentId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Domain"); + + b.Navigation("Environment"); + }); + + modelBuilder.Entity("Microsoft.SelfService.Portal.Core.API.Models.OptionModel", b => + { + b.HasOne("Microsoft.SelfService.Portal.Core.API.Models.OptionCategoryModel", "OptionCategory") + .WithMany("Options") + .HasForeignKey("OptionCategoryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("OptionCategory"); + }); + + modelBuilder.Entity("Microsoft.SelfService.Portal.Core.API.Models.QueueJobStepModel", b => + { + b.HasOne("Microsoft.SelfService.Portal.Core.API.Models.QueueJobStepModel", "DependsOnQueueJobStep") + .WithMany() + .HasForeignKey("DependsOnQueueJobStepId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("Microsoft.SelfService.Portal.Core.API.Models.QueueJobModel", "QueueJob") + .WithMany("Steps") + .HasForeignKey("QueueJobId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("DependsOnQueueJobStep"); + + b.Navigation("QueueJob"); + }); + + modelBuilder.Entity("Microsoft.SelfService.Portal.Core.API.Models.QueueJobTargetModel", b => + { + b.HasOne("Microsoft.SelfService.Portal.Core.API.Models.QueueJobModel", "QueueJob") + .WithMany("Targets") + .HasForeignKey("QueueJobId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("QueueJob"); + }); + + modelBuilder.Entity("Microsoft.SelfService.Portal.Core.API.Models.ServiceRoleDefinitionModel", b => + { + b.HasOne("Microsoft.SelfService.Portal.Core.API.Models.ServiceModel", "Service") + .WithMany("RoleDefinitions") + .HasForeignKey("ServiceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Service"); + }); + + modelBuilder.Entity("Microsoft.SelfService.Portal.Core.API.Models.TargetModel", b => + { + b.HasOne("Microsoft.SelfService.Portal.Core.API.Models.DomainModel", "Domain") + .WithMany("Targets") + .HasForeignKey("DomainID"); + + b.Navigation("Domain"); + }); + + modelBuilder.Entity("Microsoft.SelfService.Portal.Core.API.Models.TemplateCategoryModel", b => + { + b.HasOne("Microsoft.SelfService.Portal.Core.API.Models.ServiceModel", "Service") + .WithMany("TemplateCategories") + .HasForeignKey("ServiceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Service"); + }); + + modelBuilder.Entity("Microsoft.SelfService.Portal.Core.API.Models.TemplateModel", b => + { + b.HasOne("Microsoft.SelfService.Portal.Core.API.Models.DeploymentRuleModel", "DeploymentRule") + .WithMany() + .HasForeignKey("DeploymentRuleId"); + + b.HasOne("Microsoft.SelfService.Portal.Core.API.Models.TemplateCategoryModel", "TemplateCategory") + .WithMany("Templates") + .HasForeignKey("TemplateCategoryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("DeploymentRule"); + + b.Navigation("TemplateCategory"); + }); + + modelBuilder.Entity("Microsoft.SelfService.Portal.Core.API.Models.TemplateOptionModel", b => + { + b.HasOne("Microsoft.SelfService.Portal.Core.API.Models.OptionModel", "Option") + .WithMany("TemplateOptions") + .HasForeignKey("OptionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Microsoft.SelfService.Portal.Core.API.Models.TemplateModel", "Template") + .WithMany("TemplateOptions") + .HasForeignKey("TemplateId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Option"); + + b.Navigation("Template"); + }); + + modelBuilder.Entity("Microsoft.SelfService.Portal.Core.API.Models.TemplateRevisionModel", b => + { + b.HasOne("Microsoft.SelfService.Portal.Core.API.Models.TemplateVersionModel", "TemplateVersion") + .WithMany("TemplateRevisions") + .HasForeignKey("TemplateVersionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("TemplateVersion"); + }); + + modelBuilder.Entity("Microsoft.SelfService.Portal.Core.API.Models.TemplateVersionModel", b => + { + b.HasOne("Microsoft.SelfService.Portal.Core.API.Models.TemplateModel", "Template") + .WithMany("TemplateVersions") + .HasForeignKey("TemplateId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Template"); + }); + + modelBuilder.Entity("Microsoft.SelfService.Portal.Core.API.Models.ConfigurationDefinitionModel", b => + { + b.Navigation("Values"); + }); + + modelBuilder.Entity("Microsoft.SelfService.Portal.Core.API.Models.DeploymentGroupModel", b => + { + b.Navigation("Artifacts"); + + b.Navigation("Deployments"); + + b.Navigation("ParameterValues"); + + b.Navigation("TargetAssignments"); + + b.Navigation("TemplateSelections"); + }); + + modelBuilder.Entity("Microsoft.SelfService.Portal.Core.API.Models.DeploymentModel", b => + { + b.Navigation("Artifacts"); + }); + + modelBuilder.Entity("Microsoft.SelfService.Portal.Core.API.Models.DeploymentRuleModel", b => + { + b.Navigation("Steps"); + }); + + modelBuilder.Entity("Microsoft.SelfService.Portal.Core.API.Models.DomainModel", b => + { + b.Navigation("EnvironmentDomains"); + + b.Navigation("Targets"); + }); + + modelBuilder.Entity("Microsoft.SelfService.Portal.Core.API.Models.EnvironmentModel", b => + { + b.Navigation("EnvironmentDomains"); + }); + + modelBuilder.Entity("Microsoft.SelfService.Portal.Core.API.Models.OptionCategoryModel", b => + { + b.Navigation("Options"); + }); + + modelBuilder.Entity("Microsoft.SelfService.Portal.Core.API.Models.OptionModel", b => + { + b.Navigation("TemplateOptions"); + }); + + modelBuilder.Entity("Microsoft.SelfService.Portal.Core.API.Models.QueueJobModel", b => + { + b.Navigation("Steps"); + + b.Navigation("Targets"); + }); + + modelBuilder.Entity("Microsoft.SelfService.Portal.Core.API.Models.ServiceModel", b => + { + b.Navigation("RoleDefinitions"); + + b.Navigation("TemplateCategories"); + }); + + modelBuilder.Entity("Microsoft.SelfService.Portal.Core.API.Models.TargetModel", b => + { + b.Navigation("Deployments"); + }); + + modelBuilder.Entity("Microsoft.SelfService.Portal.Core.API.Models.TemplateCategoryModel", b => + { + b.Navigation("Templates"); + }); + + modelBuilder.Entity("Microsoft.SelfService.Portal.Core.API.Models.TemplateModel", b => + { + b.Navigation("DeploymentGroups"); + + b.Navigation("TemplateOptions"); + + b.Navigation("TemplateVersions"); + }); + + modelBuilder.Entity("Microsoft.SelfService.Portal.Core.API.Models.TemplateRevisionModel", b => + { + b.Navigation("ConfigurationDefinitions"); + + b.Navigation("DeploymentTemplateSelections"); + + b.Navigation("Deployments"); + }); + + modelBuilder.Entity("Microsoft.SelfService.Portal.Core.API.Models.TemplateVersionModel", b => + { + b.Navigation("TemplateRevisions"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Migrations/20260709171904_AddCentralizedAuthorizationScopes.cs b/Migrations/20260709171904_AddCentralizedAuthorizationScopes.cs new file mode 100644 index 0000000..d9585cf --- /dev/null +++ b/Migrations/20260709171904_AddCentralizedAuthorizationScopes.cs @@ -0,0 +1,33 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Microsoft.SelfService.Portal.Core.API.Migrations +{ + /// + public partial class AddCentralizedAuthorizationScopes : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.UpdateData( + table: "ApiClients", + keyColumn: "Id", + keyValue: new Guid("91000000-0000-0000-0000-000000000001"), + column: "ScopesJson", + value: "[\"configuration.read\",\"configuration.write\",\"credential.read\",\"credential.write\",\"credential.resolve\",\"deployment.read\",\"deployment.write\",\"queue.read\",\"queue.process\",\"template.read\",\"template.write\",\"token.manage\",\"token.admin\"]"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.UpdateData( + table: "ApiClients", + keyColumn: "Id", + keyValue: new Guid("91000000-0000-0000-0000-000000000001"), + column: "ScopesJson", + value: "[\"deployment.read\",\"deployment.write\",\"queue.process\",\"template.read\",\"credential.resolve\",\"token.manage\",\"token.admin\"]"); + } + } +} diff --git a/Migrations/DataContextModelSnapshot.cs b/Migrations/DataContextModelSnapshot.cs index 9749d19..227882e 100644 --- a/Migrations/DataContextModelSnapshot.cs +++ b/Migrations/DataContextModelSnapshot.cs @@ -106,7 +106,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Migrations Modified = new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), ModifiedBy = "DemoSeed", Name = "Demo Worker Client", - ScopesJson = "[\"deployment.read\",\"deployment.write\",\"queue.process\",\"template.read\",\"credential.resolve\",\"token.manage\",\"token.admin\"]", + ScopesJson = "[\"configuration.read\",\"configuration.write\",\"credential.read\",\"credential.write\",\"credential.resolve\",\"deployment.read\",\"deployment.write\",\"queue.read\",\"queue.process\",\"template.read\",\"template.write\",\"token.manage\",\"token.admin\"]", SecretHash = "PBKDF2-SHA256.100000.c3NwLWRlbW8td29ya2VyAA==.xQxe7BHCn9pdkqHozdyspEmKnz95uCUuxVvU2vgCEbo=" }); }); diff --git a/Program.cs b/Program.cs index 254900c..5866419 100644 --- a/Program.cs +++ b/Program.cs @@ -2,6 +2,7 @@ using Microsoft.AspNetCore.Authentication.Negotiate; using Microsoft.EntityFrameworkCore; using Microsoft.IdentityModel.Tokens; +using Microsoft.SelfService.Portal.Core.API.Authorization; using Microsoft.SelfService.Portal.Core.API.Context; using Microsoft.SelfService.Portal.Core.API.Interfaces; using Microsoft.SelfService.Portal.Core.API.Repository; @@ -109,20 +110,7 @@ builder.Services.AddAuthentication(options => builder.Services.AddHttpContextAccessor(); -builder.Services.AddAuthorization(options => -{ - // By default, all incoming requests will be authorized according to the default policy. - options.FallbackPolicy = options.DefaultPolicy; - options.AddPolicy("QueueProcess", policy => policy.RequireClaim("scope", "queue.process")); - options.AddPolicy("DeploymentRead", policy => policy.RequireClaim("scope", "deployment.read")); - options.AddPolicy("CredentialResolve", policy => policy.RequireClaim("scope", "credential.resolve")); - options.AddPolicy("TokenManage", policy => policy.RequireAssertion(context => - context.User.HasClaim("scope", "token.manage") - || context.User.Identity?.AuthenticationType == NegotiateDefaults.AuthenticationScheme)); - options.AddPolicy("TokenAdmin", policy => policy.RequireAssertion(context => - context.User.HasClaim("scope", "token.admin") - || context.User.Identity?.AuthenticationType == NegotiateDefaults.AuthenticationScheme)); -}); +builder.Services.AddSelfServicePortalAuthorization(); var app = builder.Build(); var frontendDistPath = Path.GetFullPath(Path.Combine( diff --git a/Services/ApiTokenService.cs b/Services/ApiTokenService.cs index 4a2649a..f0ac70e 100644 --- a/Services/ApiTokenService.cs +++ b/Services/ApiTokenService.cs @@ -3,6 +3,7 @@ using System.Security.Claims; using System.Text; using System.Text.Json; using Microsoft.IdentityModel.Tokens; +using Microsoft.SelfService.Portal.Core.API.Authorization; using Microsoft.SelfService.Portal.Core.API.Models; namespace Microsoft.SelfService.Portal.Core.API.Services @@ -138,13 +139,19 @@ namespace Microsoft.SelfService.Portal.Core.API.Services return [ - "deployment.read", - "deployment.write", - "queue.process", - "template.read", - "credential.resolve", - "token.manage", - "token.admin" + ApiScopes.ConfigurationRead, + ApiScopes.ConfigurationWrite, + ApiScopes.CredentialRead, + ApiScopes.CredentialWrite, + ApiScopes.CredentialResolve, + ApiScopes.DeploymentRead, + ApiScopes.DeploymentWrite, + ApiScopes.QueueRead, + ApiScopes.QueueProcess, + ApiScopes.TemplateRead, + ApiScopes.TemplateWrite, + ApiScopes.TokenManage, + ApiScopes.TokenAdmin ]; } diff --git a/appsettings.json b/appsettings.json index aca2c95..68eabc4 100644 --- a/appsettings.json +++ b/appsettings.json @@ -15,8 +15,14 @@ "AllowedTokenScopes": [ "deployment.read", "deployment.write", + "configuration.read", + "configuration.write", + "credential.read", + "credential.write", "queue.process", + "queue.read", "template.read", + "template.write", "credential.resolve", "token.manage", "token.admin"