feat(webui): govern actions, quick access, and metrics
Refs #264, #285, #289
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import type { AuthInfo } from "../src/types";
|
||||
import type { AuthInfo, QuickAccessResult } from "../src/types";
|
||||
import {
|
||||
createQuickAccessLaunchContext,
|
||||
isQuickAccessResultAllowed,
|
||||
quickAccessLaunchContextFromState,
|
||||
quickAccessLaunchState,
|
||||
quickAccessReturnPath
|
||||
@@ -57,15 +58,21 @@ const context = createQuickAccessLaunchContext({
|
||||
locked: false,
|
||||
availableViews: [],
|
||||
provenance: [],
|
||||
diagnostics: []
|
||||
diagnostics: [],
|
||||
presentation: {
|
||||
quickAccessRecommendedToolIds: ["mail.messages"],
|
||||
quickAccessFocusedToolIds: ["mail.messages", "files.recent"]
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
assert(context.contractVersion === "1", "launch context must be explicitly versioned");
|
||||
assert(context.contractVersion === "2", "launch context must be explicitly versioned");
|
||||
assert(context.referenceContractVersion === "1", "reference payloads must be independently versioned");
|
||||
assert(context.activeObject?.objectId === "case-1", "active object reference must survive launch");
|
||||
assert(context.actingContext?.assignmentId === "assignment-1", "acting assignment must survive launch");
|
||||
assert(context.temporalContext.validityMode === "at", "temporal selection must survive launch");
|
||||
assert(context.viewContext?.revisionId === "view-revision-3", "exact View revision must survive launch");
|
||||
assert(context.viewContext?.recommendedToolIds[0] === "mail.messages", "View recommendations must survive launch without becoming authority");
|
||||
assert(
|
||||
quickAccessReturnPath(context) === "/cases/case-1?tab=history#revision-4",
|
||||
"return path must preserve route, query and fragment"
|
||||
@@ -75,7 +82,7 @@ assert(
|
||||
"router state must decode a valid launch context"
|
||||
);
|
||||
assert(
|
||||
quickAccessLaunchContextFromState({ govoplanQuickAccessLaunch: { contractVersion: "2" } }) === null,
|
||||
quickAccessLaunchContextFromState({ govoplanQuickAccessLaunch: { contractVersion: "3" } }) === null,
|
||||
"unknown launch context versions must fail closed"
|
||||
);
|
||||
|
||||
@@ -86,3 +93,56 @@ const crossTenant = createQuickAccessLaunchContext({
|
||||
temporalContext: { validityMode: "current", validAt: null, recordedAt: null }
|
||||
});
|
||||
assert(crossTenant.activeObject === null, "cross-tenant object references must be discarded");
|
||||
|
||||
const selectedFileResult = {
|
||||
contractVersion: "1",
|
||||
outcome: "completed",
|
||||
action: "selected",
|
||||
reference: {
|
||||
ownerModule: "files",
|
||||
kind: "file-version",
|
||||
objectId: "version-1",
|
||||
tenantId: "tenant-1",
|
||||
label: "Permit evidence.pdf",
|
||||
path: "/files?version=version-1"
|
||||
}
|
||||
} as const;
|
||||
assert(
|
||||
isQuickAccessResultAllowed(selectedFileResult, context, ["files.file-version"]),
|
||||
"a declared same-tenant result reference is accepted"
|
||||
);
|
||||
assert(
|
||||
!isQuickAccessResultAllowed(
|
||||
{ ...selectedFileResult, reference: { ...selectedFileResult.reference, tenantId: "tenant-2" } },
|
||||
context,
|
||||
["files.file-version"]
|
||||
),
|
||||
"cross-tenant result references fail closed"
|
||||
);
|
||||
assert(
|
||||
!isQuickAccessResultAllowed(selectedFileResult, context, ["records.record"]),
|
||||
"undeclared result-reference kinds fail closed"
|
||||
);
|
||||
assert(
|
||||
isQuickAccessResultAllowed({ contractVersion: "1", outcome: "cancelled", reason: "user" }, context),
|
||||
"explicit cancellation is a valid terminal result"
|
||||
);
|
||||
assert(
|
||||
!isQuickAccessResultAllowed(
|
||||
{ ...selectedFileResult, outcome: "unknown" } as unknown as QuickAccessResult,
|
||||
context,
|
||||
["files.file-version"]
|
||||
),
|
||||
"unknown result outcomes fail closed"
|
||||
);
|
||||
assert(
|
||||
!isQuickAccessResultAllowed(
|
||||
{
|
||||
...selectedFileResult,
|
||||
reference: { ...selectedFileResult.reference, path: "//outside.example/files/version-1" }
|
||||
},
|
||||
context,
|
||||
["files.file-version"]
|
||||
),
|
||||
"protocol-relative result paths fail closed"
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user