audit: 33-agent comprehensive audit + critical fixes
Full team audit run, all reports verbatim in docs/AUDIT-2026-05-12.md (5900+ lines, 30+ critical findings). Already-fixed this commit: - permission-overrides PUT: self-target block + RolePermissions allow-list + cross-tenant guard - /api/auth/resolve-identifier: rate-limit + synthetic miss-email kill enumeration - admin email-change: rotates account.accountId + revokes sessions - middleware: token-gated email confirm/cancel routes whitelisted - NAV_CATALOG: 10 dead-link sweeps to existing /admin/<x> targets Feature work landing same commit: optional username sign-in (migration 0054), per-user permission overrides (0055) with three-state matrix tabbed inside UserForm, user disable button, role + outcome + stage label normalisation across the platform, admin email-change with auto-notification template. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -268,6 +268,33 @@ export function formatRole(role: string | null | undefined): string {
|
||||
.join(' ');
|
||||
}
|
||||
|
||||
// ─── Interest outcomes ───────────────────────────────────────────────────────
|
||||
// Mirrors INTEREST_OUTCOMES in src/lib/validators/interests.ts. Lives here
|
||||
// so render sites can format outcome strings without pulling in the
|
||||
// validator (which would drag zod into RSC bundles). Validator → enforces
|
||||
// the set; here → labels for humans.
|
||||
|
||||
export const OUTCOME_LABELS: Record<string, string> = {
|
||||
won: 'Won',
|
||||
lost_other_marina: 'Lost — chose another marina',
|
||||
lost_unqualified: 'Lost — not qualified',
|
||||
lost_no_response: 'Lost — no response',
|
||||
lost_other: 'Lost — other',
|
||||
cancelled: 'Cancelled',
|
||||
};
|
||||
|
||||
/** Returns the human label for a stored outcome value. Falls back to a
|
||||
* pretty Title-Case rendering for any new values added at the validator
|
||||
* before this map catches up. */
|
||||
export function formatOutcome(outcome: string | null | undefined): string | null {
|
||||
if (!outcome) return null;
|
||||
if (outcome in OUTCOME_LABELS) return OUTCOME_LABELS[outcome]!;
|
||||
return outcome
|
||||
.split('_')
|
||||
.map((part) => (part ? part[0]!.toUpperCase() + part.slice(1) : part))
|
||||
.join(' ');
|
||||
}
|
||||
|
||||
// ─── Document Types ──────────────────────────────────────────────────────────
|
||||
|
||||
export const DOCUMENT_TYPES = ['eoi', 'contract', 'nda', 'reservation_agreement', 'other'] as const;
|
||||
|
||||
Reference in New Issue
Block a user