44 lines
2.2 KiB
TypeScript
44 lines
2.2 KiB
TypeScript
import { createServer } from "node:http";
|
|
import { mkdtempSync, writeFileSync, rmSync } from "node:fs";
|
|
import { tmpdir } from "node:os";
|
|
import { join } from "node:path";
|
|
import { expect, it } from "vitest";
|
|
import { probeBootstrapDependencies } from "../src/catalog/bootstrap-probes.js";
|
|
import { probePublicEvidenceUrl } from "../src/catalog/evidence-probe-http.js";
|
|
|
|
it("refuses loopback literals and DNS answers before sending an Evidence GET", async () => {
|
|
for (const hostname of ["[::1]", "127.0.0.1", "localhost", "[::ffff:127.0.0.1]"]) {
|
|
await expect(probePublicEvidenceUrl(new URL(`http://${hostname}/private`))).rejects.toThrow("Evidence network policy refused");
|
|
}
|
|
});
|
|
|
|
it("authenticates a bounded read-only REST probe and blocks unavailable credentials/services", async () => {
|
|
const directory = mkdtempSync(join(tmpdir(), "tht-probe-"));
|
|
const secret = join(directory, "key");
|
|
writeFileSync(secret, "PRIVATE_SENTINEL", { mode: 0o600 });
|
|
let status = 200;
|
|
const requests: string[] = [];
|
|
const server = createServer((req, res) => {
|
|
requests.push(`${req.method} ${req.url}`);
|
|
res.writeHead(req.headers.authorization === "Bearer PRIVATE_SENTINEL" ? status : 401);
|
|
res.end("PRIVATE_SERVER_RESPONSE");
|
|
});
|
|
await new Promise<void>((resolve) => server.listen(0, "127.0.0.1", resolve));
|
|
const address = server.address() as { port: number };
|
|
const document = { schemaVersion: 1, databases: [{ workspaceId: "demo", engine: "postgres", databaseName: "demo", schema: "public", binding: { transport: "rest_api", baseUrl: `http://127.0.0.1:${address.port}`, restPath: "/health", restAuth: "bearer" }, secretFiles: { apiKey: secret } }] };
|
|
try {
|
|
expect((await probeBootstrapDependencies(document)).ok).toBe(true);
|
|
status = 503;
|
|
const failed = await probeBootstrapDependencies(document);
|
|
expect(failed.ok).toBe(false);
|
|
expect(JSON.stringify(failed)).not.toContain("PRIVATE");
|
|
status = 200;
|
|
writeFileSync(secret, "rotated-but-invalid");
|
|
expect((await probeBootstrapDependencies(document)).ok).toBe(false);
|
|
expect(requests).toEqual(["GET /health", "GET /health", "GET /health"]);
|
|
} finally {
|
|
await new Promise<void>((resolve) => server.close(() => resolve()));
|
|
rmSync(directory, { recursive: true });
|
|
}
|
|
});
|