Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 32 additions & 1 deletion lib/redact-patterns.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,36 @@ function looksLikeWallet(span: string): boolean {
return span.length >= 26 && span.length <= 62;
}

// Compact log/backup stamps (`20260727202423` = YYYYMMDDHHMMSS) are bare digit
// runs that the phone regex happily eats. Only a SEPARATOR-FREE 14-digit span
// qualifies: E.164 tops out at 15 digits and real numbers carry a + or spacing,
// so rejecting this shape costs no phone coverage.
function looksLikeCompactTimestamp(span: string): boolean {
if (!/^\d{14}$/.test(span)) {
return false;
}
const n = (from: number, to: number) => Number(span.slice(from, to));
const [year, month, day, hour, minute, second] = [
n(0, 4),
n(4, 6),
n(6, 8),
n(8, 10),
n(10, 12),
n(12, 14),
];
return (
year >= 1900 &&
year <= 2999 &&
month >= 1 &&
month <= 12 &&
day >= 1 &&
day <= 31 &&
hour <= 23 &&
minute <= 59 &&
second <= 59
);
}

// ── Placeholder suppression (per-matched-span, NOT per-line) ─────────────────

/**
Expand Down Expand Up @@ -431,7 +461,8 @@ export const PATTERNS: RedactPattern[] = [
regex: /(?<![\w.])(\+?[1-9]\d{0,2}[ \-.]?\(?\d{2,4}\)?[ \-.]?\d{3,4}[ \-.]?\d{3,4})(?![\w.])/,
autoRedactable: true,
redactToken: "<REDACTED-PHONE>",
validate: (span) => span.replace(/\D/g, "").length >= 10,
validate: (span) =>
span.replace(/\D/g, "").length >= 10 && !looksLikeCompactTimestamp(span),
},
{
id: "pii.ssn",
Expand Down
3 changes: 2 additions & 1 deletion test/redact-engine.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -185,8 +185,9 @@ describe("PII patterns", () => {
scan("bob@acme.co", { repoVisibility: "private", repoPublicEmails: ["bob@acme.co"] }).findings,
).toHaveLength(0);
});
test("phone E.164", () => {
test("phone E.164 flags, skips compact timestamps", () => {
expect(ids("call +14155550123 now")).toContain("pii.phone.e164");
expect(ids("backup stamp 20260727202423 ran late")).not.toContain("pii.phone.e164");
});
test("ssn flags valid, skips 000 octet", () => {
expect(ids("ssn 123-45-6789")).toContain("pii.ssn");
Expand Down