Spaces:
Running
Running
| import { describe, it, expect } from "vitest"; | |
| import type { ConsentPreview } from "@courtmitra/contracts"; | |
| import { computeConsentHash, consentHashMatches } from "../consent-hash.js"; | |
| const base: ConsentPreview = { | |
| actionType: "send_email", | |
| destination: "grievance@acme.example", | |
| public: false, | |
| body: "Dear Acme,\nPlease refund my order.\nRegards", | |
| attachments: [ | |
| { id: "ev_2", sha256: "bbb", redacted: true }, | |
| { id: "ev_1", sha256: "aaa", redacted: true }, | |
| ], | |
| piiDisclosed: ["order_id", "name"], | |
| risks: ["company may not reply"], | |
| createdAt: "2026-05-27T10:00:00+05:30", | |
| }; | |
| describe("consent hash", () => { | |
| it("is stable regardless of attachment / array ordering and createdAt", () => { | |
| const reordered: ConsentPreview = { | |
| ...base, | |
| attachments: [ | |
| { id: "ev_1", sha256: "aaa", redacted: true }, | |
| { id: "ev_2", sha256: "bbb", redacted: true }, | |
| ], | |
| piiDisclosed: ["name", "order_id"], | |
| createdAt: "2099-01-01T00:00:00+05:30", // volatile — must not affect hash | |
| }; | |
| expect(computeConsentHash(base)).toBe(computeConsentHash(reordered)); | |
| }); | |
| it("normalizes CRLF line endings in the body", () => { | |
| const crlf: ConsentPreview = { ...base, body: base.body.replace(/\n/g, "\r\n") }; | |
| expect(computeConsentHash(crlf)).toBe(computeConsentHash(base)); | |
| }); | |
| it("changes when the body text changes (bait-and-switch guard)", () => { | |
| const harsher: ConsentPreview = { ...base, body: base.body + "\nYou are a SCAM." }; | |
| expect(computeConsentHash(harsher)).not.toBe(computeConsentHash(base)); | |
| expect(consentHashMatches(computeConsentHash(base), harsher)).toBe(false); | |
| }); | |
| it("changes when an attachment hash changes", () => { | |
| const tampered: ConsentPreview = { | |
| ...base, | |
| attachments: [ | |
| { id: "ev_1", sha256: "DIFFERENT", redacted: true }, | |
| { id: "ev_2", sha256: "bbb", redacted: true }, | |
| ], | |
| }; | |
| expect(consentHashMatches(computeConsentHash(base), tampered)).toBe(false); | |
| }); | |
| it("matches itself", () => { | |
| expect(consentHashMatches(computeConsentHash(base), base)).toBe(true); | |
| }); | |
| }); | |