Private/GitHub/Test-CgrGitHubPagesMigration.ps1
|
function Test-CgrGitHubPagesMigration { <# .SYNOPSIS Independently verifies restored GitHub Pages configuration. .DESCRIPTION Reads destination GitHub-side Pages state and compares it with immutable reviewed migration-plan evidence. External DNS, domain-verification, and certificate readiness are reported separately and never used as migration-selection authority. #> [CmdletBinding()] param( [Parameter(Mandatory)] [psobject] $Plan, [Parameter(Mandatory)] [psobject] $DestinationRepository, [ValidateNotNullOrEmpty()] [string] $HostName = 'github.com' ) $pages = Get-CgrObjectProperty -InputObject $Plan -Name 'Pages' if ($null -eq $pages) { $exception = [System.InvalidOperationException]::new('Pages verification requires immutable reviewed Pages evidence in the approved migration plan.') throw [System.Management.Automation.ErrorRecord]::new($exception, 'ApprovedPagesEvidenceMissing', [System.Management.Automation.ErrorCategory]::InvalidData, $Plan) } $expectedConfigured = [bool] (Get-CgrObjectProperty -InputObject $pages -Name 'Configured') $actual = Get-CgrGitHubApiOptional -Path "repos/$($DestinationRepository.FullName)/pages" -HostName $HostName $actualConfigured = $null -ne $actual $checks = [System.Collections.Generic.List[object]]::new() $checks.Add([pscustomobject] @{ Name = 'PagesConfiguredMatches' Passed = $actualConfigured -eq $expectedConfigured Expected = $expectedConfigured Actual = $actualConfigured }) $externalReadiness = if ($actualConfigured) { $protectedDomainState = Get-CgrObjectProperty -InputObject $actual -Name 'protected_domain_state' $pendingDomainUnverifiedAt = Get-CgrObjectProperty -InputObject $actual -Name 'pending_domain_unverified_at' $httpsCertificate = Get-CgrObjectProperty -InputObject $actual -Name 'https_certificate' [pscustomobject] @{ DomainVerification = if ($null -ne $protectedDomainState) { [string] $protectedDomainState } elseif ($null -ne $pendingDomainUnverifiedAt) { 'Pending' } else { 'NotReportedByGitHub' } PendingDomainUnverifiedAt = $pendingDomainUnverifiedAt Certificate = if ($null -ne $httpsCertificate) { $httpsCertificate } else { 'NotReportedByGitHub' } Dns = 'ExternalNotQueried' AffectsConfigurationVerification = $false } } else { [pscustomobject] @{ DomainVerification = 'NotApplicable' PendingDomainUnverifiedAt = $null Certificate = 'NotApplicable' Dns = 'ExternalNotQueried' AffectsConfigurationVerification = $false } } $httpsEnforcementStatus = 'NotReviewed' if ($expectedConfigured -and $actualConfigured) { $expectedBuildType = [string] (Get-CgrObjectProperty -InputObject $pages -Name 'BuildType') $actualBuildType = [string] (Get-CgrObjectProperty -InputObject $actual -Name 'build_type') $checks.Add([pscustomobject] @{ Name = 'PagesBuildTypeMatches' Passed = $actualBuildType -ceq $expectedBuildType Expected = $expectedBuildType Actual = $actualBuildType }) if ($expectedBuildType -eq 'legacy') { $expectedSource = Get-CgrObjectProperty -InputObject $pages -Name 'Source' $actualSource = Get-CgrObjectProperty -InputObject $actual -Name 'source' $expectedBranch = [string] (Get-CgrObjectProperty -InputObject $expectedSource -Name 'Branch') $expectedPath = [string] (Get-CgrObjectProperty -InputObject $expectedSource -Name 'Path') $actualBranch = [string] (Get-CgrObjectProperty -InputObject $actualSource -Name 'branch') $actualPath = [string] (Get-CgrObjectProperty -InputObject $actualSource -Name 'path') $checks.Add([pscustomobject] @{ Name = 'PagesSourceBranchMatches' Passed = $actualBranch -ceq $expectedBranch Expected = $expectedBranch Actual = $actualBranch }) $checks.Add([pscustomobject] @{ Name = 'PagesSourcePathMatches' Passed = $actualPath -ceq $expectedPath Expected = $expectedPath Actual = $actualPath }) } $expectedDomain = Get-CgrObjectProperty -InputObject $pages -Name 'CustomDomain' $actualDomain = Get-CgrObjectProperty -InputObject $actual -Name 'cname' $normalizedExpectedDomain = if ([string]::IsNullOrWhiteSpace([string] $expectedDomain)) { $null } else { [string] $expectedDomain } $normalizedActualDomain = if ([string]::IsNullOrWhiteSpace([string] $actualDomain)) { $null } else { [string] $actualDomain } $checks.Add([pscustomobject] @{ Name = 'PagesCustomDomainMatches' Passed = [string] $normalizedActualDomain -ceq [string] $normalizedExpectedDomain Expected = $normalizedExpectedDomain Actual = $normalizedActualDomain }) $expectedHttps = Get-CgrObjectProperty -InputObject $pages -Name 'HttpsEnforced' if ($null -ne $expectedHttps) { $actualHttps = Get-CgrObjectProperty -InputObject $actual -Name 'https_enforced' $httpsCertificate = Get-CgrObjectProperty -InputObject $actual -Name 'https_certificate' $httpsNotYetEnforced = $null -eq $actualHttps -or -not [bool] $actualHttps $httpsPendingCertificate = [bool] $expectedHttps -and $httpsNotYetEnforced -and $null -eq $httpsCertificate $httpsMatches = $null -ne $actualHttps -and [bool] $actualHttps -eq [bool] $expectedHttps $httpsEnforcementStatus = if ($httpsMatches) { 'Verified' } elseif ($httpsPendingCertificate) { 'PendingCertificate' } else { 'Mismatch' } $checks.Add([pscustomobject] @{ Name = 'PagesHttpsEnforcementMatches' Passed = $httpsMatches -or $httpsPendingCertificate Expected = [bool] $expectedHttps Actual = if ($null -eq $actualHttps) { $null } else { [bool] $actualHttps } Status = $httpsEnforcementStatus }) } $mode = [string] (Get-CgrObjectProperty -InputObject $Plan -Name 'Mode') $replacementMode = $mode -in @('SameNameReplacement', 'ExistingDestinationReplacement') if ($replacementMode -and -not [string]::IsNullOrWhiteSpace([string] $normalizedExpectedDomain)) { $archiveName = [string] (Get-CgrObjectProperty -InputObject $Plan -Name 'ArchiveRepository') if ([string]::IsNullOrWhiteSpace($archiveName)) { $checks.Add([pscustomobject] @{ Name = 'PagesArchiveCustomDomainReleased' Passed = $false Expected = 'Reviewed archive repository identity' Actual = $null }) } else { $archivePages = Get-CgrGitHubApiOptional -Path "repos/$archiveName/pages" -HostName $HostName $archiveDomain = if ($archivePages) { Get-CgrObjectProperty -InputObject $archivePages -Name 'cname' } else { $null } $archiveStillOwnsDomain = [string] $archiveDomain -ceq [string] $normalizedExpectedDomain $checks.Add([pscustomobject] @{ Name = 'PagesArchiveCustomDomainReleased' Passed = -not $archiveStillOwnsDomain Expected = $null Actual = if ([string]::IsNullOrWhiteSpace([string] $archiveDomain)) { $null } else { [string] $archiveDomain } }) $checks.Add([pscustomobject] @{ Name = 'PagesReplacementCustomDomainOwned' Passed = [string] $normalizedActualDomain -ceq [string] $normalizedExpectedDomain Expected = $normalizedExpectedDomain Actual = $normalizedActualDomain }) } } } $failedChecks = @($checks | Where-Object { -not $_.Passed }) [pscustomobject] @{ PSTypeName = 'CopyGitHubRepo.GitHubPagesVerificationResult' SchemaVersion = 1 Repository = $DestinationRepository.FullName ExpectedConfigured = $expectedConfigured ActualConfigured = $actualConfigured Status = if ($failedChecks.Count -eq 0) { if ($expectedConfigured) { 'Verified' } else { 'VerifiedNotConfigured' } } else { 'Mismatch' } Checks = @($checks) HttpsEnforcementStatus = $httpsEnforcementStatus ExternalReadiness = $externalReadiness DnsMigrated = $false IsSuccessful = $failedChecks.Count -eq 0 } } |