atlas-iac/testing/tests/test_hermes_hux_ui_multimodal.mjs

270 lines
17 KiB
JavaScript
Raw Normal View History

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);
});