diff --git a/extensions/reef/src/flow.test.ts b/extensions/reef/src/flow.test.ts index 82ce3e2232da..968a58dda40e 100644 --- a/extensions/reef/src/flow.test.ts +++ b/extensions/reef/src/flow.test.ts @@ -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(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 () => { diff --git a/extensions/reef/src/flow.ts b/extensions/reef/src/flow.ts index aa0f9e53e2e4..07f26722b902 100644 --- a/extensions/reef/src/flow.ts +++ b/extensions/reef/src/flow.ts @@ -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,