Converge UI primitives and readiness guards

This commit is contained in:
rcourtman 2026-06-13 16:31:52 +01:00
parent 241ac9feaf
commit 09ed857869
28 changed files with 538 additions and 166 deletions

View file

@ -1,6 +1,7 @@
import fs from 'node:fs/promises';
import path from 'node:path';
import { spawn } from 'node:child_process';
import { randomBytes } from 'node:crypto';
import net from 'node:net';
import { withExclusiveLock } from '../../../scripts/exclusive-lock.mjs';
@ -155,6 +156,9 @@ export function buildManagedLocalBackendEnv(state, env = process.env) {
PULSE_PUBLIC_URL: state.baseURL,
PULSE_DATA_DIR: state.dataDir,
PULSE_AUDIT_DIR: state.dataDir,
PULSE_AUDIT_SIGNING_KEY: trim(env.PULSE_AUDIT_SIGNING_KEY)
|| trim(env.PULSE_E2E_AUDIT_SIGNING_KEY)
|| randomBytes(32).toString('hex'),
PULSE_METRICS_PORT: state.metricsPort,
PULSE_DEV: 'true',
PULSE_E2E_BILLING_STATE_PATH: state.billingStatePath,

View file

@ -71,6 +71,7 @@ test('buildManagedLocalBackendEnv seeds auth, bootstrap token, and billing path'
assert.equal(env.PULSE_DEV, 'true');
assert.equal(env.PULSE_DATA_DIR, state.dataDir);
assert.equal(env.PULSE_E2E_BILLING_STATE_PATH, state.billingStatePath);
assert.match(env.PULSE_AUDIT_SIGNING_KEY, /^[0-9a-f]{64}$/);
assert.equal(env.PULSE_E2E_BOOTSTRAP_TOKEN.length > 0, true);
assert.equal(env.PULSE_E2E_PRIMARY_API_TOKEN.length > 0, true);
assert.equal(env.PULSE_METRICS_PORT, '0');
@ -79,6 +80,28 @@ test('buildManagedLocalBackendEnv seeds auth, bootstrap token, and billing path'
assert.match(env.ALLOWED_ORIGINS, /5173/);
});
test('buildManagedLocalBackendEnv preserves explicit audit signing key', () => {
const state = buildManagedLocalBackendState({
PULSE_E2E_LOCAL_BACKEND_PORT: '9002',
});
const env = buildManagedLocalBackendEnv(state, {
PULSE_AUDIT_SIGNING_KEY: 'explicit-audit-key',
});
assert.equal(env.PULSE_AUDIT_SIGNING_KEY, 'explicit-audit-key');
});
test('buildManagedLocalBackendEnv accepts deterministic e2e audit signing key', () => {
const state = buildManagedLocalBackendState({
PULSE_E2E_LOCAL_BACKEND_PORT: '9002',
});
const env = buildManagedLocalBackendEnv(state, {
PULSE_E2E_AUDIT_SIGNING_KEY: 'e2e-audit-key',
});
assert.equal(env.PULSE_AUDIT_SIGNING_KEY, 'e2e-audit-key');
});
test('buildManagedLocalBackendEnv seeds deterministic auth in hosted mode', () => {
const state = buildManagedLocalBackendState({
PULSE_E2E_LOCAL_BACKEND_PORT: '9002',

View file

@ -1,5 +1,6 @@
import { test, expect } from "@playwright/test";
import { apiRequest, ensureAuthenticated } from "./helpers";
import { PATROL_ROUTE } from "./routes";
/**
* V6 License Activation E2E Test
@ -298,7 +299,7 @@ test.describe.serial("V6 license activation flow", () => {
).toBeVisible();
await expect(page.getByText(/Patrol quickstart/i)).toHaveCount(0);
await page.goto("/ai");
await page.goto(PATROL_ROUTE);
await expect(
page.getByRole("heading", { name: "Patrol" }).first(),
).toBeVisible();

View file

@ -4,6 +4,7 @@ import { fileURLToPath } from "node:url";
import { test as base, expect } from "@playwright/test";
import { createAuthenticatedStorageState } from "./helpers";
import { PATROL_ROUTE } from "./routes";
const __dirname = path.dirname(fileURLToPath(import.meta.url));
@ -321,7 +322,7 @@ test.describe("TrueNAS patrol finding links", () => {
});
});
await page.goto("/ai", { waitUntil: "domcontentloaded" });
await page.goto(PATROL_ROUTE, { waitUntil: "domcontentloaded" });
await expect(page.getByRole("button", { name: "Findings" })).toBeVisible();

View file

@ -4,6 +4,7 @@ import { fileURLToPath } from "node:url";
import { test as base, expect } from "@playwright/test";
import { createAuthenticatedStorageState } from "./helpers";
import { PATROL_ROUTE } from "./routes";
const __dirname = path.dirname(fileURLToPath(import.meta.url));
@ -252,7 +253,7 @@ test.describe("TrueNAS patrol run history", () => {
});
});
await page.goto("/ai", { waitUntil: "domcontentloaded" });
await page.goto(PATROL_ROUTE, { waitUntil: "domcontentloaded" });
await expect(page.getByRole("button", { name: "Findings" })).toBeVisible();
await page.getByRole("button", { name: "Runs" }).click();

View file

@ -1,6 +1,7 @@
import { expect, test, type Page } from "@playwright/test";
import { ensureAuthenticated } from "./helpers";
import { PATROL_ROUTE } from "./routes";
type AISettingsPayload = {
enabled: boolean;
@ -379,7 +380,7 @@ test.describe("Retired quickstart browser contract", () => {
},
});
await page.goto("/ai", { waitUntil: "domcontentloaded" });
await page.goto(PATROL_ROUTE, { waitUntil: "domcontentloaded" });
await expect(page.getByText("Patrol Paused").first()).toBeVisible();
await expect(

View file

@ -170,7 +170,7 @@ test.describe("Assistant & Patrol settings provider setup", () => {
expect(updateRequests[0]).not.toHaveProperty("model");
await expect(
page.getByText("Assistant & Patrol Model Overrides"),
page.getByRole("button", { name: "Model Overrides" }),
).toBeVisible();
const workloadDiscoveryToggle = page.getByRole("button", {
name: /workload discovery/i,
@ -179,10 +179,7 @@ test.describe("Assistant & Patrol settings provider setup", () => {
await workloadDiscoveryToggle.click();
await expect(page.getByText("Enable workload discovery")).toBeVisible();
await expect(
page.getByText(
"Workload discovery gives Pulse Assistant and Patrol concrete service context, so chat responses and verification findings can reference real services and commands instead of generic advice.",
{ exact: true },
),
page.getByRole("button", { name: "Run discovery now" }),
).toBeVisible();
await expect(
page.getByRole("button", { name: /enable assistant and patrol/i }),

View file

@ -86,9 +86,7 @@ test.describe.serial('Self-hosted paid prompt visibility', () => {
await page.goto('/settings/security-roles');
await expect(
page.getByRole('heading', { name: 'Infrastructure', exact: true }),
).toBeVisible();
await expect(page.getByRole('heading', { level: 1, name: 'Roles' })).toBeVisible();
await expect(page.getByText('Custom Roles (Pro)')).toHaveCount(0);
await expect(page.getByRole('button', { name: 'Remote Access' })).toHaveCount(0);
await expect(page.getByRole('button', { name: 'Roles' })).toHaveCount(0);

View file

@ -0,0 +1 @@
export const PATROL_ROUTE = "/patrol";