Files
HiveGrid-Wireframes/03 Quellen und Referenzen/hivegrid-cloud/scripts/verify-api-auth-surface.test.mjs
T

135 lines
4.9 KiB
JavaScript

import fs from "node:fs";
import os from "node:os";
import path from "node:path";
import assert from "node:assert/strict";
import { execFileSync } from "node:child_process";
import { afterEach, describe, it } from "vitest";
import { buildInventory, hasInventoryIntegrityFailure, renderText } from "./verify-api-auth-surface.mjs";
const fixtures = [];
function writeFile(rootDir, relativePath, content) {
const absolutePath = path.join(rootDir, relativePath);
fs.mkdirSync(path.dirname(absolutePath), { recursive: true });
fs.writeFileSync(absolutePath, content);
}
function createFixture() {
const rootDir = fs.mkdtempSync(path.join(os.tmpdir(), "api-auth-surface-"));
fixtures.push(rootDir);
return rootDir;
}
afterEach(() => {
while (fixtures.length > 0) {
fs.rmSync(fixtures.pop(), { recursive: true, force: true });
}
});
describe("verify-api-auth-surface", () => {
it("builds stable JSON inventory for apiService imports and callsites", async () => {
const rootDir = createFixture();
writeFile(
rootDir,
"apps/api/src/entity-route.ts",
`import { validateApiKey } from "~/utils/services/apiService";
export async function loader({ request, params }) {
return validateApiKey(request, params);
}
`,
);
writeFile(
rootDir,
"apps/api/src/usage-route.ts",
`import { validateTenantApiKey, getEntityApiKeyFromRequest } from "~/utils/services/apiService";
export async function loader({ request, params }) {
await validateTenantApiKey(request, params);
return getEntityApiKeyFromRequest(request, params);
}
`,
);
writeFile(
rootDir,
"apps/api/src/relationships-route.ts",
`import { getRelationshipApiKeyFromRequest } from "~/utils/services/apiService";
export async function action({ request, params }) {
return getRelationshipApiKeyFromRequest(request, params);
}
`,
);
writeFile(
rootDir,
"apps/api/src/workflows-route.ts",
`import { getWorkflowApiKeyFromRequest } from "~/utils/services/apiService";
export async function action({ request, params }) {
return getWorkflowApiKeyFromRequest(request, params);
}
`,
);
const inventory = await buildInventory(rootDir);
assert.deepEqual(inventory.scannedFiles, [
"apps/api/src/entity-route.ts",
"apps/api/src/relationships-route.ts",
"apps/api/src/usage-route.ts",
"apps/api/src/workflows-route.ts",
]);
assert.deepEqual(inventory.scannedRoots, ["apps/api/src"]);
assert.deepEqual(inventory.missingRoots, ["apps/web/app/routes/internal/api"]);
assert.deepEqual(inventory.requiredMissingRoots, []);
assert.equal(hasInventoryIntegrityFailure(inventory), false);
assert.deepEqual(
inventory.directValidateApiKeyCallsites.map((entry) => `${entry.file}:${entry.line}:${entry.symbol}`),
["apps/api/src/entity-route.ts:3:validateApiKey"],
);
assert.deepEqual(
inventory.tenantValidateCallsites.map((entry) => `${entry.file}:${entry.line}:${entry.symbol}`),
["apps/api/src/usage-route.ts:3:validateTenantApiKey"],
);
assert.deepEqual(
inventory.entityResolverCallsites.map((entry) => `${entry.file}:${entry.line}:${entry.symbol}`),
["apps/api/src/usage-route.ts:4:getEntityApiKeyFromRequest"],
);
assert.deepEqual(
inventory.relationshipHelperCallsites.map((entry) => `${entry.file}:${entry.line}:${entry.symbol}`),
["apps/api/src/relationships-route.ts:3:getRelationshipApiKeyFromRequest"],
);
assert.deepEqual(
inventory.workflowHelperCallsites.map((entry) => `${entry.file}:${entry.line}:${entry.symbol}`),
["apps/api/src/workflows-route.ts:3:getWorkflowApiKeyFromRequest"],
);
assert.equal(inventory.apiServiceImports.length, 4);
assert.equal(inventory.centralResolverFile, "apps/web/app/utils/services/apiService.ts");
assert.doesNotThrow(() => JSON.parse(JSON.stringify(inventory)));
const text = renderText(inventory);
assert.match(text, /API Auth Surface API auth surface inventory/);
assert.match(text, /getRelationshipApiKeyFromRequest callsites/);
assert.match(text, /getWorkflowApiKeyFromRequest callsites/);
});
it("CLI exits 2 for unknown flags", () => {
const scriptPath = path.resolve("scripts/verify-api-auth-surface.mjs");
assert.throws(
() => execFileSync(process.execPath, [scriptPath, "--bogus"], { encoding: "utf8", stdio: "pipe" }),
(error) => {
assert.equal(error.status, 2);
assert.match(error.stderr, /Unknown flag: --bogus/);
return true;
},
);
});
it("marks missing required API source roots as inventory failures", async () => {
const rootDir = createFixture();
const inventory = await buildInventory(rootDir);
assert.deepEqual(inventory.scannedFiles, []);
assert.deepEqual(inventory.requiredMissingRoots, ["apps/api/src"]);
assert.equal(hasInventoryIntegrityFailure(inventory), true);
});
});