Security improvements: - Create redaction utility to prevent PII leakage in logs - Redact sensitive fields: privateKey, tokens, passwords, metadata, payloads - Redact user IDs: convert to "user-***" - Redact instance IDs: convert to "instance-***" - Support recursive redaction for nested objects and arrays Changes: - Add redact.util.ts with redaction functions - Add comprehensive test coverage for redaction - Support for: - Sensitive field detection (privateKey, token, etc.) - User ID redaction (userId, remoteUserId, localUserId, user.id) - Instance ID redaction (instanceId, remoteInstanceId, instance.id) - Nested object and array redaction - Primitive and null/undefined handling Next steps: - Apply redactSensitiveData() to all logger calls in federation services - Use debug level for detailed logs with sensitive data Part of M7.1 Remediation Sprint P1 security fixes. Refs #287 Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
143 lines
4.2 KiB
TypeScript
143 lines
4.2 KiB
TypeScript
/**
|
|
* Redaction Utility Tests
|
|
*
|
|
* Tests for sensitive data redaction in logs.
|
|
*/
|
|
|
|
import { describe, it, expect } from "vitest";
|
|
import { redactSensitiveData, redactUserId, redactInstanceId } from "./redact.util";
|
|
|
|
describe("Redaction Utilities", () => {
|
|
describe("redactUserId", () => {
|
|
it("should redact user IDs", () => {
|
|
expect(redactUserId("user-12345")).toBe("user-***");
|
|
});
|
|
|
|
it("should handle null/undefined", () => {
|
|
expect(redactUserId(null)).toBe("user-***");
|
|
expect(redactUserId(undefined)).toBe("user-***");
|
|
});
|
|
});
|
|
|
|
describe("redactInstanceId", () => {
|
|
it("should redact instance IDs", () => {
|
|
expect(redactInstanceId("instance-abc-def")).toBe("instance-***");
|
|
});
|
|
|
|
it("should handle null/undefined", () => {
|
|
expect(redactInstanceId(null)).toBe("instance-***");
|
|
expect(redactInstanceId(undefined)).toBe("instance-***");
|
|
});
|
|
});
|
|
|
|
describe("redactSensitiveData", () => {
|
|
it("should redact user IDs", () => {
|
|
const data = { userId: "user-123", name: "Test" };
|
|
const redacted = redactSensitiveData(data);
|
|
|
|
expect(redacted.userId).toBe("user-***");
|
|
expect(redacted.name).toBe("Test");
|
|
});
|
|
|
|
it("should redact instance IDs", () => {
|
|
const data = { instanceId: "instance-456", url: "https://example.com" };
|
|
const redacted = redactSensitiveData(data);
|
|
|
|
expect(redacted.instanceId).toBe("instance-***");
|
|
expect(redacted.url).toBe("https://example.com");
|
|
});
|
|
|
|
it("should redact metadata objects", () => {
|
|
const data = {
|
|
metadata: { secret: "value", public: "data" },
|
|
other: "field",
|
|
};
|
|
const redacted = redactSensitiveData(data);
|
|
|
|
expect(redacted.metadata).toBe("[REDACTED]");
|
|
expect(redacted.other).toBe("field");
|
|
});
|
|
|
|
it("should redact payloads", () => {
|
|
const data = {
|
|
payload: { command: "execute", args: ["secret"] },
|
|
type: "command",
|
|
};
|
|
const redacted = redactSensitiveData(data);
|
|
|
|
expect(redacted.payload).toBe("[REDACTED]");
|
|
expect(redacted.type).toBe("command");
|
|
});
|
|
|
|
it("should redact private keys", () => {
|
|
const data = {
|
|
privateKey: "-----BEGIN PRIVATE KEY-----\n...",
|
|
publicKey: "-----BEGIN PUBLIC KEY-----\n...",
|
|
};
|
|
const redacted = redactSensitiveData(data);
|
|
|
|
expect(redacted.privateKey).toBe("[REDACTED]");
|
|
expect(redacted.publicKey).toBe("-----BEGIN PUBLIC KEY-----\n...");
|
|
});
|
|
|
|
it("should redact tokens", () => {
|
|
const data = {
|
|
token: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
|
|
oidcToken: "token-value",
|
|
};
|
|
const redacted = redactSensitiveData(data);
|
|
|
|
expect(redacted.token).toBe("[REDACTED]");
|
|
expect(redacted.oidcToken).toBe("[REDACTED]");
|
|
});
|
|
|
|
it("should handle nested objects", () => {
|
|
const data = {
|
|
user: {
|
|
id: "user-789",
|
|
email: "[email protected]",
|
|
},
|
|
metadata: { nested: "data" },
|
|
};
|
|
const redacted = redactSensitiveData(data);
|
|
|
|
expect(redacted.user.id).toBe("user-***");
|
|
expect(redacted.user.email).toBe("[email protected]");
|
|
expect(redacted.metadata).toBe("[REDACTED]");
|
|
});
|
|
|
|
it("should handle arrays", () => {
|
|
const data = {
|
|
users: [{ userId: "user-1" }, { userId: "user-2" }],
|
|
};
|
|
const redacted = redactSensitiveData(data);
|
|
|
|
expect(redacted.users[0].userId).toBe("user-***");
|
|
expect(redacted.users[1].userId).toBe("user-***");
|
|
});
|
|
|
|
it("should preserve non-sensitive data", () => {
|
|
const data = {
|
|
id: "conn-123",
|
|
status: "active",
|
|
createdAt: "2024-01-01",
|
|
remoteUrl: "https://remote.com",
|
|
};
|
|
const redacted = redactSensitiveData(data);
|
|
|
|
expect(redacted).toEqual(data);
|
|
});
|
|
|
|
it("should handle null/undefined", () => {
|
|
expect(redactSensitiveData(null)).toBeNull();
|
|
expect(redactSensitiveData(undefined)).toBeUndefined();
|
|
});
|
|
|
|
it("should handle primitives", () => {
|
|
expect(redactSensitiveData("string")).toBe("string");
|
|
expect(redactSensitiveData(123)).toBe(123);
|
|
expect(redactSensitiveData(true)).toBe(true);
|
|
});
|
|
});
|
|
});
|