Modernize: Bolt 4, async/error handling, Node 24 + GHCR/Coolify deploy - #53
Open
ddbruce wants to merge 1 commit into
Open
Modernize: Bolt 4, async/error handling, Node 24 + GHCR/Coolify deploy#53ddbruce wants to merge 1 commit into
ddbruce wants to merge 1 commit into
Conversation
… deploy Behavior-preserving modernization. Same /channel workflow: blank-request guard, moderated-channel approval flow (mod message + requester ephemeral + cancel DM), non-moderated immediate post, approve/approve-without-@channel/ reject/cancel button actions, and moderator permission checks (incl. the "can't approve your own request" case). All Block Kit message content is byte-for-byte unchanged. Runtime / SDK: - @slack/bolt 1.2 -> 4.4. Rewrote the command/action middleware chains for v4: await ack() and await next() (were unawaited). Custom HTTPReceiver adds a GET /health route; /slack/events and signing-secret verification are unchanged. - dotenv 8 -> 17; emoji-regex 8 -> 10; md5 2.2 -> 2.3. Dockerfile node:latest -> node:24-alpine, npm ci, non-root, HEALTHCHECK. - Move eslint out of runtime dependencies; nodemon 1 -> 3 (dev). Correctness / robustness: - Await the previously fire-and-forget Slack calls (postMessage/postEphemeral/ update) up the handler chain so failures surface via app.error instead of crashing on an unhandled rejection. Same messages, deterministic order. - Fix the unreachable randomEmoji default branch (concat results were discarded). Not hit by current callers, so no behavior change. Testability / tooling: - Extract the duplicated channel/user ID regex parsing into utilities/parse.js (identical regex) and randomEmoji into utilities/emoji.js; add Jest tests (6). - ESLint 6 (EOL) -> ESLint 9 flat config, matching the repo's original rule set (this repo never had a lint script; two pre-existing >90-char user-facing strings keep a targeted max-len disable to stay byte-identical). - Replace dead Drone CI with GitHub Actions (lint + test + amd64 build). - Add scripts/deploy.sh + config.example.sh (amd64 -> GHCR -> Coolify redeploy); secrets in gitignored scripts/config.sh. - Document SLACK_USER_TOKEN in .env.example (required by the code, was missing) and correct PORT -> NODE_PORT (the code reads NODE_PORT). Verified: 6 unit tests pass; boots on Bolt 4, /health -> 200, unsigned /slack/events -> 401; amd64 image builds with 0 npm vulnerabilities. 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.
Summary
Behavior-preserving modernization of
at-channel. Same/channelworkflow: blank-request guard, moderated-channel approval flow (mod message + requester ephemeral + cancel DM), non-moderated immediate post, the approve / approve-without-@channel / reject / cancel button actions, and moderator permission checks (including "can't approve your own request"). All Block Kit message content is byte-for-byte unchanged. Verified: 6 unit tests pass; boots on Bolt 4 with/health→ 200 and unsigned/slack/events→ 401; amd64 image builds with 0 npm vulnerabilities.Changes
@slack/bolt1.2 → 4.4 — this is the substantive change. Rewrote the command/action middleware chains for v4:await ack()andawait next()(were unawaited, which v4 requires). CustomHTTPReceiveraddsGET /health;/slack/eventsand signing-secret verification are unchanged, so no Slack app config change.dotenv8→17,emoji-regex8→10,md52.2→2.3; Dockerfilenode:latest→ pinnednode:24-alpine,npm ci, non-root,HEALTHCHECK; moved ESLint out of runtime deps; nodemon 1→3.awaited the previously fire-and-forget Slack calls up the handler chain so failures go throughapp.errorinstead of crashing (same messages, deterministic order). Fixed the unreachablerandomEmojidefault branch (concatresults were discarded) — not hit by current callers, so no behavior change.utilities/parse.js(identical regex) andrandomEmojiintoutilities/emoji.js; added Jest tests.lintscript, so two pre-existing >90-char user-facing strings carry a targetedmax-lendisable to stay byte-identical); dead Drone CI → GitHub Actions.scripts/deploy.sh+config.example.sh; secrets in gitignoredscripts/config.sh.Env notes (docs only, no new required vars)
.env.examplenow documentsSLACK_USER_TOKEN(the code always used it for usergroup lookups; it was missing from the example).PORT→NODE_PORTin.env.example(the code readsNODE_PORT; the oldPORTentry was never read).Recommended follow-ups (NOT done — would change behavior)
channel_id/user_idin buttonvalues. Left as-is to preserve exact behavior.switchon names (general/alerts/random/scheduling), andsendForApprovalstill posts to the literal channel name"at-channel-requests"rather thanMOD_CHANNEL_ID. Both preserved verbatim; worth making config-driven later.