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) {
                $failed = 'KDN-RELEASE-PAYLOAD-MISSING: Required payload content is missing.'
            }
        }

        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
}