mirror of
https://github.com/mvschwarz/openrig.git
synced 2026-11-07 22:58:42 -10:00
test(testbed): read-bearer helper + pin the negative control (dev-planner's auth-leg alignment)
dev-planner's adapter caught a real read-side asymmetry: the guarded routers are gated by the TERMINAL token (server.ts:632 passes deps.terminalBearerToken into transportRoutes), while publishedDaemonEnv sets the AUTH token. They coincide under this procedure ONLY because index.ts:160 copies auth -> terminal when the bind is not trusted — i.e. exactly the 0.0.0.0 bind we mandate. So a direct curl with Authorization: Bearer works as-is, but a host-side rig read needs the token under OPENRIG_TERMINAL_BEARER_TOKEN. Adds TERMINAL_BEARER_ENV + rigReadEnv(token, baseUrl) so both consumers use one helper instead of hand-assembling env, and documents the coupling where it can be read. WHY THE NEGATIVE CONTROL IS NOW PINNED: when the terminal token is null the middleware passes everything through (auth-bearer-token.ts:98-101) — the route is UNGUARDED. If the bind were ever softened back to loopback while keeping a bearer, terminalBearerToken would stay null, the guarded probe would answer without auth, and an auth-probe-only runbook would report a green proving nothing. The negative control is the assertion that the guard is armed at all, so the parity suite now fails if the runbook ever loses it. Co-Authored-By: Claude Fable 5 <[email protected]>
This commit is contained in:
1 parent
2b07b3180e
commit
ce803b3075
2 files changed
+57
No files matched your search
@@ -44,6 +44,30 @@ export const BIND_VALUE = "0.0.0.0";
|
||||
/** Env carrying the bearer the bind guard requires (auth-bearer-token.ts:240). */
|
||||
export const BEARER_ENV = "OPENRIG_AUTH_BEARER_TOKEN";
|
||||
|
||||
/**
|
||||
* Env a host-side `rig` READ needs to reach a guarded route (client.ts's
|
||||
* terminal-token resolution). DISTINCT FROM `BEARER_ENV` — and the difference is
|
||||
* load-bearing:
|
||||
*
|
||||
* The guarded routers are gated by the TERMINAL token
|
||||
* (`server.ts:632` passes `deps.terminalBearerToken` into `transportRoutes`), not
|
||||
* the auth token. Those are separate values in general. They coincide HERE only
|
||||
* because `index.ts:160` copies auth -> terminal when the bind is NOT trusted
|
||||
* (loopback/tailscale short-circuit) — i.e. exactly the `0.0.0.0` bind this
|
||||
* procedure mandates. So under this procedure ONE token value serves both, and:
|
||||
* • a DIRECT curl carrying `Authorization: Bearer <token>` works as-is;
|
||||
* • a host-side `rig` read needs the token under THIS env name.
|
||||
*
|
||||
* WHY THE NEGATIVE CONTROL IS NOT OPTIONAL: when the terminal token is null the
|
||||
* middleware PASSES EVERYTHING THROUGH (`auth-bearer-token.ts:98-101`) — an
|
||||
* unguarded route. If the bind were ever softened to loopback while keeping a
|
||||
* bearer, `terminalBearerToken` would stay null, the guarded probe would answer
|
||||
* without auth, and an auth-probe-only runbook would report a green that proves
|
||||
* nothing. The negative control (same call, NO header, MUST be 401) is what
|
||||
* detects that state — it is the assertion that the guard is armed at all.
|
||||
*/
|
||||
export const TERMINAL_BEARER_ENV = "OPENRIG_TERMINAL_BEARER_TOKEN";
|
||||
|
||||
/** Unauthenticated reachability probe. */
|
||||
export const HEALTH_PATH = "/healthz";
|
||||
|
||||
@@ -80,3 +104,18 @@ export function publishedDaemonEnv(bearerToken: string): Record<string, string>
|
||||
export function publishedDaemonEnvFlags(bearerToken: string): string[] {
|
||||
return Object.entries(publishedDaemonEnv(bearerToken)).flatMap(([k, v]) => ["-e", `${k}=${v}`]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Env for a host-side `rig` read against the published daemon: the terminal
|
||||
* token (see TERMINAL_BEARER_ENV) plus the daemon URL the read should target.
|
||||
* Use this instead of hand-assembling env in each consumer.
|
||||
*/
|
||||
export function rigReadEnv(bearerToken: string, baseUrl: string): Record<string, string> {
|
||||
if (!bearerToken) {
|
||||
throw new Error(
|
||||
"testbed rig-read: a non-empty token is required — a guarded route answers 401 without it, " +
|
||||
"and a NULL terminal token would leave the route unguarded entirely (see TERMINAL_BEARER_ENV).",
|
||||
);
|
||||
}
|
||||
return { [TERMINAL_BEARER_ENV]: bearerToken, OPENRIG_URL: baseUrl };
|
||||
}
|
||||
@@ -8,6 +8,7 @@ import { resolve } from "node:path";
|
||||
import {
|
||||
BIND_ENV, BIND_VALUE, BEARER_ENV, L3_HOST_PORT, CONTAINER_PORT,
|
||||
HEALTH_PATH, GUARDED_PROBE_PATH, publishArg, publishedDaemonEnv,
|
||||
TERMINAL_BEARER_ENV, rigReadEnv,
|
||||
} from "./helpers/testbed-published-daemon.js";
|
||||
|
||||
const RUNBOOK = readFileSync(
|
||||
@@ -33,6 +34,23 @@ describe("published-daemon procedure — module/runbook parity", () => {
|
||||
expect(() => publishArg(0)).toThrow(/explicit positive integer/);
|
||||
});
|
||||
|
||||
it("rig READS carry the TERMINAL token env — distinct name, same value under this procedure", () => {
|
||||
expect(TERMINAL_BEARER_ENV).toBe("OPENRIG_TERMINAL_BEARER_TOKEN");
|
||||
expect(TERMINAL_BEARER_ENV).not.toBe(BEARER_ENV); // separate concepts; coincide only via the non-trusted-bind copy
|
||||
expect(rigReadEnv("t", "http://127.0.0.1:19433")).toEqual({
|
||||
[TERMINAL_BEARER_ENV]: "t",
|
||||
OPENRIG_URL: "http://127.0.0.1:19433",
|
||||
});
|
||||
expect(() => rigReadEnv("", "http://x")).toThrow(/non-empty token/);
|
||||
});
|
||||
|
||||
it("the runbook keeps the NEGATIVE CONTROL — the only assertion that the guard is armed", () => {
|
||||
// A null terminal token leaves the guarded route wide open (middleware passes
|
||||
// through), so an auth-probe-only runbook could go green while proving nothing.
|
||||
expect(RUNBOOK).toMatch(/NEGATIVE CONTROL/i);
|
||||
expect(RUNBOOK).toMatch(/401/);
|
||||
});
|
||||
|
||||
it("the env helper refuses an empty bearer — the guard is satisfied, never weakened", () => {
|
||||
expect(publishedDaemonEnv("t")).toEqual({ [BIND_ENV]: BIND_VALUE, [BEARER_ENV]: "t" });
|
||||
expect(() => publishedDaemonEnv("")).toThrow(/REFUSES a non-loopback bind/);
|
||||
|
||||
Reference in new issue
Block a user