$ErrorActionPreference = 'Stop' $root = Split-Path -Parent $PSScriptRoot $api = Get-Content -Raw -Encoding UTF8 -LiteralPath (Join-Path $root 'utils/api.js') $page = Get-Content -Raw -Encoding UTF8 -LiteralPath (Join-Path $root 'pages/profile/m04-change-password.vue') $issues = New-Object System.Collections.Generic.List[string] function Require-Text { param([string]$Source, [string]$Text, [string]$Description) if (-not $Source.Contains($Text)) { $script:issues.Add($Description) } } Require-Text $api 'async changePassword({ oldPasswordHash, newPasswordHash }, requestOptions = {}) {' 'api owner must expose password change' Require-Text $api "url: '/genealogy/app/auth/password'" 'password change must use the declared APP password owner' Require-Text $api "method: 'PUT'" 'password change must use PUT' Require-Text $api 'oldPassword: assertPasswordHash(oldPasswordHash)' 'old password must be the declared 32-character digest' Require-Text $api 'newPassword: assertPasswordHash(newPasswordHash)' 'new password must be the declared 32-character digest' Require-Text $api 'requireData: false' 'password change must accept the declared VoidResult envelope' Require-Text $api 'requestController: requestOptions.requestController ?? null' 'password change must accept page cancellation ownership' Require-Text $page 'appApi.changePassword({' 'M04 must call the shared password owner' Require-Text $page 'oldPasswordHash: calcMD5(passwordForm.current)' 'M04 must hash the current password before transport' Require-Text $page 'newPasswordHash: calcMD5(passwordForm.next)' 'M04 must hash the new password before transport' Require-Text $page 'passwordRequestController.abort()' 'M04 must cancel an in-flight request when unloading' Require-Text $page 'isRequestCancelled(error)' 'M04 must not report a cancelled request as a password-change failure' if ($api -match "url: '/genealogy/app/auth/password'[\s\S]{0,260}passwordForm\.") { $issues.Add('password API owner must not depend on page form state') } if ($page -notmatch 'oldPasswordHash:\s*calcMD5\(passwordForm\.current\)[\s\S]{0,160}newPasswordHash:\s*calcMD5\(passwordForm\.next\)') { $issues.Add('M04 must pass only the MD5 digests to the API owner') } if ($issues.Count -gt 0) { throw ("PASSWORD-CHANGE-OPENAPI-CONTRACT FAIL`n- " + ($issues -join "`n- ")) } Write-Output 'PASSWORD-CHANGE-OPENAPI-CONTRACT PASS'