Fix Slack daily-summary crash (OTP TLS handshake) + unblock CI#560
Merged
Conversation
OTP 27.2.x has a TLS certificate-validation bug that rejects Slack's
(recently rotated) certificate chain with a fatal `key_usage_mismatch`
alert — an intermediate carrying serverAuth EKU alongside CA key usage.
This raised out of SlackClient.send_message and crashed the record-pears
LiveView handler when posting the daily pairs summary, so "Save" timed
out in the browser ({timeout: true}) and no message posted.
Reproduced with a bare :ssl.connect to api.slack.com:
- OTP 27.2.1: fails (key_usage_mismatch)
- OTP 27.3.4.11 / 28.5: handshake succeeds
Bumps the pin in .tool-versions, both CI matrices, and the Dockerfile
builder image (with the matching debian-bookworm-20260518 snapshot that
has a published hexpm image; runner image moves with it).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Two issues kept main red and undeployable: - `mix deps.unlock --check-unused` failed because :castore became unused after the Phoenix 1.8 upgrade. Removed it from the lock. - config/runtime.exs called System.fetch_env! for SLACK_CLIENT_ID, SLACK_CLIENT_SECRET and SLACK_SIGNING_SECRET unconditionally, crashing the app at boot in test/CI whenever SLACK_SIGNING_SECRET is unset. These are now required only in :prod; dev/test fall back to placeholders. Note: prod (fly app pears-app) is still missing the SLACK_SIGNING_SECRET secret, so it must be set before the next deploy will boot. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What broke
A user on team titus reported that clicking Save in Pears did nothing — no daily-pairs message posted to Slack, and the browser console showed
Uncaught (in promise) Object { timeout: true }.Root cause (reproduced)
Save →
record-pears→Slack.send_daily_pears_summary→SlackClient.send_messagemakes a synchronous outbound HTTPS call to Slack from inside the LiveView process. On OTP 27.2.1 that TLS handshake now fails and raises, crashing thehandle_event/3handler — so the browser never gets a reply ({timeout: true}) and nothing posts.The failure is a fatal TLS alert:
Slack's (recently rotated) cert chain includes an intermediate carrying
serverAuthEKU alongside CA key usage (keyCertSign, cRLSign). OTP 27.2.x has a cert-validation bug that wrongly rejects this; it's fixed in 27.3+. This broke without any deploy because the trigger was Slack's cert rotation, not our code.Reproduced with a bare
:ssl.connecttoapi.slack.com:key_usage_mismatchThe fix
27.2.1 → 27.3.4.13in.tool-versions, the CI matrix, and the Dockerfile builder image (debian snapshot bumped to a matching published hexpm tag).Also unblocks CI/deploy (main was red, so this couldn't ship)
:castorefrommix.lock(mix deps.unlock --check-unusedwas failing after the Phoenix 1.8 upgrade).config/runtime.exswasfetch_env!-ingSLACK_CLIENT_ID/SECRET/SIGNING_SECRETunconditionally, crashing boot in test/CI whenSLACK_SIGNING_SECRETis unset. Now required only in:prod; dev/test use placeholders.The Fly app
pears-appis missing theSLACK_SIGNING_SECRETsecret (it hasSLACK_CLIENT_IDandSLACK_CLIENT_SECRET). Prod config stays strict, so the app will fail to boot until you set it:Verification
mix deps.unlock --check-unused,mix compile --warnings-as-errors,mix format --check-formatted,mix credo --strict: all greenmix test: 288 tests, 0 failures, 4 skippedFollow-up (not in this PR)
Harden
record-pearsso a Slack failure can't crash/block the LiveView again: move the send off the reply path and surface a flash on failure, and fix the non-{:noreply}fallback branch atpairing_board_live.ex:126.🤖 Generated with Claude Code