Skip to content

Hardening: self-exclusion, login rate-limit, SSE keepalive, graceful shutdown#2

Merged
StrandedTurtle merged 1 commit into
mainfrom
claude/review-hardening
Jun 23, 2026
Merged

Hardening: self-exclusion, login rate-limit, SSE keepalive, graceful shutdown#2
StrandedTurtle merged 1 commit into
mainfrom
claude/review-hardening

Conversation

@StrandedTurtle

Copy link
Copy Markdown
Owner

Review-pass hardening to make the app ship-ready for other users (no functional rewrites — the core flows were already sound). Branched off main.

Fixes

  • Self-update foot-gun — the dashboard listed the updater's own container; updating it would recreate the container running the in-flight update and kill the process. Now excluded (SELF_CONTAINER_NAME, default diun-updater, + hostname match).
  • Login rate-limiting — single-password auth was brute-forceable if exposed. Added per-client-IP failed-attempt tracking with a temporary lockout (429 too_many_attempts). New unit tests (52 total, all passing).
  • SSE resilience behind proxies — 15s keepalive comments + X-Accel-Buffering: no so a reverse proxy doesn't drop the log stream during a long pull with sparse output; keepalive cleared on finish/disconnect.
  • Graceful shutdown — SIGTERM/SIGINT closes the HTTP server and checkpoints/closes SQLite so docker stop doesn't leave the WAL half-written. Also x-powered-by disabled.
  • Docker HEALTHCHECK against /api/health.
  • ClientuseUpdateRunner now settles exactly once, so a stream-close error arriving after the result can't overwrite a success or double-refresh; accurate empty-state copy; iOS PWA meta tags.
  • Docs/licensingLICENSE (MIT), plus .env.example, API_CONTRACT.md, and README updated for all of the above.

Verified

  • node --test: 52/52 pass (incl. 5 new rate-limit tests).
  • Client vite build clean.
  • Runtime smoke: 10 bad logins → 401, 11th → 429; SIGTERM → clean shutdown.

Still pending (unchanged from before): live Docker E2E on a real host — this build env has no daemon. Follow the README's 5-minute throwaway-stack test.

🤖 Generated with Claude Code


Generated by Claude Code

…tdown

Review-pass hardening for shipping to other users:

- docker.js: exclude the app's own container from the dashboard (best-effort
  via SELF_CONTAINER_NAME + hostname match) so it can't be told to update and
  thereby kill itself mid-update.
- auth.js: per-client-IP failed-login rate limiting with a temporary lockout
  (returns 429 too_many_attempts); covered by new unit tests (52 total).
- sse.js: 15s keepalive comments + X-Accel-Buffering:no so reverse proxies
  don't drop the log stream during long, sparse pulls; clear keepalive on
  finish/disconnect.
- index.js: graceful SIGTERM/SIGINT shutdown (close server + SQLite), and
  disable x-powered-by.
- Dockerfile: HEALTHCHECK against /api/health.
- client: useUpdateRunner settles exactly once (a late stream-close error no
  longer overwrites a success); accurate empty-state copy; iOS PWA meta tags.
- docs: LICENSE (MIT), env/contract/README updates for the above.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013Lj6nYJQDtLaZFvvEQJGM4
@StrandedTurtle StrandedTurtle merged commit 323a4a1 into main Jun 23, 2026
4 checks passed
@StrandedTurtle StrandedTurtle deleted the claude/review-hardening branch June 23, 2026 12:06
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.

1 participant