fix(hub): enable tenant Typst package resolution

This commit is contained in:
2026-07-22 17:47:56 +08:00
parent 6462e42823
commit 36660f72d6
6 changed files with 156 additions and 45 deletions
+61 -1
View File
@@ -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();