import assert from "node:assert/strict"; import test from "node:test"; import {createMultimodalEndpointContract} from "../../dockerfiles/hermes-webui-hux/multimodal/endpoints.ts"; import { ARTIFACTS_FLAG, AUTONOMY_FLAG, FOUNDATION_FLAG, MULTIMODAL_FLAG, PROJECTS_FLAG, buildAnnotation, buildCaptureIntent, buildImageEdit, buildTranscriptCorrection, captureAuthorization, multimodalEnabled, normalizeMultimodalPage, } from "../../dockerfiles/hermes-webui-hux/multimodal/model.ts"; import { classifyMime, isOpaqueId, isUtc, normalizeIdentity, normalizeScope, safeBlobUrl, safeEndpointPart, safePreviewText, safeText, sameIdentity, sameScope, validateUpload, } from "../../dockerfiles/hermes-webui-hux/multimodal/security.ts"; const IDENTITY = {tenantRef: "tnt_0123456789abcdef", userRef: "usr_0123456789abcdef", surface: "chat"}; const RAW_IDENTITY = {tenant_ref: IDENTITY.tenantRef, user_ref: IDENTITY.userRef, surface: "chat"}; const SCOPE = {projectId: "prj_test1234", conversationId: "conv_test1234"}; const RAW_SCOPE = {project_id: SCOPE.projectId, conversation_id: SCOPE.conversationId}; const FLAGS = [FOUNDATION_FLAG, PROJECTS_FLAG, ARTIFACTS_FLAG, AUTONOMY_FLAG, MULTIMODAL_FLAG]; function media(extra = {}) { return {schema: "hux.media.v1", id: "med_image1234", owner: IDENTITY.userRef, project_id: SCOPE.projectId, conversation_id: SCOPE.conversationId, artifact_id: "art_image1234", artifact_version: 1, kind: "image", file_name: "garden.png", mime: "image/png", bytes: 1200, preview_url: "blob:https://chat.bstein.dev/123", preview_text: null, preview_authorized: true, alt_text: "A garden", annotations: [], lineage: null, ...extra}; } function document(extra = {}) { return media({id: "med_document1", artifact_id: "art_document1", kind: "document", file_name: "notes.pdf", mime: "application/pdf", preview_url: null, preview_text: "Safe document\npreview", preview_authorized: true, annotations: [{id: "ann_note1234", page: 2, note: "Check this paragraph"}], ...extra}); } function variant(extra = {}) { return {id: "var_first1234", media_id: "med_image1234", artifact_id: "art_image1234", artifact_version: 1, parent_variant_id: null, created_at: "2026-08-24T10:00:00Z", ...extra}; } function thread(extra = {}) { return {id: "thr_garden123", owner: IDENTITY.userRef, project_id: SCOPE.projectId, conversation_id: SCOPE.conversationId, prompt: "A calm garden", variants: [variant()], ...extra}; } function transcript(extra = {}) { return {schema: "hux.voice_transcript.v1", id: "trn_voice1234", turn_id: "turn_voice123", owner: IDENTITY.userRef, project_id: SCOPE.projectId, conversation_id: SCOPE.conversationId, revision: 2, language: "en", text: "A clean transcript", finalized: true, ...extra}; } function page(extra = {}) { return {schema: "hux.multimodal_page.v1", api_version: "hux.v1", identity: RAW_IDENTITY, binding: RAW_SCOPE, media: [media(), document()], threads: [thread()], transcript: transcript(), upload_authorization: "authorized", ...extra}; } function policy(decision = "allow", autonomy = "autonomous") { return {id: "pol_policy123", owner: IDENTITY.userRef, scope: {level: "conversation", scopeId: SCOPE.conversationId}, autonomy, grants: {network: decision}, budgets: { tokensPerRun: 1, toolCallsPerRun: 1, wallClockSeconds: 1, delegationsPerRun: 0}, updatedAt: "2026-08-24T10:00:00Z"}; } test("HUX-07 is inert unless every dependency is active", () => { assert.equal(multimodalEnabled(), false); assert.equal(multimodalEnabled([]), false); for (const flag of FLAGS) assert.equal(multimodalEnabled(FLAGS.filter((item) => item !== flag)), false); assert.equal(multimodalEnabled(FLAGS), true); }); test("security primitives validate identity, binding, ids, time, URLs, and text", () => { assert.equal(isOpaqueId("med_image1234", "med"), true); assert.equal(isOpaqueId("art_image1234", "med"), false); assert.equal(isOpaqueId(4), false); assert.equal(isUtc("2026-08-24T10:00:00.12Z"), true); assert.equal(isUtc("today"), false); assert.equal(isUtc(4), false); assert.deepEqual(normalizeIdentity(RAW_IDENTITY), IDENTITY); assert.deepEqual(normalizeIdentity(IDENTITY), IDENTITY); assert.equal(normalizeIdentity(null), null); assert.equal(normalizeIdentity([]), null); for (const bad of [{...RAW_IDENTITY, tenant_ref: "bad"}, {...RAW_IDENTITY, user_ref: "bad"}, {...RAW_IDENTITY, surface: "browser"}]) assert.equal(normalizeIdentity(bad), null); assert.deepEqual(normalizeScope(RAW_SCOPE), SCOPE); assert.deepEqual(normalizeScope(SCOPE), SCOPE); assert.equal(normalizeScope(null), null); assert.equal(normalizeScope([]), null); assert.equal(normalizeScope({...RAW_SCOPE, project_id: "bad"}), null); assert.equal(normalizeScope({...RAW_SCOPE, conversation_id: "bad"}), null); assert.equal(sameIdentity(IDENTITY, IDENTITY), true); assert.equal(sameIdentity(null, IDENTITY), false); assert.equal(sameIdentity({...IDENTITY, surface: "voice"}, IDENTITY), false); assert.equal(sameScope(SCOPE, SCOPE), true); assert.equal(sameScope(null, SCOPE), false); assert.equal(sameScope({...SCOPE, projectId: "prj_other1234"}, SCOPE), false); assert.equal(safeBlobUrl("blob:https://chat.bstein.dev/a"), "blob:https://chat.bstein.dev/a"); assert.equal(safeBlobUrl("blob:null/a"), "blob:null/a"); for (const bad of ["data:image/png;base64,a", "https://remote/a", "blob:data:image/png", "blob:has space", 4]) { assert.equal(safeBlobUrl(bad), null); } assert.equal(safePreviewText("line one\nline two"), "line one\nline two"); assert.equal(safePreviewText("bad\u0000text"), null); assert.equal(safePreviewText("abc", 2), null); assert.equal(safePreviewText({}), null); assert.equal(safeText(null, "fallback"), "fallback"); assert.equal(safeText(" \n ", "fallback"), "fallback"); assert.equal(safeText("token=private\u0000 next", "fallback"), "token=[redacted] next"); assert.equal(safeText("abcdef", "x", 4), "abc…"); assert.equal(safeEndpointPart("med_image1234", "med"), "med_image1234"); assert.throws(() => safeEndpointPart("../bad", "med"), TypeError); }); test("upload validation is MIME, size, name, and authorization bounded", () => { const cases = [["image/png", "image"], ["image/jpeg", "image"], ["image/webp", "image"], ["application/pdf", "document"], ["text/plain", "document"], ["text/markdown", "document"], ["audio/webm", "audio"], ["audio/wav", "audio"], ["audio/mpeg", "audio"], ["audio/ogg", "audio"]]; for (const [mime, kind] of cases) { assert.equal(classifyMime(mime), kind); assert.deepEqual(validateUpload({name: "safe.file", type: mime.toUpperCase(), size: 1}, "authorized"), {ok: true, kind, file: {name: "safe.file", type: mime, size: 1}}); } assert.equal(classifyMime("image/svg+xml"), null); assert.equal(classifyMime(null), null); assert.match(validateUpload({name: "x", type: "image/png", size: 1}, "requires_approval").reason, /approval/); assert.match(validateUpload({name: "x", type: "image/png", size: 1}, "denied").reason, /denied/); assert.match(validateUpload({name: "x.svg", type: "image/svg+xml", size: 1}, "authorized").reason, /not supported/); for (const file of [{name: "x.png", type: "image/png", size: 0}, {name: "x.png", type: "image/png", size: 20 * 1024 * 1024 + 1}, {name: "../x.png", type: "image/png", size: 1}, {name: "", type: "image/png", size: 1}, {name: "x.png", type: "image/png", size: 1.2}]) { assert.equal(validateUpload(file, "authorized").ok, false); } }); test("page normalization preserves safe media, variants, annotations, and transcript", () => { const result = normalizeMultimodalPage(page(), IDENTITY, SCOPE); assert.equal(result.rejected, 0); assert.equal(result.media.length, 2); assert.equal(result.media[0].previewUrl, "blob:https://chat.bstein.dev/123"); assert.equal(result.media[1].previewText, "Safe document\npreview"); assert.deepEqual(result.media[1].annotations, [{id: "ann_note1234", page: 2, note: "Check this paragraph"}]); assert.equal(result.threads[0].variants[0].mediaId, "med_image1234"); assert.equal(result.transcript.text, "A clean transcript"); assert.equal(normalizeMultimodalPage(page({transcript: null}), IDENTITY, SCOPE).transcript, null); }); test("envelope and records cannot cross tenant, user, project, or conversation scope", () => { const invalidPages = [null, {}, page({schema: "old"}), page({api_version: "hux.v0"}), page({identity: {...RAW_IDENTITY, tenant_ref: "tnt_ffffffffffffffff"}}), page({identity: {...RAW_IDENTITY, user_ref: "usr_ffffffffffffffff"}}), page({binding: {...RAW_SCOPE, project_id: "prj_other1234"}}), page({binding: {...RAW_SCOPE, conversation_id: "conv_other1234"}}), page({media: null}), page({media: Array(201).fill(media())}), page({threads: null}), page({threads: Array(101).fill(thread())}), page({upload_authorization: "maybe"})]; for (const raw of invalidPages) assert.equal(normalizeMultimodalPage(raw, IDENTITY, SCOPE), null); const invalidMedia = [null, media({schema: "old"}), media({id: "bad"}), media({owner: "usr_ffffffffffffffff"}), media({project_id: "prj_other1234"}), media({conversation_id: "conv_other1234"}), media({artifact_id: "bad"}), media({artifact_version: 0}), media({kind: "video"}), media({file_name: ""}), media({mime: "image/svg+xml"}), media({mime: "application/pdf"}), media({bytes: 0}), media({annotations: null}), media({annotations: Array(501).fill({})}), media({annotations: [null]}), media({annotations: [{id: "bad", page: null, note: "x"}]}), media({annotations: [{id: "ann_note1234", page: 0, note: "x"}]}), media({annotations: [{id: "ann_note1234", page: null, note: ""}]}), media({preview_url: "data:image/png;base64,a"}), media({lineage: {}}), media({preview_authorized: false}), media({preview_text: "text"}), document({preview_text: "bad\u0000text"}), document({preview_authorized: false}), document({preview_url: "blob:https://chat.bstein.dev/doc"}), media({preview_url: null, preview_text: null, preview_authorized: false, bytes: "1200"}), media({lineage: {media_id: "bad", artifact_id: "art_image1234", artifact_version: 1}}), media({lineage: {media_id: "med_image1234", artifact_id: "art_image1234", artifact_version: 1}})]; for (const raw of invalidMedia) { assert.equal(normalizeMultimodalPage(page({media: [raw]}), IDENTITY, SCOPE).media.length, 0); } }); test("lineage, thread cohesion, and transcript failures are withheld clearly", () => { const child = media({id: "med_child1234", artifact_id: "art_child1234", artifact_version: 2, lineage: {media_id: "med_image1234", artifact_id: "art_image1234", artifact_version: 1}}); assert.equal(normalizeMultimodalPage(page({media: [media(), child]}), IDENTITY, SCOPE).media.length, 2); const orphan = {...child, lineage: {...child.lineage, artifact_version: 9}}; assert.equal(normalizeMultimodalPage(page({media: [media(), orphan]}), IDENTITY, SCOPE).media.length, 1); const duplicate = normalizeMultimodalPage(page({media: [media(), media()]}), IDENTITY, SCOPE); assert.equal(duplicate.media.length, 1); assert.equal(duplicate.rejected, 1); const badThreads = [null, thread({id: "bad"}), thread({owner: "usr_ffffffffffffffff"}), thread({project_id: "prj_other1234"}), thread({conversation_id: "conv_other1234"}), thread({prompt: ""}), thread({variants: null}), thread({variants: []}), thread({variants: Array(201).fill(variant())}), thread({variants: [variant({id: "bad"})]}), thread({variants: [variant({media_id: "med_missing1"})]}), thread({variants: [variant({artifact_id: "art_other1234"})]}), thread({variants: [variant({artifact_version: 2})]}), thread({variants: [variant({parent_variant_id: "bad"})]}), thread({variants: [variant({created_at: "today"})]}), thread({variants: [variant(), variant()]}), thread({variants: [variant({parent_variant_id: "var_missing12"})]})]; for (const raw of badThreads) { assert.equal(normalizeMultimodalPage(page({threads: [raw]}), IDENTITY, SCOPE).threads.length, 0); } const second = variant({id: "var_second123", parent_variant_id: "var_first1234", created_at: "2026-08-24T10:00:01Z"}); assert.equal(normalizeMultimodalPage(page({threads: [thread({variants: [variant(), second]})]}), IDENTITY, SCOPE).threads[0].variants.length, 2); const badTranscripts = [{}, transcript({schema: "old"}), transcript({owner: "usr_ffffffffffffffff"}), transcript({project_id: "prj_other1234"}), transcript({conversation_id: "conv_other1234"}), transcript({id: "bad"}), transcript({turn_id: "bad"}), transcript({revision: 0}), transcript({language: ""}), transcript({text: ""}), transcript({finalized: "yes"})]; for (const raw of badTranscripts) { const result = normalizeMultimodalPage(page({transcript: raw}), IDENTITY, SCOPE); assert.equal(result.transcript, null); assert.equal(result.rejected, 1); } }); test("edit, annotation, transcript, and capture intents are bounded and optimistic", () => { const normalized = normalizeMultimodalPage(page(), IDENTITY, SCOPE); const image = normalized.media[0]; const doc = normalized.media[1]; assert.deepEqual(buildImageEdit(image, SCOPE, " Make it warmer "), { artifactId: image.artifactId, expectedVersion: 1, scope: SCOPE, mediaId: image.id, instruction: "Make it warmer", lineage: {artifactId: image.artifactId, version: 1}}); assert.throws(() => buildImageEdit(doc, SCOPE, "edit"), TypeError); assert.throws(() => buildImageEdit(image, SCOPE, ""), TypeError); assert.deepEqual(buildAnnotation(doc, SCOPE, " Note this ", 2).page, 2); assert.equal(buildAnnotation(doc, SCOPE, "Note", null).page, null); for (const args of [[image, "note", 1], [doc, "", 1], [doc, "note", 0], [doc, "note", 100001], [doc, "note", 1.2]]) assert.throws(() => buildAnnotation(args[0], SCOPE, args[1], args[2]), TypeError); assert.equal(buildTranscriptCorrection(normalized.transcript, " corrected ", IDENTITY, SCOPE).correctedText, "corrected"); assert.throws(() => buildTranscriptCorrection({...normalized.transcript, finalized: false}, "x", IDENTITY, SCOPE), TypeError); assert.throws(() => buildTranscriptCorrection(normalized.transcript, "", IDENTITY, SCOPE), TypeError); assert.equal(captureAuthorization(null, null, IDENTITY), "deny"); assert.equal(captureAuthorization(policy("deny"), null, IDENTITY), "deny"); assert.equal(captureAuthorization(policy("allow"), null, IDENTITY), "approval_required"); assert.equal(captureAuthorization(policy("ask", "ask_first"), null, IDENTITY), "approval_required"); assert.deepEqual(buildCaptureIntent("camera", policy(), IDENTITY, SCOPE), {kind: "camera", autonomyCapability: "network", requiredDecision: "ask", identity: IDENTITY, scope: SCOPE}); assert.equal(buildCaptureIntent("screen", policy(), IDENTITY, SCOPE).kind, "screen"); assert.throws(() => buildCaptureIntent("microphone", policy(), IDENTITY, SCOPE), TypeError); assert.throws(() => buildCaptureIntent("camera", policy("deny"), IDENTITY, SCOPE), TypeError); }); test("endpoint descriptions remain same-origin, scoped, default-off, and non-executing", () => { const client = {apiVersion: "hux.v1", identity: IDENTITY, endpoint(path) { assert.match(path, /^\/projects\/prj_[^/]+\/conversations\/conv_[^/]+\/multimodal/); return `/hux/v1${path}`; }}; assert.equal(createMultimodalEndpointContract(client, SCOPE), null); assert.equal(createMultimodalEndpointContract(client, SCOPE, FLAGS.slice(1)), null); const contract = createMultimodalEndpointContract(client, SCOPE, FLAGS); assert.equal(contract.page.path, "/hux/v1/projects/prj_test1234/conversations/conv_test1234/multimodal"); assert.equal(contract.beginUpload.method, "POST"); assert.match(contract.finalizeUpload("upl_upload123").path, /uploads\/upl_upload123\/finalize$/); assert.match(contract.editImage("med_image1234").path, /media\/med_image1234\/edits$/); assert.match(contract.annotate("med_image1234").path, /annotations$/); assert.match(contract.correctTranscript("trn_voice1234").path, /corrections$/); assert.match(contract.requestCapture("camera").path, /captures\/camera\/approvals$/); assert.match(contract.requestCapture("screen").path, /captures\/screen\/approvals$/); assert.match(contract.createVariant("thr_garden123").path, /threads\/thr_garden123\/variants$/); for (const call of [() => contract.finalizeUpload("bad"), () => contract.editImage("bad"), () => contract.correctTranscript("bad"), () => contract.requestCapture("audio"), () => contract.createVariant("bad")]) assert.throws(call, TypeError); assert.throws(() => createMultimodalEndpointContract({...client, apiVersion: "hux.v2"}, SCOPE, FLAGS), TypeError); assert.throws(() => createMultimodalEndpointContract({...client, identity: {...IDENTITY, userRef: "bad"}}, SCOPE, FLAGS), TypeError); assert.throws(() => createMultimodalEndpointContract(client, {...SCOPE, projectId: "bad"}, FLAGS), TypeError); });