Files
HiveGrid-Wireframes/hivegrid-cloud/apps/web/app/modules/emails/services/EmailService.pii.test.ts
T

48 lines
2.1 KiB
TypeScript

import { describe, expect, it } from "vitest";
import { readFileSync } from "node:fs";
import { resolve } from "node:path";
/**
* PII-protection regression test for EmailService.
*
* The legacy `console.log` printed `{ providerSettings, alias, hasTemplateData }`
* which is borderline; we tightened it further (no full alias, only boolean).
* This test asserts we never regress to logging `to`, `subject`, `body`, or `data`.
*/
describe("EmailService PII discipline", () => {
const SOURCE = readFileSync(resolve(__dirname, "EmailService.ts"), "utf8");
it("contains no live console.* call sites", () => {
const live = SOURCE.split("\n").filter((line, idx, all) => {
if (!/console\.(log|error|warn|info|debug)\s*\(/.test(line)) return false;
const trimmed = line.trimStart();
if (trimmed.startsWith("//") || trimmed.startsWith("*")) return false;
const prev = idx > 0 ? all[idx - 1].trim() : "";
if (/eslint-disable-next-line[^\n]*no-console/.test(prev)) return false;
return true;
});
expect(live).toEqual([]);
});
it("never passes recipient address / subject / body / template-data as own logger fields", () => {
// Pattern: emailLogger.<level>({ <key>: ... }) — flag if `<key>` is one of the PII fields.
// Note: We check key positions (property keys), not value expressions like `Boolean(data)`.
const pattern = /emailLogger\.(info|warn|error|debug)\s*\(\s*\{([\s\S]*?)\}/g;
const forbiddenKeys = ["to", "subject", "body", "templateData", "recipient", "html", "text"];
let match: RegExpExecArray | null;
const offenders: string[] = [];
while ((match = pattern.exec(SOURCE)) !== null) {
const objContent = match[2];
for (const key of forbiddenKeys) {
const keyRe = new RegExp(`(^|[\\s,{])${key}\\s*:`, "m");
if (keyRe.test(objContent)) offenders.push(`key "${key}" in ${match[0].slice(0, 80)}...`);
}
}
expect(offenders, `emailLogger must not log PII fields: ${offenders.join("; ")}`).toEqual([]);
});
it("uses createScopedLogger('email')", () => {
expect(SOURCE).toMatch(/createScopedLogger\(\s*["']email["']\s*\)/);
});
});