fix(reef): prevent blank guard keys from denying every message (#109667)

* fix(reef): reject blank guard credentials

* fix(reef): type fetch mock in guard credential test

Co-authored-by: Cursor <cursoragent@cursor.com>

* refactor: normalize Reef guard credentials canonically

Co-authored-by: ZengWen-DT <ceng.wen@xydigit.com>

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
This commit is contained in:
Wynne668
2026-07-17 10:19:21 +01:00
committed by GitHub
co-authored by Cursor Peter Steinberger
parent 0471b293bb
commit 708d2020d8
2 changed files with 36 additions and 5 deletions
+32 -2
View File
@@ -9,7 +9,7 @@ import {
verifyReceipt,
type Verdict,
} from "../protocol/index.js";
import { ReefMessageFlow } from "./flow.js";
import { createConfiguredGuard, ReefMessageFlow } from "./flow.js";
import {
allow,
config,
@@ -26,7 +26,37 @@ import type { ReefTransportClient } from "./transport.js";
import type { InboxEntry } from "./types.js";
beforeEach(resetFlowStoresForTests);
afterEach(resetFlowStoresForTests);
afterEach(() => {
vi.unstubAllEnvs();
resetFlowStoresForTests();
});
describe("createConfiguredGuard", () => {
it("rejects a whitespace-only guard credential", () => {
vi.stubEnv("REEF_TEST_KEY", " ");
expect(() => createConfiguredGuard(config())).toThrow(
"Reef guard credential environment variable REEF_TEST_KEY is unset",
);
});
it("trims a configured guard credential before requests", async () => {
vi.stubEnv("REEF_TEST_KEY", " guard-key ");
const fetcher = vi.fn<typeof fetch>(async () => new Response("", { status: 401 }));
const classifier = createConfiguredGuard(config(), fetcher);
await classifier.classify({
direction: "outbound",
source: "alice#1",
destination: "bob#1",
text: "hello",
policyVersion: "v1",
});
const init = fetcher.mock.calls[0]?.[1];
expect(new Headers(init?.headers).get("authorization")).toBe("Bearer guard-key");
});
});
describe("ReefMessageFlow inbound", () => {
it("delivers and persists before ack, then acks duplicate redelivery without delivering twice", async () => {
+4 -3
View File
@@ -1,3 +1,4 @@
import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
import {
appendAudit,
appendInboxRead,
@@ -449,14 +450,14 @@ export function createConfiguredGuard(
if (!config.guard) {
throw new Error("Reef guard is not configured");
}
const apiKey = process.env[config.guard.apiKeyEnv];
if (!apiKey) {
const guardCredential = normalizeOptionalString(process.env[config.guard.apiKeyEnv]);
if (!guardCredential) {
throw new Error(
`Reef guard credential environment variable ${config.guard.apiKeyEnv} is unset`,
);
}
const options = {
apiKey,
apiKey: guardCredential,
pinnedModel: config.guard.pinnedModel,
timeoutMs: config.guard.timeoutMs,
fetch: fetcher,