forked from EduCraft/curriculum-project-hub
fix(hub): enable tenant Typst package resolution
This commit is contained in:
@@ -32,6 +32,8 @@ describe("agent subprocess security policy", () => {
|
||||
ALL_PROXY: "socks5h://127.0.0.1:7890",
|
||||
NO_PROXY: "127.0.0.1,localhost,::1",
|
||||
NODE_USE_ENV_PROXY: "1",
|
||||
TYPST_PACKAGE_PATH: "/srv/curriculum-project-hub/typst-packages/para-26071100",
|
||||
TYPST_PACKAGE_CACHE_PATH: "/srv/curriculum-project-hub/typst-packages/para-26071100",
|
||||
DATABASE_URL: "postgresql://platform-secret",
|
||||
FEISHU_APP_SECRET: "feishu-secret",
|
||||
HUB_SESSION_SECRET: "session-secret",
|
||||
@@ -44,6 +46,8 @@ describe("agent subprocess security policy", () => {
|
||||
PATH: "/usr/local/bin:/usr/bin:/bin",
|
||||
LANG: "C.UTF-8",
|
||||
CPH_BIN: "/usr/local/bin/cph",
|
||||
TYPST_PACKAGE_PATH: "/srv/curriculum-project-hub/typst-packages/para-26071100",
|
||||
TYPST_PACKAGE_CACHE_PATH: "/srv/curriculum-project-hub/typst-packages/para-26071100",
|
||||
ANTHROPIC_BASE_URL: "http://127.0.0.1:43123",
|
||||
ANTHROPIC_AUTH_TOKEN: "run-proxy-capability",
|
||||
ANTHROPIC_API_KEY: "",
|
||||
@@ -72,7 +76,10 @@ describe("agent subprocess security policy", () => {
|
||||
autoAllowBashIfSandboxed: true,
|
||||
allowUnsandboxedCommands: false,
|
||||
filesystem: {
|
||||
allowWrite: [canonicalWorkspace],
|
||||
allowWrite: expect.arrayContaining([
|
||||
canonicalWorkspace,
|
||||
"/srv/curriculum-project-hub/typst-packages/para-26071100",
|
||||
]),
|
||||
denyRead: ["/"],
|
||||
allowRead: expect.arrayContaining([canonicalWorkspace, "/usr/bin"]),
|
||||
},
|
||||
@@ -85,6 +92,59 @@ describe("agent subprocess security policy", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("passes configured Typst package roots and exposes them read-only to the sandbox", async () => {
|
||||
const { workspaceRoot, workspace } = await makeWorkspace();
|
||||
const packageRoot = "/srv/curriculum-project-hub/typst-packages/para-26071100";
|
||||
const cacheRoot = "/var/cache/cph-hub/para-26071100/typst";
|
||||
const policy = await createAgentSecurityPolicy({
|
||||
runId: "run-test",
|
||||
workspaceRoot,
|
||||
workspaceDir: workspace,
|
||||
hostEnv: {
|
||||
PATH: "/usr/bin:/bin",
|
||||
TYPST_PACKAGE_PATH: packageRoot,
|
||||
TYPST_PACKAGE_CACHE_PATH: cacheRoot,
|
||||
},
|
||||
});
|
||||
const canonicalWorkspace = await realpath(workspace);
|
||||
|
||||
expect(policy.env).toMatchObject({
|
||||
TYPST_PACKAGE_PATH: packageRoot,
|
||||
TYPST_PACKAGE_CACHE_PATH: cacheRoot,
|
||||
});
|
||||
expect(policy.sandbox.filesystem.allowRead).toEqual(expect.arrayContaining([packageRoot, cacheRoot]));
|
||||
expect(policy.sandbox.filesystem.allowWrite).toEqual(expect.arrayContaining([canonicalWorkspace, cacheRoot]));
|
||||
expect(policy.sandbox.filesystem.allowWrite).not.toContain(packageRoot);
|
||||
});
|
||||
|
||||
it("rejects a relative Typst package root instead of silently losing package access", async () => {
|
||||
const { workspaceRoot, workspace } = await makeWorkspace();
|
||||
|
||||
await expect(createAgentSecurityPolicy({
|
||||
runId: "run-test",
|
||||
workspaceRoot,
|
||||
workspaceDir: workspace,
|
||||
hostEnv: {
|
||||
PATH: "/usr/bin:/bin",
|
||||
TYPST_PACKAGE_PATH: "typst-packages",
|
||||
},
|
||||
})).rejects.toThrow("TYPST_PACKAGE_PATH must be absolute");
|
||||
});
|
||||
|
||||
it("rejects a Typst cache rooted at the filesystem root instead of widening writes", async () => {
|
||||
const { workspaceRoot, workspace } = await makeWorkspace();
|
||||
|
||||
await expect(createAgentSecurityPolicy({
|
||||
runId: "run-test",
|
||||
workspaceRoot,
|
||||
workspaceDir: workspace,
|
||||
hostEnv: {
|
||||
PATH: "/usr/bin:/bin",
|
||||
TYPST_PACKAGE_CACHE_PATH: "/",
|
||||
},
|
||||
})).rejects.toThrow("TYPST_PACKAGE_CACHE_PATH must not be the filesystem root");
|
||||
});
|
||||
|
||||
it("rejects provider environment keys outside the explicit protocol", async () => {
|
||||
const { workspaceRoot, workspace } = await makeWorkspace();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user