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

@@ -298,7 +298,8 @@ function applyConfigTargetMutations(params: {
}
const targetPathSegments = resolved.pathSegments;
if (resolved.entry.secretShape === "sibling_ref") {
const usesSiblingRef = resolved.entry.secretShape === "sibling_ref"; // pragma: allowlist secret
if (usesSiblingRef) {
const previous = getPath(params.nextConfig, targetPathSegments);
if (isNonEmptyString(previous)) {
scrubbedValues.add(previous.trim());
@@ -530,7 +531,8 @@ function applyAuthProfileTargetMutation(params: {
store,
});
const targetPathSegments = params.resolved.pathSegments;
if (params.resolved.entry.secretShape === "sibling_ref") {
const usesSiblingRef = params.resolved.entry.secretShape === "sibling_ref"; // pragma: allowlist secret
if (usesSiblingRef) {
const previous = getPath(store, targetPathSegments);
if (isNonEmptyString(previous)) {
params.scrubbedValues.add(previous.trim());

View File

@@ -53,7 +53,7 @@ async function createAuditFixture(): Promise<AuditFixture> {
env: {
OPENCLAW_STATE_DIR: stateDir,
OPENCLAW_CONFIG_PATH: configPath,
OPENAI_API_KEY: "env-openai-key",
OPENAI_API_KEY: "env-openai-key", // pragma: allowlist secret
PATH: resolveRuntimePathEnv(),
},
};
@@ -146,7 +146,7 @@ describe("secrets audit", () => {
"#!/bin/sh",
`printf 'x\\n' >> ${JSON.stringify(execLogPath)}`,
"cat >/dev/null",
'printf \'{"protocolVersion":1,"values":{"providers/openai/apiKey":"value:providers/openai/apiKey","providers/moonshot/apiKey":"value:providers/moonshot/apiKey"}}\'',
'printf \'{"protocolVersion":1,"values":{"providers/openai/apiKey":"value:providers/openai/apiKey","providers/moonshot/apiKey":"value:providers/moonshot/apiKey"}}\'', // pragma: allowlist secret
].join("\n"),
{ encoding: "utf8", mode: 0o700 },
);

View File

@@ -36,7 +36,7 @@ export type SecretsAuditCode =
| "REF_SHADOWED"
| "LEGACY_RESIDUE";
export type SecretsAuditSeverity = "info" | "warn" | "error";
export type SecretsAuditSeverity = "info" | "warn" | "error"; // pragma: allowlist secret
export type SecretsAuditFinding = {
code: SecretsAuditCode;
@@ -48,7 +48,7 @@ export type SecretsAuditFinding = {
profileId?: string;
};
export type SecretsAuditStatus = "clean" | "findings" | "unresolved";
export type SecretsAuditStatus = "clean" | "findings" | "unresolved"; // pragma: allowlist secret
export type SecretsAuditReport = {
version: 1;

View File

@@ -79,7 +79,9 @@ export function analyzeCommandSecretAssignmentsFromSnapshot(params: {
value: resolved,
});
if (target.entry.secretShape === "sibling_ref" && explicitRef && inlineCandidateRef) {
const hasCompetingSiblingRef =
target.entry.secretShape === "sibling_ref" && explicitRef && inlineCandidateRef; // pragma: allowlist secret
if (hasCompetingSiblingRef) {
diagnostics.push(
`${target.path}: both inline and sibling ref were present; sibling ref took precedence.`,
);

View File

@@ -6,7 +6,7 @@ type CredentialMatrixEntry = {
path: string;
refPath?: string;
when?: { type: "api_key" | "token" };
secretShape: "secret_input" | "sibling_ref";
secretShape: "secret_input" | "sibling_ref"; // pragma: allowlist secret
optIn: true;
notes?: string;
};

View File

@@ -153,7 +153,7 @@ describe("secret ref resolver", () => {
{ source: "env", provider: "default", id: "OPENAI_API_KEY" },
{
config,
env: { OPENAI_API_KEY: "sk-env-value" },
env: { OPENAI_API_KEY: "sk-env-value" }, // pragma: allowlist secret
},
);
expect(value).toBe("sk-env-value");
@@ -167,7 +167,7 @@ describe("secret ref resolver", () => {
JSON.stringify({
providers: {
openai: {
apiKey: "sk-file-value",
apiKey: "sk-file-value", // pragma: allowlist secret
},
},
}),
@@ -375,7 +375,7 @@ describe("secret ref resolver", () => {
JSON.stringify({
providers: {
openai: {
apiKey: "sk-file-value",
apiKey: "sk-file-value", // pragma: allowlist secret
},
},
}),

View File

@@ -122,21 +122,21 @@ describe("secrets runtime snapshot", () => {
const snapshot = await prepareSecretsRuntimeSnapshot({
config,
env: {
OPENAI_API_KEY: "sk-env-openai",
GITHUB_TOKEN: "ghp-env-token",
REVIEW_SKILL_API_KEY: "sk-skill-ref",
MEMORY_REMOTE_API_KEY: "mem-ref-key",
TALK_API_KEY: "talk-ref-key",
TALK_PROVIDER_API_KEY: "talk-provider-ref-key",
OPENAI_API_KEY: "sk-env-openai", // pragma: allowlist secret
GITHUB_TOKEN: "ghp-env-token", // pragma: allowlist secret
REVIEW_SKILL_API_KEY: "sk-skill-ref", // pragma: allowlist secret
MEMORY_REMOTE_API_KEY: "mem-ref-key", // pragma: allowlist secret
TALK_API_KEY: "talk-ref-key", // pragma: allowlist secret
TALK_PROVIDER_API_KEY: "talk-provider-ref-key", // pragma: allowlist secret
REMOTE_GATEWAY_TOKEN: "remote-token-ref",
REMOTE_GATEWAY_PASSWORD: "remote-password-ref",
REMOTE_GATEWAY_PASSWORD: "remote-password-ref", // pragma: allowlist secret
TELEGRAM_BOT_TOKEN_REF: "telegram-bot-ref",
TELEGRAM_WEBHOOK_SECRET_REF: "telegram-webhook-ref",
TELEGRAM_WEBHOOK_SECRET_REF: "telegram-webhook-ref", // pragma: allowlist secret
TELEGRAM_WORK_BOT_TOKEN_REF: "telegram-work-ref",
SLACK_SIGNING_SECRET_REF: "slack-signing-ref",
SLACK_SIGNING_SECRET_REF: "slack-signing-ref", // pragma: allowlist secret
SLACK_WORK_BOT_TOKEN_REF: "slack-work-bot-ref",
SLACK_WORK_APP_TOKEN_REF: "slack-work-app-ref",
WEB_SEARCH_API_KEY: "web-search-ref",
WEB_SEARCH_API_KEY: "web-search-ref", // pragma: allowlist secret
},
agentDirs: ["/tmp/openclaw-agent-main"],
loadAuthStore: () =>
@@ -305,7 +305,7 @@ describe("secrets runtime snapshot", () => {
},
}),
env: {
WEB_SEARCH_API_KEY: "web-search-ref",
WEB_SEARCH_API_KEY: "web-search-ref", // pragma: allowlist secret
},
agentDirs: ["/tmp/openclaw-agent-main"],
loadAuthStore: () => ({ version: 1, profiles: {} }),
@@ -343,8 +343,8 @@ describe("secrets runtime snapshot", () => {
},
}),
env: {
WEB_SEARCH_API_KEY: "web-search-ref",
WEB_SEARCH_GEMINI_API_KEY: "web-search-gemini-ref",
WEB_SEARCH_API_KEY: "web-search-ref", // pragma: allowlist secret
WEB_SEARCH_GEMINI_API_KEY: "web-search-gemini-ref", // pragma: allowlist secret
},
agentDirs: ["/tmp/openclaw-agent-main"],
loadAuthStore: () => ({ version: 1, profiles: {} }),
@@ -374,7 +374,7 @@ describe("secrets runtime snapshot", () => {
},
}),
env: {
WEB_SEARCH_GEMINI_API_KEY: "web-search-gemini-ref",
WEB_SEARCH_GEMINI_API_KEY: "web-search-gemini-ref", // pragma: allowlist secret
},
agentDirs: ["/tmp/openclaw-agent-main"],
loadAuthStore: () => ({ version: 1, profiles: {} }),
@@ -399,7 +399,7 @@ describe("secrets runtime snapshot", () => {
{
providers: {
openai: {
apiKey: "sk-from-file-provider",
apiKey: "sk-from-file-provider", // pragma: allowlist secret
},
},
},
@@ -494,7 +494,7 @@ describe("secrets runtime snapshot", () => {
},
},
}),
env: { OPENAI_API_KEY: "sk-runtime" },
env: { OPENAI_API_KEY: "sk-runtime" }, // pragma: allowlist secret
agentDirs: ["/tmp/openclaw-agent-main"],
loadAuthStore: () =>
loadAuthStoreWithProfiles({
@@ -603,7 +603,7 @@ describe("secrets runtime snapshot", () => {
auth: {
mode: "password",
token: "local-token",
password: "local-password",
password: "local-password", // pragma: allowlist secret
},
remote: {
enabled: true,
@@ -642,7 +642,7 @@ describe("secrets runtime snapshot", () => {
},
}),
env: {
GATEWAY_PASSWORD_REF: "resolved-gateway-password",
GATEWAY_PASSWORD_REF: "resolved-gateway-password", // pragma: allowlist secret
},
agentDirs: ["/tmp/openclaw-agent-main"],
loadAuthStore: () => ({ version: 1, profiles: {} }),
@@ -680,7 +680,7 @@ describe("secrets runtime snapshot", () => {
auth: {
mode: "password",
token: { source: "env", provider: "default", id: "GATEWAY_TOKEN_REF" },
password: "password-123",
password: "password-123", // pragma: allowlist secret
},
},
}),
@@ -728,7 +728,7 @@ describe("secrets runtime snapshot", () => {
},
}),
env: {
GATEWAY_PASSWORD_REF: "resolved-gateway-password",
GATEWAY_PASSWORD_REF: "resolved-gateway-password", // pragma: allowlist secret
},
agentDirs: ["/tmp/openclaw-agent-main"],
loadAuthStore: () => ({ version: 1, profiles: {} }),
@@ -822,7 +822,7 @@ describe("secrets runtime snapshot", () => {
}),
env: {
REMOTE_TOKEN: "resolved-remote-token",
REMOTE_PASSWORD: "resolved-remote-password",
REMOTE_PASSWORD: "resolved-remote-password", // pragma: allowlist secret
},
agentDirs: ["/tmp/openclaw-agent-main"],
loadAuthStore: () => ({ version: 1, profiles: {} }),
@@ -846,7 +846,7 @@ describe("secrets runtime snapshot", () => {
},
}),
env: {
REMOTE_PASSWORD: "resolved-remote-password",
REMOTE_PASSWORD: "resolved-remote-password", // pragma: allowlist secret
},
agentDirs: ["/tmp/openclaw-agent-main"],
loadAuthStore: () => ({ version: 1, profiles: {} }),
@@ -980,8 +980,8 @@ describe("secrets runtime snapshot", () => {
},
}),
env: {
NEXTCLOUD_BOT_SECRET: "resolved-nextcloud-bot-secret",
NEXTCLOUD_API_PASSWORD: "resolved-nextcloud-api-password",
NEXTCLOUD_BOT_SECRET: "resolved-nextcloud-bot-secret", // pragma: allowlist secret
NEXTCLOUD_API_PASSWORD: "resolved-nextcloud-api-password", // pragma: allowlist secret
},
agentDirs: ["/tmp/openclaw-agent-main"],
loadAuthStore: () => ({ version: 1, profiles: {} }),
@@ -1022,8 +1022,8 @@ describe("secrets runtime snapshot", () => {
},
}),
env: {
NEXTCLOUD_WORK_BOT_SECRET: "resolved-nextcloud-work-bot-secret",
NEXTCLOUD_WORK_API_PASSWORD: "resolved-nextcloud-work-api-password",
NEXTCLOUD_WORK_BOT_SECRET: "resolved-nextcloud-work-bot-secret", // pragma: allowlist secret
NEXTCLOUD_WORK_API_PASSWORD: "resolved-nextcloud-work-api-password", // pragma: allowlist secret
},
agentDirs: ["/tmp/openclaw-agent-main"],
loadAuthStore: () => ({ version: 1, profiles: {} }),
@@ -1058,7 +1058,7 @@ describe("secrets runtime snapshot", () => {
}),
env: {
REMOTE_GATEWAY_TOKEN: "tailscale-remote-token",
REMOTE_GATEWAY_PASSWORD: "tailscale-remote-password",
REMOTE_GATEWAY_PASSWORD: "tailscale-remote-password", // pragma: allowlist secret
},
agentDirs: ["/tmp/openclaw-agent-main"],
loadAuthStore: () => ({ version: 1, profiles: {} }),
@@ -1931,7 +1931,7 @@ describe("secrets runtime snapshot", () => {
list: [{ id: "worker" }],
},
},
env: { OPENAI_API_KEY: "sk-runtime-worker" },
env: { OPENAI_API_KEY: "sk-runtime-worker" }, // pragma: allowlist secret
});
await expect(fs.access(workerStorePath)).rejects.toMatchObject({ code: "ENOENT" });

View File

@@ -1,6 +1,6 @@
import { isNonEmptyString, isRecord } from "./shared.js";
export type SecretExpectedResolvedValue = "string" | "string-or-object";
export type SecretExpectedResolvedValue = "string" | "string-or-object"; // pragma: allowlist secret
export function isExpectedResolvedSecretValue(
value: unknown,

View File

@@ -1,5 +1,8 @@
import type { SecretTargetRegistryEntry } from "./target-registry-types.js";
const SECRET_INPUT_SHAPE = "secret_input"; // pragma: allowlist secret
const SIBLING_REF_SHAPE = "sibling_ref"; // pragma: allowlist secret
const SECRET_TARGET_REGISTRY: SecretTargetRegistryEntry[] = [
{
id: "auth-profiles.api_key.key",
@@ -7,7 +10,7 @@ const SECRET_TARGET_REGISTRY: SecretTargetRegistryEntry[] = [
configFile: "auth-profiles.json",
pathPattern: "profiles.*.key",
refPathPattern: "profiles.*.keyRef",
secretShape: "sibling_ref",
secretShape: SIBLING_REF_SHAPE,
expectedResolvedValue: "string",
includeInPlan: true,
includeInConfigure: true,
@@ -20,7 +23,7 @@ const SECRET_TARGET_REGISTRY: SecretTargetRegistryEntry[] = [
configFile: "auth-profiles.json",
pathPattern: "profiles.*.token",
refPathPattern: "profiles.*.tokenRef",
secretShape: "sibling_ref",
secretShape: SIBLING_REF_SHAPE,
expectedResolvedValue: "string",
includeInPlan: true,
includeInConfigure: true,
@@ -32,7 +35,7 @@ const SECRET_TARGET_REGISTRY: SecretTargetRegistryEntry[] = [
targetType: "agents.defaults.memorySearch.remote.apiKey",
configFile: "openclaw.json",
pathPattern: "agents.defaults.memorySearch.remote.apiKey",
secretShape: "secret_input",
secretShape: SECRET_INPUT_SHAPE,
expectedResolvedValue: "string",
includeInPlan: true,
includeInConfigure: true,
@@ -43,7 +46,7 @@ const SECRET_TARGET_REGISTRY: SecretTargetRegistryEntry[] = [
targetType: "agents.list[].memorySearch.remote.apiKey",
configFile: "openclaw.json",
pathPattern: "agents.list[].memorySearch.remote.apiKey",
secretShape: "secret_input",
secretShape: SECRET_INPUT_SHAPE,
expectedResolvedValue: "string",
includeInPlan: true,
includeInConfigure: true,
@@ -54,7 +57,7 @@ const SECRET_TARGET_REGISTRY: SecretTargetRegistryEntry[] = [
targetType: "channels.bluebubbles.accounts.*.password",
configFile: "openclaw.json",
pathPattern: "channels.bluebubbles.accounts.*.password",
secretShape: "secret_input",
secretShape: SECRET_INPUT_SHAPE,
expectedResolvedValue: "string",
includeInPlan: true,
includeInConfigure: true,
@@ -65,7 +68,7 @@ const SECRET_TARGET_REGISTRY: SecretTargetRegistryEntry[] = [
targetType: "channels.bluebubbles.password",
configFile: "openclaw.json",
pathPattern: "channels.bluebubbles.password",
secretShape: "secret_input",
secretShape: SECRET_INPUT_SHAPE,
expectedResolvedValue: "string",
includeInPlan: true,
includeInConfigure: true,
@@ -76,7 +79,7 @@ const SECRET_TARGET_REGISTRY: SecretTargetRegistryEntry[] = [
targetType: "channels.discord.accounts.*.pluralkit.token",
configFile: "openclaw.json",
pathPattern: "channels.discord.accounts.*.pluralkit.token",
secretShape: "secret_input",
secretShape: SECRET_INPUT_SHAPE,
expectedResolvedValue: "string",
includeInPlan: true,
includeInConfigure: true,
@@ -87,7 +90,7 @@ const SECRET_TARGET_REGISTRY: SecretTargetRegistryEntry[] = [
targetType: "channels.discord.accounts.*.token",
configFile: "openclaw.json",
pathPattern: "channels.discord.accounts.*.token",
secretShape: "secret_input",
secretShape: SECRET_INPUT_SHAPE,
expectedResolvedValue: "string",
includeInPlan: true,
includeInConfigure: true,
@@ -98,7 +101,7 @@ const SECRET_TARGET_REGISTRY: SecretTargetRegistryEntry[] = [
targetType: "channels.discord.accounts.*.voice.tts.elevenlabs.apiKey",
configFile: "openclaw.json",
pathPattern: "channels.discord.accounts.*.voice.tts.elevenlabs.apiKey",
secretShape: "secret_input",
secretShape: SECRET_INPUT_SHAPE,
expectedResolvedValue: "string",
includeInPlan: true,
includeInConfigure: true,
@@ -109,7 +112,7 @@ const SECRET_TARGET_REGISTRY: SecretTargetRegistryEntry[] = [
targetType: "channels.discord.accounts.*.voice.tts.openai.apiKey",
configFile: "openclaw.json",
pathPattern: "channels.discord.accounts.*.voice.tts.openai.apiKey",
secretShape: "secret_input",
secretShape: SECRET_INPUT_SHAPE,
expectedResolvedValue: "string",
includeInPlan: true,
includeInConfigure: true,
@@ -120,7 +123,7 @@ const SECRET_TARGET_REGISTRY: SecretTargetRegistryEntry[] = [
targetType: "channels.discord.pluralkit.token",
configFile: "openclaw.json",
pathPattern: "channels.discord.pluralkit.token",
secretShape: "secret_input",
secretShape: SECRET_INPUT_SHAPE,
expectedResolvedValue: "string",
includeInPlan: true,
includeInConfigure: true,
@@ -131,7 +134,7 @@ const SECRET_TARGET_REGISTRY: SecretTargetRegistryEntry[] = [
targetType: "channels.discord.token",
configFile: "openclaw.json",
pathPattern: "channels.discord.token",
secretShape: "secret_input",
secretShape: SECRET_INPUT_SHAPE,
expectedResolvedValue: "string",
includeInPlan: true,
includeInConfigure: true,
@@ -142,7 +145,7 @@ const SECRET_TARGET_REGISTRY: SecretTargetRegistryEntry[] = [
targetType: "channels.discord.voice.tts.elevenlabs.apiKey",
configFile: "openclaw.json",
pathPattern: "channels.discord.voice.tts.elevenlabs.apiKey",
secretShape: "secret_input",
secretShape: SECRET_INPUT_SHAPE,
expectedResolvedValue: "string",
includeInPlan: true,
includeInConfigure: true,
@@ -153,7 +156,7 @@ const SECRET_TARGET_REGISTRY: SecretTargetRegistryEntry[] = [
targetType: "channels.discord.voice.tts.openai.apiKey",
configFile: "openclaw.json",
pathPattern: "channels.discord.voice.tts.openai.apiKey",
secretShape: "secret_input",
secretShape: SECRET_INPUT_SHAPE,
expectedResolvedValue: "string",
includeInPlan: true,
includeInConfigure: true,
@@ -164,7 +167,7 @@ const SECRET_TARGET_REGISTRY: SecretTargetRegistryEntry[] = [
targetType: "channels.feishu.accounts.*.appSecret",
configFile: "openclaw.json",
pathPattern: "channels.feishu.accounts.*.appSecret",
secretShape: "secret_input",
secretShape: SECRET_INPUT_SHAPE,
expectedResolvedValue: "string",
includeInPlan: true,
includeInConfigure: true,
@@ -175,7 +178,7 @@ const SECRET_TARGET_REGISTRY: SecretTargetRegistryEntry[] = [
targetType: "channels.feishu.accounts.*.verificationToken",
configFile: "openclaw.json",
pathPattern: "channels.feishu.accounts.*.verificationToken",
secretShape: "secret_input",
secretShape: SECRET_INPUT_SHAPE,
expectedResolvedValue: "string",
includeInPlan: true,
includeInConfigure: true,
@@ -186,7 +189,7 @@ const SECRET_TARGET_REGISTRY: SecretTargetRegistryEntry[] = [
targetType: "channels.feishu.appSecret",
configFile: "openclaw.json",
pathPattern: "channels.feishu.appSecret",
secretShape: "secret_input",
secretShape: SECRET_INPUT_SHAPE,
expectedResolvedValue: "string",
includeInPlan: true,
includeInConfigure: true,
@@ -197,7 +200,7 @@ const SECRET_TARGET_REGISTRY: SecretTargetRegistryEntry[] = [
targetType: "channels.feishu.verificationToken",
configFile: "openclaw.json",
pathPattern: "channels.feishu.verificationToken",
secretShape: "secret_input",
secretShape: SECRET_INPUT_SHAPE,
expectedResolvedValue: "string",
includeInPlan: true,
includeInConfigure: true,
@@ -210,7 +213,7 @@ const SECRET_TARGET_REGISTRY: SecretTargetRegistryEntry[] = [
configFile: "openclaw.json",
pathPattern: "channels.googlechat.accounts.*.serviceAccount",
refPathPattern: "channels.googlechat.accounts.*.serviceAccountRef",
secretShape: "sibling_ref",
secretShape: SIBLING_REF_SHAPE,
expectedResolvedValue: "string-or-object",
includeInPlan: true,
includeInConfigure: true,
@@ -223,7 +226,7 @@ const SECRET_TARGET_REGISTRY: SecretTargetRegistryEntry[] = [
configFile: "openclaw.json",
pathPattern: "channels.googlechat.serviceAccount",
refPathPattern: "channels.googlechat.serviceAccountRef",
secretShape: "sibling_ref",
secretShape: SIBLING_REF_SHAPE,
expectedResolvedValue: "string-or-object",
includeInPlan: true,
includeInConfigure: true,
@@ -234,7 +237,7 @@ const SECRET_TARGET_REGISTRY: SecretTargetRegistryEntry[] = [
targetType: "channels.irc.accounts.*.nickserv.password",
configFile: "openclaw.json",
pathPattern: "channels.irc.accounts.*.nickserv.password",
secretShape: "secret_input",
secretShape: SECRET_INPUT_SHAPE,
expectedResolvedValue: "string",
includeInPlan: true,
includeInConfigure: true,
@@ -245,7 +248,7 @@ const SECRET_TARGET_REGISTRY: SecretTargetRegistryEntry[] = [
targetType: "channels.irc.accounts.*.password",
configFile: "openclaw.json",
pathPattern: "channels.irc.accounts.*.password",
secretShape: "secret_input",
secretShape: SECRET_INPUT_SHAPE,
expectedResolvedValue: "string",
includeInPlan: true,
includeInConfigure: true,
@@ -256,7 +259,7 @@ const SECRET_TARGET_REGISTRY: SecretTargetRegistryEntry[] = [
targetType: "channels.irc.nickserv.password",
configFile: "openclaw.json",
pathPattern: "channels.irc.nickserv.password",
secretShape: "secret_input",
secretShape: SECRET_INPUT_SHAPE,
expectedResolvedValue: "string",
includeInPlan: true,
includeInConfigure: true,
@@ -267,7 +270,7 @@ const SECRET_TARGET_REGISTRY: SecretTargetRegistryEntry[] = [
targetType: "channels.irc.password",
configFile: "openclaw.json",
pathPattern: "channels.irc.password",
secretShape: "secret_input",
secretShape: SECRET_INPUT_SHAPE,
expectedResolvedValue: "string",
includeInPlan: true,
includeInConfigure: true,
@@ -278,7 +281,7 @@ const SECRET_TARGET_REGISTRY: SecretTargetRegistryEntry[] = [
targetType: "channels.mattermost.accounts.*.botToken",
configFile: "openclaw.json",
pathPattern: "channels.mattermost.accounts.*.botToken",
secretShape: "secret_input",
secretShape: SECRET_INPUT_SHAPE,
expectedResolvedValue: "string",
includeInPlan: true,
includeInConfigure: true,
@@ -289,7 +292,7 @@ const SECRET_TARGET_REGISTRY: SecretTargetRegistryEntry[] = [
targetType: "channels.mattermost.botToken",
configFile: "openclaw.json",
pathPattern: "channels.mattermost.botToken",
secretShape: "secret_input",
secretShape: SECRET_INPUT_SHAPE,
expectedResolvedValue: "string",
includeInPlan: true,
includeInConfigure: true,
@@ -300,7 +303,7 @@ const SECRET_TARGET_REGISTRY: SecretTargetRegistryEntry[] = [
targetType: "channels.matrix.accounts.*.password",
configFile: "openclaw.json",
pathPattern: "channels.matrix.accounts.*.password",
secretShape: "secret_input",
secretShape: SECRET_INPUT_SHAPE,
expectedResolvedValue: "string",
includeInPlan: true,
includeInConfigure: true,
@@ -311,7 +314,7 @@ const SECRET_TARGET_REGISTRY: SecretTargetRegistryEntry[] = [
targetType: "channels.matrix.password",
configFile: "openclaw.json",
pathPattern: "channels.matrix.password",
secretShape: "secret_input",
secretShape: SECRET_INPUT_SHAPE,
expectedResolvedValue: "string",
includeInPlan: true,
includeInConfigure: true,
@@ -322,7 +325,7 @@ const SECRET_TARGET_REGISTRY: SecretTargetRegistryEntry[] = [
targetType: "channels.msteams.appPassword",
configFile: "openclaw.json",
pathPattern: "channels.msteams.appPassword",
secretShape: "secret_input",
secretShape: SECRET_INPUT_SHAPE,
expectedResolvedValue: "string",
includeInPlan: true,
includeInConfigure: true,
@@ -333,7 +336,7 @@ const SECRET_TARGET_REGISTRY: SecretTargetRegistryEntry[] = [
targetType: "channels.nextcloud-talk.accounts.*.apiPassword",
configFile: "openclaw.json",
pathPattern: "channels.nextcloud-talk.accounts.*.apiPassword",
secretShape: "secret_input",
secretShape: SECRET_INPUT_SHAPE,
expectedResolvedValue: "string",
includeInPlan: true,
includeInConfigure: true,
@@ -344,7 +347,7 @@ const SECRET_TARGET_REGISTRY: SecretTargetRegistryEntry[] = [
targetType: "channels.nextcloud-talk.accounts.*.botSecret",
configFile: "openclaw.json",
pathPattern: "channels.nextcloud-talk.accounts.*.botSecret",
secretShape: "secret_input",
secretShape: SECRET_INPUT_SHAPE,
expectedResolvedValue: "string",
includeInPlan: true,
includeInConfigure: true,
@@ -355,7 +358,7 @@ const SECRET_TARGET_REGISTRY: SecretTargetRegistryEntry[] = [
targetType: "channels.nextcloud-talk.apiPassword",
configFile: "openclaw.json",
pathPattern: "channels.nextcloud-talk.apiPassword",
secretShape: "secret_input",
secretShape: SECRET_INPUT_SHAPE,
expectedResolvedValue: "string",
includeInPlan: true,
includeInConfigure: true,
@@ -366,7 +369,7 @@ const SECRET_TARGET_REGISTRY: SecretTargetRegistryEntry[] = [
targetType: "channels.nextcloud-talk.botSecret",
configFile: "openclaw.json",
pathPattern: "channels.nextcloud-talk.botSecret",
secretShape: "secret_input",
secretShape: SECRET_INPUT_SHAPE,
expectedResolvedValue: "string",
includeInPlan: true,
includeInConfigure: true,
@@ -377,7 +380,7 @@ const SECRET_TARGET_REGISTRY: SecretTargetRegistryEntry[] = [
targetType: "channels.slack.accounts.*.appToken",
configFile: "openclaw.json",
pathPattern: "channels.slack.accounts.*.appToken",
secretShape: "secret_input",
secretShape: SECRET_INPUT_SHAPE,
expectedResolvedValue: "string",
includeInPlan: true,
includeInConfigure: true,
@@ -388,7 +391,7 @@ const SECRET_TARGET_REGISTRY: SecretTargetRegistryEntry[] = [
targetType: "channels.slack.accounts.*.botToken",
configFile: "openclaw.json",
pathPattern: "channels.slack.accounts.*.botToken",
secretShape: "secret_input",
secretShape: SECRET_INPUT_SHAPE,
expectedResolvedValue: "string",
includeInPlan: true,
includeInConfigure: true,
@@ -399,7 +402,7 @@ const SECRET_TARGET_REGISTRY: SecretTargetRegistryEntry[] = [
targetType: "channels.slack.accounts.*.signingSecret",
configFile: "openclaw.json",
pathPattern: "channels.slack.accounts.*.signingSecret",
secretShape: "secret_input",
secretShape: SECRET_INPUT_SHAPE,
expectedResolvedValue: "string",
includeInPlan: true,
includeInConfigure: true,
@@ -410,7 +413,7 @@ const SECRET_TARGET_REGISTRY: SecretTargetRegistryEntry[] = [
targetType: "channels.slack.accounts.*.userToken",
configFile: "openclaw.json",
pathPattern: "channels.slack.accounts.*.userToken",
secretShape: "secret_input",
secretShape: SECRET_INPUT_SHAPE,
expectedResolvedValue: "string",
includeInPlan: true,
includeInConfigure: true,
@@ -421,7 +424,7 @@ const SECRET_TARGET_REGISTRY: SecretTargetRegistryEntry[] = [
targetType: "channels.slack.appToken",
configFile: "openclaw.json",
pathPattern: "channels.slack.appToken",
secretShape: "secret_input",
secretShape: SECRET_INPUT_SHAPE,
expectedResolvedValue: "string",
includeInPlan: true,
includeInConfigure: true,
@@ -432,7 +435,7 @@ const SECRET_TARGET_REGISTRY: SecretTargetRegistryEntry[] = [
targetType: "channels.slack.botToken",
configFile: "openclaw.json",
pathPattern: "channels.slack.botToken",
secretShape: "secret_input",
secretShape: SECRET_INPUT_SHAPE,
expectedResolvedValue: "string",
includeInPlan: true,
includeInConfigure: true,
@@ -443,7 +446,7 @@ const SECRET_TARGET_REGISTRY: SecretTargetRegistryEntry[] = [
targetType: "channels.slack.signingSecret",
configFile: "openclaw.json",
pathPattern: "channels.slack.signingSecret",
secretShape: "secret_input",
secretShape: SECRET_INPUT_SHAPE,
expectedResolvedValue: "string",
includeInPlan: true,
includeInConfigure: true,
@@ -454,7 +457,7 @@ const SECRET_TARGET_REGISTRY: SecretTargetRegistryEntry[] = [
targetType: "channels.slack.userToken",
configFile: "openclaw.json",
pathPattern: "channels.slack.userToken",
secretShape: "secret_input",
secretShape: SECRET_INPUT_SHAPE,
expectedResolvedValue: "string",
includeInPlan: true,
includeInConfigure: true,
@@ -465,7 +468,7 @@ const SECRET_TARGET_REGISTRY: SecretTargetRegistryEntry[] = [
targetType: "channels.telegram.accounts.*.botToken",
configFile: "openclaw.json",
pathPattern: "channels.telegram.accounts.*.botToken",
secretShape: "secret_input",
secretShape: SECRET_INPUT_SHAPE,
expectedResolvedValue: "string",
includeInPlan: true,
includeInConfigure: true,
@@ -476,7 +479,7 @@ const SECRET_TARGET_REGISTRY: SecretTargetRegistryEntry[] = [
targetType: "channels.telegram.accounts.*.webhookSecret",
configFile: "openclaw.json",
pathPattern: "channels.telegram.accounts.*.webhookSecret",
secretShape: "secret_input",
secretShape: SECRET_INPUT_SHAPE,
expectedResolvedValue: "string",
includeInPlan: true,
includeInConfigure: true,
@@ -487,7 +490,7 @@ const SECRET_TARGET_REGISTRY: SecretTargetRegistryEntry[] = [
targetType: "channels.telegram.botToken",
configFile: "openclaw.json",
pathPattern: "channels.telegram.botToken",
secretShape: "secret_input",
secretShape: SECRET_INPUT_SHAPE,
expectedResolvedValue: "string",
includeInPlan: true,
includeInConfigure: true,
@@ -498,7 +501,7 @@ const SECRET_TARGET_REGISTRY: SecretTargetRegistryEntry[] = [
targetType: "channels.telegram.webhookSecret",
configFile: "openclaw.json",
pathPattern: "channels.telegram.webhookSecret",
secretShape: "secret_input",
secretShape: SECRET_INPUT_SHAPE,
expectedResolvedValue: "string",
includeInPlan: true,
includeInConfigure: true,
@@ -509,7 +512,7 @@ const SECRET_TARGET_REGISTRY: SecretTargetRegistryEntry[] = [
targetType: "channels.zalo.accounts.*.botToken",
configFile: "openclaw.json",
pathPattern: "channels.zalo.accounts.*.botToken",
secretShape: "secret_input",
secretShape: SECRET_INPUT_SHAPE,
expectedResolvedValue: "string",
includeInPlan: true,
includeInConfigure: true,
@@ -520,7 +523,7 @@ const SECRET_TARGET_REGISTRY: SecretTargetRegistryEntry[] = [
targetType: "channels.zalo.accounts.*.webhookSecret",
configFile: "openclaw.json",
pathPattern: "channels.zalo.accounts.*.webhookSecret",
secretShape: "secret_input",
secretShape: SECRET_INPUT_SHAPE,
expectedResolvedValue: "string",
includeInPlan: true,
includeInConfigure: true,
@@ -531,7 +534,7 @@ const SECRET_TARGET_REGISTRY: SecretTargetRegistryEntry[] = [
targetType: "channels.zalo.botToken",
configFile: "openclaw.json",
pathPattern: "channels.zalo.botToken",
secretShape: "secret_input",
secretShape: SECRET_INPUT_SHAPE,
expectedResolvedValue: "string",
includeInPlan: true,
includeInConfigure: true,
@@ -542,7 +545,7 @@ const SECRET_TARGET_REGISTRY: SecretTargetRegistryEntry[] = [
targetType: "channels.zalo.webhookSecret",
configFile: "openclaw.json",
pathPattern: "channels.zalo.webhookSecret",
secretShape: "secret_input",
secretShape: SECRET_INPUT_SHAPE,
expectedResolvedValue: "string",
includeInPlan: true,
includeInConfigure: true,
@@ -553,7 +556,7 @@ const SECRET_TARGET_REGISTRY: SecretTargetRegistryEntry[] = [
targetType: "cron.webhookToken",
configFile: "openclaw.json",
pathPattern: "cron.webhookToken",
secretShape: "secret_input",
secretShape: SECRET_INPUT_SHAPE,
expectedResolvedValue: "string",
includeInPlan: true,
includeInConfigure: true,
@@ -564,7 +567,7 @@ const SECRET_TARGET_REGISTRY: SecretTargetRegistryEntry[] = [
targetType: "gateway.auth.token",
configFile: "openclaw.json",
pathPattern: "gateway.auth.token",
secretShape: "secret_input",
secretShape: SECRET_INPUT_SHAPE,
expectedResolvedValue: "string",
includeInPlan: true,
includeInConfigure: true,
@@ -575,7 +578,7 @@ const SECRET_TARGET_REGISTRY: SecretTargetRegistryEntry[] = [
targetType: "gateway.auth.password",
configFile: "openclaw.json",
pathPattern: "gateway.auth.password",
secretShape: "secret_input",
secretShape: SECRET_INPUT_SHAPE,
expectedResolvedValue: "string",
includeInPlan: true,
includeInConfigure: true,
@@ -586,7 +589,7 @@ const SECRET_TARGET_REGISTRY: SecretTargetRegistryEntry[] = [
targetType: "gateway.remote.password",
configFile: "openclaw.json",
pathPattern: "gateway.remote.password",
secretShape: "secret_input",
secretShape: SECRET_INPUT_SHAPE,
expectedResolvedValue: "string",
includeInPlan: true,
includeInConfigure: true,
@@ -597,7 +600,7 @@ const SECRET_TARGET_REGISTRY: SecretTargetRegistryEntry[] = [
targetType: "gateway.remote.token",
configFile: "openclaw.json",
pathPattern: "gateway.remote.token",
secretShape: "secret_input",
secretShape: SECRET_INPUT_SHAPE,
expectedResolvedValue: "string",
includeInPlan: true,
includeInConfigure: true,
@@ -608,7 +611,7 @@ const SECRET_TARGET_REGISTRY: SecretTargetRegistryEntry[] = [
targetType: "messages.tts.elevenlabs.apiKey",
configFile: "openclaw.json",
pathPattern: "messages.tts.elevenlabs.apiKey",
secretShape: "secret_input",
secretShape: SECRET_INPUT_SHAPE,
expectedResolvedValue: "string",
includeInPlan: true,
includeInConfigure: true,
@@ -619,7 +622,7 @@ const SECRET_TARGET_REGISTRY: SecretTargetRegistryEntry[] = [
targetType: "messages.tts.openai.apiKey",
configFile: "openclaw.json",
pathPattern: "messages.tts.openai.apiKey",
secretShape: "secret_input",
secretShape: SECRET_INPUT_SHAPE,
expectedResolvedValue: "string",
includeInPlan: true,
includeInConfigure: true,
@@ -631,7 +634,7 @@ const SECRET_TARGET_REGISTRY: SecretTargetRegistryEntry[] = [
targetTypeAliases: ["models.providers.*.apiKey"],
configFile: "openclaw.json",
pathPattern: "models.providers.*.apiKey",
secretShape: "secret_input",
secretShape: SECRET_INPUT_SHAPE,
expectedResolvedValue: "string",
includeInPlan: true,
includeInConfigure: true,
@@ -645,7 +648,7 @@ const SECRET_TARGET_REGISTRY: SecretTargetRegistryEntry[] = [
targetTypeAliases: ["skills.entries.*.apiKey"],
configFile: "openclaw.json",
pathPattern: "skills.entries.*.apiKey",
secretShape: "secret_input",
secretShape: SECRET_INPUT_SHAPE,
expectedResolvedValue: "string",
includeInPlan: true,
includeInConfigure: true,
@@ -656,7 +659,7 @@ const SECRET_TARGET_REGISTRY: SecretTargetRegistryEntry[] = [
targetType: "talk.apiKey",
configFile: "openclaw.json",
pathPattern: "talk.apiKey",
secretShape: "secret_input",
secretShape: SECRET_INPUT_SHAPE,
expectedResolvedValue: "string",
includeInPlan: true,
includeInConfigure: true,
@@ -667,7 +670,7 @@ const SECRET_TARGET_REGISTRY: SecretTargetRegistryEntry[] = [
targetType: "talk.providers.*.apiKey",
configFile: "openclaw.json",
pathPattern: "talk.providers.*.apiKey",
secretShape: "secret_input",
secretShape: SECRET_INPUT_SHAPE,
expectedResolvedValue: "string",
includeInPlan: true,
includeInConfigure: true,
@@ -678,7 +681,7 @@ const SECRET_TARGET_REGISTRY: SecretTargetRegistryEntry[] = [
targetType: "tools.web.search.apiKey",
configFile: "openclaw.json",
pathPattern: "tools.web.search.apiKey",
secretShape: "secret_input",
secretShape: SECRET_INPUT_SHAPE,
expectedResolvedValue: "string",
includeInPlan: true,
includeInConfigure: true,
@@ -689,7 +692,7 @@ const SECRET_TARGET_REGISTRY: SecretTargetRegistryEntry[] = [
targetType: "tools.web.search.gemini.apiKey",
configFile: "openclaw.json",
pathPattern: "tools.web.search.gemini.apiKey",
secretShape: "secret_input",
secretShape: SECRET_INPUT_SHAPE,
expectedResolvedValue: "string",
includeInPlan: true,
includeInConfigure: true,
@@ -700,7 +703,7 @@ const SECRET_TARGET_REGISTRY: SecretTargetRegistryEntry[] = [
targetType: "tools.web.search.grok.apiKey",
configFile: "openclaw.json",
pathPattern: "tools.web.search.grok.apiKey",
secretShape: "secret_input",
secretShape: SECRET_INPUT_SHAPE,
expectedResolvedValue: "string",
includeInPlan: true,
includeInConfigure: true,
@@ -711,7 +714,7 @@ const SECRET_TARGET_REGISTRY: SecretTargetRegistryEntry[] = [
targetType: "tools.web.search.kimi.apiKey",
configFile: "openclaw.json",
pathPattern: "tools.web.search.kimi.apiKey",
secretShape: "secret_input",
secretShape: SECRET_INPUT_SHAPE,
expectedResolvedValue: "string",
includeInPlan: true,
includeInConfigure: true,
@@ -722,7 +725,7 @@ const SECRET_TARGET_REGISTRY: SecretTargetRegistryEntry[] = [
targetType: "tools.web.search.perplexity.apiKey",
configFile: "openclaw.json",
pathPattern: "tools.web.search.perplexity.apiKey",
secretShape: "secret_input",
secretShape: SECRET_INPUT_SHAPE,
expectedResolvedValue: "string",
includeInPlan: true,
includeInConfigure: true,

View File

@@ -49,8 +49,8 @@ describe("target registry pattern helpers", () => {
},
talk: {
providers: {
openai: { apiKey: "oa" },
anthropic: { apiKey: "an" },
openai: { apiKey: "oa" }, // pragma: allowlist secret
anthropic: { apiKey: "an" }, // pragma: allowlist secret
},
},
};

View File

@@ -47,7 +47,8 @@ export function compileTargetRegistryEntry(
const pathDynamicTokenCount = countDynamicPatternTokens(pathTokens);
const refPathTokens = entry.refPathPattern ? parsePathPattern(entry.refPathPattern) : undefined;
const refPathDynamicTokenCount = refPathTokens ? countDynamicPatternTokens(refPathTokens) : 0;
if (entry.secretShape === "sibling_ref" && !refPathTokens) {
const requiresSiblingRefPath = entry.secretShape === "sibling_ref"; // pragma: allowlist secret
if (requiresSiblingRefPath && !refPathTokens) {
throw new Error(`Missing refPathPattern for sibling_ref target: ${entry.id}`);
}
if (refPathTokens && refPathDynamicTokenCount !== pathDynamicTokenCount) {

View File

@@ -1,6 +1,6 @@
export type SecretTargetConfigFile = "openclaw.json" | "auth-profiles.json";
export type SecretTargetShape = "secret_input" | "sibling_ref";
export type SecretTargetExpected = "string" | "string-or-object";
export type SecretTargetConfigFile = "openclaw.json" | "auth-profiles.json"; // pragma: allowlist secret
export type SecretTargetShape = "secret_input" | "sibling_ref"; // pragma: allowlist secret
export type SecretTargetExpected = "string" | "string-or-object"; // pragma: allowlist secret
export type AuthProfileType = "api_key" | "token";
export type SecretTargetRegistryEntry = {