fix(audit-wave-9): standardize on Sheet for previews; doctrine in CLAUDE.md
Swap the one outlier (client-interests-tab.tsx) from Vaul Drawer to Sheet side=right so every detail-preview surface uses the same primitive. Document the doctrine: Sheet for side panels on both desktop and mobile; Vaul Drawer reserved for mobile-only bottom-sheet UX (currently just MoreSheet). Closes ui/ux M11. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -25,43 +25,52 @@ const BODY_MAX_BYTES = 1 * 1024;
|
||||
// A 5xx in /api/v1/clients (create / update) was landing full client
|
||||
// PII (full name, DOB, address, phone, nationality, email) in
|
||||
// error_events.request_body_excerpt for the super-admin inspector.
|
||||
// Extend to cover GDPR-relevant fields too.
|
||||
const SENSITIVE_KEYS = new Set([
|
||||
// Match fragments case-insensitively + snake/kebab-normalized so the
|
||||
// redactor catches `recipientEmail`, `client_email`, `phone_number`,
|
||||
// `tax_id`, `passwordHash`, etc. without an exhaustive enumeration.
|
||||
const SENSITIVE_KEY_FRAGMENTS = [
|
||||
// Credentials
|
||||
'password',
|
||||
'newPassword',
|
||||
'oldPassword',
|
||||
'token',
|
||||
'secret',
|
||||
'apiKey',
|
||||
'accessKey',
|
||||
'secretKey',
|
||||
'creditCard',
|
||||
'cardNumber',
|
||||
'api_key',
|
||||
'apikey',
|
||||
'access_key',
|
||||
'secret_key',
|
||||
'credit_card',
|
||||
'card_number',
|
||||
'cvv',
|
||||
'ssn',
|
||||
'authorization',
|
||||
'cookie',
|
||||
// PII
|
||||
'email',
|
||||
'emails',
|
||||
'phone',
|
||||
'phoneNumber',
|
||||
'mobile',
|
||||
'whatsapp',
|
||||
'dob',
|
||||
'dateOfBirth',
|
||||
'date_of_birth',
|
||||
'birthdate',
|
||||
'address',
|
||||
'street',
|
||||
'postcode',
|
||||
'zip',
|
||||
'nationalId',
|
||||
'national_id',
|
||||
'passport',
|
||||
'taxId',
|
||||
'fullName',
|
||||
'firstName',
|
||||
'lastName',
|
||||
]);
|
||||
'iban',
|
||||
'tax_id',
|
||||
'taxid',
|
||||
'full_name',
|
||||
'fullname',
|
||||
'first_name',
|
||||
'last_name',
|
||||
'recipient',
|
||||
];
|
||||
|
||||
function isSensitiveKey(key: string): boolean {
|
||||
const k = key.toLowerCase().replace(/[-]/g, '_');
|
||||
return SENSITIVE_KEY_FRAGMENTS.some((frag) => k.includes(frag));
|
||||
}
|
||||
|
||||
/** Drop sensitive keys + cap the JSON length. */
|
||||
function sanitizeBody(body: unknown): string | null {
|
||||
@@ -77,7 +86,7 @@ function sanitizeBody(body: unknown): string | null {
|
||||
if (value && typeof value === 'object') {
|
||||
const out: Record<string, unknown> = {};
|
||||
for (const [k, v] of Object.entries(value)) {
|
||||
if (SENSITIVE_KEYS.has(k)) {
|
||||
if (isSensitiveKey(k)) {
|
||||
out[k] = '[REDACTED]';
|
||||
} else {
|
||||
out[k] = walk(v);
|
||||
|
||||
Reference in New Issue
Block a user