Private/Test-KadenBetaInvitation.ps1

function Test-KadenBetaInvitation {
    <#
    .SYNOPSIS
        Accept a PascalCase beta invitation passphrase that ends with Beta.
    .DESCRIPTION
        The passphrase must be five curated words in PascalCase with no spaces,
        then the literal Beta suffix. This is a cohort signal only. It does not
        enforce use, confidentiality, licensing, or authorization.
        An invalid invitation returns Valid false and a Message that starts with
        KDN-BETA-INVITATION-INVALID.
    .PARAMETER Invitation
        The passphrase to check. Empty and incorrectly formed values are invalid.
    #>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true)]
        [AllowEmptyString()]
        [string]$Invitation
    )

    $suffix = 'Beta'
    $invalidForm = "KDN-BETA-INVITATION-INVALID: Beta invitation must be five curated PascalCase words with no spaces, ending in $suffix."
    $invalidSuffix = "KDN-BETA-INVITATION-INVALID: Beta invitation must end with the literal word $suffix."

    function Get-InvalidBetaInvitationResult {
        param([Parameter(Mandatory = $true)][string]$ResultMessage)
        return [pscustomobject]@{
            Valid   = $false
            Message = $ResultMessage
        }
    }

    if ([string]::IsNullOrWhiteSpace($Invitation) -or ($Invitation -match '\s')) {
        return (Get-InvalidBetaInvitationResult -ResultMessage $invalidForm)
    }
    if (-not $Invitation.EndsWith($suffix, [System.StringComparison]::Ordinal)) {
        return (Get-InvalidBetaInvitationResult -ResultMessage $invalidSuffix)
    }

    $core = $Invitation.Substring(0, $Invitation.Length - $suffix.Length)
    if ([string]::IsNullOrEmpty($core)) {
        return (Get-InvalidBetaInvitationResult -ResultMessage $invalidForm)
    }

    $allowed = @{}
    foreach ($word in @(Get-KadenInvitationWordList)) {
        $token = ConvertTo-KadenInvitationToken -Word $word
        $allowed[$token] = $true
    }

    $tokenMatches = [regex]::Matches($core, '[A-Z][a-z]*')
    if ($tokenMatches.Count -ne 5) {
        return (Get-InvalidBetaInvitationResult -ResultMessage $invalidForm)
    }

    $rebuilt = ''
    foreach ($match in $tokenMatches) {
        $token = $match.Value
        $rebuilt += $token
        if (-not $allowed.ContainsKey($token)) {
            return (Get-InvalidBetaInvitationResult -ResultMessage $invalidForm)
        }
    }
    # Every PascalCase token must be a curated word, and those tokens must be
    # the entire core. A leftover character means the invitation is not five words.
    if ($rebuilt -cne $core) {
        return (Get-InvalidBetaInvitationResult -ResultMessage $invalidForm)
    }

    return [pscustomobject]@{
        Valid   = $true
        Message = 'Beta acknowledgement accepted. Start with docs/kaden/developer-playbook.md.'
    }
}