Files
jhonny-editor/bm/premiere-pro-mcp-main/tests/uxp/workspace.test.ts
T
João Henrique b541f502ba feat: initial commit - Jhonny Editor
- Adicionado estrutura completa do projeto
- Configurado MCP server para Premiere Pro
- Adicionado documentação e skills
- Configurado Gitignore para o projeto
2026-09-08 09:59:31 -04:00

124 lines
6.6 KiB
TypeScript
Executable File

import { createRequire } from "node:module";
import { readFileSync } from "node:fs";
import { join } from "node:path";
import { describe, expect, it, vi } from "vitest";
const require = createRequire(import.meta.url);
const Workspace = require("../../uxp-plugin/workspace.cjs");
function storageFixture() {
const files = new Map<string, string>();
const dataFolder = {
getEntry: vi.fn(async (name: string) => {
if (!files.has(name)) throw new Error("missing");
return {
read: vi.fn(async () => files.get(name)),
delete: vi.fn(async () => { files.delete(name); return 0; }),
};
}),
createFile: vi.fn(async (name: string) => ({
write: vi.fn(async (value: string) => { files.set(name, value); }),
})),
};
const root = { isFolder: true, name: "Approved Media", nativePath: "D:\\Projects\\Film" };
const fs = {
getDataFolder: vi.fn(async () => dataFolder),
getFolder: vi.fn(async () => root),
createPersistentToken: vi.fn(async () => "persistent-capability-token"),
getEntryForPersistentToken: vi.fn(async () => root),
};
const resolveCanonicalPath = vi.fn(async (value: string) => value);
return { fs, files, resolveCanonicalPath };
}
describe("least-privilege UXP workspace broker", () => {
it("uses Adobe's compatible manifest permission while retaining a loopback runtime boundary", () => {
const manifest = JSON.parse(readFileSync(join(process.cwd(), "uxp-plugin", "manifest.json"), "utf8"));
expect(manifest.requiredPermissions.network.domains).toBe("all");
expect(Workspace.validateLoopbackBridgeUrl("ws://127.0.0.1:7777/uxp").hostname).toBe("127.0.0.1");
expect(() => Workspace.validateLoopbackBridgeUrl("ws://example.com:7777/uxp")).toThrow("Bridge URL must");
});
it("normalizes absolute paths without allowing root traversal", () => {
expect(Workspace.parseAbsolutePath("D:\\Projects\\Film\\media\\..\\clip.mov", "path")).toMatchObject({
normalized: "D:/Projects/Film/clip.mov",
kind: "windows",
});
expect(Workspace.isContained("D:\\Projects\\Film", "d:/projects/film/clip.mov", false)).toBe(true);
expect(Workspace.isContained("D:\\Projects\\Film", "D:/Projects/Filmography/clip.mov", false)).toBe(false);
expect(Workspace.parseAbsolutePath("/Projects/Film\\Archive/clip.mov", "path")).toMatchObject({
normalized: "/Projects/Film\\Archive/clip.mov",
kind: "posix",
});
expect(Workspace.isContained("/Projects/Film\\Archive", "/Projects/Film/Archive/clip.mov", false)).toBe(false);
expect(() => Workspace.parseAbsolutePath("D:/../Windows/system.ini", "path")).toThrow("escapes");
expect(() => Workspace.parseAbsolutePath("D:/Projects/Film/NUL", "path")).toThrow("Windows-ambiguous");
expect(() => Workspace.parseAbsolutePath("D:/Projects/Film/clip.mov:stream", "path")).toThrow("Windows-ambiguous");
expect(Workspace.parseAbsolutePath("/Volumes/Film/ clip .mov ", "path").normalized)
.toBe("/Volumes/Film/ clip .mov ");
});
it("accepts only the manifest's exact loopback WebSocket endpoint", () => {
expect(Workspace.validateLoopbackBridgeUrl("ws://127.0.0.1:7777/uxp?ignored=true").toString())
.toBe("ws://127.0.0.1:7777/uxp");
expect(Workspace.validateLoopbackBridgeUrl("ws://localhost:9000/uxp").hostname).toBe("localhost");
expect(() => Workspace.validateLoopbackBridgeUrl("wss://example.com/uxp")).toThrow("Bridge URL must");
expect(() => Workspace.validateLoopbackBridgeUrl("ws://localhost.evil/uxp")).toThrow("Bridge URL must");
expect(() => Workspace.validateLoopbackBridgeUrl("ws://localhost:7777/other")).toThrow("Bridge URL must");
});
it("persists only the opaque token and never discloses the native root", async () => {
const fixture = storageFixture();
const broker = Workspace.createWorkspaceBroker({ fs: fixture.fs, resolveCanonicalPath: fixture.resolveCanonicalPath });
await expect(broker.requestRoot()).resolves.toEqual({
configured: true,
accessMode: "request",
rootName: "Approved Media",
persistent: true,
pathDisclosure: "redacted",
canonicalPathValidation: "available",
});
expect(JSON.parse(fixture.files.get("workspace-access.json") ?? "{}")).toEqual({
schemaVersion: 1,
persistentToken: "persistent-capability-token",
});
await expect(broker.assertPathAllowed("D:\\Projects\\Film\\exports\\edit.aaf", { label: "output", kind: "file" }))
.resolves.toBe("D:/Projects/Film/exports/edit.aaf");
await expect(broker.assertPathAllowed("D:\\Projects\\Other\\edit.aaf", { label: "output", kind: "file" }))
.rejects.toMatchObject({ code: "UXP_PATH_OUTSIDE_WORKSPACE" });
});
it("rejects canonical link targets outside the approved workspace and fails closed without a resolver", async () => {
const fixture = storageFixture();
fixture.resolveCanonicalPath.mockImplementation(async (value: string) =>
value.includes("linked") ? "D:/Secrets/outside.mov" : value);
const broker = Workspace.createWorkspaceBroker({ fs: fixture.fs, resolveCanonicalPath: fixture.resolveCanonicalPath });
await broker.requestRoot();
await expect(broker.assertPathAllowed("D:/Projects/Film/linked/outside.mov", { label: "media", kind: "file" }))
.rejects.toMatchObject({ code: "UXP_PATH_OUTSIDE_WORKSPACE" });
const unavailable = Workspace.createWorkspaceBroker({ fs: fixture.fs });
await unavailable.requestRoot();
await expect(unavailable.assertPathAllowed("D:/Projects/Film/media.mov", { label: "media", kind: "file" }))
.rejects.toMatchObject({ code: "UXP_CANONICAL_PATH_UNAVAILABLE" });
});
it("restores and revokes a persisted folder capability", async () => {
const fixture = storageFixture();
const first = Workspace.createWorkspaceBroker({ fs: fixture.fs });
await first.requestRoot();
const restored = Workspace.createWorkspaceBroker({ fs: fixture.fs });
await expect(restored.initialize()).resolves.toMatchObject({ configured: true, rootName: "Approved Media" });
expect(fixture.fs.getEntryForPersistentToken).toHaveBeenCalledWith("persistent-capability-token");
await expect(restored.revoke()).resolves.toMatchObject({ configured: false, persistent: false });
expect(fixture.files.has("workspace-access.json")).toBe(false);
});
it("rejects filesystem-root grants as broader than a project workspace", async () => {
const fixture = storageFixture();
fixture.fs.getFolder.mockResolvedValueOnce({ isFolder: true, name: "Drive", nativePath: "D:\\" });
const broker = Workspace.createWorkspaceBroker({ fs: fixture.fs });
await expect(broker.requestRoot()).rejects.toMatchObject({ code: "UXP_WORKSPACE_TOO_BROAD" });
expect(fixture.files.size).toBe(0);
});
});