Secrets: add inline allowlist review set (#38314)

* Secrets: add inline allowlist review set

* Secrets: narrow detect-secrets file exclusions

* Secrets: exclude Docker fingerprint false positive

* Secrets: allowlist test and docs false positives

* Secrets: refresh baseline after allowlist updates

* Secrets: fix gateway chat fixture pragma

* Secrets: format pre-commit config

* Android: keep talk mode fixture JSON valid

* Feishu: rely on client timeout injection

* Secrets: allowlist provider auth test fixtures

* Secrets: allowlist onboard search fixtures

* Secrets: allowlist onboard mode fixture

* Secrets: allowlist gateway auth mode fixture

* Secrets: allowlist APNS wake test key

* Secrets: allowlist gateway reload fixtures

* Secrets: allowlist moonshot video fixture

* Secrets: allowlist auto audio fixture

* Secrets: allowlist tiny audio fixture

* Secrets: allowlist embeddings fixtures

* Secrets: allowlist resolve fixtures

* Secrets: allowlist target registry pattern fixtures

* Secrets: allowlist gateway chat env fixture

* Secrets: refresh baseline after fixture allowlists

* Secrets: reapply gateway chat env allowlist

* Secrets: reapply gateway chat env allowlist

* Secrets: stabilize gateway chat env allowlist

* Secrets: allowlist runtime snapshot save fixture

* Secrets: allowlist oauth profile fixtures

* Secrets: allowlist compaction identifier fixture

* Secrets: allowlist model auth fixture

* Secrets: allowlist model status fixtures

* Secrets: allowlist custom onboarding fixture

* Secrets: allowlist mattermost token summary fixtures

* Secrets: allowlist gateway auth suite fixtures

* Secrets: allowlist channel summary fixture

* Secrets: allowlist provider usage auth fixtures

* Secrets: allowlist media proxy fixture

* Secrets: allowlist secrets audit fixtures

* Secrets: refresh baseline after final fixture allowlists

* Feishu: prefer explicit client timeout

* Feishu: test direct timeout precedence
This commit is contained in:
Vincent Koc
2026-03-06 19:35:26 -05:00
committed by GitHub
parent 3070fafec1
commit 42e3d8d693
80 changed files with 363 additions and 317 deletions

View File

@@ -20,7 +20,7 @@ import type { SecretInputMode } from "./onboard-types.js";
const ENV_SOURCE_LABEL_RE = /(?:^|:\s)([A-Z][A-Z0-9_]*)$/;
type SecretRefChoice = "env" | "provider";
type SecretRefChoice = "env" | "provider"; // pragma: allowlist secret
export type SecretInputModePromptCopy = {
modeMessage?: string;
@@ -101,7 +101,7 @@ export async function promptSecretRefForOnboarding(params: {
const defaultEnvVar =
params.preferredEnvVar ?? resolveDefaultProviderEnvVar(params.provider) ?? "";
const defaultFilePointer = resolveDefaultFilePointerId(params.provider);
let sourceChoice: SecretRefChoice = "env";
let sourceChoice: SecretRefChoice = "env"; // pragma: allowlist secret
while (true) {
const sourceRaw: SecretRefChoice = await params.prompter.select<SecretRefChoice>({

View File

@@ -9,14 +9,14 @@ const mocks = vi.hoisted(() => {
type: "oauth",
provider: "anthropic",
access: "sk-ant-oat01-ACCESS-TOKEN-1234567890",
refresh: "sk-ant-ort01-REFRESH-TOKEN-1234567890",
refresh: "sk-ant-ort01-REFRESH-TOKEN-1234567890", // pragma: allowlist secret
expires: Date.now() + 60_000,
email: "peter@example.com",
},
"anthropic:work": {
type: "api_key",
provider: "anthropic",
key: "sk-ant-api-0123456789abcdefghijklmnopqrstuvwxyz",
key: "sk-ant-api-0123456789abcdefghijklmnopqrstuvwxyz", // pragma: allowlist secret
},
"openai-codex:default": {
type: "oauth",
@@ -49,13 +49,13 @@ const mocks = vi.hoisted(() => {
resolveEnvApiKey: vi.fn((provider: string) => {
if (provider === "openai") {
return {
apiKey: "sk-openai-0123456789abcdefghijklmnopqrstuvwxyz",
apiKey: "sk-openai-0123456789abcdefghijklmnopqrstuvwxyz", // pragma: allowlist secret
source: "shell env: OPENAI_API_KEY",
};
}
if (provider === "anthropic") {
return {
apiKey: "sk-ant-oat01-ACCESS-TOKEN-1234567890",
apiKey: "sk-ant-oat01-ACCESS-TOKEN-1234567890", // pragma: allowlist secret
source: "env: ANTHROPIC_OAUTH_TOKEN",
};
}
@@ -231,7 +231,7 @@ describe("modelsStatusCommand auth overview", () => {
it("does not emit raw short api-key values in JSON labels", async () => {
const localRuntime = createRuntime();
const shortSecret = "abc123";
const shortSecret = "abc123"; // pragma: allowlist secret
const originalProfiles = { ...mocks.store.profiles };
mocks.store.profiles = {
...mocks.store.profiles,

View File

@@ -63,7 +63,8 @@ function resolveApiKeySecretInput(
if (inlineEnvRef) {
return inlineEnvRef;
}
if (options?.secretInputMode === "ref") {
const useSecretRefMode = options?.secretInputMode === "ref"; // pragma: allowlist secret
if (useSecretRefMode) {
return resolveProviderDefaultEnvSecretRef(provider);
}
return normalized;

View File

@@ -429,7 +429,7 @@ describe("parseNonInteractiveCustomApiFlags", () => {
baseUrl: "https://llm.example.com/v1",
modelId: "foo-large",
compatibility: "openai",
apiKey: "custom-test-key",
apiKey: "custom-test-key", // pragma: allowlist secret
providerId: "my-custom",
});
});

View File

@@ -184,7 +184,7 @@ describe("onboard (non-interactive): provider auth", () => {
await withOnboardEnv("openclaw-onboard-minimax-", async (env) => {
const cfg = await runOnboardingAndReadConfig(env, {
authChoice: "minimax-api",
minimaxApiKey: "sk-minimax-test",
minimaxApiKey: "sk-minimax-test", // pragma: allowlist secret
});
expect(cfg.auth?.profiles?.["minimax:default"]?.provider).toBe("minimax");
@@ -203,7 +203,7 @@ describe("onboard (non-interactive): provider auth", () => {
await withOnboardEnv("openclaw-onboard-minimax-cn-", async (env) => {
const cfg = await runOnboardingAndReadConfig(env, {
authChoice: "minimax-api-key-cn",
minimaxApiKey: "sk-minimax-test",
minimaxApiKey: "sk-minimax-test", // pragma: allowlist secret
});
expect(cfg.auth?.profiles?.["minimax-cn:default"]?.provider).toBe("minimax-cn");
@@ -222,7 +222,7 @@ describe("onboard (non-interactive): provider auth", () => {
await withOnboardEnv("openclaw-onboard-zai-", async (env) => {
const cfg = await runOnboardingAndReadConfig(env, {
authChoice: "zai-api-key",
zaiApiKey: "zai-test-key",
zaiApiKey: "zai-test-key", // pragma: allowlist secret
});
expect(cfg.auth?.profiles?.["zai:default"]?.provider).toBe("zai");
@@ -237,7 +237,7 @@ describe("onboard (non-interactive): provider auth", () => {
await withOnboardEnv("openclaw-onboard-zai-cn-", async (env) => {
const cfg = await runOnboardingAndReadConfig(env, {
authChoice: "zai-coding-cn",
zaiApiKey: "zai-test-key",
zaiApiKey: "zai-test-key", // pragma: allowlist secret
});
expect(cfg.models?.providers?.zai?.baseUrl).toBe(
@@ -264,7 +264,7 @@ describe("onboard (non-interactive): provider auth", () => {
it("infers Mistral auth choice from --mistral-api-key and sets default model", async () => {
await withOnboardEnv("openclaw-onboard-mistral-infer-", async (env) => {
const cfg = await runOnboardingAndReadConfig(env, {
mistralApiKey: "mistral-test-key",
mistralApiKey: "mistral-test-key", // pragma: allowlist secret
});
expect(cfg.auth?.profiles?.["mistral:default"]?.provider).toBe("mistral");
@@ -282,7 +282,7 @@ describe("onboard (non-interactive): provider auth", () => {
await withOnboardEnv("openclaw-onboard-volcengine-", async (env) => {
const cfg = await runOnboardingAndReadConfig(env, {
authChoice: "volcengine-api-key",
volcengineApiKey: "volcengine-test-key",
volcengineApiKey: "volcengine-test-key", // pragma: allowlist secret
});
expect(cfg.agents?.defaults?.model?.primary).toBe("volcengine-plan/ark-code-latest");
@@ -292,7 +292,7 @@ describe("onboard (non-interactive): provider auth", () => {
it("infers BytePlus auth choice from --byteplus-api-key and sets default model", async () => {
await withOnboardEnv("openclaw-onboard-byteplus-infer-", async (env) => {
const cfg = await runOnboardingAndReadConfig(env, {
byteplusApiKey: "byteplus-test-key",
byteplusApiKey: "byteplus-test-key", // pragma: allowlist secret
});
expect(cfg.agents?.defaults?.model?.primary).toBe("byteplus-plan/ark-code-latest");
@@ -303,7 +303,7 @@ describe("onboard (non-interactive): provider auth", () => {
await withOnboardEnv("openclaw-onboard-ai-gateway-", async (env) => {
const cfg = await runOnboardingAndReadConfig(env, {
authChoice: "ai-gateway-api-key",
aiGatewayApiKey: "gateway-test-key",
aiGatewayApiKey: "gateway-test-key", // pragma: allowlist secret
});
expect(cfg.auth?.profiles?.["vercel-ai-gateway:default"]?.provider).toBe("vercel-ai-gateway");
@@ -350,7 +350,7 @@ describe("onboard (non-interactive): provider auth", () => {
await withOnboardEnv("openclaw-onboard-openai-", async (env) => {
const cfg = await runOnboardingAndReadConfig(env, {
authChoice: "openai-api-key",
openaiApiKey: "sk-openai-test",
openaiApiKey: "sk-openai-test", // pragma: allowlist secret
});
expect(cfg.agents?.defaults?.model?.primary).toBe(OPENAI_DEFAULT_MODEL);
@@ -410,10 +410,10 @@ describe("onboard (non-interactive): provider auth", () => {
"fails fast for $name when --secret-input-mode ref uses explicit key without env and does not leak the key",
async ({ prefix, authChoice, optionKey, flagName, envVar }) => {
await withOnboardEnv(prefix, async ({ runtime }) => {
const providedSecret = `${envVar.toLowerCase()}-should-not-leak`;
const providedSecret = `${envVar.toLowerCase()}-should-not-leak`; // pragma: allowlist secret
const options: Record<string, unknown> = {
authChoice,
secretInputMode: "ref",
secretInputMode: "ref", // pragma: allowlist secret
[optionKey]: providedSecret,
skipSkills: true,
};
@@ -447,12 +447,12 @@ describe("onboard (non-interactive): provider auth", () => {
await withEnvAsync(
{
OPENCODE_API_KEY: undefined,
OPENCODE_ZEN_API_KEY: "opencode-zen-env-key",
OPENCODE_ZEN_API_KEY: "opencode-zen-env-key", // pragma: allowlist secret
},
async () => {
await runNonInteractiveOnboardingWithDefaults(runtime, {
authChoice: "opencode-zen",
secretInputMode: "ref",
secretInputMode: "ref", // pragma: allowlist secret
skipSkills: true,
});
@@ -487,7 +487,7 @@ describe("onboard (non-interactive): provider auth", () => {
await withOnboardEnv("openclaw-onboard-litellm-", async (env) => {
const cfg = await runOnboardingAndReadConfig(env, {
authChoice: "litellm-api-key",
litellmApiKey: "litellm-test-key",
litellmApiKey: "litellm-test-key", // pragma: allowlist secret
});
expect(cfg.auth?.profiles?.["litellm:default"]?.provider).toBe("litellm");
@@ -519,7 +519,7 @@ describe("onboard (non-interactive): provider auth", () => {
await runNonInteractiveOnboardingWithDefaults(runtime, {
cloudflareAiGatewayAccountId: "cf-account-id",
cloudflareAiGatewayGatewayId: "cf-gateway-id",
cloudflareAiGatewayApiKey: "cf-gateway-test-key",
cloudflareAiGatewayApiKey: "cf-gateway-test-key", // pragma: allowlist secret
skipSkills: true,
...options,
});
@@ -543,7 +543,7 @@ describe("onboard (non-interactive): provider auth", () => {
it("infers Together auth choice from --together-api-key and sets default model", async () => {
await withOnboardEnv("openclaw-onboard-together-infer-", async (env) => {
const cfg = await runOnboardingAndReadConfig(env, {
togetherApiKey: "together-test-key",
togetherApiKey: "together-test-key", // pragma: allowlist secret
});
expect(cfg.auth?.profiles?.["together:default"]?.provider).toBe("together");
@@ -560,7 +560,7 @@ describe("onboard (non-interactive): provider auth", () => {
it("infers QIANFAN auth choice from --qianfan-api-key and sets default model", async () => {
await withOnboardEnv("openclaw-onboard-qianfan-infer-", async (env) => {
const cfg = await runOnboardingAndReadConfig(env, {
qianfanApiKey: "qianfan-test-key",
qianfanApiKey: "qianfan-test-key", // pragma: allowlist secret
});
expect(cfg.auth?.profiles?.["qianfan:default"]?.provider).toBe("qianfan");
@@ -579,7 +579,7 @@ describe("onboard (non-interactive): provider auth", () => {
await runNonInteractiveOnboardingWithDefaults(runtime, {
authChoice: "custom-api-key",
customBaseUrl: "https://llm.example.com/v1",
customApiKey: "custom-test-key",
customApiKey: "custom-test-key", // pragma: allowlist secret
customModelId: "foo-large",
customCompatibility: "anthropic",
skipSkills: true,
@@ -603,7 +603,7 @@ describe("onboard (non-interactive): provider auth", () => {
await runNonInteractiveOnboardingWithDefaults(runtime, {
customBaseUrl: "https://models.custom.local/v1",
customModelId: "local-large",
customApiKey: "custom-test-key",
customApiKey: "custom-test-key", // pragma: allowlist secret
skipSkills: true,
});
@@ -624,7 +624,7 @@ describe("onboard (non-interactive): provider auth", () => {
await withOnboardEnv(
"openclaw-onboard-custom-provider-env-fallback-",
async ({ configPath, runtime }) => {
process.env.CUSTOM_API_KEY = "custom-env-key";
process.env.CUSTOM_API_KEY = "custom-env-key"; // pragma: allowlist secret
await runCustomLocalNonInteractive(runtime);
expect(await readCustomLocalProviderApiKey(configPath)).toBe("custom-env-key");
},
@@ -635,9 +635,9 @@ describe("onboard (non-interactive): provider auth", () => {
await withOnboardEnv(
"openclaw-onboard-custom-provider-env-ref-",
async ({ configPath, runtime }) => {
process.env.CUSTOM_API_KEY = "custom-env-key";
process.env.CUSTOM_API_KEY = "custom-env-key"; // pragma: allowlist secret
await runCustomLocalNonInteractive(runtime, {
secretInputMode: "ref",
secretInputMode: "ref", // pragma: allowlist secret
});
expect(await readCustomLocalProviderApiKeyInput(configPath)).toEqual({
source: "env",
@@ -650,12 +650,12 @@ describe("onboard (non-interactive): provider auth", () => {
it("fails fast for custom provider ref mode when --custom-api-key is set but CUSTOM_API_KEY env is missing", async () => {
await withOnboardEnv("openclaw-onboard-custom-provider-ref-flag-", async ({ runtime }) => {
const providedSecret = "custom-inline-key-should-not-leak";
const providedSecret = "custom-inline-key-should-not-leak"; // pragma: allowlist secret
await withEnvAsync({ CUSTOM_API_KEY: undefined }, async () => {
let thrown: Error | undefined;
try {
await runCustomLocalNonInteractive(runtime, {
secretInputMode: "ref",
secretInputMode: "ref", // pragma: allowlist secret
customApiKey: providedSecret,
});
} catch (error) {
@@ -731,7 +731,7 @@ describe("onboard (non-interactive): provider auth", () => {
async ({ runtime }) => {
await expect(
runNonInteractiveOnboardingWithDefaults(runtime, {
customApiKey: "custom-test-key",
customApiKey: "custom-test-key", // pragma: allowlist secret
skipSkills: true,
}),
).rejects.toThrow('Auth choice "custom-api-key" requires a base URL and model ID.');

View File

@@ -70,7 +70,8 @@ export async function resolveNonInteractiveApiKey(params: {
const resolvedEnvKey = envResolved?.apiKey ?? explicitEnvKey;
const resolvedEnvVarName = parseEnvVarNameFromSourceLabel(envResolved?.source) ?? explicitEnvVar;
if (params.secretInputMode === "ref") {
const useSecretRefMode = params.secretInputMode === "ref"; // pragma: allowlist secret
if (useSecretRefMode) {
if (!resolvedEnvKey && flagKey) {
params.runtime.error(
[

View File

@@ -91,7 +91,8 @@ export async function applyNonInteractiveAuthChoice(params: {
? { secretInputMode: requestedSecretInputMode }
: undefined;
const toStoredSecretInput = (resolved: ResolvedNonInteractiveApiKey): SecretInput | null => {
if (requestedSecretInputMode !== "ref") {
const storePlaintextSecret = requestedSecretInputMode !== "ref"; // pragma: allowlist secret
if (storePlaintextSecret) {
return resolved.key;
}
if (resolved.source !== "env") {
@@ -948,7 +949,8 @@ export async function applyNonInteractiveAuthChoice(params: {
});
let customApiKeyInput: SecretInput | undefined;
if (resolvedCustomApiKey) {
if (requestedSecretInputMode === "ref") {
const storeCustomApiKeyAsRef = requestedSecretInputMode === "ref"; // pragma: allowlist secret
if (storeCustomApiKeyAsRef) {
const stored = toStoredSecretInput(resolvedCustomApiKey);
if (!stored) {
return null;

View File

@@ -121,7 +121,7 @@ describe("setupSearch", () => {
web: {
search: {
provider: "perplexity",
perplexity: { apiKey: "existing-key" },
perplexity: { apiKey: "existing-key" }, // pragma: allowlist secret
},
},
},
@@ -142,7 +142,7 @@ describe("setupSearch", () => {
search: {
provider: "perplexity",
enabled: false,
perplexity: { apiKey: "existing-key" },
perplexity: { apiKey: "existing-key" }, // pragma: allowlist secret
},
},
},
@@ -162,7 +162,7 @@ describe("setupSearch", () => {
web: {
search: {
provider: "perplexity",
perplexity: { apiKey: "stored-pplx-key" },
perplexity: { apiKey: "stored-pplx-key" }, // pragma: allowlist secret
},
},
},
@@ -184,7 +184,7 @@ describe("setupSearch", () => {
search: {
provider: "perplexity",
enabled: false,
perplexity: { apiKey: "stored-pplx-key" },
perplexity: { apiKey: "stored-pplx-key" }, // pragma: allowlist secret
},
},
},
@@ -212,7 +212,7 @@ describe("setupSearch", () => {
it("quickstart skips key prompt when env var is available", async () => {
const orig = process.env.BRAVE_API_KEY;
process.env.BRAVE_API_KEY = "env-brave-key";
process.env.BRAVE_API_KEY = "env-brave-key"; // pragma: allowlist secret
try {
const cfg: OpenClawConfig = {};
const { prompter } = createPrompter({ selectValue: "brave" });
@@ -235,13 +235,13 @@ describe("setupSearch", () => {
const cfg: OpenClawConfig = {};
const { prompter } = createPrompter({ selectValue: "perplexity" });
const result = await setupSearch(cfg, runtime, prompter, {
secretInputMode: "ref",
secretInputMode: "ref", // pragma: allowlist secret
});
expect(result.tools?.web?.search?.provider).toBe("perplexity");
expect(result.tools?.web?.search?.perplexity?.apiKey).toEqual({
source: "env",
provider: "default",
id: "PERPLEXITY_API_KEY",
id: "PERPLEXITY_API_KEY", // pragma: allowlist secret
});
expect(prompter.text).not.toHaveBeenCalled();
});
@@ -250,7 +250,7 @@ describe("setupSearch", () => {
const cfg: OpenClawConfig = {};
const { prompter } = createPrompter({ selectValue: "brave" });
const result = await setupSearch(cfg, runtime, prompter, {
secretInputMode: "ref",
secretInputMode: "ref", // pragma: allowlist secret
});
expect(result.tools?.web?.search?.provider).toBe("brave");
expect(result.tools?.web?.search?.apiKey).toEqual({

View File

@@ -115,7 +115,8 @@ function resolveSearchSecretInput(
key: string,
secretInputMode?: SecretInputMode,
): SecretInput {
if (secretInputMode === "ref") {
const useSecretRefMode = secretInputMode === "ref"; // pragma: allowlist secret
if (useSecretRefMode) {
return buildSearchEnvRef(provider);
}
return key;
@@ -254,7 +255,8 @@ export async function setupSearch(
return preserveDisabledState(config, result);
}
if (opts?.secretInputMode === "ref") {
const useSecretRefMode = opts?.secretInputMode === "ref"; // pragma: allowlist secret
if (useSecretRefMode) {
if (keyConfigured) {
return preserveDisabledState(config, applyProviderOnly(config, choice));
}

View File

@@ -87,7 +87,7 @@ export type NodeManagerChoice = "npm" | "pnpm" | "bun";
export type ChannelChoice = ChannelId;
// Legacy alias (pre-rename).
export type ProviderChoice = ChannelChoice;
export type SecretInputMode = "plaintext" | "ref";
export type SecretInputMode = "plaintext" | "ref"; // pragma: allowlist secret
export type OnboardOptions = {
mode?: OnboardMode;

View File

@@ -47,7 +47,7 @@ describe("onboardCommand", () => {
await onboardCommand(
{
secretInputMode: "invalid" as never,
secretInputMode: "invalid" as never, // pragma: allowlist secret
},
runtime,
);

View File

@@ -39,8 +39,8 @@ export async function onboardCommand(opts: OnboardOptions, runtime: RuntimeEnv =
: { ...opts, authChoice: normalizedAuthChoice, flow };
if (
normalizedOpts.secretInputMode &&
normalizedOpts.secretInputMode !== "plaintext" &&
normalizedOpts.secretInputMode !== "ref"
normalizedOpts.secretInputMode !== "plaintext" && // pragma: allowlist secret
normalizedOpts.secretInputMode !== "ref" // pragma: allowlist secret
) {
runtime.error('Invalid --secret-input-mode. Use "plaintext" or "ref".');
runtime.exit(1);

View File

@@ -236,9 +236,9 @@ function makeHttpSlackUnavailablePlugin(): ChannelPlugin {
botToken: "xoxb-http",
signingSecret: "",
botTokenSource: "config",
signingSecretSource: "config",
signingSecretSource: "config", // pragma: allowlist secret
botTokenStatus: "available",
signingSecretStatus: "configured_unavailable",
signingSecretStatus: "configured_unavailable", // pragma: allowlist secret
}),
resolveAccount: () => ({
name: "Primary",
@@ -248,9 +248,9 @@ function makeHttpSlackUnavailablePlugin(): ChannelPlugin {
botToken: "xoxb-http",
signingSecret: "",
botTokenSource: "config",
signingSecretSource: "config",
signingSecretSource: "config", // pragma: allowlist secret
botTokenStatus: "available",
signingSecretStatus: "configured_unavailable",
signingSecretStatus: "configured_unavailable", // pragma: allowlist secret
}),
isConfigured: () => true,
isEnabled: () => true,

View File

@@ -177,7 +177,10 @@ const buildAccountNotes = (params: {
if (snapshot.appTokenSource && snapshot.appTokenSource !== "none") {
notes.push(`app:${snapshot.appTokenSource}`);
}
if (snapshot.signingSecretSource && snapshot.signingSecretSource !== "none") {
if (
snapshot.signingSecretSource &&
snapshot.signingSecretSource !== "none" /* pragma: allowlist secret */
) {
notes.push(`signing:${snapshot.signingSecretSource}`);
}
if (hasConfiguredUnavailableCredentialStatus(entry.account)) {