Skip to content

Modernize: Bolt 4, Node 24, error handling + GHCR/Coolify deploy - #8

Open
ddbruce wants to merge 1 commit into
masterfrom
modernization
Open

Modernize: Bolt 4, Node 24, error handling + GHCR/Coolify deploy#8
ddbruce wants to merge 1 commit into
masterfrom
modernization

Conversation

@ddbruce

@ddbruce ddbruce commented Jul 24, 2026

Copy link
Copy Markdown
Member

Summary

Behavior-preserving modernization of watchdog. Same behavior: a message from a non-admin/non-moderator in a monitored channel is deleted and the user gets the same ephemeral warning; thread replies and message_deleted events are ignored. Verified: 8 unit tests pass; app boots on Bolt 4 with /health → 200 and unsigned /slack/events → 401; amd64 image builds with 0 npm vulnerabilities.

Changes

  • SDK/runtime: @slack/bolt 3.6 → 4.4, dotenv 10 → 17; Dockerfile node:16-alpine (EOL 2023) → pinned node:24-alpine, npm ci, non-root, HEALTHCHECK.
  • Health endpoint: custom HTTPReceiver with a GET /health route. The Slack events path (/slack/events) and its signing-secret verification are unchanged.
  • Correctness: app.message handler is now async and awaits processMessage; added an app.error handler; chat.delete is now awaited inside try/catch (was fire-and-forget); MONITORED_CHANNELS parsing is guarded so a missing env var no longer throws at startup.
  • Testability: pure decision logic extracted into src/utilities/moderation.js (no Slack import) with Jest tests. The admin-list short-circuit in isNotModerator (mod group only fetched if the user isn't an admin) is preserved exactly.
  • Tooling/CI: ESLint 7 (EOL) → ESLint 9 flat config; dead Drone CI → GitHub Actions (lint + test + amd64 build).
  • Deploy: scripts/deploy.sh + config.example.sh (amd64 → GHCR → Coolify POST /api/v1/deploy?uuid=); secrets in gitignored scripts/config.sh.

Notes

  • No env-var changes — same variables as before.
  • On Bolt 4, an invalid/expired bot token now makes the app fail fast at startup (Bolt runs auth.test on start). With valid creds this is a no-op; worth knowing for crash-loop debugging.

Recommended follow-up (NOT done — would change behavior)

  • Cache usergroup membership with a short TTL to cut two Slack API calls per message. Skipped because it delays when admin/mod role changes take effect; happy to add if you want it.

Behavior-preserving modernization. Same monitoring behavior: messages from
non-admin/non-moderator users in monitored channels are deleted and the user
gets the same ephemeral warning; thread replies and deletions are ignored.

Runtime / SDK:
- @slack/bolt 3.6 -> 4.4; dotenv 10 -> 17; Dockerfile node:16-alpine (EOL) ->
  node:24-alpine, npm ci, non-root, HEALTHCHECK.
- Custom HTTPReceiver adds a GET /health route; /slack/events and its
  signing-secret verification are unchanged.

Correctness / robustness:
- Make the app.message handler async and await processMessage; add app.error
  so listener errors surface instead of rejecting unhandled.
- await chat.delete inside try/catch (was fire-and-forget).
- Guard MONITORED_CHANNELS parsing so a missing env var no longer throws at
  startup.

Testability / tooling:
- Extract pure decision logic (isMonitoredChannel, isModerator,
  buildEphemeralBlocks) into src/utilities/moderation.js with no Slack import;
  add Jest tests (8). The admin-list short-circuit in isNotModerator is
  preserved exactly.
- ESLint 7 (EOL) -> ESLint 9 flat config.
- 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.

Verified: 8 unit tests pass; app 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>
@ddbruce
ddbruce requested a review from lramos15 as a code owner July 24, 2026 15:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants