fix: enforce active organization boundary

This commit is contained in:
2026-07-10 18:42:12 +08:00
parent f07f280b8f
commit d730e51c3d
24 changed files with 1686 additions and 460 deletions
+6 -1
View File
@@ -250,7 +250,7 @@ function mockPrisma(): PrismaClient {
let lock: { projectId: string; runId: string } | null = null;
const session = { id: "session-1", metadata: {} };
return {
const client = {
feishuEventReceipt: {
findUnique: vi.fn(async () => null),
create: vi.fn(async () => ({ id: "receipt-1" })),
@@ -286,6 +286,11 @@ function mockPrisma(): PrismaClient {
create: vi.fn(async () => ({ id: "audit-1" })),
},
} as unknown as PrismaClient;
Object.assign(client, {
$transaction: vi.fn(async (callback: (tx: PrismaClient) => Promise<unknown>) => callback(client)),
$queryRaw: vi.fn(async () => [{ id: "org_test_default", status: "ACTIVE" }]),
});
return client;
}
function silentLogger(): FeishuRuntime["logger"] {
+39
View File
@@ -0,0 +1,39 @@
import { mkdir, mkdtemp, readdir, rm, symlink, writeFile } from "node:fs/promises";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { afterEach, describe, expect, it } from "vitest";
import { removeAbandonedMessageResourceStages } from "../../src/feishu/resourceStaging.js";
const roots: string[] = [];
describe("Feishu resource staging recovery", () => {
afterEach(async () => {
await Promise.all(roots.splice(0).map((root) => rm(root, { recursive: true, force: true })));
});
it("removes every abandoned batch during startup recovery", async () => {
const root = await tempRoot();
const batch = join(root, ".cph-staging", "abandoned-batch");
await mkdir(batch, { recursive: true });
await writeFile(join(batch, "resource-0"), "sensitive attachment");
await expect(removeAbandonedMessageResourceStages(root)).resolves.toBe(1);
await expect(readdir(join(root, ".cph-staging"))).resolves.toEqual([]);
});
it("refuses to traverse a staging-base symlink", async () => {
const root = await tempRoot();
const outside = await tempRoot();
await symlink(outside, join(root, ".cph-staging"));
await expect(removeAbandonedMessageResourceStages(root)).rejects.toThrow(
/staging base is not a real directory/,
);
});
});
async function tempRoot(): Promise<string> {
const root = await mkdtemp(join(tmpdir(), "cph-resource-staging-test-"));
roots.push(root);
return root;
}