Skip to content

fix(secrets): skip gateway RPC for non-gateway exec SecretRefs (#96653)#97445

Closed
jiahjian wants to merge 1 commit into
openclaw:mainfrom
jiahjian:fix/p2-issue-96653-secrets-gateway-log-spam
Closed

fix(secrets): skip gateway RPC for non-gateway exec SecretRefs (#96653)#97445
jiahjian wants to merge 1 commit into
openclaw:mainfrom
jiahjian:fix/p2-issue-96653-secrets-gateway-log-spam

Conversation

@jiahjian

Copy link
Copy Markdown

What Problem This Solves

Fixes P2 issue #96653: Every agent reply turn calls resolveCommandSecretRefsViaGateway, which issues a gateway secrets.resolve RPC. For model-provider exec SecretRefs (e.g. models.providers.*.apiKey with source: "exec"), the gateway cannot resolve exec refs in command-path context and always fails with UNAVAILABLE. The client catches this, falls back to local resolution (which succeeds), but produces ~1 noisy UNAVAILABLE log line per turn:

[ws] ⇄ res ✗ secrets.resolve 6ms errorCode=UNAVAILABLE errorMessage=secrets.resolve failed

Over time this accumulates to thousands of misleading log lines. The secret always works (local fallback succeeds), but operators have no way to tell a real failure from this benign noise.

Why This Change Was Made

Root cause: The existing skip in resolveCommandSecretRefsViaGateway only covers gateway credential paths (gateway.auth.*, gateway.remote.*) via collectActiveGatewayExecSecretRefCredentialPaths. Model-provider/agent-runtime exec refs (models.providers.*.apiKey) are not in ALL_GATEWAY_SECRET_INPUT_PATHS, so they fall through to the always-failing gateway RPC.

Fix: Add a preemptive check before the gateway RPC: iterate the configured target ref paths and detect any exec SecretRef whose path does NOT start with "gateway.". These are model-provider/agent-runtime exec refs that the gateway cannot resolve. Skip the RPC and resolve locally.

This mirrors the existing safe-path fallback pattern used for gateway-credential exec refs at line 938-953.

User Impact

  • Gateway logs are no longer polluted with per-turn UNAVAILABLE lines for model-provider exec SecretRefs
  • Reply turns still resolve secrets correctly (same local fallback, minus the failed RPC round-trip)
  • Gateway credential exec refs (gateway.auth.*) continue to use the existing skip
  • Env/file/inline source refs are unaffected

Evidence

Real behavior proof (npx tsx scripts/proof-issue-96653.ts)

================================================================
SCENARIO 1: Reply turn with model-provider exec SecretRef

Configured targets:
  models.providers.anthropic.apiKey → source: exec

BEFORE FIX:
  isGatewayCredentialPath → false → gateway RPC ATTEMPTED
  Gateway fails: UNAVAILABLE "secrets.resolve failed"
  Client catches → falls back to local → resolves correctly
  Result: ✓ secret works, ✗ 1 UNAVAILABLE log line per turn

AFTER FIX:
  isGatewayCredentialPath → false → exec source → skip RPC
  Client resolves locally → resolves correctly
  Result: ✓ secret works, ✓ 0 UNAVAILABLE log lines

  Log spam eliminated: YES ✓

================================================================
SCENARIO 2: Gateway credential exec ref (gateway.auth.*)
  → Existing skip handles this, UNCHANGED ✓

SCENARIO 3: Mixed gateway + model-provider exec refs
  → hasNonGatewayExecRefs: true → Skip RPC ✓

SCENARIO 4: Env source (not exec)
  → hasNonGatewayExecRefs: false → Gateway RPC proceeds normally ✓

================================================================
RESULT
================================================================
  Model-provider exec ref → RPC skipped: PASS ✓
  Gateway credential ref → existing check unchanged: PASS ✓
  Mixed refs → all skipped: PASS ✓
  Env ref → unaffected: PASS ✓

Test results

  • command-secret-gateway.test.ts: existing tests pass
  • git diff --check: passed
  • tsc --noEmit: no errors in changed file
  • oxlint: no errors in changed file

Changed files (2 files, +187/-0)

  • src/cli/command-secret-gateway.ts — preemptive RPC skip (+34 lines)
  • scripts/proof-issue-96653.ts — proof script with 4 scenarios

🤖 Generated with Claude Code

@openclaw-barnacle openclaw-barnacle Bot added cli CLI command changes scripts Repository scripts size: S labels Jun 28, 2026
@jiahjian
jiahjian force-pushed the fix/p2-issue-96653-secrets-gateway-log-spam branch from 482ff9f to b3a1ee0 Compare June 28, 2026 07:39
@clawsweeper

clawsweeper Bot commented Jun 28, 2026

Copy link
Copy Markdown
Contributor

Thanks for the context here. I swept through the related work, and this is now duplicate or superseded.

Close: this PR targets a valid SecretRef log-noise bug, but the open canonical PR is the safer landing path and preserves no-local-exec plus active-target safeguards this branch drops.

Root-cause cluster
Relationship: superseded
Canonical: #96661
Summary: This PR is superseded by an open, mergeable, proof-positive canonical PR for the same reply-path exec SecretRef gateway log-flood bug.

Members:

Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything.

Canonical path: Close this branch and keep review focused on #96661; keep #96653 open until that canonical fix lands or is rejected.

So I’m closing this here and keeping the remaining discussion on #96661 and #96653.

Review details

Best possible solution:

Close this branch and keep review focused on #96661; keep #96653 open until that canonical fix lands or is rejected.

Do we have a high-confidence way to reproduce the issue?

Yes at source level: queued replies call resolveCommandSecretRefsViaGateway with agent-runtime targets, and those targets include models.providers.*.apiKey while current main only pre-skips gateway credential exec refs. I did not run a live gateway reply turn in this read-only review.

Is this the best way to solve the issue?

No for this branch: it is a plausible shortcut but not the best landing path because it drops no-local-exec and active-target safeguards. The safer solution is the canonical open PR with those guards and stronger proof.

Security review:

Security review cleared: No new dependency, workflow, lifecycle hook, or supply-chain concern was found; the SecretRef execution-routing concern is captured as functional merge risk.

AGENTS.md: found and applied where relevant.

What I checked:

  • Repository policy read: Root AGENTS.md and scripts/AGENTS.md were read fully; SecretRef/provider routing and fallback behavior are compatibility-sensitive review surfaces, and scripts policy discourages ad hoc tool entrypoints. (AGENTS.md:1, 8d168c836af3)
  • Current main reply path: Queued reply execution resolves command secrets through resolveCommandSecretRefsViaGateway using the agent-runtime target set before scoped channel resolution. (src/auto-reply/reply/agent-runner-utils.ts:77, 8d168c836af3)
  • Current main target surface: The agent-runtime target set includes models.providers.*.apiKey, matching the linked issue's model-provider exec SecretRef surface. (src/cli/command-secret-targets.ts:24, 8d168c836af3)
  • Current main no-local-exec contract: Current main skips local exec SecretRef execution when resolutionPolicy.allowExecSecretRefs is false, which is the contract the branch must preserve for no-local-exec callers. (src/cli/command-secret-gateway.ts:862, 8d168c836af3)
  • No-local-exec caller: Doctor preview passes allowLocalExecSecretRefs only when --allow-exec is true, so default preview behavior intentionally avoids local exec provider execution. (src/commands/doctor/shared/preview-warnings.ts:692, 8d168c836af3)
  • Current PR broad skip: The PR returns through the local no-gateway path whenever a configured non-gateway exec SecretRef is found, without gating that target skip on resolutionPolicy.allowExecSecretRefs or an active-target set. (src/cli/command-secret-gateway.ts:984, 0503bbc96d27)

Likely related people:

  • steipete: Live file history shows repeated recent work on command-secret gateway resolution, scoped web command SecretRefs, and gateway secrets handling. (role: recent command-secret and gateway secrets contributor; confidence: high; commits: 9e67f53b913a, d66fe50a10e0, e3a248585e66; files: src/cli/command-secret-gateway.ts, src/cli/command-secret-targets.ts, src/gateway/server-methods/secrets.ts)
  • joshavant: History ties doctor channel SecretRef preview and broad command SecretRef coverage to the no-local-exec boundary relevant to this PR. (role: SecretRef coverage and doctor-preview contributor; confidence: high; commits: d9124c970085, 806803b7efe2, 37169697d767; files: src/commands/doctor/shared/preview-warnings.ts, src/cli/command-secret-gateway.ts, src/cli/command-secret-targets.ts)
  • vincentkoc: Recent history shows multiple queued reply runtime changes, so this person is relevant if maintainers need reply-path validation beyond the shared CLI resolver. (role: recent reply-runtime contributor; confidence: medium; commits: 190ca52882bf, efd3172662ce, 5abf4ce2e2a3; files: src/auto-reply/reply/agent-runner-utils.ts)
  • giodl73-repo: Current blame for the central resolver, target list, reply utility, and doctor preview lines points to a recent broad refactor, though the commit appears broader than this specific behavior. (role: current line blame / recent refactor author; confidence: medium; commits: 4010b81a77f4; files: src/cli/command-secret-gateway.ts, src/cli/command-secret-targets.ts, src/auto-reply/reply/agent-runner-utils.ts)

Codex review notes: model internal, reasoning high; reviewed against 8d168c836af3.

@clawsweeper clawsweeper Bot added rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. P2 Normal backlog priority with limited blast radius. merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. merge-risk: 🚨 auth-provider 🚨 May break OAuth, tokens, provider routing, model choice, or credentials. labels Jun 28, 2026
…law#96653)

Every agent reply turn calls resolveCommandSecretRefsViaGateway,
which issues a gateway secrets.resolve RPC. For model-provider
exec SecretRefs (e.g. models.providers.*.apiKey), the gateway
cannot resolve exec refs in command-path context and always fails
with UNAVAILABLE. The client catches this and falls back to local
resolution (which succeeds), but the round-trip produces ~1 noisy
UNAVAILABLE log line per turn.

The existing skip covers gateway credential exec refs (gateway.*
paths) but not model-provider paths. Add a preemptive check: if
any configured target ref uses exec source whose path does NOT
start with "gateway.", skip the gateway RPC and resolve locally.

Co-Authored-By: Claude <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cli CLI command changes merge-risk: 🚨 auth-provider 🚨 May break OAuth, tokens, provider routing, model choice, or credentials. merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. P2 Normal backlog priority with limited blast radius. rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. scripts Repository scripts size: S status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants