mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-10 04:52:43 +00:00
Gateway: add SecretRef support for gateway.auth.token with auth-mode guardrails (#35094)
This commit is contained in:
@@ -8,6 +8,7 @@ const detectBrowserOpenSupportMock = vi.hoisted(() => vi.fn());
|
||||
const openUrlMock = vi.hoisted(() => vi.fn());
|
||||
const formatControlUiSshHintMock = vi.hoisted(() => vi.fn());
|
||||
const copyToClipboardMock = vi.hoisted(() => vi.fn());
|
||||
const resolveSecretRefValuesMock = vi.hoisted(() => vi.fn());
|
||||
|
||||
vi.mock("../config/config.js", () => ({
|
||||
readConfigFileSnapshot: readConfigFileSnapshotMock,
|
||||
@@ -25,6 +26,10 @@ vi.mock("../infra/clipboard.js", () => ({
|
||||
copyToClipboard: copyToClipboardMock,
|
||||
}));
|
||||
|
||||
vi.mock("../secrets/resolve.js", () => ({
|
||||
resolveSecretRefValues: resolveSecretRefValuesMock,
|
||||
}));
|
||||
|
||||
const runtime = {
|
||||
log: vi.fn(),
|
||||
error: vi.fn(),
|
||||
@@ -37,7 +42,7 @@ function resetRuntime() {
|
||||
runtime.exit.mockClear();
|
||||
}
|
||||
|
||||
function mockSnapshot(token = "abc") {
|
||||
function mockSnapshot(token: unknown = "abc") {
|
||||
readConfigFileSnapshotMock.mockResolvedValue({
|
||||
path: "/tmp/openclaw.json",
|
||||
exists: true,
|
||||
@@ -53,6 +58,7 @@ function mockSnapshot(token = "abc") {
|
||||
httpUrl: "http://127.0.0.1:18789/",
|
||||
wsUrl: "ws://127.0.0.1:18789",
|
||||
});
|
||||
resolveSecretRefValuesMock.mockReset();
|
||||
}
|
||||
|
||||
describe("dashboardCommand", () => {
|
||||
@@ -65,6 +71,8 @@ describe("dashboardCommand", () => {
|
||||
openUrlMock.mockClear();
|
||||
formatControlUiSshHintMock.mockClear();
|
||||
copyToClipboardMock.mockClear();
|
||||
delete process.env.OPENCLAW_GATEWAY_TOKEN;
|
||||
delete process.env.CLAWDBOT_GATEWAY_TOKEN;
|
||||
});
|
||||
|
||||
it("opens and copies the dashboard link by default", async () => {
|
||||
@@ -115,4 +123,71 @@ describe("dashboardCommand", () => {
|
||||
"Browser launch disabled (--no-open). Use the URL above.",
|
||||
);
|
||||
});
|
||||
|
||||
it("prints non-tokenized URL with guidance when token SecretRef is unresolved", async () => {
|
||||
mockSnapshot({
|
||||
source: "env",
|
||||
provider: "default",
|
||||
id: "MISSING_GATEWAY_TOKEN",
|
||||
});
|
||||
copyToClipboardMock.mockResolvedValue(true);
|
||||
detectBrowserOpenSupportMock.mockResolvedValue({ ok: true });
|
||||
openUrlMock.mockResolvedValue(true);
|
||||
resolveSecretRefValuesMock.mockRejectedValue(new Error("missing env var"));
|
||||
|
||||
await dashboardCommand(runtime);
|
||||
|
||||
expect(copyToClipboardMock).toHaveBeenCalledWith("http://127.0.0.1:18789/");
|
||||
expect(runtime.log).toHaveBeenCalledWith(
|
||||
expect.stringContaining("Token auto-auth unavailable"),
|
||||
);
|
||||
expect(runtime.log).toHaveBeenCalledWith(
|
||||
expect.stringContaining(
|
||||
"gateway.auth.token SecretRef is unresolved (env:default:MISSING_GATEWAY_TOKEN).",
|
||||
),
|
||||
);
|
||||
expect(runtime.log).not.toHaveBeenCalledWith(expect.stringContaining("missing env var"));
|
||||
});
|
||||
|
||||
it("keeps URL non-tokenized when token SecretRef is unresolved but env fallback exists", async () => {
|
||||
mockSnapshot({
|
||||
source: "env",
|
||||
provider: "default",
|
||||
id: "MISSING_GATEWAY_TOKEN",
|
||||
});
|
||||
process.env.OPENCLAW_GATEWAY_TOKEN = "fallback-token";
|
||||
copyToClipboardMock.mockResolvedValue(true);
|
||||
detectBrowserOpenSupportMock.mockResolvedValue({ ok: true });
|
||||
openUrlMock.mockResolvedValue(true);
|
||||
resolveSecretRefValuesMock.mockRejectedValue(new Error("missing env var"));
|
||||
|
||||
await dashboardCommand(runtime);
|
||||
|
||||
expect(copyToClipboardMock).toHaveBeenCalledWith("http://127.0.0.1:18789/");
|
||||
expect(openUrlMock).toHaveBeenCalledWith("http://127.0.0.1:18789/");
|
||||
expect(runtime.log).toHaveBeenCalledWith(
|
||||
expect.stringContaining("Token auto-auth is disabled for SecretRef-managed"),
|
||||
);
|
||||
expect(runtime.log).not.toHaveBeenCalledWith(
|
||||
expect.stringContaining("Token auto-auth unavailable"),
|
||||
);
|
||||
});
|
||||
|
||||
it("resolves env-template gateway.auth.token before building dashboard URL", async () => {
|
||||
mockSnapshot("${CUSTOM_GATEWAY_TOKEN}");
|
||||
copyToClipboardMock.mockResolvedValue(true);
|
||||
detectBrowserOpenSupportMock.mockResolvedValue({ ok: true });
|
||||
openUrlMock.mockResolvedValue(true);
|
||||
resolveSecretRefValuesMock.mockResolvedValue(
|
||||
new Map([["env:default:CUSTOM_GATEWAY_TOKEN", "resolved-secret-token"]]),
|
||||
);
|
||||
|
||||
await dashboardCommand(runtime);
|
||||
|
||||
expect(copyToClipboardMock).toHaveBeenCalledWith("http://127.0.0.1:18789/");
|
||||
expect(openUrlMock).toHaveBeenCalledWith("http://127.0.0.1:18789/");
|
||||
expect(runtime.log).toHaveBeenCalledWith(
|
||||
expect.stringContaining("Token auto-auth is disabled for SecretRef-managed"),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user