UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

670 lines (669 loc) 30.7 kB
import { o as normalizeLowercaseStringOrEmpty } from "./string-coerce-CIXf7egm.js"; import { v as resolveSecretInputRef } from "./types.secrets-kC0nOetj.js"; import { t as formatErrorMessage } from "./errors-Db3Ymjlb.js"; import { i as resolveManifestContractOwnerPluginId } from "./plugin-registry-contributions-BwuDvm89.js"; import { r as copyConfigResolutionFactsExcept, t as cloneConfigWithResolutionFacts, u as resolveConfigSecretRef } from "./resolution-facts-Dks1tbik.js"; import { f as assertExpectedResolvedSecretValue, i as createResolverContext } from "./runtime-shared-CqbaocQu.js"; import { r as discoverConfigSecretTargetsByIds } from "./target-registry-query-qVhyD-Hq.js"; import { i as setPathExistingStrict, n as getPath } from "./path-utils-BSrJtisq.js"; import "./target-registry-BHDUOLUU.js"; import { i as GATEWAY_CLIENT_NAMES, r as GATEWAY_CLIENT_MODES } from "./client-info-B1bPgeKr.js"; import { n as resolveSecretRefValue } from "./resolve-224YoYfx.js"; import { a as readGatewaySecretInputValue, t as ALL_GATEWAY_SECRET_INPUT_PATHS } from "./secret-input-paths-g1iYY9cj.js"; import { t as gatewaySecretInputPathCanWin } from "./credentials-secret-inputs-BlthacCl.js"; import { o as callGateway } from "./call-BWR5pPgw.js"; import { pr as validateSecretsResolveResult } from "./src-BiL5aQto.js"; import { t as analyzeCommandSecretAssignmentsFromSnapshot } from "./command-config-B9C-NY8K.js"; import { t as collectConfigAssignments } from "./runtime-config-collectors-C6FGy6ti.js"; import { t as resolveRuntimeWebTools } from "./runtime-web-tools-DYZFauRm.js"; //#region src/cli/command-secret-gateway.ts const WEB_RUNTIME_SECRET_TARGET_ID_PREFIXES = ["plugins.entries."]; const WEB_RUNTIME_SECRET_PATH_PREFIXES = ["plugins.entries."]; const commandSecretGatewayDeps = { analyzeCommandSecretAssignmentsFromSnapshot, collectConfigAssignments, discoverConfigSecretTargetsByIds, resolveManifestContractOwnerPluginId, resolveRuntimeWebTools }; const testing = { setDepsForTest(overrides) { const previous = { ...commandSecretGatewayDeps }; Object.assign(commandSecretGatewayDeps, overrides); return () => { Object.assign(commandSecretGatewayDeps, previous); }; }, resetDepsForTest() { Object.assign(commandSecretGatewayDeps, { analyzeCommandSecretAssignmentsFromSnapshot, collectConfigAssignments, discoverConfigSecretTargetsByIds, resolveManifestContractOwnerPluginId, resolveRuntimeWebTools }); } }; if (process.env.VITEST || false) globalThis[Symbol.for("openclaw.commandSecretGatewayTestApi")] = testing; function pluginIdFromRuntimeWebPath(path) { return /^plugins\.entries\.([^.]+)\.config\.(webSearch|webFetch)\.apiKey$/.exec(path)?.[1]; } function normalizeCommandSecretResolutionMode(mode) { if (!mode || mode === "enforce_resolved" || mode === "strict") return "enforce_resolved"; if (mode === "read_only_status" || mode === "summary") return "read_only_status"; return "read_only_operational"; } function enforcesResolvedSecrets(mode) { return mode === "enforce_resolved"; } function dedupeDiagnostics(entries) { const seen = /* @__PURE__ */ new Set(); const ordered = []; for (const entry of entries) { const trimmed = entry.trim(); if (!trimmed || seen.has(trimmed)) continue; seen.add(trimmed); ordered.push(trimmed); } return ordered; } function targetsRuntimeWebPath(path) { return WEB_RUNTIME_SECRET_PATH_PREFIXES.some((prefix) => path.startsWith(prefix)); } function classifyRuntimeWebTargetPathState(params) { const pluginId = pluginIdFromRuntimeWebPath(params.path); if (pluginId) { if (params.path.endsWith(".config.webFetch.apiKey")) { const fetch = params.config.tools?.web?.fetch; if (fetch?.enabled === false) return "inactive"; const configuredProvider = normalizeLowercaseStringOrEmpty(fetch?.provider); if (!configuredProvider) return "active"; const configuredPluginId = commandSecretGatewayDeps.resolveManifestContractOwnerPluginId({ contract: "webFetchProviders", value: configuredProvider, origin: "bundled", config: params.config }); if (!configuredPluginId) return "unknown"; return configuredPluginId === pluginId ? "active" : "inactive"; } const search = params.config.tools?.web?.search; if (search?.enabled === false) return "inactive"; const configuredProvider = normalizeLowercaseStringOrEmpty(search?.provider); if (!configuredProvider) return "active"; const configuredPluginId = commandSecretGatewayDeps.resolveManifestContractOwnerPluginId({ contract: "webSearchProviders", value: configuredProvider, origin: "bundled", config: params.config }); if (!configuredPluginId) return "unknown"; return configuredPluginId === pluginId ? "active" : "inactive"; } return "unknown"; } function describeInactiveRuntimeWebTargetPath(params) { const pluginId = pluginIdFromRuntimeWebPath(params.path); if (pluginId) { if (params.path.endsWith(".config.webFetch.apiKey")) { const fetch = params.config.tools?.web?.fetch; if (fetch?.enabled === false) return "tools.web.fetch is disabled."; const configuredProvider = normalizeLowercaseStringOrEmpty(fetch?.provider); if (configuredProvider) return `tools.web.fetch.provider is "${configuredProvider}".`; return; } const search = params.config.tools?.web?.search; if (search?.enabled === false) return "tools.web.search is disabled."; const configuredProvider = normalizeLowercaseStringOrEmpty(search?.provider); const configuredPluginId = configuredProvider ? commandSecretGatewayDeps.resolveManifestContractOwnerPluginId({ contract: "webSearchProviders", value: configuredProvider, origin: "bundled", config: params.config }) : void 0; if (configuredPluginId && configuredPluginId !== pluginId) return `tools.web.search.provider is "${configuredProvider}".`; return; } } function targetsRuntimeWebResolution(params) { if (params.allowedPaths) { for (const path of params.allowedPaths) if (targetsRuntimeWebPath(path)) return true; return false; } for (const targetId of params.targetIds) if (WEB_RUNTIME_SECRET_TARGET_ID_PREFIXES.some((prefix) => targetId.startsWith(prefix))) return true; return false; } function collectConfiguredTargetRefPaths(params) { const defaults = params.config.secrets?.defaults; const configuredTargetRefPaths = /* @__PURE__ */ new Set(); for (const target of commandSecretGatewayDeps.discoverConfigSecretTargetsByIds(params.config, params.targetIds)) { if (params.allowedPaths && !params.allowedPaths.has(target.path)) continue; const { ref } = resolveSecretInputRef({ value: resolveConfigSecretRef({ config: params.config, path: target.path, value: target.value, defaults }), refValue: target.refValue, defaults }); if (ref) configuredTargetRefPaths.add(target.path); } return configuredTargetRefPaths; } function classifyConfiguredTargetRefs(params) { if (params.configuredTargetRefPaths.size === 0) return { hasActiveConfiguredRef: false, hasUnknownConfiguredRef: false, diagnostics: [] }; const context = createResolverContext({ sourceConfig: params.config, env: process.env }); commandSecretGatewayDeps.collectConfigAssignments({ config: cloneConfigWithResolutionFacts(params.config), context, agentId: params.agentId }); const activePaths = new Set(context.assignments.map((assignment) => assignment.path)); const inactiveWarningsByPath = /* @__PURE__ */ new Map(); for (const warning of context.warnings) { if (warning.code !== "SECRETS_REF_IGNORED_INACTIVE_SURFACE") continue; inactiveWarningsByPath.set(warning.path, warning.message); } const diagnostics = /* @__PURE__ */ new Set(); let hasActiveConfiguredRef = false; let hasUnknownConfiguredRef = false; for (const path of params.configuredTargetRefPaths) { if (activePaths.has(path) || params.forcedActivePaths?.has(path) || params.optionalActivePaths?.has(path)) { hasActiveConfiguredRef = true; continue; } const inactiveWarning = inactiveWarningsByPath.get(path); if (inactiveWarning) { diagnostics.add(inactiveWarning); continue; } hasUnknownConfiguredRef = true; } return { hasActiveConfiguredRef, hasUnknownConfiguredRef, diagnostics: [...diagnostics] }; } function parseGatewaySecretsResolveResult(payload) { if (!validateSecretsResolveResult(payload)) throw new Error("gateway returned invalid secrets.resolve payload."); const parsed = payload; return { assignments: parsed.assignments ?? [], diagnostics: (parsed.diagnostics ?? []).filter((entry) => entry.trim().length > 0), inactiveRefPaths: (parsed.inactiveRefPaths ?? []).filter((entry) => entry.trim().length > 0) }; } function collectInactiveSurfacePathsFromDiagnostics(diagnostics) { const paths = /* @__PURE__ */ new Set(); for (const entry of diagnostics) { const markerIndex = entry.indexOf(": secret ref is configured on an inactive surface;"); if (markerIndex <= 0) continue; const path = entry.slice(0, markerIndex).trim(); if (path.length > 0) paths.add(path); } return paths; } function filterAllowedGatewayDiagnostics(params) { return params.diagnostics.filter((diagnostic) => { const markerIndex = diagnostic.indexOf(":"); if (markerIndex <= 0) return true; const path = diagnostic.slice(0, markerIndex).trim(); if (!path.includes(".")) return true; if (params.forcedActivePaths?.has(path) || params.optionalActivePaths?.has(path)) return false; return !params.allowedPaths || params.allowedPaths.has(path); }); } function isUnsupportedSecretsResolveError(err) { const message = normalizeLowercaseStringOrEmpty(formatErrorMessage(err)); if (!message.includes("secrets.resolve")) return false; return message.includes("does not support required method") || message.includes("unknown method") || message.includes("method not found") || message.includes("invalid request"); } function isAllowedPathsSecretsResolveCompatError(err) { const message = normalizeLowercaseStringOrEmpty(formatErrorMessage(err)); if (!message.includes("secrets.resolve")) return false; return message.includes("invalid request") || message.includes("invalid secrets.resolve params"); } function hasForcedActivePaths(paths) { return paths !== void 0 && paths.size > 0; } function resolveLocalResolutionPolicy(params) { return { allowExecSecretRefs: params.allowLocalExecSecretRefs !== false, scrubUnresolvedSecretRefs: params.scrubUnresolvedSecretRefs !== false }; } function collectActiveGatewayExecSecretRefCredentialPaths(config) { const defaults = config.secrets?.defaults; return ALL_GATEWAY_SECRET_INPUT_PATHS.filter((path) => { const { ref } = resolveSecretInputRef({ value: readGatewaySecretInputValue(config, path), defaults }); return ref?.source === "exec" && gatewaySecretInputPathCanWin({ config, path, env: process.env }); }); } async function resolveCommandSecretRefsWithoutGateway(params) { const fallback = await resolveCommandSecretRefsLocally({ config: params.config, commandName: params.commandName, targetIds: params.targetIds, agentId: params.agentId, preflightDiagnostics: params.preflightDiagnostics, mode: params.mode, allowedPaths: params.allowedPaths, forcedActivePaths: params.forcedActivePaths, optionalActivePaths: params.optionalActivePaths, resolutionPolicy: params.resolutionPolicy }); return { ...fallback, diagnostics: dedupeDiagnostics([...fallback.diagnostics, params.reasonDiagnostic]) }; } async function callGatewaySecretsResolve(params) { const request = { config: params.config, method: "secrets.resolve", requiredMethods: ["secrets.resolve"], params: { commandName: params.commandName, targetIds: [...params.targetIds], ...params.allowedPaths ? { allowedPaths: [...params.allowedPaths] } : {}, ...params.forcedActivePaths ? { forcedActivePaths: [...params.forcedActivePaths] } : {}, ...params.optionalActivePaths ? { optionalActivePaths: [...params.optionalActivePaths] } : {} }, timeoutMs: 3e4, clientName: GATEWAY_CLIENT_NAMES.CLI, mode: GATEWAY_CLIENT_MODES.CLI }; try { return await callGateway(request); } catch (err) { if (!params.allowedPaths && !params.forcedActivePaths && !params.optionalActivePaths || hasForcedActivePaths(params.forcedActivePaths) || !isAllowedPathsSecretsResolveCompatError(err)) throw err; return callGateway({ ...request, params: { commandName: params.commandName, targetIds: [...params.targetIds] } }); } } function isDirectRuntimeWebTargetPath(path) { return /^plugins\.entries\.[^.]+\.config\.(webSearch|webFetch)\.apiKey$/.test(path); } async function resolveCommandSecretRefsLocally(params) { const sourceConfig = params.config; const resolvedConfig = cloneConfigWithResolutionFacts(params.config); const context = createResolverContext({ sourceConfig, env: process.env }); const localResolutionDiagnostics = []; const discoveredTargets = commandSecretGatewayDeps.discoverConfigSecretTargetsByIds(sourceConfig, params.targetIds).filter((target) => !params.allowedPaths || params.allowedPaths.has(target.path)); const runtimeWebTargets = discoveredTargets.filter((target) => targetsRuntimeWebPath(target.path)); commandSecretGatewayDeps.collectConfigAssignments({ config: cloneConfigWithResolutionFacts(params.config), context, agentId: params.agentId }); if (targetsRuntimeWebResolution({ targetIds: params.targetIds, allowedPaths: params.allowedPaths }) && !runtimeWebTargets.every((target) => isDirectRuntimeWebTargetPath(target.path))) try { await commandSecretGatewayDeps.resolveRuntimeWebTools({ sourceConfig, resolvedConfig, context }); } catch (error) { if (enforcesResolvedSecrets(params.mode)) throw error; localResolutionDiagnostics.push(`${params.commandName}: failed to resolve web tool secrets locally (${formatErrorMessage(error)}).`); } const inactiveRefPaths = new Set(context.warnings.filter((warning) => warning.code === "SECRETS_REF_IGNORED_INACTIVE_SURFACE").filter((warning) => !params.allowedPaths || params.allowedPaths.has(warning.path)).filter((warning) => !params.forcedActivePaths?.has(warning.path)).filter((warning) => !params.optionalActivePaths?.has(warning.path)).map((warning) => warning.path)); const runtimeWebActivePaths = /* @__PURE__ */ new Set(); const runtimeWebInactiveDiagnostics = []; for (const target of runtimeWebTargets) { if (params.forcedActivePaths?.has(target.path) || params.optionalActivePaths?.has(target.path)) { runtimeWebActivePaths.add(target.path); continue; } const runtimeState = classifyRuntimeWebTargetPathState({ config: sourceConfig, path: target.path }); if (runtimeState === "inactive") { inactiveRefPaths.add(target.path); const inactiveDetail = describeInactiveRuntimeWebTargetPath({ config: sourceConfig, path: target.path }); if (inactiveDetail) runtimeWebInactiveDiagnostics.push(`${target.path}: ${inactiveDetail}`); continue; } if (runtimeState === "active") runtimeWebActivePaths.add(target.path); } const inactiveWarningDiagnostics = context.warnings.filter((warning) => warning.code === "SECRETS_REF_IGNORED_INACTIVE_SURFACE").filter((warning) => !params.allowedPaths || params.allowedPaths.has(warning.path)).filter((warning) => !params.forcedActivePaths?.has(warning.path)).filter((warning) => !params.optionalActivePaths?.has(warning.path)).map((warning) => warning.message); const activePaths = new Set(context.assignments.map((assignment) => assignment.path)); for (const target of discoveredTargets) await resolveTargetSecretLocally({ target, sourceConfig, resolvedConfig, env: context.env, cache: context.cache, activePaths, runtimeWebActivePaths, inactiveRefPaths, forcedActivePaths: params.forcedActivePaths, optionalActivePaths: params.optionalActivePaths, mode: params.mode, commandName: params.commandName, localResolutionDiagnostics, resolutionPolicy: params.resolutionPolicy }); let analyzed = commandSecretGatewayDeps.analyzeCommandSecretAssignmentsFromSnapshot({ sourceConfig, resolvedConfig, targetIds: params.targetIds, inactiveRefPaths, ...params.allowedPaths ? { allowedPaths: params.allowedPaths } : {} }); const optionalUnresolvedPaths = analyzed.unresolved.filter((entry) => params.optionalActivePaths?.has(entry.path)).map((entry) => entry.path); if (optionalUnresolvedPaths.length > 0) { for (const path of optionalUnresolvedPaths) inactiveRefPaths.add(path); analyzed = commandSecretGatewayDeps.analyzeCommandSecretAssignmentsFromSnapshot({ sourceConfig, resolvedConfig, targetIds: params.targetIds, inactiveRefPaths, ...params.allowedPaths ? { allowedPaths: params.allowedPaths } : {} }); } const targetStatesByPath = buildTargetStatesByPath({ analyzed, resolvedState: "resolved_local" }); if (analyzed.unresolved.length > 0) { if (enforcesResolvedSecrets(params.mode)) throw new Error(`${params.commandName}: ${analyzed.unresolved[0]?.path ?? "target"} is unresolved in the active runtime snapshot.`); if (params.resolutionPolicy.scrubUnresolvedSecretRefs) scrubUnresolvedAssignments(resolvedConfig, analyzed.unresolved); } return { resolvedConfig, diagnostics: dedupeDiagnostics([ ...params.preflightDiagnostics, ...runtimeWebInactiveDiagnostics, ...inactiveWarningDiagnostics, ...filterInactiveSurfaceDiagnostics({ diagnostics: analyzed.diagnostics, inactiveRefPaths }), ...localResolutionDiagnostics, ...buildUnresolvedDiagnostics(params.commandName, analyzed.unresolved, params.mode) ]), targetStatesByPath, hadUnresolvedTargets: analyzed.unresolved.length > 0 }; } function buildTargetStatesByPath(params) { const states = {}; for (const assignment of params.analyzed.assignments) states[assignment.path] = params.resolvedState; for (const entry of params.analyzed.inactive) states[entry.path] = "inactive_surface"; for (const entry of params.analyzed.unresolved) states[entry.path] = "unresolved"; return states; } function buildUnresolvedDiagnostics(commandName, unresolved, mode) { if (enforcesResolvedSecrets(mode)) return []; return unresolved.map((entry) => `${commandName}: ${entry.path} is unavailable in this command path; continuing with degraded read-only config.`); } function scrubUnresolvedAssignments(config, unresolved) { for (const entry of unresolved) setPathExistingStrict(config, entry.pathSegments, void 0); } function filterInactiveSurfaceDiagnostics(params) { return params.diagnostics.filter((entry) => { const markerIndex = entry.indexOf(": secret ref is configured on an inactive surface;"); if (markerIndex <= 0) return true; const path = entry.slice(0, markerIndex).trim(); return !params.inactiveRefPaths.has(path); }); } async function resolveTargetSecretLocally(params) { const defaults = params.sourceConfig.secrets?.defaults; const { ref } = resolveSecretInputRef({ value: resolveConfigSecretRef({ config: params.sourceConfig, path: params.target.path, value: params.target.value, defaults }), refValue: params.target.refValue, defaults }); if (!ref || params.inactiveRefPaths.has(params.target.path) || !params.activePaths.has(params.target.path) && !params.runtimeWebActivePaths.has(params.target.path) && !params.forcedActivePaths?.has(params.target.path) && !params.optionalActivePaths?.has(params.target.path)) return; if (ref.source === "exec" && !params.resolutionPolicy.allowExecSecretRefs) { if (!enforcesResolvedSecrets(params.mode)) params.localResolutionDiagnostics.push(`${params.commandName}: skipped local exec SecretRef resolution for ${params.target.path}; rerun with --allow-exec to execute configured exec providers.`); return; } try { const resolved = await resolveSecretRefValue(ref, { config: params.sourceConfig, env: params.env, cache: params.cache }); assertExpectedResolvedSecretValue({ value: resolved, expected: params.target.entry.expectedResolvedValue, errorMessage: params.target.entry.expectedResolvedValue === "string" ? `${params.target.path} resolved to a non-string or empty value.` : `${params.target.path} resolved to an unsupported value type.` }); setPathExistingStrict(params.resolvedConfig, params.target.pathSegments, resolved); copyConfigResolutionFactsExcept(params.resolvedConfig, params.resolvedConfig, [params.target.path]); } catch (error) { if (!enforcesResolvedSecrets(params.mode)) params.localResolutionDiagnostics.push(`${params.commandName}: failed to resolve ${params.target.path} locally (${formatErrorMessage(error)}).`); } } async function resolveCommandSecretRefsViaGateway(params) { const mode = normalizeCommandSecretResolutionMode(params.mode); const resolutionPolicy = resolveLocalResolutionPolicy({ allowLocalExecSecretRefs: params.allowLocalExecSecretRefs, scrubUnresolvedSecretRefs: params.scrubUnresolvedSecretRefs }); const configuredTargetRefPaths = collectConfiguredTargetRefPaths({ config: params.config, targetIds: params.targetIds, allowedPaths: params.allowedPaths }); if (configuredTargetRefPaths.size === 0) return { resolvedConfig: params.config, diagnostics: [], targetStatesByPath: {}, hadUnresolvedTargets: false }; const preflight = classifyConfiguredTargetRefs({ config: params.config, configuredTargetRefPaths, agentId: params.agentId, forcedActivePaths: params.forcedActivePaths, optionalActivePaths: params.optionalActivePaths }); if (!preflight.hasActiveConfiguredRef && !preflight.hasUnknownConfiguredRef) return { resolvedConfig: params.config, diagnostics: preflight.diagnostics, targetStatesByPath: {}, hadUnresolvedTargets: false }; const gatewayExecSecretRefCredentialPaths = resolutionPolicy.allowExecSecretRefs ? [] : collectActiveGatewayExecSecretRefCredentialPaths(params.config); if (gatewayExecSecretRefCredentialPaths.length > 0) return await resolveCommandSecretRefsWithoutGateway({ config: params.config, commandName: params.commandName, targetIds: params.targetIds, agentId: params.agentId, preflightDiagnostics: preflight.diagnostics, mode, allowedPaths: params.allowedPaths, forcedActivePaths: params.forcedActivePaths, optionalActivePaths: params.optionalActivePaths, resolutionPolicy, reasonDiagnostic: `${params.commandName}: skipped gateway secrets.resolve because gateway credentials use exec SecretRefs at ${gatewayExecSecretRefCredentialPaths.join(", ")}; rerun with --allow-exec to execute configured exec providers.` }); let payload; try { payload = await callGatewaySecretsResolve({ config: params.config, commandName: params.commandName, targetIds: params.targetIds, allowedPaths: params.allowedPaths, forcedActivePaths: params.forcedActivePaths, optionalActivePaths: params.optionalActivePaths }); } catch (err) { let forcedActiveCompatFailure; try { const fallback = await resolveCommandSecretRefsLocally({ config: params.config, commandName: params.commandName, targetIds: params.targetIds, agentId: params.agentId, preflightDiagnostics: preflight.diagnostics, mode, allowedPaths: params.allowedPaths, forcedActivePaths: params.forcedActivePaths, optionalActivePaths: params.optionalActivePaths, resolutionPolicy }); const recoveredLocally = Object.values(fallback.targetStatesByPath).some((state) => state === "resolved_local"); if (hasForcedActivePaths(params.forcedActivePaths) && isAllowedPathsSecretsResolveCompatError(err) && (!recoveredLocally || fallback.hadUnresolvedTargets)) forcedActiveCompatFailure = new Error(`${params.commandName}: active gateway does not support command-scoped secret resolution (${formatErrorMessage(err)}). Update the gateway or run this command where the configured SecretRefs can be resolved locally.`, { cause: err }); else { const fallbackMessage = recoveredLocally && !fallback.hadUnresolvedTargets ? "resolved command secrets locally." : "attempted local command-secret resolution."; return { resolvedConfig: fallback.resolvedConfig, diagnostics: dedupeDiagnostics([...fallback.diagnostics, `${params.commandName}: gateway secrets.resolve unavailable (${formatErrorMessage(err)}); ${fallbackMessage}`]), targetStatesByPath: fallback.targetStatesByPath, hadUnresolvedTargets: fallback.hadUnresolvedTargets }; } } catch {} if (forcedActiveCompatFailure) throw forcedActiveCompatFailure; if (hasForcedActivePaths(params.forcedActivePaths) && isAllowedPathsSecretsResolveCompatError(err)) throw new Error(`${params.commandName}: active gateway does not support command-scoped secret resolution (${formatErrorMessage(err)}). Update the gateway or run this command where the configured SecretRefs can be resolved locally.`, { cause: err }); if (isUnsupportedSecretsResolveError(err)) throw new Error(`${params.commandName}: active gateway does not support secrets.resolve (${formatErrorMessage(err)}). Update the gateway or run without SecretRefs.`, { cause: err }); throw new Error(`${params.commandName}: failed to resolve secrets from the active gateway snapshot (${formatErrorMessage(err)}). Start the gateway and retry.`, { cause: err }); } const parsed = parseGatewaySecretsResolveResult(payload); const gatewayDiagnostics = filterAllowedGatewayDiagnostics({ allowedPaths: params.allowedPaths, forcedActivePaths: params.forcedActivePaths, optionalActivePaths: params.optionalActivePaths, diagnostics: parsed.diagnostics }); const gatewayInactiveRefPaths = params.allowedPaths ? parsed.inactiveRefPaths.filter((path) => params.allowedPaths?.has(path)) : parsed.inactiveRefPaths; const resolvedConfig = cloneConfigWithResolutionFacts(params.config); const assignments = params.allowedPaths ? parsed.assignments.filter((assignment) => { const path = assignment.path ?? assignment.pathSegments.join("."); return params.allowedPaths?.has(path); }) : parsed.assignments; const resolvedAssignmentPaths = []; for (const assignment of assignments) { const pathSegments = assignment.pathSegments.filter((segment) => segment.length > 0); if (pathSegments.length === 0) continue; const path = pathSegments.join("."); try { setPathExistingStrict(resolvedConfig, pathSegments, assignment.value); resolvedAssignmentPaths.push(path); } catch (err) { throw new Error(`${params.commandName}: failed to apply resolved secret assignment at ${path} (${formatErrorMessage(err)}).`, { cause: err }); } } copyConfigResolutionFactsExcept(resolvedConfig, resolvedConfig, resolvedAssignmentPaths); const inactiveRefPaths = new Set(gatewayInactiveRefPaths.length > 0 ? gatewayInactiveRefPaths : collectInactiveSurfacePathsFromDiagnostics(gatewayDiagnostics)); for (const path of params.forcedActivePaths ?? []) inactiveRefPaths.delete(path); for (const path of params.optionalActivePaths ?? []) inactiveRefPaths.delete(path); let analyzed = commandSecretGatewayDeps.analyzeCommandSecretAssignmentsFromSnapshot({ sourceConfig: params.config, resolvedConfig, targetIds: params.targetIds, inactiveRefPaths, allowedPaths: params.allowedPaths }); const optionalUnresolvedPaths = analyzed.unresolved.filter((entry) => params.optionalActivePaths?.has(entry.path)).map((entry) => entry.path); if (optionalUnresolvedPaths.length > 0) { for (const path of optionalUnresolvedPaths) inactiveRefPaths.add(path); analyzed = commandSecretGatewayDeps.analyzeCommandSecretAssignmentsFromSnapshot({ sourceConfig: params.config, resolvedConfig, targetIds: params.targetIds, inactiveRefPaths, allowedPaths: params.allowedPaths }); } let diagnostics = dedupeDiagnostics(gatewayDiagnostics); const targetStatesByPath = buildTargetStatesByPath({ analyzed, resolvedState: "resolved_gateway" }); if (analyzed.unresolved.length > 0) try { const localFallback = await resolveCommandSecretRefsLocally({ config: params.config, commandName: params.commandName, targetIds: params.targetIds, agentId: params.agentId, preflightDiagnostics: [], mode, allowedPaths: new Set(analyzed.unresolved.map((entry) => entry.path)), forcedActivePaths: params.forcedActivePaths, optionalActivePaths: params.optionalActivePaths, resolutionPolicy }); const handledPaths = /* @__PURE__ */ new Set(); const locallyResolvedPaths = /* @__PURE__ */ new Set(); for (const unresolved of analyzed.unresolved) { const localState = localFallback.targetStatesByPath[unresolved.path]; if (localState === "inactive_surface") { targetStatesByPath[unresolved.path] = localState; handledPaths.add(unresolved.path); continue; } if (localState !== "resolved_local") continue; setPathExistingStrict(resolvedConfig, unresolved.pathSegments, getPath(localFallback.resolvedConfig, unresolved.pathSegments)); targetStatesByPath[unresolved.path] = localState; handledPaths.add(unresolved.path); locallyResolvedPaths.add(unresolved.path); } copyConfigResolutionFactsExcept(resolvedConfig, resolvedConfig, [...locallyResolvedPaths]); diagnostics = dedupeDiagnostics([...diagnostics, ...localFallback.diagnostics]); const stillUnresolved = analyzed.unresolved.filter((entry) => !handledPaths.has(entry.path)); if (stillUnresolved.length > 0) { if (enforcesResolvedSecrets(mode)) throw new Error(`${params.commandName}: ${stillUnresolved[0]?.path ?? "target"} is unresolved in the active runtime snapshot.`); if (resolutionPolicy.scrubUnresolvedSecretRefs) scrubUnresolvedAssignments(resolvedConfig, stillUnresolved); diagnostics = dedupeDiagnostics([...diagnostics, ...buildUnresolvedDiagnostics(params.commandName, stillUnresolved, mode)]); for (const unresolved of stillUnresolved) targetStatesByPath[unresolved.path] = "unresolved"; } else if (locallyResolvedPaths.size > 0) diagnostics = dedupeDiagnostics([...diagnostics, `${params.commandName}: resolved ${locallyResolvedPaths.size} secret ${locallyResolvedPaths.size === 1 ? "path" : "paths"} locally after the gateway snapshot was incomplete.`]); } catch (error) { if (enforcesResolvedSecrets(mode)) throw error; if (resolutionPolicy.scrubUnresolvedSecretRefs) scrubUnresolvedAssignments(resolvedConfig, analyzed.unresolved); diagnostics = dedupeDiagnostics([ ...diagnostics, `${params.commandName}: local fallback after incomplete gateway snapshot failed (${formatErrorMessage(error)}).`, ...buildUnresolvedDiagnostics(params.commandName, analyzed.unresolved, mode) ]); } return { resolvedConfig, diagnostics, targetStatesByPath, hadUnresolvedTargets: Object.values(targetStatesByPath).includes("unresolved") }; } //#endregion export { resolveCommandSecretRefsViaGateway as t };