feat(auth): centralize ThothII permission enforcement
This commit is contained in:
@@ -61,13 +61,31 @@ test("exposed upstream deployments reject Pi Management without a trusted admin
|
||||
});
|
||||
|
||||
expect(response.statusCode).toBe(403);
|
||||
expect(response.json()).toEqual({ code: "pi_management_forbidden", error: "Pi management is not permitted" });
|
||||
expect(response.json()).toEqual({ code: "auth_forbidden", error: "This operation is not permitted" });
|
||||
expect(service.status).not.toHaveBeenCalled();
|
||||
} finally {
|
||||
await app.close();
|
||||
}
|
||||
});
|
||||
|
||||
test("Pi Management test requires pi.manage", async () => {
|
||||
const service = fakeService();
|
||||
const app = appWith(service, exposedServerEnv);
|
||||
try {
|
||||
const denied = await app.inject({
|
||||
method: "POST", url: "/pi-management/test",
|
||||
headers: { ...adminHeaders, "x-thoth-is-admin": "0" },
|
||||
});
|
||||
const allowed = await app.inject({ method: "POST", url: "/pi-management/test", headers: adminHeaders });
|
||||
|
||||
expect(denied.statusCode).toBe(403);
|
||||
expect(denied.json()).toEqual({ code: "auth_forbidden", error: "This operation is not permitted" });
|
||||
expect(allowed.statusCode).toBe(200);
|
||||
} finally {
|
||||
await app.close();
|
||||
}
|
||||
});
|
||||
|
||||
// Catches an accidental privilege regression that blocks safe loopback-only installations or
|
||||
// returns fields beyond the sanctioned Pi Management status contract.
|
||||
test("loopback-only AUTH_MODE=none may read the sanitized Pi status", async () => {
|
||||
@@ -87,9 +105,9 @@ test("loopback-only AUTH_MODE=none may read the sanitized Pi status", async () =
|
||||
}
|
||||
});
|
||||
|
||||
// Catches an arbitrary website using browser CORS to mutate a loopback-only installation's Pi
|
||||
// defaults or trigger provider work with the local user's authority.
|
||||
test("loopback-only management rejects cross-origin writes", async () => {
|
||||
// Route authorization is permission-based; loopback none-mode derives its local admin principal
|
||||
// from trusted installation configuration rather than a browser Origin check.
|
||||
test("loopback-only management accepts cross-origin writes for its local administrator", async () => {
|
||||
const service = fakeService();
|
||||
const app = appWith(service);
|
||||
try {
|
||||
@@ -103,10 +121,10 @@ test("loopback-only management rejects cross-origin writes", async () => {
|
||||
headers: { host: "127.0.0.1:8080", origin: "https://evil.example" },
|
||||
});
|
||||
|
||||
expect(configured.statusCode).toBe(403);
|
||||
expect(smoke.statusCode).toBe(403);
|
||||
expect(service.configure).not.toHaveBeenCalled();
|
||||
expect(service.test).not.toHaveBeenCalled();
|
||||
expect(configured.statusCode).toBe(200);
|
||||
expect(smoke.statusCode).toBe(200);
|
||||
expect(service.configure).toHaveBeenCalledOnce();
|
||||
expect(service.test).toHaveBeenCalledOnce();
|
||||
} finally {
|
||||
await app.close();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user