feat(auth): include authentication in workspace and tht diagnostics

This commit is contained in:
2026-08-17 15:51:16 +02:00
parent cb0e873ed7
commit 3ed00ff086
19 changed files with 1050 additions and 34 deletions
+55 -1
View File
@@ -10,6 +10,7 @@ import { createProductionWorkspaceDiagnoser } from "../src/workspaces/diagnostic
import { WorkspaceRegistry, type WorkspaceRevision } from "../src/workspaces/registry.js";
import { serializeWorkspaceYaml, type CanonicalWorkspace } from "../src/workspaces/schema.js";
import { WorkspaceSecretStore } from "../src/workspaces/secret-store.js";
import type { AuthDiagnoser, AuthDiagnostics } from "../src/auth/diagnostics.js";
const workspace: CanonicalWorkspace = {
workspace: {
@@ -70,11 +71,18 @@ function registryFake(overrides: Partial<RegistryFake> = {}): RegistryFake {
};
}
const readyAuthentication: AuthDiagnostics = {
ready: true,
mode: "none",
checks: [{ level: "info", code: "auth_ready", message: "Authentication is ready." }],
};
function appFor(
registry: RegistryFake,
diagnose = vi.fn(async () => ({ activatable: true, diagnostics: [] })),
secretStore = testSecretStore(),
env: Record<string, string> = {},
authDiagnoser: AuthDiagnoser = { inspect: vi.fn(async () => readyAuthentication) },
) {
return buildApp(loadConfig({
THT_HARNESS_DIR: "/missing-harness",
@@ -85,6 +93,7 @@ function appFor(
workspaceRegistry: registry as WorkspaceRegistry,
workspaceDiagnoser: diagnose,
workspaceSecretStore: secretStore,
authDiagnoser,
} as any);
}
@@ -196,6 +205,51 @@ test("validates a schema v3 workspace without mutating the repository", async ()
expect(response.json()).toMatchObject({ workspace });
});
test("aggregates one static and one live authentication report without reordering connector diagnostics", async () => {
const connectorDiagnostics = [{
level: "info" as const,
code: "binding_ok" as const,
message: "Installation bindings and diagnostics succeeded.",
}];
const diagnose = vi.fn(async () => ({ activatable: true, diagnostics: connectorDiagnostics }));
const authentication: AuthDiagnostics = {
ready: false,
mode: "oidc",
checks: [{
level: "error",
code: "oidc_mapped_group_missing",
field: "Thoth Administrators",
message: "A configured authorization group does not exist.",
}],
};
const authDiagnoser: AuthDiagnoser = { inspect: vi.fn(async () => authentication) };
const app = appFor(registryFake(), diagnose, testSecretStore(), {}, authDiagnoser);
const validation = await app.inject({
method: "POST", url: "/workspaces/validate", payload: { workspace },
});
const connection = await app.inject({
method: "POST", url: "/workspaces/psd-clinical/test", payload: {},
});
expect(validation.statusCode).toBe(200);
expect(validation.json()).toMatchObject({
workspace,
activatable: false,
diagnostics: [],
authentication,
});
expect(connection.statusCode).toBe(200);
expect(connection.json()).toEqual({
activatable: false,
diagnostics: connectorDiagnostics,
authentication,
});
expect(diagnose).toHaveBeenCalledTimes(1);
expect(authDiagnoser.inspect).toHaveBeenNthCalledWith(1, { live: false });
expect(authDiagnoser.inspect).toHaveBeenNthCalledWith(2, { live: true });
});
test.each([1, 2])("rejects schema v%s at the validation boundary with a sanitized error", async (version) => {
const legacy = {
...workspace,
@@ -219,7 +273,7 @@ test("runs diagnostics for a schema v3 workspace", async () => {
});
expect(response.statusCode).toBe(200);
expect(response.json()).toEqual({ activatable: true, diagnostics: [] });
expect(response.json()).toEqual({ activatable: true, diagnostics: [], authentication: readyAuthentication });
expect(diagnose).toHaveBeenCalledWith(workspace, {
dwh: expect.objectContaining({ transport: "postgres_direct" }),
evidence: { missing: [], values: {} },