b3a7f98e5a
CI / E2E Cloudflare (4/8) (push) Failing after 0s
CI / E2E Cloudflare (8/8) (push) Failing after 1s
CI / Lint (push) Failing after 1s
Auto Extract / Extract (push) Failing after 4s
CI / Version Check (push) Failing after 9s
CI / Integration Tests (push) Failing after 1s
CI / E2E tests (1/8) (push) Failing after 1s
CI / E2E tests (2/8) (push) Failing after 2s
CI / E2E tests (3/8) (push) Failing after 2s
CI / Browser Tests (push) Failing after 1s
CI / E2E tests (5/8) (push) Failing after 1s
CI / E2E Cloudflare (2/8) (push) Failing after 2s
CI / Typecheck (push) Failing after 1s
CI / Changeset Validation (push) Failing after 2s
CI / E2E Cloudflare (5/8) (push) Failing after 1s
CI / E2E Cloudflare (6/8) (push) Failing after 1s
CI / E2E Cloudflare (7/8) (push) Failing after 1s
CodeQL / Analyze (javascript-typescript) (push) Failing after 1s
Format / Format (push) Failing after 0s
CodeQL / Analyze (actions) (push) Failing after 4s
CI / E2E tests (4/8) (push) Failing after 1s
CI / E2E tests (6/8) (push) Failing after 1s
CI / E2E tests (7/8) (push) Failing after 2s
CI / E2E tests (8/8) (push) Failing after 1s
CI / E2E Cloudflare (1/8) (push) Failing after 1s
CI / E2E Cloudflare (3/8) (push) Failing after 2s
Preview Releases / Publish Preview (push) Failing after 0s
zizmor / Run zizmor (push) Failing after 1s
Release / Release (push) Failing after 2s
CI / Smoke Tests (push) Failing after 5m36s
CI / Tests (push) Failing after 6m36s
Release / Sync Templates (push) Has been skipped
CI / E2E Tests (push) Has been cancelled
78 lines
2.4 KiB
TypeScript
78 lines
2.4 KiB
TypeScript
/**
|
|
* Plugin admin list handler: a statically-sandboxed entry surfaces flagged
|
|
* sandboxed, and a configured plugin shadows a sandboxed entry with the same id.
|
|
*/
|
|
|
|
import type { Kysely } from "kysely";
|
|
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
|
|
|
import { handlePluginList } from "../../../src/api/handlers/plugins.js";
|
|
import type { Database } from "../../../src/database/types.js";
|
|
import type { SandboxedPluginEntry } from "../../../src/emdash-runtime.js";
|
|
import type { ResolvedPlugin } from "../../../src/plugins/types.js";
|
|
import { setupTestDatabase, teardownTestDatabase } from "../../utils/test-db.js";
|
|
|
|
function createTestPlugin(overrides: Partial<ResolvedPlugin> = {}): ResolvedPlugin {
|
|
return {
|
|
id: "trusted-plugin",
|
|
version: "1.0.0",
|
|
capabilities: [],
|
|
allowedHosts: [],
|
|
storage: {},
|
|
admin: { pages: [], widgets: [], fieldWidgets: {} },
|
|
hooks: {},
|
|
routes: {},
|
|
settings: undefined,
|
|
...overrides,
|
|
} as ResolvedPlugin;
|
|
}
|
|
|
|
function createSandboxedEntry(overrides: Partial<SandboxedPluginEntry> = {}): SandboxedPluginEntry {
|
|
return {
|
|
id: "sandboxed-plugin",
|
|
version: "2.1.0",
|
|
options: {},
|
|
code: "",
|
|
capabilities: ["read:content"],
|
|
allowedHosts: [],
|
|
storage: {},
|
|
adminPages: [{ path: "settings" }],
|
|
adminWidgets: [{ id: "status" }],
|
|
...overrides,
|
|
};
|
|
}
|
|
|
|
describe("plugin admin handlers: sandboxed plugins", () => {
|
|
let db: Kysely<Database>;
|
|
|
|
beforeEach(async () => {
|
|
db = await setupTestDatabase();
|
|
});
|
|
|
|
afterEach(async () => {
|
|
await teardownTestDatabase(db);
|
|
});
|
|
|
|
it("surfaces a sandboxed entry, and a configured plugin shadows one with the same id", async () => {
|
|
const result = await handlePluginList(
|
|
db,
|
|
[createTestPlugin({ id: "shared-id", version: "1.0.0" })],
|
|
[createSandboxedEntry({ id: "sandboxed-only" }), createSandboxedEntry({ id: "shared-id" })],
|
|
);
|
|
|
|
expect(result.success).toBe(true);
|
|
if (!result.success) return;
|
|
|
|
// A sandboxed-only entry surfaces, flagged.
|
|
const surfaced = result.data.items.filter((p) => p.id === "sandboxed-only");
|
|
expect(surfaced).toHaveLength(1);
|
|
expect(surfaced[0]).toMatchObject({ source: "config", sandboxed: true });
|
|
|
|
// A configured plugin with the same id wins; the sandboxed entry is not listed twice.
|
|
const shared = result.data.items.filter((p) => p.id === "shared-id");
|
|
expect(shared).toHaveLength(1);
|
|
expect(shared[0]?.version).toBe("1.0.0");
|
|
expect(shared[0]?.sandboxed).toBeUndefined();
|
|
});
|
|
});
|