import { describe, expect, it } from "vitest"; import { z } from "zod/v4"; import { COLINE_PROTOCOL_HEADER, ColineProtocolError, buildSignedProtocolRequest, parseSignedProtocolRequest, type ColineProtocolEnvelope, } from "./protocol"; import { COLINE_SIGNATURE_HEADER, COLINE_TIMESTAMP_HEADER } from "./signing"; const SECRET = "test-secret-of-sufficient-length"; const envelope: ColineProtocolEnvelope = { protocol: 2, deliveryId: "dlv_0123456789", sentAt: "2026-08-10T12:00:00.000Z", workspace: { workspaceId: "ws_1", workspaceSlug: "acme" }, app: { appKey: "crm", installId: "inst_1" }, actor: { kind: "user", userId: "user_1" }, kind: "tool.invoke", payload: { tool: "crm.create_contact", input: { name: "Sarah" } }, }; function toHeaders(record: Record): Headers { return new Headers(record); } describe("protocol v2 envelope", () => { it("round-trips a signed request", async () => { const signed = await buildSignedProtocolRequest({ secret: SECRET, envelope }); const parsed = await parseSignedProtocolRequest({ request: { body: signed.body, headers: toHeaders(signed.headers) }, secret: SECRET, now: () => Date.parse(signed.headers[COLINE_TIMESTAMP_HEADER] ?? ""), payloadSchema: z.object({ tool: z.string(), input: z.object({ name: z.string() }), }), }); expect(parsed.envelope.app.appKey).toBe("crm"); expect(parsed.envelope.actor).toEqual({ kind: "user", userId: "user_1" }); expect(parsed.payload.input.name).toBe("Sarah"); expect(parsed.deliveryId).toBe("dlv_0123456789"); }); it("fails closed on a missing protocol header", async () => { const signed = await buildSignedProtocolRequest({ secret: SECRET, envelope }); const headers = toHeaders(signed.headers); headers.delete(COLINE_PROTOCOL_HEADER); await expect( parseSignedProtocolRequest({ request: { body: signed.body, headers }, secret: SECRET, }), ).rejects.toMatchObject({ code: "unsupported_protocol" }); }); it("fails closed on an unknown protocol version — no silent coercion", async () => { const signed = await buildSignedProtocolRequest({ secret: SECRET, envelope }); const headers = toHeaders(signed.headers); headers.set(COLINE_PROTOCOL_HEADER, "3"); await expect( parseSignedProtocolRequest({ request: { body: signed.body, headers }, secret: SECRET, }), ).rejects.toMatchObject({ code: "unsupported_protocol" }); }); it("rejects a tampered body", async () => { const signed = await buildSignedProtocolRequest({ secret: SECRET, envelope }); const tampered = signed.body.replace("Sarah", "Mallory"); await expect( parseSignedProtocolRequest({ request: { body: tampered, headers: toHeaders(signed.headers) }, secret: SECRET, now: () => Date.parse(signed.headers[COLINE_TIMESTAMP_HEADER] ?? ""), }), ).rejects.toMatchObject({ code: "invalid_signature" }); }); it("rejects a wrong secret", async () => { const signed = await buildSignedProtocolRequest({ secret: SECRET, envelope }); await expect( parseSignedProtocolRequest({ request: { body: signed.body, headers: toHeaders(signed.headers) }, secret: "another-secret-of-sufficient-length", now: () => Date.parse(signed.headers[COLINE_TIMESTAMP_HEADER] ?? ""), }), ).rejects.toMatchObject({ code: "invalid_signature" }); }); it("rejects stale timestamps", async () => { const signed = await buildSignedProtocolRequest({ secret: SECRET, envelope }); await expect( parseSignedProtocolRequest({ request: { body: signed.body, headers: toHeaders(signed.headers) }, secret: SECRET, now: () => Date.parse(signed.headers[COLINE_TIMESTAMP_HEADER] ?? "") + 6 * 60 * 1000, }), ).rejects.toMatchObject({ code: "stale_timestamp" }); }); it("binds the delivery id into the signature (no cross-delivery replay)", async () => { const signed = await buildSignedProtocolRequest({ secret: SECRET, envelope }); const otherSigned = await buildSignedProtocolRequest({ secret: SECRET, envelope: { ...envelope, deliveryId: "dlv_9876543210" }, timestamp: signed.headers[COLINE_TIMESTAMP_HEADER], }); // Replay the first body under the second delivery's headers. await expect( parseSignedProtocolRequest({ request: { body: signed.body, headers: toHeaders(otherSigned.headers) }, secret: SECRET, now: () => Date.parse(signed.headers[COLINE_TIMESTAMP_HEADER] ?? ""), }), ).rejects.toMatchObject({ code: "invalid_signature" }); }); it("rejects an envelope whose deliveryId disagrees with the signed header", async () => { const mismatched = { ...envelope, deliveryId: "dlv_inner_differs" }; const body = JSON.stringify(mismatched); const signed = await buildSignedProtocolRequest({ secret: SECRET, envelope }); // Sign the mismatched body properly under the outer header's delivery id. const { hmacSha256Hex } = await import("./signing"); const timestamp = signed.headers[COLINE_TIMESTAMP_HEADER] ?? ""; const signature = await hmacSha256Hex( SECRET, `2.${envelope.deliveryId}.${timestamp}.${body}`, ); const headers = toHeaders({ ...signed.headers, [COLINE_SIGNATURE_HEADER]: signature }); await expect( parseSignedProtocolRequest({ request: { body, headers }, secret: SECRET, now: () => Date.parse(timestamp), }), ).rejects.toMatchObject({ code: "invalid_envelope" }); }); it("validates payloads when a schema is provided", async () => { const signed = await buildSignedProtocolRequest({ secret: SECRET, envelope }); await expect( parseSignedProtocolRequest({ request: { body: signed.body, headers: toHeaders(signed.headers) }, secret: SECRET, now: () => Date.parse(signed.headers[COLINE_TIMESTAMP_HEADER] ?? ""), payloadSchema: z.object({ somethingElse: z.string() }), }), ).rejects.toMatchObject({ code: "invalid_payload" }); }); it("exposes a typed error class", async () => { const signed = await buildSignedProtocolRequest({ secret: SECRET, envelope }); const headers = toHeaders(signed.headers); headers.set(COLINE_PROTOCOL_HEADER, "999"); try { await parseSignedProtocolRequest({ request: { body: signed.body, headers }, secret: SECRET, }); expect.unreachable(); } catch (error) { expect(error).toBeInstanceOf(ColineProtocolError); } }); });