One bus: the runtime pins the certificate after the server speaks, and the old transport goes

Every module that dialled the new bus failed its handshake with "wrong version
number": the runtime pinned the server's certificate by a raw TLS connection to a
port on which the server speaks first, in the clear. The pin is taken after the
INFO line now, on the same socket, and then the real connection verifies against
exactly that certificate.

And the old transport is deleted — its client, its tests, its dependency — with
the wire-compatibility pins that only existed for the move (novox/hq ADR 0131,
design 28 task 5.5). A credential names the bus, and there is one.
This commit is contained in:
2026-09-28 03:08:59 +02:00
parent cd26131c61
commit f0104b7846
9 changed files with 110 additions and 697 deletions
+3 -6
View File
@@ -1,6 +1,6 @@
import { test } from "node:test";
import assert from "node:assert/strict";
import { fatalBrokerReason, PinMismatchError } from "../src/broker-amqp.ts";
import { fatalBrokerReason, PinMismatchError } from "../src/broker-nats.ts";
// novox/hq issue 058 (and its review): serve mode retries a broker that is not up yet, but must
// give up at once on a failure waiting cannot fix — otherwise a permanent fault loops for ever
@@ -31,11 +31,8 @@ test("a malformed broker URL is fatal — it never parses on the next try", () =
});
test("a refused login is fatal — a wrong or revoked credential, not an absent broker", () => {
for (const msg of [
"Handshake terminated by server: 403 (ACCESS-REFUSED) with message \"ACCESS_REFUSED - Login was refused\"",
"Login was refused using authentication mechanism PLAIN",
"ACCESS_REFUSED",
]) {
// The bus refuses a login in its own words; each is final, because the next try says the same.
for (const msg of ["Authorization Violation", "nats: user authentication expired", "Permissions Violation for Subscription to \"x\""]) {
assert.notEqual(fatalBrokerReason(new Error(msg)), null, `should be fatal: ${msg}`);
}
});