refactor: trim v2 hardening scaffolding
This commit is contained in:
1 parent
ecfb9d59e0
commit
2eb0baf17e
75 files changed
+334
-2067
No files matched your search
@@ -4,16 +4,13 @@ import { beforeEach, describe, expect, test, vi } from "vitest";
|
||||
|
||||
const mocks = vi.hoisted(() => ({
|
||||
auth: vi.fn(),
|
||||
env: { CUSTOM_WIDGETS_ENABLED: true },
|
||||
}));
|
||||
|
||||
vi.mock("@homarr/auth/next", () => ({ auth: mocks.auth }));
|
||||
vi.mock("~/env", () => ({ env: mocks.env }));
|
||||
|
||||
import { requireCustomWidgetAdmin } from "./admin";
|
||||
|
||||
beforeEach(() => {
|
||||
mocks.env.CUSTOM_WIDGETS_ENABLED = true;
|
||||
mocks.auth.mockResolvedValue({ user: { permissions: ["admin"] } });
|
||||
});
|
||||
|
||||
@@ -30,11 +27,4 @@ describe("Custom Widget HTTP resource access", () => {
|
||||
const response = await requireCustomWidgetAdmin();
|
||||
expect(response?.status).toBe(403);
|
||||
});
|
||||
|
||||
test("returns an unavailable response when the emergency switch is off", async () => {
|
||||
mocks.env.CUSTOM_WIDGETS_ENABLED = false;
|
||||
const response = await requireCustomWidgetAdmin();
|
||||
expect(response?.status).toBe(503);
|
||||
await expect(response?.json()).resolves.toMatchObject({ error: expect.stringContaining("temporarily disabled") });
|
||||
});
|
||||
});
|
||||
@@ -2,18 +2,10 @@ import { NextResponse } from "next/server";
|
||||
|
||||
import { auth } from "@homarr/auth/next";
|
||||
|
||||
import { env } from "~/env";
|
||||
|
||||
export const requireCustomWidgetAdmin = async (): Promise<NextResponse | null> => {
|
||||
const session = await auth();
|
||||
if (!session?.user.permissions.includes("admin")) {
|
||||
return NextResponse.json({ error: "Administrator access is required." }, { status: 403 });
|
||||
}
|
||||
if (env.CUSTOM_WIDGETS_ENABLED === false) {
|
||||
return NextResponse.json(
|
||||
{ error: "Custom Widgets are temporarily disabled by the server administrator." },
|
||||
{ status: 503 },
|
||||
);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
@@ -7,7 +7,6 @@ const mocks = vi.hoisted(() => ({
|
||||
rateLimitAddress: vi.fn(() => "127.0.0.1"),
|
||||
toolProcedure: vi.fn(),
|
||||
loggerWarn: vi.fn(),
|
||||
env: { CUSTOM_WIDGETS_ENABLED: true, WORKSHOP_ENABLED: true },
|
||||
buildPrompt: vi.fn((request?: string, documentationUrl?: string) =>
|
||||
[`Request: ${request ?? ""}`, `Documentation: ${documentationUrl ?? ""}`].join("\n"),
|
||||
),
|
||||
@@ -39,7 +38,6 @@ vi.mock("@homarr/custom-widgets/core", () => ({
|
||||
getCustomWidgetJsonSchema: () => ({ type: "object", title: "Custom Widget" }),
|
||||
}));
|
||||
vi.mock("@homarr/db", () => ({ db: {} }));
|
||||
vi.mock("~/env", () => ({ env: mocks.env }));
|
||||
vi.mock("~/versions/package-reader", () => ({ getPackageVersion: () => "test-version" }));
|
||||
vi.mock("../_extract-tools", () => ({
|
||||
extractMcpTools: () => [
|
||||
@@ -75,8 +73,6 @@ interface JsonRpcResponse {
|
||||
|
||||
beforeEach(() => {
|
||||
mocks.authenticate.mockResolvedValue({ user: { id: "user-1", permissions: ["admin"] } });
|
||||
mocks.env.CUSTOM_WIDGETS_ENABLED = true;
|
||||
mocks.env.WORKSHOP_ENABLED = true;
|
||||
mocks.buildPrompt.mockClear();
|
||||
mocks.getComponent.mockClear();
|
||||
mocks.rateLimitAddress.mockClear();
|
||||
@@ -242,27 +238,6 @@ describe("non-admin MCP discovery", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("MCP emergency switches", () => {
|
||||
test("removes Custom Widget authoring discovery when Custom Widgets are disabled", async () => {
|
||||
mocks.env.CUSTOM_WIDGETS_ENABLED = false;
|
||||
expect((await callMcp("prompts/list")).body.result).toEqual({ prompts: [] });
|
||||
expect((await callMcp("resources/list")).body.result).toEqual({ resources: [] });
|
||||
const tools = await callMcp("tools/list");
|
||||
expect(((tools.body.result?.tools ?? []) as Array<{ name: string }>).map(({ name }) => name)).toEqual([
|
||||
"board_getAllBoards",
|
||||
]);
|
||||
});
|
||||
|
||||
test("removes only Workshop tools when Workshop is disabled", async () => {
|
||||
mocks.env.WORKSHOP_ENABLED = false;
|
||||
const tools = await callMcp("tools/list");
|
||||
expect(((tools.body.result?.tools ?? []) as Array<{ name: string }>).map(({ name }) => name)).toEqual([
|
||||
"board_getAllBoards",
|
||||
"customWidget_list",
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("MCP protocol errors", () => {
|
||||
test.each([
|
||||
["prompts/get", { name: "unknown" }],
|
||||
|
||||
@@ -27,7 +27,6 @@ import {
|
||||
import { customJsxExamples, getCustomWidgetJsonSchema } from "@homarr/custom-widgets/core";
|
||||
import { db } from "@homarr/db";
|
||||
|
||||
import { env } from "~/env";
|
||||
import { getPackageVersion } from "~/versions/package-reader";
|
||||
import { extractMcpTools } from "../_extract-tools";
|
||||
|
||||
@@ -124,17 +123,14 @@ function getVisibleTools() {
|
||||
if (!isCustomWidgetMcpEnabled()) {
|
||||
return tools.filter((tool) => !tool.name.startsWith("customWidget_"));
|
||||
}
|
||||
return env.WORKSHOP_ENABLED === false
|
||||
? tools.filter((tool) => !tool.name.startsWith("customWidget_workshop"))
|
||||
: tools;
|
||||
return tools;
|
||||
}
|
||||
|
||||
function requireCustomWidgetMcpAdmin() {
|
||||
if (!isCustomWidgetMcpEnabled()) throw new Error("Resource not found");
|
||||
}
|
||||
|
||||
const isCustomWidgetMcpEnabled = () =>
|
||||
Boolean(callerStorage.getStore()?.isAdmin) && env.CUSTOM_WIDGETS_ENABLED !== false;
|
||||
const isCustomWidgetMcpEnabled = () => Boolean(callerStorage.getStore()?.isAdmin);
|
||||
|
||||
const SAFE_ERROR_MESSAGES: Record<string, string> = {
|
||||
UNAUTHORIZED: "You do not have permission to perform this action",
|
||||
|
||||
Reference in new issue
Block a user