Repository navigation
fix(slack): name the slack proxy settings when production validation never reaches slack - #3684
Conversation
…never reaches slack On an Installation with no Slack proxy (no Helm slackProxy.enabled or api.channelDirectoryProxyUrl), the production API's default-deny egress means auth.test never gets an answer. Provisioning and deploy answered 503 CHANNEL_CREDENTIAL_UNAVAILABLE "temporarily unavailable. Retry before deploying.", which a retry can never fix. Production composition now builds the Slack Channel Driver with expectProxy. With no proxy URL, a credential check whose request gets no HTTP answer raises SlackRouteNotConfiguredError: 409 RESOURCE_CONFLICT with a fixed message naming the Helm settings and no retry. An answer from Slack (any HTTP status) keeps today's errors, a route an operator approved instead of the proxy still validates, and development composition is unchanged. Binding and token-prefix checks still answer first; no token text is echoed. Finding 2521 (D728).
|
🦞👀 Pull request received. I will update this pull request when review starts. ClawSweeper review completeClawSweeper finished reviewing this revision. The review result is being finalized. |
# Conflicts: # apps/controller/src/drivers/channel/slack.ts
|
Codex review: needs changes before merge. What this changesThis PR names the Slack proxy settings when production credential validation fails before receiving an HTTP response. Example: Provision a Slack-enabled Agent with valid token bindings, no API proxy URL, and blocked Slack egress.
Review scores
ProductKind: Bug fix · Worth it: Yes · Fix scope: Complete Merge readiness⛔ Needs changes before merge - 2 items remain Keep this PR open: the diagnostic improvement is useful and maintainer-directed, but HTTP redirects are incorrectly classified as unanswered requests. Priority: P2 Before merge
Findings
Provenance
Tests
Agent review detailsHow this fits togetherProduction composition configures the Slack Channel Driver; OCC authorizes Secret access, invokes credential validation before provisioning or deployment, and translates errors into API responses. flowchart TD
A[Provision or deploy request] --> B[OCC authorization]
B --> C[Secret Driver callback]
C --> D[Slack credential validation]
E[Production proxy settings] --> D
D --> F[Slack auth test]
F --> G[API result]
Technical reviewBest possible solution: Keep the existing request owner, expose redirect responses without following them, and reserve the missing-proxy diagnostic for transport failures. Do we have a high-confidence way to reproduce the issue? Current main maps Slack fetch failures to the retryable credential-unavailable error even without a configured proxy; source inspection establishes the path, and no target code was run. Is this the best way to solve the issue? The existing Driver is the right owner, but rejected HTTP redirects must remain distinguishable from requests that receive no response. Full review comments:
Overall correctness: patch is incorrect AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning medium; reviewed against 3918205bc18f. Provenance checked
TestingProof path: in-process harness. SecurityNone. EvidenceAcceptance criteria:
What I checked:
Likely related people:
LabelsLabel changes:
Label justifications:
Rating scale6/6 🦀 challenger crab · 5/6 🦞 diamond lobster · 4/6 🐚 platinum hermit · 3/6 🦐 gold shrimp · 2/6 🦪 silver shellfish · 1/6 🧂 unranked krab. Overall follows the weaker of proof and patch quality; ✨ marks media proof (a screenshot, video, or linked artifact) that directly shows the changed behavior. WorkflowClawSweeper edits this one comment on every review. Comment Reviewed October 25, 2026, 7:07 PM ET / 23:07 UTC. |
…d timeout failures A production Installation can reach Slack without a proxy: a sign-in setting with empty egressCidrs opens API TCP 443. A transient timeout on that route also got the 409, which told the administrator to configure a proxy they do not need. The message now says to try again when the API has another approved route, and otherwise names the Helm settings. It names the Slack integration guide instead of the URL to stay inside the 256-character error message cap. Only fetch failures whose cause is a refused or unreachable connection, a DNS failure, a connect timeout or the expired time budget count as "Slack never answered". A redirect refused by redirect: "error", a TLS failure or an invalid header value keeps the retryable unavailable error. The conformance case now drives Node's own fetch at local endpoints (closed port, 302, invalid header byte) so each rejection has its real shape. The integration case asserts that auth.test ran on the working route. Findings 2531, 2532.
Problem
On an Installation with no Slack proxy (neither Helm
slackProxy.enablednorapi.channelDirectoryProxyUrl), the production API's default-deny egress never lets the Slack Channel Driver'sauth.testreach Slack. Create Agent provisioning and Agent deploy of a correctly bound Slack channel (whole${SLACK_BOT_TOKEN}/${SLACK_APP_TOKEN}) answered503 CHANNEL_CREDENTIAL_UNAVAILABLE"Channel credential validation is temporarily unavailable. Retry before deploying." A retry can never succeed, and nothing named the setting the Slack guide requires (dogfood finding 2521).Change
expectProxy. The ChannelDriver contract does not change.expectProxyand no proxy URL, a credential check whoseauth.testrequest gets no answer from Slack raisesSlackRouteNotConfiguredError. "No answer" means the fetch rejected with a refused or unreachable connection, a DNS failure (ENOTFOUND,EAI_AGAIN), a connect timeout, or the 8 s budget running out. Any other fetch rejection (a redirect refused byredirect: "error", a TLS failure, an invalid header value) keeps the retryable503.SlackRouteNotConfiguredErroris aResourceStateConflictError, so the API answers409 RESOURCE_CONFLICTwith this fixed text:RepositoryDriverNotConfiguredError, finding 2362;ServiceAccountDriverNotConfiguredError). The Console already shows a named 409 as written, with no Retry button, on Create Agent and on the Agent page.invalid_auth, ...) and any fetch rejection other than the ones listed above keep today's errors, including the retryable503.expectProxy, is unchanged.CHANNEL_DIRECTORY_*.Verification
tests/integration/occ-api.test.mjs"Slack validation with no Slack proxy names the setting at provision and deploy" runs the real API routes with the Driver built as production builds it. It checks that a wrong token role still answers 400 first, a connection timeout (the rejection shape Node's fetch gives) gets the 409 at provision with no Agent created, an HTTP 503 from Slack stays503 CHANNEL_CREDENTIAL_UNAVAILABLE, a working route passes validation withauth.testactually called, and deploy of a saved Agent gets the same 409.tests/conformance/slack-channel-directory.test.mjs"...name the missing proxy only when production expects one and Slack never answered" drives Node's own fetch at local endpoints, so each rejection has its real shape. A refused connection and an expired time budget give the named refusal. A refused 302 redirect and an invalid header byte in the token stay unavailable. Development stays unavailable, and a configured proxy that refuses its tunnel stays unavailable.SlackRouteNotConfiguredError) and on this PR's previous head277166da2c(old message; the redirect and header cases got the 409). Two classifier mutants (always/never "unanswered") fail the conformance test. The tests pass 20/20 at 2 CPUs on a remote test VM. The existing Slack validation tests pass.tsc --build, eslint and prettier are clean on the touched files.Risks
egressCidrsallows API TCP 443 to any address. That is a common setup, not a rare one. There, a transient failure (Slack slower than the 8 s budget, a DNSEAI_AGAIN, or a multi-account check that used up the shared budget) now gets this 409 instead of the retryable 503. The message covers that case ("If the API has another approved route to Slack, try again"), but the administrator also reads proxy settings they may not need, and the Console shows no Retry button for a 409; resubmitting works.expectProxyonly then. It is a follow-up, not part of this PR.slack.ts. A later merge may need to carry the option across.