From eb855f75ce7161461b46d853ad054cb2d817f773 Mon Sep 17 00:00:00 2001 From: joshavant <830519+joshavant@users.noreply.github.com> Date: Sun, 22 Feb 2026 14:37:20 -0800 Subject: [PATCH] Gateway: emit one-shot operator events for secrets degraded/recovered --- src/gateway/server.impl.ts | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/src/gateway/server.impl.ts b/src/gateway/server.impl.ts index b5c1b121370..721207df2b0 100644 --- a/src/gateway/server.impl.ts +++ b/src/gateway/server.impl.ts @@ -19,6 +19,7 @@ import { writeConfigFile, } from "../config/config.js"; import { applyPluginAutoEnable } from "../config/plugin-auto-enable.js"; +import { resolveMainSessionKey } from "../config/sessions.js"; import { clearAgentRunContext, onAgentEvent } from "../infra/agent-events.js"; import { ensureControlUiAssetsBuilt, @@ -38,6 +39,7 @@ import { refreshRemoteBinsForConnectedNodes, setSkillsRemoteRegistry, } from "../infra/skills-remote.js"; +import { enqueueSystemEvent } from "../infra/system-events.js"; import { scheduleGatewayUpdateCheck } from "../infra/update-startup.js"; import { startDiagnosticHeartbeat, stopDiagnosticHeartbeat } from "../logging/diagnostic.js"; import { createSubsystemLogger, runtimeForLogger } from "../logging/subsystem.js"; @@ -257,6 +259,16 @@ export async function startGatewayServer( } let secretsDegraded = false; + const emitSecretsStateEvent = ( + code: "SECRETS_RELOADER_DEGRADED" | "SECRETS_RELOADER_RECOVERED", + message: string, + cfg: OpenClawConfig, + ) => { + enqueueSystemEvent(`[${code}] ${message}`, { + sessionKey: resolveMainSessionKey(cfg), + contextKey: code, + }); + }; const activateRuntimeSecrets = async ( config: OpenClawConfig, params: { reason: "startup" | "reload" | "restart-check"; activate: boolean }, @@ -270,9 +282,10 @@ export async function startGatewayServer( logSecrets.warn(`[${warning.code}] ${warning.message}`); } if (secretsDegraded) { - logSecrets.info( - "[SECRETS_RELOADER_RECOVERED] Secret resolution recovered; runtime remained on last-known-good during the outage.", - ); + const recoveredMessage = + "Secret resolution recovered; runtime remained on last-known-good during the outage."; + logSecrets.info(`[SECRETS_RELOADER_RECOVERED] ${recoveredMessage}`); + emitSecretsStateEvent("SECRETS_RELOADER_RECOVERED", recoveredMessage, prepared.config); } secretsDegraded = false; return prepared; @@ -280,6 +293,13 @@ export async function startGatewayServer( const details = String(err); if (!secretsDegraded) { logSecrets.error(`[SECRETS_RELOADER_DEGRADED] ${details}`); + if (params.reason !== "startup") { + emitSecretsStateEvent( + "SECRETS_RELOADER_DEGRADED", + `Secret resolution failed; runtime remains on last-known-good snapshot. ${details}`, + config, + ); + } } else { logSecrets.warn(`[SECRETS_RELOADER_DEGRADED] ${details}`); }