refactor: derive CLI web credential targets

This commit is contained in:
Peter Steinberger
2026-04-22 05:06:05 +01:00
parent bc9c2cc162
commit 0a027ff591
3 changed files with 52 additions and 15 deletions

View File

@@ -20,14 +20,34 @@ describe("command secret targets module import", () => {
expect(listSecretTargetRegistryEntries).not.toHaveBeenCalled();
expect(mod.getModelsCommandSecretTargetIds().has("models.providers.*.apiKey")).toBe(true);
expect(mod.getQrRemoteCommandSecretTargetIds().has("gateway.remote.token")).toBe(true);
expect(
mod.getAgentRuntimeCommandSecretTargetIds().has("agents.defaults.memorySearch.remote.apiKey"),
).toBe(true);
expect(listSecretTargetRegistryEntries).not.toHaveBeenCalled();
expect(() => mod.getChannelsCommandSecretTargetIds()).toThrow("registry touched too early");
expect(listSecretTargetRegistryEntries).toHaveBeenCalledTimes(1);
});
it("loads registry lazily for agent runtime plugin credential targets", async () => {
const listSecretTargetRegistryEntries = vi.fn(() => [
{ id: "plugins.entries.example.config.webSearch.apiKey" },
{ id: "plugins.entries.example.config.other.apiKey" },
{ id: "channels.telegram.botToken" },
]);
vi.doMock("../secrets/target-registry.js", () => ({
discoverConfigSecretTargetsByIds: vi.fn(() => []),
listSecretTargetRegistryEntries,
}));
const mod = await import("./command-secret-targets.js");
expect(listSecretTargetRegistryEntries).not.toHaveBeenCalled();
const ids = mod.getAgentRuntimeCommandSecretTargetIds();
expect(ids.has("agents.defaults.memorySearch.remote.apiKey")).toBe(true);
expect(ids.has("plugins.entries.example.config.webSearch.apiKey")).toBe(true);
expect(ids.has("plugins.entries.example.config.other.apiKey")).toBe(false);
expect(ids.has("channels.telegram.botToken")).toBe(false);
expect(listSecretTargetRegistryEntries).toHaveBeenCalledTimes(1);
});
it("can resolve configured-channel status targets without the full registry", async () => {
const listSecretTargetRegistryEntries = vi.fn(() => {
throw new Error("registry touched too early");

View File

@@ -30,16 +30,6 @@ const STATIC_AGENT_RUNTIME_BASE_TARGET_IDS = [
"messages.tts.providers.*.apiKey",
"skills.entries.*.apiKey",
"tools.web.search.apiKey",
"plugins.entries.brave.config.webSearch.apiKey",
"plugins.entries.google.config.webSearch.apiKey",
"plugins.entries.exa.config.webSearch.apiKey",
"plugins.entries.xai.config.webSearch.apiKey",
"plugins.entries.moonshot.config.webSearch.apiKey",
"plugins.entries.perplexity.config.webSearch.apiKey",
"plugins.entries.firecrawl.config.webSearch.apiKey",
"plugins.entries.firecrawl.config.webFetch.apiKey",
"plugins.entries.tavily.config.webSearch.apiKey",
"plugins.entries.minimax.config.webSearch.apiKey",
] as const;
const STATIC_STATUS_TARGET_IDS = [
"agents.defaults.memorySearch.remote.apiKey",
@@ -67,6 +57,7 @@ type CommandSecretTargets = {
};
let cachedCommandSecretTargets: CommandSecretTargets | undefined;
let cachedAgentRuntimeBaseTargetIds: string[] | undefined;
let cachedChannelSecretTargetIds: string[] | undefined;
function getChannelSecretTargetIds(): string[] {
@@ -74,6 +65,26 @@ function getChannelSecretTargetIds(): string[] {
return cachedChannelSecretTargetIds;
}
function isPluginWebCredentialTargetId(id: string): boolean {
const segments = id.split(".");
if (segments[0] !== "plugins" || segments[1] !== "entries" || segments[3] !== "config") {
return false;
}
const configPath = segments.slice(4).join(".");
return configPath === "webSearch.apiKey" || configPath === "webFetch.apiKey";
}
function getAgentRuntimeBaseTargetIds(): string[] {
cachedAgentRuntimeBaseTargetIds ??= [
...STATIC_AGENT_RUNTIME_BASE_TARGET_IDS,
...listSecretTargetRegistryEntries()
.map((entry) => entry.id)
.filter(isPluginWebCredentialTargetId)
.toSorted(),
];
return cachedAgentRuntimeBaseTargetIds;
}
function isScopedChannelSecretTargetEntry(params: {
entry: {
id: string;
@@ -120,7 +131,7 @@ function buildCommandSecretTargets(): CommandSecretTargets {
const channelTargetIds = getChannelSecretTargetIds();
return {
channels: channelTargetIds,
agentRuntime: [...STATIC_AGENT_RUNTIME_BASE_TARGET_IDS, ...channelTargetIds],
agentRuntime: [...getAgentRuntimeBaseTargetIds(), ...channelTargetIds],
status: [...STATIC_STATUS_TARGET_IDS, ...channelTargetIds],
securityAudit: [...STATIC_SECURITY_AUDIT_TARGET_IDS, ...channelTargetIds],
};
@@ -213,7 +224,7 @@ export function getAgentRuntimeCommandSecretTargetIds(params?: {
includeChannelTargets?: boolean;
}): Set<string> {
if (params?.includeChannelTargets !== true) {
return toTargetIdSet(STATIC_AGENT_RUNTIME_BASE_TARGET_IDS);
return toTargetIdSet(getAgentRuntimeBaseTargetIds());
}
return toTargetIdSet(getCommandSecretTargets().agentRuntime);
}

View File

@@ -26,6 +26,12 @@ const CORE_SECRET_SURFACE_GUARDS = [
/plugins\.entries\.(?:brave|google|exa|xai|moonshot|perplexity|firecrawl|tavily|minimax)\.config\.web(?:Search|Fetch)\.apiKey/,
],
},
{
path: "src/cli/command-secret-targets.ts",
forbiddenPatterns: [
/plugins\.entries\.(?:brave|google|exa|xai|moonshot|perplexity|firecrawl|tavily|minimax)\.config\.web(?:Search|Fetch)\.apiKey/,
],
},
{
path: "src/config/markdown-tables.ts",
forbiddenPatterns: [/["']signal["']/, /["']whatsapp["']/, /["']mattermost["']/],