Adds apps/web-next/instrumentation.ts (server) and instrumentation-client.ts (browser) hooks, wraps next.config.mjs with withSentryConfig (R52), and adds the R38 per-app PII scrubber smoke test. Spec deviation: extend PII_KEY_SUBSTRINGS with "ipaddress" so keys like ipAddress trigger key-level redaction (tighter posture than the spec's substring list; existing scrub.test.ts still passes). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
57 lines
2.0 KiB
TypeScript
57 lines
2.0 KiB
TypeScript
import { describe, it, expect } from "vitest";
|
|
import {
|
|
beforeSend,
|
|
beforeSendTransaction,
|
|
} from "@repo/core-shared/instrumentation/sentry/scrub";
|
|
|
|
describe("R38 — apps/web-next PII scrubber", () => {
|
|
it("strips email/password/cookie/auth/IP from event payload", () => {
|
|
const event = {
|
|
extra: {
|
|
userEmail: "alice@example.com",
|
|
password: "p4$$w0rd",
|
|
ipAddress: "192.168.1.10",
|
|
note: "request from 10.0.0.1",
|
|
},
|
|
request: {
|
|
headers: {
|
|
Authorization: "Bearer secret",
|
|
"Set-Cookie": "session=abc",
|
|
"User-Agent": "Mozilla",
|
|
},
|
|
},
|
|
} as Parameters<typeof beforeSend>[0];
|
|
const result = beforeSend(event, {}) as {
|
|
extra: Record<string, string>;
|
|
request: { headers: Record<string, string> };
|
|
};
|
|
expect(result.extra["userEmail"]).toBe("[redacted]");
|
|
expect(result.extra["password"]).toBe("[redacted]");
|
|
expect(result.extra["ipAddress"]).toBe("[redacted]");
|
|
expect(result.extra["note"]).toContain("[redacted-ip]");
|
|
expect(result.request.headers["Authorization"]).toBe("[redacted]");
|
|
expect(result.request.headers["Set-Cookie"]).toBe("[redacted]");
|
|
expect(result.request.headers["User-Agent"]).toBe("Mozilla");
|
|
});
|
|
|
|
it("strips ?token / ?email / ?password / ?secret / ?signature from URLs", () => {
|
|
const event = {
|
|
request: {
|
|
url: "https://app/api/x?token=abc&email=a@b.c&password=p&secret=z&signature=s&safe=1",
|
|
},
|
|
transaction: "/foo?accessToken=t",
|
|
} as Parameters<typeof beforeSendTransaction>[0];
|
|
const result = beforeSendTransaction(event, {}) as {
|
|
request: { url: string };
|
|
transaction: string;
|
|
};
|
|
const url = decodeURIComponent(result.request.url);
|
|
const txn = decodeURIComponent(result.transaction);
|
|
for (const key of ["token", "email", "password", "secret", "signature"]) {
|
|
expect(url).toContain(`${key}=[redacted]`);
|
|
}
|
|
expect(url).toContain("safe=1");
|
|
expect(txn).toContain("accessToken=[redacted]");
|
|
});
|
|
});
|