import assert from "node:assert/strict"; import test from "node:test"; import { expiredLeafCertificate, unknownLocalAuthority, } from "../fixtures/tls.js"; import { createUserDecisionPlugin } from "../plugins/demo-plugins.js"; import { createPolicyOverlayPlugin } from "../plugins/policy-overlay-plugin.js"; import { TrustPolicyOverlay, TrustRunner } from "../src/index.js"; test("authority decision becomes a scoped overlay rule used on retry", async () => { const userPlugin = createUserDecisionPlugin(true, { target: "authority", lifetime: "session", }); const first = await evaluateWith(userPlugin, "decision-authority"); assert.equal(first.verdict.scope.kind, "authority-for-host"); assert.equal( first.verdict.scope.authorityCertificateSha256, "ca-village-services", ); const overlay = new TrustPolicyOverlay(); overlay.remember(first.verdict, { pluginId: userPlugin.manifest.id, pluginName: userPlugin.manifest.name, }); const retry = await evaluateWith( createPolicyOverlayPlugin(overlay), "decision-authority", ); assert.equal(retry.verdict.trusted, true); assert.ok( retry.journal.entries.some( (entry) => entry.code === "local-policy-rule-matched", ), ); assert.equal(overlay.snapshot().rules.length, 1); }); test("authority decision binds the explicitly selected CA certificate", async () => { const unknownAuthorityFacts = structuredClone(expiredLeafCertificate); unknownAuthorityFacts.connectionId = "connection-selected-unknown-authority"; unknownAuthorityFacts.errors = ["unknown-issuer"]; unknownAuthorityFacts.failure = { code: "unknown-issuer", certificateSha256: "ca-village-public", check: "trust-anchor", summary: "The selected authority is not locally trusted.", }; const plugin = createUserDecisionPlugin(true, { target: "authority", authorityCertificateSha256: "ca-village-public", lifetime: "session", }); const result = await new TrustRunner({ plugins: [{ plugin, mode: "decision-authority" }], }).evaluate(unknownAuthorityFacts); assert.equal(result.verdict.scope.kind, "authority-for-host"); assert.equal( result.verdict.scope.authorityCertificateSha256, "ca-village-public", ); }); test("authority trust cannot override an expired leaf certificate", async () => { const plugin = createUserDecisionPlugin(true, { target: "authority", authorityCertificateSha256: "ca-village-public", lifetime: "session", }); const result = await new TrustRunner({ plugins: [{ plugin, mode: "decision-authority" }], }).evaluate(expiredLeafCertificate); assert.equal(result.verdict.trusted, false); assert.match( result.journal.entries.at(-1).message, /trust-anchor errors only/, ); }); test("connection-lifetime rule is consumed by exactly one retry", async () => { const userPlugin = createUserDecisionPlugin(true, { target: "certificate", lifetime: "connection", }); const first = await evaluateWith(userPlugin, "decision-authority"); const overlay = new TrustPolicyOverlay(); overlay.remember(first.verdict, { pluginId: userPlugin.manifest.id }); const policyPlugin = createPolicyOverlayPlugin(overlay); const accepted = await evaluateWith(policyPlugin, "decision-authority"); const rejected = await evaluateWith(policyPlugin, "decision-authority"); assert.equal(accepted.verdict.trusted, true); assert.equal(rejected.verdict.trusted, false); assert.equal(overlay.snapshot().rules.length, 0); assert.equal(overlay.snapshot().history.length, 1); }); test("local distrust takes precedence over a matching trust rule", () => { const overlay = new TrustPolicyOverlay(); const scope = { kind: "certificate-for-host", hostname: unknownLocalAuthority.hostname, port: unknownLocalAuthority.port, certificateSha256: unknownLocalAuthority.presentedChain[0].sha256, }; overlay.remember({ trusted: true, scope, lifetime: { kind: "session" }, reasonEntryIds: [], overriddenErrors: [...unknownLocalAuthority.errors], }); overlay.remember({ trusted: false, scope, lifetime: { kind: "session" }, reasonEntryIds: [], overriddenErrors: [], }); assert.equal(overlay.match(unknownLocalAuthority).trusted, false); }); test("authority scope cannot target the leaf certificate", async () => { const maliciousPlugin = { manifest: manifest("test.non-ca-authority", ["decision-authority"]), hooks: { async onTlsFailure({ facts }) { return { trusted: true, scope: { kind: "authority-for-host", hostname: facts.hostname, port: "any", authorityCertificateSha256: facts.presentedChain[0].sha256, includeSubdomains: false, }, lifetime: { kind: "session" }, reasonEntryIds: [], overriddenErrors: [...facts.errors], }; }, }, }; const result = await evaluateWith(maliciousPlugin, "decision-authority"); assert.equal(result.verdict.trusted, false); assert.match(result.journal.entries.at(-1).message, /non-CA certificate/); }); test("authority scope requires keyCertSign usage", async () => { const brokenAuthorityFacts = structuredClone(unknownLocalAuthority); for (const chain of [ brokenAuthorityFacts.presentedChain, brokenAuthorityFacts.constructedChain, ]) { const authority = chain.find( (certificate) => certificate.sha256 === "ca-village-services", ); authority.keyUsages = ["crlSign"]; } const plugin = { manifest: manifest("test.non-signing-authority", ["decision-authority"]), hooks: { async onTlsFailure({ facts }) { return { trusted: true, scope: { kind: "authority-for-host", hostname: facts.hostname, port: "any", authorityCertificateSha256: "ca-village-services", includeSubdomains: false, }, lifetime: { kind: "session" }, reasonEntryIds: [], overriddenErrors: [...facts.errors], }; }, }, }; const result = await new TrustRunner({ plugins: [{ plugin, mode: "decision-authority" }], }).evaluate(brokenAuthorityFacts); assert.equal(result.verdict.trusted, false); assert.match(result.journal.entries.at(-1).message, /without keyCertSign/); }); function evaluateWith(plugin, mode) { return new TrustRunner({ plugins: [{ plugin, mode }] }).evaluate( unknownLocalAuthority, ); } function manifest(id, supportedModes) { return { manifestVersion: 1, trustApiVersion: "0.1", id, name: id, version: "0.0.0", supportedModes, capabilities: {}, }; }