From 0c53c311b1723ea29df6f1db888dd98f6331663f Mon Sep 17 00:00:00 2001 From: Logan Johnson Date: Thu, 20 Aug 2026 02:45:30 +0000 Subject: [PATCH] Match Board reference UTF-8 limits Co-authored-by: Larry Signed-off-by: Logan Johnson --- .../lib/boardReferences.test.mjs | 50 +++++++++++++++++++ .../workstream-board/lib/boardReferences.ts | 2 +- 2 files changed, 51 insertions(+), 1 deletion(-) diff --git a/desktop/src/features/workstream-board/lib/boardReferences.test.mjs b/desktop/src/features/workstream-board/lib/boardReferences.test.mjs index fbf43741f1..b23b9667ba 100644 --- a/desktop/src/features/workstream-board/lib/boardReferences.test.mjs +++ b/desktop/src/features/workstream-board/lib/boardReferences.test.mjs @@ -67,6 +67,56 @@ test("strict decoding rejects unknown fields and Unicode controls per reference" ); }); +test("strict decoding enforces Rust-compatible UTF-8 byte limits without hiding the message", () => { + const valid = ref("pull-request", "valid"); + const exact160Bytes = "é".repeat(80); + const exact512Bytes = "é".repeat(256); + const over160Bytes = "é".repeat(100); + const over512Bytes = "é".repeat(300); + const malformed = [ + { ...valid, snapshot: { ...valid.snapshot, label: over160Bytes } }, + { ...valid, snapshot: { ...valid.snapshot, detail: over160Bytes } }, + { + ...valid, + placement: { ...valid.placement, workstreamLabel: over160Bytes }, + }, + { ...valid, placement: { ...valid.placement, sectionLabel: over160Bytes } }, + { ...valid, identity: over512Bytes }, + { ...valid, placement: { ...valid.placement, sectionId: over512Bytes } }, + ]; + const exactBoundary = { + ...valid, + identity: exact512Bytes, + snapshot: { label: exact160Bytes, detail: exact160Bytes }, + placement: { + ...valid.placement, + workstreamLabel: exact160Bytes, + sectionId: exact512Bytes, + sectionLabel: exact160Bytes, + }, + }; + assert.equal(Buffer.byteLength(exact160Bytes, "utf8"), 160); + assert.equal(Buffer.byteLength(exact512Bytes, "utf8"), 512); + assert.ok(over160Bytes.length < 160); + assert.ok(Buffer.byteLength(over160Bytes, "utf8") > 160); + assert.ok(over512Bytes.length < 512); + assert.ok(Buffer.byteLength(over512Bytes, "utf8") > 512); + + const malformedTags = malformed.map((value) => [ + "buzz:board-ref", + "1", + JSON.stringify(value), + ]); + assert.deepEqual( + parseBoardReferences([ + ...malformedTags, + ["client-only", "message remains usable"], + ...boardReferenceTags([exactBoundary, valid]), + ]), + [exactBoundary, valid], + ); +}); + test("workstream identity is canonically bound to placement", () => { const forged = ref("workstream", OTHER); forged.placement.workstreamId = WS; diff --git a/desktop/src/features/workstream-board/lib/boardReferences.ts b/desktop/src/features/workstream-board/lib/boardReferences.ts index 3120049cd8..d5f1f35339 100644 --- a/desktop/src/features/workstream-board/lib/boardReferences.ts +++ b/desktop/src/features/workstream-board/lib/boardReferences.ts @@ -41,7 +41,7 @@ const CONTROL_CHARACTER = /\p{Cc}/u; const safe = (value: unknown, max = 160): value is string => typeof value === "string" && value.trim().length > 0 && - value.length <= max && + new TextEncoder().encode(value).byteLength <= max && !CONTROL_CHARACTER.test(value); const hasExactKeys = (