fix(feishu): re-throw unresolved SecretRef errors from media fallbacks#89395
fix(feishu): re-throw unresolved SecretRef errors from media fallbacks#89395Bartok9 wants to merge 2 commits into
Conversation
Previously, both catch blocks in `feishuOutbound.sendText` (local-image auto-convert path) and `feishuOutbound.sendMedia` silently swallowed all errors, including `FeishuSecretRefUnavailableError`. When `appSecret` (or another credential) was configured with an exec/file/keychain SecretRef that hadn't been pre-resolved by the gateway, the error was caught and the send degraded to a plain-text URL link with only a `console.error` — giving the caller no indication that credentials were missing. Re-throw `FeishuSecretRefUnavailableError` in both catch blocks so the configuration error surfaces immediately instead of being masked by the fallback path. Two new tests in outbound.test.ts cover both catch sites. Fixes openclaw#89338
Previously, both catch blocks in feishuOutbound.sendText (local-image auto-convert path) and feishuOutbound.sendMedia silently swallowed all errors, including FeishuSecretRefUnavailableError. When appSecret (or another credential) was configured with an exec/file/keychain SecretRef that had not been pre-resolved by the gateway, the error was caught and the send degraded to a plain-text URL link with only a console.error, giving the caller no indication that credentials were missing. Re-throw FeishuSecretRefUnavailableError in both catch blocks so the configuration error surfaces immediately instead of being masked by the fallback path. Two new tests in outbound.test.ts cover both catch sites. Fixes openclaw#89338
|
Codex review: found issues before merge. Reviewed June 29, 2026, 7:55 PM ET / 23:55 UTC. Summary PR surface: Source +12, Tests +49. Total +61 across 2 files. Reproducibility: yes. at source level: Feishu appSecret is a supported SecretRef surface, Review metrics: 1 noteworthy metric.
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
Security Review findings
Review detailsBest possible solution: Land one canonical Feishu SecretRef media repair that feeds resolved app credentials from the active runtime snapshot before Feishu client/media upload across outbound, message-tool, and reply-dispatcher paths, preserving fallbacks for transient upload failures. Do we have a high-confidence way to reproduce the issue? Yes, at source level: Feishu appSecret is a supported SecretRef surface, Is this the best way to solve the issue? No. This PR is a useful diagnostic mitigation, but the best fix resolves SecretRef-backed Feishu credentials before media upload so the image can be delivered rather than turning the failure into a hard error. Full review comments:
Overall correctness: patch is incorrect AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against 18b2ff683fd3. Label changesLabel justifications:
Evidence reviewedPR surface: Source +12, Tests +49. Total +61 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
|
|
This pull request has been automatically marked as stale due to inactivity. |
|
Still relevant and ready for review. This fix ensures unresolved |
|
ClawSweeper status: review started. I am starting a fresh review of this pull request: fix(feishu): re-throw unresolved SecretRef errors from media fallbacks This is item 1/1 in the current shard. Shard 0/1. This placeholder means the worker is alive and reading the current context. I will edit this same comment with the actual review when the claws are done clicking. Crustacean status: shell secured, claws on keyboard, evidence pebbles being sorted. |
Summary
Re-throw
FeishuSecretRefUnavailableErrorin two catch blocks insidefeishuOutbound.sendText(local-image auto-convert path) andfeishuOutbound.sendMediathat previously swallowed it silently.Motivation
When
appSecret(or another Feishu credential) is configured as anexec/file/keychainSecretRefand the gateway has not pre-resolvedit before the action is dispatched,
resolveFeishuRuntimeAccountthrowsFeishuSecretRefUnavailableError. Both catch blocks caught this errorand silently fell back — one to plain text, the other to a URL link with
only a
console.error. The caller received a successful-looking resultwhile the media was never actually uploaded (issue reported by wangh88 in
#89338).
The fallback behaviour is correct for transient network / upload errors,
but a
FeishuSecretRefUnavailableErroris a configuration error: thesecret is genuinely unavailable and retrying the fallback path with the
same
cfgwon't help. Re-throwing surfaces the root cause immediately sothe caller or operator can act on it.
Before: image upload silently degrades to URL link / plain text.
After:
FeishuSecretRefUnavailableErrorpropagates to the caller.Verification
Two new vitest cases added to
outbound.test.ts:propagates FeishuSecretRefUnavailableError from sendMedia instead of silently falling backpropagates FeishuSecretRefUnavailableError from local-image path instead of silently falling backEach test injects the error via
sendMediaFeishuMock.mockRejectedValueOnceand asserts:
sendMedia/sendTextrejects withFeishuSecretRefUnavailableErrorsendMessageFeishuMockwas not called (no silent fallback)Closes #89338
Real behavior proof
Driven against the real production
extensions/feishu/src/accounts.ts(realresolveFeishuRuntimeAccount, realcoerceSecretReffromsrc/config/types.secrets.ts, realFeishuSecretRefUnavailableError/isFeishuSecretRefUnavailableError) on this PR headf5b4600776e. A realunresolved
exec:SecretRefis configured aschannels.feishu.appSecret,exactly the shape the gateway leaves when it has not pre-resolved the secret
before the action dispatches. The genuine error is then fed through the exact
patched
sendMediacatch block to observe whether it propagates or isswallowed.
Behavior or issue addressed: Feishu media send silently degraded to a URL
link / plain text when
appSecretwas an unresolvedexec/file/keychainSecretRef, masking the configuration error and returning a success-lookingresult while the media was never uploaded ([Bug]: Feishu MEDIA/image upload fails when appSecret uses SecretRef (Keychain) #89338). The fix re-throws
FeishuSecretRefUnavailableErrorfrom thesendTextlocal-image path and thesendMediaupload path so the root cause surfaces.Real environment tested: macOS (Darwin arm64), Node v25.5.0, running the
real compiled
extensions/feishu/src/accounts.tsproduction module from thisbranch head with a real unresolved
exec:SecretRef aschannels.feishu.appSecret.Exact steps or command run after this patch:
node_modules/.bin/esbuild extensions/feishu/src/accounts.ts --bundle --platform=node --format=cjs(real production source, realcoerceSecretRef).node feishu-proof.cjs— calls the realresolveFeishuRuntimeAccount({ cfg })withappSecret: { source: "exec", provider: "shell", id: "echo-secret" }, then runs the exact patchedsendMediacatch logic (if (isFeishuSecretRefUnavailableError(err)) throw err) on the genuine thrown error.Evidence after fix: live console output captured from
noderunning the real module:For contrast, the pre-fix catch block (no guard) produces this live output on
the same real error — confirming the original swallow:
Observed result after fix: the real
FeishuSecretRefUnavailableErrorthrown by the production
resolveFeishuRuntimeAccountpropagates to the caller(
PROPAGATED to caller: true), and the silent URL-link fallback never runs(
silent fallback to URL link happened: false). Before the patch, the samereal error was caught and the caller received a degraded success result.
What was not tested: an end-to-end send against a live Feishu/Lark tenant
(no real tenant credentials available); the account-selection/merge helpers
that run before the strict
appSecretresolution were isolated so the runexercises the genuine secret-resolution throw path under change. The unit
suite in
outbound.test.tscovers the full adapter wiring as a supplement.