# Staging auth rehearsal helper (Windows / Laragon). # Docs: docs/staging-auth-rehearsal.md # # Does NOT read repo `.env` or any live secrets file. # Requires DATABASE_URL in the environment (or -DatabaseUrl). # # Examples: # $env:DATABASE_URL = "postgres://descrybe:descrybe@localhost:5433/descrybe?sslmode=disable" # .\scripts\staging-auth-rehearsal.ps1 # print SQL + next steps # .\scripts\staging-auth-rehearsal.ps1 -IssueInvites # also re-issue invites (no SMTP) # .\scripts\staging-auth-rehearsal.ps1 -IssueInvites -DryRun param( [string]$DatabaseUrl = $env:DATABASE_URL, [string]$WebOrigin = $env:WEB_ORIGIN, [string]$MapsDir = "", [switch]$IssueInvites, [switch]$DryRun ) $ErrorActionPreference = "Stop" $Root = Resolve-Path (Join-Path $PSScriptRoot "..") $ApiDir = Join-Path $Root "apps\api" if (-not $MapsDir) { $MapsDir = Join-Path $Root "artifacts" } Write-Host "==> Staging auth rehearsal (no SMTP / link-copy path)" Write-Host " Docs: docs/staging-auth-rehearsal.md" Write-Host "" if (-not $DatabaseUrl) { Write-Host "DATABASE_URL is not set. Export it in this shell only (do not paste production secrets into the repo)." Write-Host 'Example: $env:DATABASE_URL = "postgres://descrybe:descrybe@localhost:5433/descrybe?sslmode=disable"' Write-Host "" } Write-Host "=== 1. Promote company admin (preferred: migrator CLI; dry-run first) ===" Write-Host @" cd apps/api go run ./cmd/migrator -list-member-memberships -postgres "`$DATABASE_URL" go run ./cmd/migrator -promote-company-admins -email '' -dry-run -postgres "`$DATABASE_URL" go run ./cmd/migrator -promote-company-admins -email '' -confirm -postgres "`$DATABASE_URL" # SQL alternate (fill UUIDs): -- List SELECT u.id AS user_id, u.email, u.must_set_password, u.is_platform_admin, m.company_id, c.name AS company_name, m.role, m.status FROM memberships m JOIN users u ON u.id = m.user_id JOIN companies c ON c.id = m.company_id WHERE m.status = 'active' ORDER BY c.name, u.email; -- Promote (fill UUIDs) UPDATE memberships SET role = 'admin' WHERE user_id = '' AND company_id = '' AND status = 'active' RETURNING user_id, company_id, role; "@ Write-Host "" if (-not $IssueInvites) { Write-Host "=== 2. Re-issue set-password (skipped) ===" Write-Host "Re-run with -IssueInvites after emails are real (not *@legacy.local)." Write-Host " .\scripts\staging-auth-rehearsal.ps1 -IssueInvites" Write-Host "" Write-Host "=== 3. Login smoke (manual) ===" Write-Host "Copy one URL from migrator stdout or artifacts/password_invites.json" Write-Host "-> open /accept-invite -> set password -> /login -> confirm must_set_password=false" exit 0 } if (-not $DatabaseUrl) { Write-Error "DATABASE_URL is required for -IssueInvites" } if ($WebOrigin) { $env:WEB_ORIGIN = $WebOrigin Write-Host "WEB_ORIGIN=$WebOrigin" } else { Write-Host "WEB_ORIGIN unset -> migrator default http://localhost:28472" } New-Item -ItemType Directory -Force -Path $MapsDir | Out-Null Set-Location $ApiDir $mapsRel = Resolve-Path $MapsDir Write-Host "=== 2. Re-issue set-password invites (maps-dir=$mapsRel) ===" $migratorArgs = @( "./cmd/migrator", "-issue-set-password-invites", "-postgres", $DatabaseUrl, "-maps-dir", $mapsRel ) if ($DryRun) { $migratorArgs += "-dry-run" Write-Host "(dry-run: no invites written)" } & go run @migratorArgs if ($LASTEXITCODE -ne 0) { Write-Error "migrator -issue-set-password-invites failed (exit $LASTEXITCODE)" } Write-Host "" Write-Host "=== 3. Login smoke (manual - no SMTP) ===" Write-Host "1. Copy one emailurl line from stdout above (or $mapsRel\password_invites.json)." Write-Host "2. Open the URL -> set password (at least 8 chars)." Write-Host "3. Sign in at /login with the same email." Write-Host '4. SQL: SELECT email, must_set_password FROM users WHERE lower(email)=lower('''');' Write-Host "Do NOT run cmd/mailhooks for this rehearsal."