Public/Test-KadenReleaseProvenance.ps1
|
function Test-KadenReleaseProvenance { <# .SYNOPSIS Verify a release candidate against tag, commit, package, and owner facts. .DESCRIPTION Maps a protected, signed semver tag `vX.Y.Z` whose target is on main to package version `X.Y.Z`. `Protected`, `Signed`, and `TargetsMain` are facts supplied by the caller. Gallery owner is the caller-supplied -GalleryOwner string compared with -ExpectedGalleryOwner. The command does not read the manifest Author and does not query the Gallery account that owns the package. An eligible result records the tag, target commit, package version, and that owner string. `-RecordPath` writes that record only when the check is eligible. A failed check names a KDN-RELEASE code and the requirement and does not write the file. Credential text found in the package is not copied into the result. This command does not publish and does not take a Gallery API key. .EXAMPLE Test-KadenReleaseProvenance -Tag v1.2.3 -TargetCommit 0123456789abcdef0123456789abcdef01234567 -GalleryOwner kaden-maintainers -ExpectedGalleryOwner kaden-maintainers -PackagePath .\tools\Kaden -Protected $true -Signed $true -TargetsMain $true -RecordPath .\release-record.json #> [CmdletBinding()] param( [Parameter(Mandatory = $true)] [string]$Tag, [Parameter(Mandatory = $true)] [string]$TargetCommit, [Parameter(Mandatory = $true)] [string]$GalleryOwner, [Parameter(Mandatory = $true)] [string]$ExpectedGalleryOwner, [Parameter(Mandatory = $true)] [string]$PackagePath, [Parameter(Mandatory = $true)] [bool]$Protected, [Parameter(Mandatory = $true)] [bool]$Signed, [Parameter(Mandatory = $true)] [bool]$TargetsMain, [string]$RecordPath ) $failed = $null $packageVersion = $null if ($Tag -match '^v(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$') { $packageVersion = $Tag.Substring(1) } else { $failed = 'KDN-RELEASE-TAG-SEMVER: Tag is not a semver release tag.' } if (-not $failed -and -not $Protected) { $failed = 'KDN-RELEASE-TAG-PROTECTED: Tag is not protected.' } if (-not $failed -and -not $Signed) { $failed = 'KDN-RELEASE-TAG-SIGNED: Tag is not signed.' } if (-not $failed -and -not $TargetsMain) { $failed = 'KDN-RELEASE-TAG-MAIN: Tag target is not on main.' } if (-not $failed) { $packageRoot = [System.IO.Path]::GetFullPath($PackagePath) $required = @( 'Kaden.psd1' 'Kaden.psm1' 'Public' 'Private' ) foreach ($relative in $required) { $full = Join-Path $packageRoot ($relative -replace '/', [System.IO.Path]::DirectorySeparatorChar) if (-not (Test-Path -LiteralPath $full)) { $failed = 'KDN-RELEASE-PAYLOAD-MISSING: Required payload content is missing.' break } } if (-not $failed) { $payload = Test-KadenPackagePayload -PayloadRoot (Join-Path $packageRoot 'Payload') if (-not $payload.Valid) { $detail = [string]$payload.Message if ([string]::IsNullOrWhiteSpace($detail)) { $failed = 'KDN-RELEASE-PAYLOAD-MISSING: Required payload content is missing.' } else { $failed = "KDN-RELEASE-PAYLOAD-MISSING: $detail" } } } if (-not $failed) { $moduleVersion = $null try { $manifestData = Import-PowerShellDataFile -Path (Join-Path $packageRoot 'Kaden.psd1') $moduleVersion = [string]$manifestData.ModuleVersion } catch { $moduleVersion = $null } if ([string]::IsNullOrWhiteSpace($moduleVersion) -or $moduleVersion -ne $packageVersion) { $failed = 'KDN-RELEASE-VERSION-MISMATCH: Module version does not match the release tag.' } } if (-not $failed) { $observedOwner = $GalleryOwner.Trim() $allowedOwner = $ExpectedGalleryOwner.Trim() if ([string]::IsNullOrWhiteSpace($observedOwner)) { $failed = 'KDN-RELEASE-OWNER-MISSING: Gallery owner is not recorded.' } elseif ($observedOwner -ne $allowedOwner) { $failed = 'KDN-RELEASE-OWNER-MISMATCH: Gallery owner does not match the package owner.' } } if (-not $failed -and (Test-KadenPackageContainsCredential -PackageRoot $packageRoot)) { $failed = 'KDN-RELEASE-CREDENTIAL: Package contains a private-source credential.' } } $eligible = -not $failed $result = [pscustomobject]@{ Eligible = [bool]$eligible Tag = $Tag TargetCommit = $TargetCommit PackageVersion = $(if ($eligible) { $packageVersion } else { $null }) GalleryOwner = $(if ($eligible) { $GalleryOwner.Trim() } else { $null }) FailedRequirement = $failed } if ($eligible -and -not [string]::IsNullOrWhiteSpace($RecordPath)) { Write-KadenJsonAtomic -LiteralPath $RecordPath -Object $result } return $result } |