atlas-iac/testing/tests/test_hermes_hux_ui_autonomy.mjs
jenkins b66c762f5d hermes(webui): add HUX card UI models with contract-locked suites
Standalone per-card browser model/security/view modules for HUX-01..10
plus node+pytest suites that read the hux.v1 contract schemas directly.
Reconciled drift found on integration: the activity model now accepts
all 32 hux.event.v1 kinds (delegation.*, memory.suppressed,
memory.retrieval_removed, budget.exhausted, side_effect.*), the
autonomy model carries the external_side_effect capability, and the
foundation boundary test now asserts the shipped static HUX surface
exists on disk and that images never bake activated HUX_FLAGS.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BvMSXH8VH2tMWXanb8SJdf
2026-08-24 04:12:03 -03:00

314 lines
16 KiB
JavaScript

import assert from "node:assert/strict";
import test from "node:test";
import { createAutonomyEndpointContract } from "../../dockerfiles/hermes-webui-hux/autonomy/endpoints.ts";
import {
ACTIVITY_TIMELINE_FLAG, AUTONOMY_FLAG, BUDGET_MAX, CAPABILITIES,
FOUNDATION_FLAG, actionAuthorization, autonomyControlsEnabled,
buildApprovalDecision, buildPolicyUpdate, buildStopIntent,
normalizeAutonomyPage, normalizeStopReceipt,
} from "../../dockerfiles/hermes-webui-hux/autonomy/model.ts";
import {
boundedInteger, exactKeys, identityKey, isOpaqueId, isUtc, normalizeIdentity,
safeText, sameIdentity,
} from "../../dockerfiles/hermes-webui-hux/autonomy/security.ts";
const IDENTITY = {
tenantRef: "tnt_0123456789abcdef",
userRef: "usr_0123456789abcdef",
surface: "chat",
};
const CONVERSATION = "conv_test1234";
const NOW = Date.parse("2026-08-24T10:05:00Z");
const grants = (decision = "ask") => CAPABILITIES.map((capability) => ({capability, decision}));
function policy(extra = {}) {
return {
schema: "hux.policy.v1",
id: "pol_test1234",
owner: IDENTITY.userRef,
scope: {level: "conversation", scope_id: CONVERSATION},
autonomy: "safe",
grants: grants(),
budgets: {
tokens_per_run: 200000,
tool_calls_per_run: 40,
wall_clock_seconds: 900,
delegations_per_run: 4,
},
provenance: {surface: "chat"},
updated_at: "2026-08-24T10:00:00Z",
...extra,
};
}
function approval(id = "apr_test1234", extra = {}) {
return {
schema: "hux.approval.v1",
id,
run_id: "run_test1234",
conversation_id: CONVERSATION,
capability: "send_message",
request: {summary: "Send the completed report", risk: "high"},
status: "pending",
requested_at: "2026-08-24T10:00:00Z",
expires_at: "2026-08-24T10:10:00Z",
...extra,
};
}
function envelope(extra = {}) {
return {
schema: "hux.autonomy_page.v1",
api_version: "hux.v1",
identity: {tenant_ref: IDENTITY.tenantRef, user_ref: IDENTITY.userRef, surface: "chat"},
conversation_id: CONVERSATION,
policy: policy(),
approvals: [approval()],
...extra,
};
}
test("HUX-05 is inert unless all three dependency flags are present", () => {
assert.equal(autonomyControlsEnabled(), false);
assert.equal(autonomyControlsEnabled([]), false);
assert.equal(autonomyControlsEnabled([AUTONOMY_FLAG]), false);
assert.equal(autonomyControlsEnabled([FOUNDATION_FLAG, AUTONOMY_FLAG]), false);
assert.equal(autonomyControlsEnabled([FOUNDATION_FLAG, ACTIVITY_TIMELINE_FLAG]), false);
assert.equal(autonomyControlsEnabled([FOUNDATION_FLAG, ACTIVITY_TIMELINE_FLAG, AUTONOMY_FLAG]), true);
});
test("security helpers reject unscoped identity and redact display text", () => {
assert.deepEqual(normalizeIdentity({tenant_ref: IDENTITY.tenantRef,
user_ref: IDENTITY.userRef, surface: "chat"}), IDENTITY);
assert.deepEqual(normalizeIdentity(IDENTITY), IDENTITY);
assert.equal(normalizeIdentity(null), null);
assert.equal(normalizeIdentity([]), null);
assert.equal(normalizeIdentity({...IDENTITY, tenantRef: "tenant"}), null);
assert.equal(normalizeIdentity({...IDENTITY, userRef: "brad@example.test"}), null);
assert.equal(normalizeIdentity({...IDENTITY, surface: "browser"}), null);
assert.equal(sameIdentity(IDENTITY, {...IDENTITY}), true);
assert.equal(sameIdentity(IDENTITY, {...IDENTITY, surface: "worker"}), false);
assert.match(identityKey(IDENTITY), /^tnt_.*:usr_.*:chat$/);
assert.equal(isOpaqueId("apr_test1234", "apr"), true);
assert.equal(isOpaqueId("pol_test1234", "apr"), false);
assert.equal(isOpaqueId(4), false);
assert.equal(isUtc("2026-08-24T10:00:00.123Z"), true);
assert.equal(isUtc("2026-99-24T10:00:00Z"), false);
assert.equal(isUtc(4), false);
assert.equal(boundedInteger(5, 5), 5);
assert.equal(boundedInteger(-1, 5), null);
assert.equal(boundedInteger(6, 5), null);
assert.equal(boundedInteger(1.5, 5), null);
assert.equal(exactKeys({b: 1, a: 2}, ["a", "b"]), true);
assert.equal(exactKeys({a: 1, extra: 2}, ["a"]), false);
assert.equal(safeText({}, "fallback"), "fallback");
assert.equal(safeText(" \n ", "fallback"), "fallback");
assert.equal(safeText("token=secret Bearer abc.def\u0000", "fallback"),
"token=[redacted] Bearer [redacted]");
assert.equal(safeText("abcdef", "fallback", 4), "abc…");
});
test("policy and pending approvals normalize against exact identity and scope", () => {
const page = normalizeAutonomyPage(envelope(), IDENTITY, CONVERSATION, NOW);
assert.ok(page);
assert.equal(page.policy.autonomy, "safe");
assert.deepEqual(page.policy.scope, {level: "conversation", scopeId: CONVERSATION});
assert.deepEqual(page.policy.budgets, {
tokensPerRun: 200000, toolCallsPerRun: 40, wallClockSeconds: 900,
delegationsPerRun: 4,
});
assert.equal(page.approvals.length, 1);
assert.equal(page.approvals[0].risk, "high");
assert.equal(page.rejectedApprovals, 0);
const partial = normalizeAutonomyPage(envelope({approvals: [
approval(),
approval("apr_expired1", {expires_at: "2026-08-24T10:04:59Z"}),
approval("apr_cross123", {conversation_id: "conv_other1234"}),
approval("apr_secret12", {request: {summary: "token=do-not-show", risk: "low"}}),
]}), IDENTITY, CONVERSATION, NOW);
assert.equal(partial.approvals.length, 2);
assert.equal(partial.rejectedApprovals, 2);
assert.doesNotMatch(partial.approvals[1].summary, /do-not-show/);
});
test("page normalization rejects malformed envelopes, policies, and budgets", () => {
const invalidEnvelopes = [
null,
{...envelope(), schema: "hux.autonomy_page.v0"},
{...envelope(), api_version: "hux.v0"},
{...envelope(), conversation_id: "bad"},
{...envelope(), identity: {...envelope().identity, user_ref: "usr_ffffffffffffffff"}},
{...envelope(), identity: null},
{...envelope(), approvals: {}},
{...envelope(), approvals: Array(101).fill(approval())},
{...envelope(), policy: {...policy(), surprise: true}},
{...envelope(), policy: {...policy(), schema: "old"}},
{...envelope(), policy: {...policy(), id: "bad"}},
{...envelope(), policy: {...policy(), owner: "usr_ffffffffffffffff"}},
{...envelope(), policy: {...policy(), autonomy: "reckless"}},
{...envelope(), policy: {...policy(), updated_at: "today"}},
{...envelope(), policy: {...policy(), scope: null}},
{...envelope(), policy: {...policy(), scope: {level: "global", scope_id: CONVERSATION}}},
{...envelope(), policy: {...policy(), scope: {level: "project", scope_id: "bad"}}},
{...envelope(), policy: {...policy(), scope: {level: "planet"}}},
{...envelope(), policy: {...policy(), grants: {}}},
{...envelope(), policy: {...policy(), grants: Array(65).fill({capability: "shell", decision: "ask"})}},
{...envelope(), policy: {...policy(), grants: [{capability: "unknown", decision: "ask"}]}},
{...envelope(), policy: {...policy(), grants: [{capability: "shell", decision: "maybe"}]}},
{...envelope(), policy: {...policy(), grants: [{capability: "shell", decision: "ask"}, {capability: "shell", decision: "deny"}]}},
{...envelope(), policy: {...policy(), budgets: null}},
{...envelope(), policy: {...policy(), budgets: {unknown: 1}}},
{...envelope(), policy: {...policy(), budgets: {tokens_per_run: BUDGET_MAX.tokensPerRun + 1}}},
];
for (const value of invalidEnvelopes) {
assert.equal(normalizeAutonomyPage(value, IDENTITY, CONVERSATION, NOW), null);
}
});
test("approval rows fail closed when malformed, resolved, stale, or reordered", () => {
const invalid = [
null,
{...approval(), extra: true},
{...approval(), schema: "old"},
{...approval(), id: "bad"},
{...approval(), run_id: ""},
{...approval(), run_id: "x".repeat(121)},
{...approval(), capability: "unknown"},
{...approval(), status: "approved"},
{...approval(), requested_at: "today"},
{...approval(), expires_at: "today"},
{...approval(), requested_at: "2026-08-24T10:11:00Z"},
{...approval(), request: null},
{...approval(), request: {summary: "x", risk: "extreme"}},
{...approval(), request: {summary: "x", risk: "low", injected: true}},
];
const page = normalizeAutonomyPage(envelope({approvals: invalid}), IDENTITY, CONVERSATION, NOW);
assert.deepEqual(page.approvals, []);
assert.equal(page.rejectedApprovals, invalid.length);
});
test("policy updates preserve canonical budgets and require bounded spend and scope", () => {
const page = normalizeAutonomyPage(envelope(), IDENTITY, CONVERSATION, NOW);
const draft = {...page.policy.budgets, spendCentsPerRun: 2500, scopeLimit: "conversation"};
const intent = buildPolicyUpdate(page.policy, IDENTITY, "autonomous", page.policy.grants, draft);
assert.equal(intent.expectedPolicyId, page.policy.id);
assert.equal(intent.guardrails.spendCentsPerRun, 2500);
assert.equal("spendCentsPerRun" in intent.budgets, false);
assert.deepEqual(Object.keys(intent.grants), CAPABILITIES);
const invalidDrafts = [
{...draft, tokensPerRun: -1}, {...draft, toolCallsPerRun: 501},
{...draft, wallClockSeconds: 86401}, {...draft, delegationsPerRun: 33},
{...draft, spendCentsPerRun: 100001}, {...draft, scopeLimit: "internet"},
];
for (const bad of invalidDrafts) assert.throws(() =>
buildPolicyUpdate(page.policy, IDENTITY, "safe", page.policy.grants, bad), /bounds/);
assert.throws(() => buildPolicyUpdate(page.policy, {...IDENTITY, userRef: "usr_ffffffffffffffff"},
"safe", page.policy.grants, draft), /bounds/);
assert.throws(() => buildPolicyUpdate(page.policy, IDENTITY, "turbo", page.policy.grants, draft), /bounds/);
assert.throws(() => buildPolicyUpdate(page.policy, IDENTITY, "safe",
{...page.policy.grants, shell: "maybe"}, draft), /bounds/);
});
test("authorization requires exact live approval whenever policy says ask", () => {
const page = normalizeAutonomyPage(envelope(), IDENTITY, CONVERSATION, NOW);
const pending = page.approvals[0];
assert.equal(actionAuthorization(null, "read_files", null, IDENTITY, NOW), "deny");
assert.equal(actionAuthorization({...page.policy, owner: "usr_ffffffffffffffff"},
"read_files", null, IDENTITY, NOW), "deny");
assert.equal(actionAuthorization(page.policy, "unknown", null, IDENTITY, NOW), "deny");
assert.equal(actionAuthorization(page.policy, "send_message", null, IDENTITY, NOW), "approval_required");
assert.equal(actionAuthorization(page.policy, "send_message", pending, IDENTITY, NOW), "approval_required");
assert.equal(actionAuthorization(page.policy, "shell", pending, IDENTITY, NOW), "approval_required");
assert.equal(actionAuthorization(page.policy, "send_message", {...pending, status: "denied"}, IDENTITY, NOW), "approval_required");
assert.equal(actionAuthorization(page.policy, "send_message", {...pending, expiresAt: "2026-08-24T10:04:00Z"}, IDENTITY, NOW), "approval_required");
assert.equal(actionAuthorization(page.policy, "send_message", {...pending, identityKey: "cross"}, IDENTITY, NOW), "approval_required");
const allow = {...page.policy, autonomy: "autonomous",
grants: {...page.policy.grants, read_files: "allow", send_message: "allow"}};
assert.equal(actionAuthorization(allow, "read_files", null, IDENTITY, NOW), "allow");
assert.equal(actionAuthorization(allow, "send_message", null, IDENTITY, NOW), "allow");
const safe = {...allow, autonomy: "safe"};
assert.equal(actionAuthorization(safe, "read_files", null, IDENTITY, NOW), "allow");
assert.equal(actionAuthorization(safe, "send_message", null, IDENTITY, NOW), "approval_required");
assert.equal(actionAuthorization({...allow, grants: {...allow.grants, deploy: "deny"}},
"deploy", null, IDENTITY, NOW), "deny");
});
test("approval decision proves identity and original timestamp", () => {
const item = normalizeAutonomyPage(envelope(), IDENTITY, CONVERSATION, NOW).approvals[0];
for (const choice of ["once", "session", "always", "deny"]) {
const intent = buildApprovalDecision(item, choice, IDENTITY, item.requestedAt, NOW);
assert.equal(intent.choice, choice);
assert.equal(intent.expectedRunId, item.runId);
assert.equal(intent.expectedConversationId, CONVERSATION);
}
assert.throws(() => buildApprovalDecision(item, "once", IDENTITY, "2026-08-24T10:00:01Z", NOW), /denied/);
assert.throws(() => buildApprovalDecision(item, "once", {...IDENTITY, surface: "worker"}, item.requestedAt, NOW), /denied/);
assert.throws(() => buildApprovalDecision({...item, status: "denied"}, "once", IDENTITY, item.requestedAt, NOW), /denied/);
assert.throws(() => buildApprovalDecision({...item, expiresAt: "2026-08-24T10:04:00Z"}, "once", IDENTITY, item.requestedAt, NOW), /denied/);
assert.throws(() => buildApprovalDecision(item, "later", IDENTITY, item.requestedAt, NOW), /denied/);
});
test("stop intent and receipt require exact ownership and remain bounded", () => {
const run = {runId: "run_test1234", conversationId: CONVERSATION,
tenantRef: IDENTITY.tenantRef, owner: IDENTITY.userRef};
assert.deepEqual(buildStopIntent(run, IDENTITY, run.runId), {
runId: run.runId, conversationId: CONVERSATION, identity: IDENTITY,
});
for (const bad of [
{...run, runId: ""}, {...run, runId: "x".repeat(121)},
{...run, conversationId: "bad"}, {...run, owner: "usr_ffffffffffffffff"},
{...run, tenantRef: "tnt_ffffffffffffffff"},
]) assert.throws(() => buildStopIntent(bad, IDENTITY, run.runId), /ownership/);
assert.throws(() => buildStopIntent(run, IDENTITY, "run_stale1234"), /ownership/);
const raw = {
schema: "hux.cancel_receipt.v1", id: "rcpt_test1234", run_id: run.runId,
requested_by: {type: "user", id: IDENTITY.userRef},
requested_at: "2026-08-24T10:05:00Z", outcome: "cancelled",
side_effects: Array.from({length: 7}, (_, index) => ({
description: index ? `Effect ${index}` : "token=do-not-show", reverted: index % 2 === 0,
})),
};
const receipt = normalizeStopReceipt(raw, run, IDENTITY);
assert.equal(receipt.effects.length, 4);
assert.equal(receipt.omittedEffects, 3);
assert.equal(receipt.stopped, 2);
assert.equal(receipt.remaining, 2);
assert.doesNotMatch(JSON.stringify(receipt), /do-not-show/);
assert.equal(normalizeStopReceipt({...raw, run_id: "run_other1234"}, run, IDENTITY), null);
assert.equal(normalizeStopReceipt({...raw, requested_by: null}, run, IDENTITY), null);
assert.equal(normalizeStopReceipt({...raw, requested_by: {type: "system", id: IDENTITY.userRef}}, run, IDENTITY), null);
assert.equal(normalizeStopReceipt({...raw, requested_by: {type: "user", id: "usr_ffffffffffffffff"}}, run, IDENTITY), null);
assert.equal(normalizeStopReceipt({...raw, schema: "old"}, run, IDENTITY), null);
assert.equal(normalizeStopReceipt(raw, {...run, owner: "usr_ffffffffffffffff"}, IDENTITY), null);
assert.equal(normalizeStopReceipt(raw, {...run, tenantRef: "tnt_ffffffffffffffff"}, IDENTITY), null);
});
test("endpoint adapter is inert, same-origin, versioned, and release-aware", () => {
const enabled = new Set([FOUNDATION_FLAG, ACTIVITY_TIMELINE_FLAG, AUTONOMY_FLAG]);
const client = {
apiVersion: "hux.v1", identity: IDENTITY,
enabled: (flag) => enabled.has(flag), endpoint: (path) => `/hux/v1${path}`,
};
const contract = createAutonomyEndpointContract(client);
assert.equal(contract.policy.path, "/hux/v1/autonomy/policy");
assert.equal(contract.updatePolicy.responseSchema, "hux.policy.v1");
assert.equal(contract.approvals.path, "/hux/v1/approvals?status=pending&limit=100");
assert.match(contract.decideApproval("apr_test1234").path, /\/approvals\/apr_test1234\/decision$/);
assert.match(contract.stop("run_test1234").path, /\/runs\/run_test1234\/stop$/);
assert.deepEqual(contract.release, {schema: "hux.release.v1", requiredState: "live_verified",
featureFlags: [FOUNDATION_FLAG, ACTIVITY_TIMELINE_FLAG, AUTONOMY_FLAG]});
assert.throws(() => contract.decideApproval("bad"), /Opaque/);
assert.throws(() => contract.stop("bad"), /Exact/);
for (const flag of enabled) {
assert.equal(createAutonomyEndpointContract({...client, enabled: (candidate) =>
candidate !== flag && enabled.has(candidate)}), null);
}
assert.equal(createAutonomyEndpointContract({...client, apiVersion: "hux.v0"}), null);
assert.throws(() => createAutonomyEndpointContract({...client,
identity: {...IDENTITY, userRef: "raw-email"}}), /identity/);
});