fix(gateway): skip secrets.resolve when target SecretRefs use exec providers#96661
fix(gateway): skip secrets.resolve when target SecretRefs use exec providers#96661SunnyShu0925 wants to merge 3 commits into
Conversation
|
Codex review: needs maintainer review before merge. Reviewed July 7, 2026, 2:17 PM ET / 18:17 UTC. Summary PR surface: Source +50, Tests +158. Total +208 across 2 files. Reproducibility: yes. at source level: queued replies use Review metrics: 1 noteworthy metric.
Stored data model Root-cause cluster Members:
Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything. Merge readiness Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch. Rank-up moves:
Risk before merge
Maintainer options:
Next step before merge
Maintainer decision needed
Security Review detailsBest possible solution: Land this PR or an equivalent maintainer-sponsored patch after accepting active exec target refs as local-resolution triggers, preserving the active-target filter, no-local-exec gate, inactive-target safeguard, and regression tests. Do we have a high-confidence way to reproduce the issue? Yes at source level: queued replies use Is this the best way to solve the issue? Yes, if maintainers accept the boundary: the PR fixes the narrow log-flood path in the shared command-secret resolver and preserves active-target, inactive-target, and no-local-exec safeguards. A gateway-owned partial-resolution design is the main alternative if maintainers prefer gateway-first semantics. AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against a6768d9de567. Label changesLabel justifications:
Evidence reviewedPR surface: Source +50, Tests +158. Total +208 across 2 files. View PR surface stats
What I checked:
Likely related people:
What the crustacean ranks mean
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics. How this review workflow works
|
bc505e8 to
d2d3e87
Compare
|
@clawsweeper re-review |
|
🦞🧹 I asked ClawSweeper to review this item again. |
… gate behind policy resolveCommandSecretRefsViaGateway now skips the gateway RPC when target SecretRefs use exec providers — not just when gateway credentials themselves are exec refs. Gateway cannot resolve exec refs, so the round-trip always produced UNAVAILABLE → local fallback → log flood on every reply turn. Three safeguards applied: 1. Collect active (not just discovered) exec target ref paths, so inactive exec refs in a mixed target set do not bypass gateway snapshot resolution for unrelated active targets. 2. Gate the target-exec skip behind resolutionPolicy.allowExecSecretRefs, so no-local-exec callers (e.g. doctor preview) still attempt the gateway. 3. Diagnostic message unified to cover both gateway-credential and target-ref exec paths. Related to openclaw#96653 Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
8680e67 to
fa813b5
Compare
|
Landed the corrected current-main replacement as #105160 / The final implementation preserves @SunnyShu0925's contribution while fixing the mixed-target regression in the original bypass: Gateway snapshot assignments remain authoritative and local fallback resolves only missing paths. The fork branch's stale ancestry could not be updated safely without carrying unrelated mainline history, so I rebuilt the reviewed patch as exactly one commit atop current main and landed that replacement. Thank you, @SunnyShu0925. |
Summary
reply-path
secrets.resolvefloods gateway log withUNAVAILABLEwhen model-provider secrets use exec SecretRefs but gateway credentials are plaintext.resolveCommandSecretRefsViaGatewayskip logic only checksALL_GATEWAY_SECRET_INPUT_PATHS(4 gateway credential paths), missing model-provider exec ref targets. Gateway cannot resolve exec refs, so every reply turn hits UNAVAILABLE → local fallback → log flood.resolutionPolicy.allowExecSecretRefsand filtered to active command targets only, so inactive exec refs do not bypass gateway snapshot resolution for unrelated active targets.src/cli/command-secret-gateway.ts(newcollectActiveExecTargetRefPathshelper withactiveConfiguredRefPathsfilter,classifyConfiguredTargetRefsnow returnsactiveConfiguredRefPaths, skip condition extended, gated behindresolutionPolicy.allowExecSecretRefs) andsrc/cli/command-secret-gateway.test.ts(3 new/updated tests including mixed-target regression test).allowExecSecretRefspolicy handling.collectActiveExecTargetRefPathsis gated byresolutionPolicy.allowExecSecretRefsand filtered to active command refs only — no-local-exec callers still attempt gateway, inactive exec refs do not poison skip decisions.Change Type (select all)
Scope (select all)
Linked Issue/PR
Motivation
When a user configures model-provider secrets with
source: "exec"(e.g.models.providers.openai.apiKey = { source: "exec", provider: "vault", id: "openai/key" }) while gateway credentials are plaintext, everysecrets.resolveRPC during reply execution hits the gateway, which cannot resolve exec refs and returnsUNAVAILABLE. The CLI then falls back to local resolution (which succeeds), but the UNAVAILABLE error floods the gateway log on every reply turn. This is pure noise: the skip logic already existed for the case where gateway credentials themselves use exec refs, but was scoped too narrowly and did not filter inactive exec refs.Real behavior proof
Behavior addressed: Gateway log flooded with
secrets.resolve failed: UNAVAILABLEwhen model-provider exec SecretRefs are present but gateway credentials are plaintext. Additionally, inactive exec refs in mixed target sets must not trigger the skip.Real environment tested: Linux x64, Node v22.11.0, branch
fix/secrets-resolve-exec-skip-96653Exact steps or command run after this patch:
Evidence after fix:
Live dist bundle proof (production built code, real exec child process) — 3 scenarios:
Unit tests (36/36) with real exec provider child processes + mixed-target regression test:
Key tests and what they prove:
skips gateway resolution when gateway credentials would execute exec SecretRefsskips gateway resolution when target SecretRefs include exec providerscallGatewaynot calledskips local exec SecretRef fallback when the caller disallows exec providersallowLocalExecSecretRefs: false, gateway is attempted (not skipped); exec ref stays unresolveddoes not skip gateway resolution when only inactive targets use exec SecretRefskeeps local exec SecretRef fallback enabled by defaultObserved result after fix:
secrets.resolveRPC is not attempted when any active target SecretRef uses an exec providerallowLocalExecSecretRefs=falsecallers (e.g. doctor preview) still attempt the gateway (not skipped)skipped gateway secrets.resolve because SecretRefs use exec providers at ...resolveCommandSecretRefsViaGateway, shared by all callers)What was not tested:
resolveCommandSecretRefsViaGatewayapplies; target discovery is genericRoot Cause (if applicable)
Introduced by commit
1ee2733b2f(Vincent Koc, 2026-06-17,fix(qa-lab): harden live cleanup and readiness). ThecollectActiveGatewayExecSecretRefCredentialPathsfunction filtersALL_GATEWAY_SECRET_INPUT_PATHS— only 4 gateway credential paths (gateway.auth.token/password,gateway.remote.token/password). Model-provider secrets (models.providers.*.apiKey, etc.) are never checked. The target ref paths were already known at the decision point, but this information was discarded before the skip check.Additionally, ClawSweeper review identified:
collectActiveExecTargetRefPathscollected all discovered exec refs including inactive ones, which could bypass gateway snapshot resolution for unrelated active targets in mixed target sets.Regression Test Plan (if applicable)
Target test:
src/cli/command-secret-gateway.test.tsUser-visible / Behavior Changes
None. The fix changes when the skip triggers (earlier in more cases for active exec refs, not at all for inactive exec refs) but the resolution outcome is identical — local resolution was already the fallback after UNAVAILABLE. Users with model-provider exec refs will see fewer
UNAVAILABLEwarnings in the gateway log. Users with only inactive exec refs see no behavior change.Security Impact (required)
Human Verification (required)
activeConfiguredRefPathsis computed fromclassifyConfiguredTargetRefswhich is target-agnostic); live gateway with real mixed exec targetsReview Conversations
Compatibility / Migration
Best-fix Verdict
classifyConfiguredTargetRefs.collectActiveExecTargetRefPathsfollows the same pattern as existing helpers.classifyConfiguredTargetRefsreturns an additional field (activeConfiguredRefPaths) that is a natural byproduct of its existing computation.ALL_GATEWAY_SECRET_INPUT_PATHSto include model-provider paths — rejected because those are not fixed paths (different providers have different key paths), making a static list fragile and incomplete. Collecting all discovered exec refs unconditionally — rejected because inactive exec refs in mixed target sets would bypass gateway snapshot resolution for active non-exec targets.AI Assistance
Risks and Mitigations
None. The fix only expands when the gateway RPC skip triggers. The local fallback path is the same code that already executed after every UNAVAILABLE error. The active/inactive filter reuses the pre-existing classification from
classifyConfiguredTargetRefs. Three merge-risk labels are addressed:🚨 auth-provider— inactive exec refs do not affect active model-provider credential resolution🚨 compatibility— users with only inactive exec refs see no behavior change🚨 security-boundary— only active exec refs enter local resolution path; inactive exec refs do not change security boundariesNo new code path is introduced for resolution, only for the skip decision. All existing tests continue to pass (36/36, including new mixed-target regression test).
Related to #96653