Initial Commit

This commit is contained in:
2026-05-27 23:29:53 +01:00
commit fbc70f96e6
10000 changed files with 1102152 additions and 0 deletions

View File

@@ -0,0 +1,184 @@
import { OpenAPIHono } from "@hono/zod-openapi";
import {
createOpenAPIRegistry,
definePluginRoutes,
} from "@suaveplan/api-openapi";
import type { Principal } from "@suaveplan/api-plugin-auth";
import { describe, expect, it } from "@suaveplan/testing/runner";
import { VAULT_PLUGIN_CODES } from "../../src/error-codes/error-codes.js";
import { defaultUnlockExtractor } from "../../src/plugin/unlock.js";
import { buildVaultRoutes } from "../../src/routes/build-routes.js";
import { createVaultService } from "../../src/services/vault-service.js";
import type { VaultPluginConfig } from "../../src/types/types.js";
import { createMemoryDrive } from "../setup/memory-drive.js";
const noopLogger = {
debug: () => undefined,
info: () => undefined,
warn: () => undefined,
error: () => undefined,
};
function buildApp(principal: Principal) {
const drive = createMemoryDrive();
const service = createVaultService({
storage: drive,
serverPepper: "test-pepper",
logger: noopLogger,
});
const config: VaultPluginConfig = {
storage: drive,
routePrefix: "/vault",
maxItemSizeBytes: 10 * 1024 * 1024,
applySchemaOnInit: false,
unlockExtractor: defaultUnlockExtractor,
serverPepper: "test-pepper",
};
const app = new OpenAPIHono();
app.use("*", async (c, next) => {
c.set("user", principal);
await next();
});
const registry = createOpenAPIRegistry({
info: { title: "t", version: "0.1" },
});
definePluginRoutes(buildVaultRoutes(service, config), {
app,
registry,
pluginName: "vault",
});
app.onError((err, c) => {
const status =
(err as { context?: { statusCode?: number } }).context
?.statusCode ?? 500;
return c.json(
{
success: false,
error: {
code: (err as { code?: string }).code ?? "X",
message: (err as Error).message,
timestamp: new Date().toISOString(),
},
},
status as 400 | 401 | 403 | 404 | 500
);
});
return { app, service, drive };
}
describe("cross-user-isolation", () => {
it("user A cannot see / modify user B's items", {
timeout: 120_000,
}, async () => {
const alice: Principal = {
id: "user:alice",
emailVerified: true,
roles: [],
};
const bob: Principal = {
id: "user:bob",
emailVerified: true,
roles: [],
};
// Alice's setup shares the drive with Bob's app — but each
// principal opens its own vault container.
const drive = createMemoryDrive();
function makeApp(principal: Principal) {
const service = createVaultService({
storage: drive,
serverPepper: "test-pepper",
logger: noopLogger,
});
const config: VaultPluginConfig = {
storage: drive,
routePrefix: "/vault",
maxItemSizeBytes: 10 * 1024 * 1024,
applySchemaOnInit: false,
unlockExtractor: defaultUnlockExtractor,
serverPepper: "test-pepper",
};
const app = new OpenAPIHono();
app.use("*", async (c, next) => {
c.set("user", principal);
await next();
});
const registry = createOpenAPIRegistry({
info: { title: "t", version: "0.1" },
});
definePluginRoutes(buildVaultRoutes(service, config), {
app,
registry,
pluginName: "vault",
});
app.onError((err, c) => {
const status =
(err as { context?: { statusCode?: number } }).context
?.statusCode ?? 500;
return c.json(
{
success: false,
error: {
code: (err as { code?: string }).code ?? "X",
message: (err as Error).message,
timestamp: new Date().toISOString(),
},
},
status as 400 | 401 | 403 | 404 | 500
);
});
return { app };
}
// Bob creates an item.
const bobApp = makeApp(bob).app;
const bobCreate = await bobApp.request("/vault/items", {
method: "POST",
headers: {
"X-Vault-Unlock": "BobPwd-2026",
"Content-Type": "application/json",
},
body: JSON.stringify({
title: "bob-secret",
kind: "credential",
body: "bob-content",
}),
});
expect(bobCreate.status).toBe(201);
const bobItem = (await bobCreate.json()) as {
data: { id: string };
};
// Alice tries to read Bob's item. Even though Alice supplies
// a valid X-Vault-Unlock header, her vault container is
// distinct from Bob's, so the lookup yields ITEM_NOT_FOUND.
const aliceApp = makeApp(alice).app;
const aliceRead = await aliceApp.request(
`/vault/items/${bobItem.data.id}`,
{
headers: { "X-Vault-Unlock": "AlicePwd-2026" },
}
);
expect(aliceRead.status).toBe(404);
const json = (await aliceRead.json()) as { error: { code: string } };
expect(json.error.code).toBe(VAULT_PLUGIN_CODES.ITEM_NOT_FOUND);
// Alice's own listing returns zero items.
const aliceList = await aliceApp.request("/vault/items", {
headers: { "X-Vault-Unlock": "AlicePwd-2026" },
});
const listJson = (await aliceList.json()) as {
meta: { total: number };
};
expect(listJson.meta.total).toBe(0);
});
it("makeApp helper is exported (sanity)", { timeout: 5000 }, () => {
const result = buildApp({
id: "x",
emailVerified: true,
roles: [],
});
expect(result.app).toBeDefined();
expect(result.service).toBeDefined();
});
});