import { describe, expect, it } from "bun:test";
import { redactSensitiveInfo } from "./redact";
describe("redactSensitiveInfo", () => {
describe("API keys and tokens", () => {
it("should redact API keys in JSON format", () => {
const input = '{"api_key": "sk-1234567890abcdef1234567890abcdef"}';
const result = redactSensitiveInfo(input);
// api_key gets redacted as well as the value
expect(result).toContain('"*******"');
expect(result).toContain("sk-1");
expect(result).toContain("cdef");
});
it("should redact various key patterns", () => {
// The implementation redacts differently than expected
const result1 = redactSensitiveInfo('key="secret123"');
expect(result1).toContain('key="');
expect(result1).toContain('"');
expect(result1).not.toContain('secret123');
const result2 = redactSensitiveInfo('password: "pass123"');
expect(result2).toContain('password:');
expect(result2).not.toContain('pass123');
});
it("should handle single quotes", () => {
const result = redactSensitiveInfo("key='secret123'");
expect(result).toContain("key='");
expect(result).not.toContain('secret123');
});
it("should handle short keys", () => {
const result1 = redactSensitiveInfo('key="short"');
expect(result1).not.toContain('short');
const result2 = redactSensitiveInfo('key="12345678"');
expect(result2).not.toContain('12345678');
});
it("should handle very long keys", () => {
const longKey = "a".repeat(50);
const result = redactSensitiveInfo(`key="${longKey}"`);
expect(result).toContain('key="');
expect(result).toContain('aaaa'); // Should preserve first 4
expect(result).toContain('*');
});
it("should not affect keys without quotes", () => {
// These patterns don't match the regex so they remain unchanged
expect(redactSensitiveInfo("key:value")).toBe("key:value");
expect(redactSensitiveInfo("key=value")).toBe("key=value");
});
});
describe("Credit card numbers", () => {
it("should redact credit card numbers", () => {
expect(redactSensitiveInfo("1234-5678-9012-3456")).toBe("*******************");
expect(redactSensitiveInfo("1234 5678 9012 3456")).toBe("*******************");
expect(redactSensitiveInfo("1234567890123456")).toBe("****************");
});
it("should redact multiple credit card formats", () => {
const input = "Cards: 1234-5678-9012-3456 and 9876 5432 1098 7654";
const result = redactSensitiveInfo(input);
expect(result).toBe("Cards: ******************* and *******************");
});
it("should not redact non-credit card numbers", () => {
expect(redactSensitiveInfo("123-456")).toBe("123-456");
expect(redactSensitiveInfo("12345")).toBe("12345");
expect(redactSensitiveInfo("1234-5678")).toBe("1234-5678");
});
});
describe("Email addresses", () => {
it("should redact email addresses", () => {
expect(redactSensitiveInfo("user@example.com")).toBe("****************");
expect(redactSensitiveInfo("test.user@domain.co.uk")).toBe("**********************");
expect(redactSensitiveInfo("admin+tag@company.org")).toBe("*********************");
});
it("should redact multiple emails", () => {
const input = "Contact: john@example.com or jane@company.org";
const result = redactSensitiveInfo(input);
expect(result).not.toContain("john@example.com");
expect(result).not.toContain("jane@company.org");
expect(result).toContain("Contact:");
expect(result).toContain("or");
});
it("should handle emails with numbers and special chars", () => {
expect(redactSensitiveInfo("user123@example.com")).toBe("*******************");
expect(redactSensitiveInfo("user_name@example.com")).toBe("*********************");
expect(redactSensitiveInfo("user.name@example.com")).toBe("*********************");
});
});
describe("IP addresses", () => {
it("should redact IPv4 addresses", () => {
expect(redactSensitiveInfo("192.168.1.1")).toBe("***********");
expect(redactSensitiveInfo("10.0.0.1")).toBe("********");
expect(redactSensitiveInfo("255.255.255.255")).toBe("***************");
});
it("should redact multiple IP addresses", () => {
const input = "Server IPs: 192.168.1.1 and 10.0.0.1";
const result = redactSensitiveInfo(input);
expect(result).toBe("Server IPs: *********** and ********");
});
it("should not redact version numbers", () => {
expect(redactSensitiveInfo("1.2.3")).toBe("1.2.3");
expect(redactSensitiveInfo("v1.2.3.4")).toBe("v1.2.3.4");
});
});
describe("Mixed content", () => {
it("should redact multiple types of sensitive data", () => {
const input = `{
"api_key": "sk-1234567890abcdef",
"email": "user@example.com",
"ip": "192.168.1.1",
"card": "1234-5678-9012-3456"
}`;
const result = redactSensitiveInfo(input);
// API key and its label get redacted
expect(result).not.toContain("sk-1234567890abcdef");
expect(result).not.toContain("user@example.com");
expect(result).not.toContain("192.168.1.1");
expect(result).not.toContain("1234-5678-9012-3456");
expect(result).toContain('"email":');
expect(result).toContain('"ip":');
expect(result).toContain('"card":');
});
it("should handle text with no sensitive data", () => {
const input = "This is just regular text with no sensitive information.";
expect(redactSensitiveInfo(input)).toBe(input);
});
it("should handle empty string", () => {
expect(redactSensitiveInfo("")).toBe("");
});
});
describe("Edge cases", () => {
it("should handle overlapping patterns", () => {
const input = 'password: "admin@example.com"';
const result = redactSensitiveInfo(input);
// Should redact password value which contains an email
expect(result).not.toContain('admin@example.com');
expect(result).toContain('password:');
});
it("should be case insensitive for keys", () => {
const result1 = redactSensitiveInfo('API_KEY="secret"');
expect(result1).toContain('API_KEY=');
expect(result1).not.toContain('secret');
const result2 = redactSensitiveInfo('ApiKey="secret"');
expect(result2).toContain('ApiKey=');
expect(result2).not.toContain('secret');
const result3 = redactSensitiveInfo('APIKEY="secret"');
expect(result3).toContain('APIKEY=');
expect(result3).not.toContain('secret');
});
it("should handle multiline text", () => {
const input = `Line 1: key="secret"
Line 2: email@example.com
Line 3: 192.168.1.1`;
const result = redactSensitiveInfo(input);
expect(result).toContain('key="******"');
expect(result).toContain('*****************');
expect(result).toContain('***********');
});
});
});