feat(auth): centralize ThothII permission enforcement
This commit is contained in:
@@ -74,10 +74,12 @@ function appFor(
|
||||
registry: RegistryFake,
|
||||
diagnose = vi.fn(async () => ({ activatable: true, diagnostics: [] })),
|
||||
secretStore = testSecretStore(),
|
||||
env: Record<string, string> = {},
|
||||
) {
|
||||
return buildApp(loadConfig({
|
||||
THT_HARNESS_DIR: "/missing-harness",
|
||||
THT_WORKSPACE_REGISTRY_ROOT: "/tmp/thoth-route-test-registry",
|
||||
...env,
|
||||
}), {
|
||||
thtRunner: {} as any,
|
||||
workspaceRegistry: registry as WorkspaceRegistry,
|
||||
@@ -86,6 +88,13 @@ function appFor(
|
||||
} as any);
|
||||
}
|
||||
|
||||
const userHeaders = {
|
||||
"x-thoth-principal-issuer": "portal",
|
||||
"x-thoth-principal-subject": "alice",
|
||||
"x-thoth-is-admin": "0",
|
||||
};
|
||||
const adminHeaders = { ...userHeaders, "x-thoth-principal-subject": "admin", "x-thoth-is-admin": "1" };
|
||||
|
||||
const secretStoreRoots: string[] = [];
|
||||
|
||||
function testSecretStore(): WorkspaceSecretStore {
|
||||
@@ -118,6 +127,37 @@ test("returns a redacted registry status and pulls without Git credential detail
|
||||
expect(registry.pull).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
test("workspace mutations and secret writes require their catalog permissions", async () => {
|
||||
const registry = registryFake();
|
||||
const app = appFor(registry, undefined, testSecretStore(), { AUTH_MODE: "upstream" });
|
||||
try {
|
||||
const deniedPull = await app.inject({ method: "POST", url: "/workspace-registry/pull", headers: userHeaders });
|
||||
const allowedPull = await app.inject({ method: "POST", url: "/workspace-registry/pull", headers: adminHeaders });
|
||||
const deniedBootstrap = await app.inject({ method: "GET", url: "/workspace-registry/status", headers: userHeaders });
|
||||
const allowedBootstrap = await app.inject({ method: "GET", url: "/workspace-registry/status", headers: adminHeaders });
|
||||
const deniedSecret = await app.inject({
|
||||
method: "PUT", url: "/workspaces/psd-clinical/secrets", headers: userHeaders,
|
||||
payload: { values: { "dwh.password": "secret" } },
|
||||
});
|
||||
const allowedSecret = await app.inject({
|
||||
method: "PUT", url: "/workspaces/psd-clinical/secrets", headers: adminHeaders,
|
||||
payload: { values: { "dwh.password": "secret" } },
|
||||
});
|
||||
|
||||
expect(deniedPull.statusCode).toBe(403);
|
||||
expect(deniedPull.json()).toEqual({ code: "auth_forbidden", error: "This operation is not permitted" });
|
||||
expect(allowedPull.statusCode).toBe(200);
|
||||
expect(deniedBootstrap.statusCode).toBe(403);
|
||||
expect(deniedBootstrap.json()).toEqual({ code: "auth_forbidden", error: "This operation is not permitted" });
|
||||
expect(allowedBootstrap.statusCode).toBe(200);
|
||||
expect(deniedSecret.statusCode).toBe(403);
|
||||
expect(deniedSecret.json()).toEqual({ code: "auth_forbidden", error: "This operation is not permitted" });
|
||||
expect(allowedSecret.statusCode).toBe(200);
|
||||
} finally {
|
||||
await app.close();
|
||||
}
|
||||
});
|
||||
|
||||
test.each([
|
||||
["POST", "/workspaces/publish"],
|
||||
["GET", "/workspaces/psd-clinical/export"],
|
||||
|
||||
Reference in New Issue
Block a user