Claude/cpu guard script dn d8u - #125
Conversation
… main
Combines all changes from this PR into a single clean commit:
- backend.js: store raw buffer on req.rawBody before express.json() runs
so HMAC verification uses the original bytes (not JSON.stringify output);
guard log stream creation in try-catch with .on('error') fallback to
console so filesystem failures never crash the process
- package.json: broaden engine range from >=20 <22 to >=20 (Node v24 compat)
- package-lock.json: regenerate with express@4.x and all transitive deps
(was missing, causing npm ci to fail on VPS)
- runewager-endpoint.service: User/Group → root (VPS runs as root)
- runewager.service: User/Group → root (VPS runs as root)
https://claude.ai/code/session_01WpEqAiDbpqnBywMjYXJHf4
- Pin express to 4.22.1 (remove ^ semver range) to match the explicitly installed version and prevent future version drift that caused the missing-dependency failure on Node 21. - Add ExecStartPre to runewager-endpoint.service: kills any stale process holding port 3001 before each systemd start, eliminating the EADDRINUSE → instant-crash → restart loop. Also tightened StartLimitBurst=4 / RestartSec=10 / StartLimitIntervalSec=120 to reduce CPU spike if the service still fails repeatedly. - Add section 9d to prod-run.sh: installs/refreshes the endpoint service unit from the repo copy, clears port 3001 before restart, restarts via systemd with a nohup fallback — so a full prod-run now brings both services up cleanly without manual intervention. https://claude.ai/code/session_01WpEqAiDbpqnBywMjYXJHf4
Monitoring-only companion to rw_cpu_guard.sh. Generates timestamped Markdown reports under /root/CPU_LOGS for /var/www/html/gcz and /var/www/html/Runewager stacks, rotates to keep last 10 reports, and symlinks the latest as CPU_report.md. Never kills, renice-s, or restarts any process — purely observational. Coexists safely with rw_cpu_guard.sh (separate log path, no shared state). Features: - System-wide CPU summary via top - High-CPU process table (>85% threshold) - GCZ stack process listing with⚠️ flag on hot processes - Best-effort dpkg package attribution for flagged pids - --status, --install-cron, --dry-run modes - Self-exclusion and kernel-thread exclusion from reports https://claude.ai/code/session_01WpEqAiDbpqnBywMjYXJHf4
…de processes `pkill -f "node .*backend.js"` was too broad — on a shared host it could kill any Node process whose cmdline contains "backend.js". Narrowed both pkill calls (systemd fallback + no-systemd path) to `node .*<PROJECT_DIR>/backend.js` so only the Runewager endpoint process is targeted. https://claude.ai/code/session_01WpEqAiDbpqnBywMjYXJHf4
gcz_cpu_guard.sh lives on the VPS directly, not in this repo. Added "gcz_cpu_guard" to WHITELIST_PATTERNS in rw_cpu_guard.sh so the Runewager CPU governor never renice/kills/stops the GCZ monitoring script regardless of its CPU usage. https://claude.ai/code/session_01WpEqAiDbpqnBywMjYXJHf4
Both static service files were hardcoding User=root/Group=root, meaning any RCE in index.js or backend.js yielded full system control and made ProtectSystem/NoNewPrivileges sandboxing meaningless. Changes: - runewager.service: User/Group → runewager (prod-run.sh already creates this system user and chowns logs/ + data/ to it) - runewager-endpoint.service: User/Group → runewager; ExecStartPre prefixed with '+' so systemd runs only that port-clear step as root (needed to kill stale root-owned processes), while backend.js itself runs unprivileged https://claude.ai/code/session_01WpEqAiDbpqnBywMjYXJHf4
prod-run.sh: kept scoped pkill pattern (node .*PROJECT_DIR/backend.js) over the broad main version (node .*backend.js) — prevents killing unrelated node processes on shared hosts. runewager-endpoint.service: kept our version with ExecStartPre '+' prefix (root-exec for port-clear step) and User/Group=runewager over main's root user with unprefixed ExecStartPre. https://claude.ai/code/session_01WpEqAiDbpqnBywMjYXJHf4
backend.js — _write double-logging: Filter to writable streams first; fall back to a single console.log only when none are available. Previously logger.error() with two null streams would print the same line twice to stdout. backend.js — rawBody guard on webhook: Treat missing/non-Buffer req.rawBody as a 500 (middleware misconfiguration) rather than silently falling back to Buffer.alloc(0), which was indistinguishable from a genuine signature mismatch. prod-run.sh — port race in nohup fallback: After a failed systemctl restart, re-check and free ENDPOINT_PORT before launching the nohup fallback. The original cleanup ran before the systemd attempt, leaving a race window where another process could bind the port. Note: log paths are NOT a conflict — prod-run.sh LOG_DIR resolves to $PROJECT_DIR/logs, same as backend.js path.join(__dirname, 'logs'). https://claude.ai/code/session_01WpEqAiDbpqnBywMjYXJHf4
…rds, log fallback) runewager-endpoint.service — aggressive prestart kill: Replace direct SIGKILL with SIGTERM → 3s wait → SIGKILL escalation. Gives the port holder a chance to shut down gracefully before forcing. backend.js — stream write guards: Filter streams by !destroyed && writable before writing, and wrap each write in try/catch so a mid-flight stream error is logged to stderr rather than crashing or silently corrupting output. prod-run.sh — silent log creation: Replace `touch ... 2>/dev/null || true` with an explicit failure check; when the log directory is not writable, warn and fall back to /tmp so the nohup backend process always has somewhere to log. https://claude.ai/code/session_01WpEqAiDbpqnBywMjYXJHf4
|
CodeAnt AI is reviewing your PR. Thanks for using CodeAnt! 🎉We're free for open-source projects. if you're enjoying it, help us grow by sharing. Share on X · |
Reviewer's GuideAdjusts endpoint startup robustness, backend logging resilience, webhook signature validation safety, and CPU guard whitelisting to improve reliability and avoid killing monitoring scripts. Sequence diagram for autofix webhook signature validationsequenceDiagram
actor Client
participant ExpressApp
participant WebhookHandler
participant Logger
participant SignatureVerifier
Client->>ExpressApp: POST /autofix/webhook (body)
ExpressApp->>ExpressApp: Middleware parses body
ExpressApp->>ExpressApp: Set req.rawBody (Buffer)
ExpressApp->>WebhookHandler: Invoke handler with req, res
WebhookHandler->>WebhookHandler: Read headers x-autofix-signature or x-hub-signature-256
WebhookHandler->>WebhookHandler: Read req.rawBody as rawBody
WebhookHandler->>WebhookHandler: Check rawBody exists and is Buffer
alt rawBody missing or not Buffer
WebhookHandler->>Logger: error(autofix.webhook, Missing rawBody, { requestId })
Logger-->>WebhookHandler: Logged error
WebhookHandler-->>Client: 500 JSON { ok: false, error: Internal server error, requestId }
else rawBody valid
WebhookHandler->>SignatureVerifier: verifySignature(rawBody, signature)
SignatureVerifier-->>WebhookHandler: result
alt AUTOFIX_SECRET missing or signature invalid
WebhookHandler-->>Client: Error response (unauthorized or misconfigured)
else Signature valid
WebhookHandler-->>Client: 200 JSON { ok: true, ... }
end
end
Class diagram for backend logger utilityclassDiagram
class Logger {
+info(eventType, msg, extra)
+error(eventType, msg, extra)
+debug(eventType, msg, extra)
+_write(streams, obj)
}
class Stream {
+destroyed : boolean
+writable : boolean
+write(line)
}
Logger "1" --> "*" Stream : writes to
class AutofixWebhookHandler {
+handle(req, res)
}
class ExpressRequest {
+id
+headers
+rawBody
}
class ExpressResponse {
+status(code)
+json(body)
}
class SignatureVerifier {
+verifySignature(rawBody, signature)
}
AutofixWebhookHandler --> Logger : uses
AutofixWebhookHandler --> ExpressRequest : receives
AutofixWebhookHandler --> ExpressResponse : responds via
AutofixWebhookHandler --> SignatureVerifier : calls
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
|
Warning Rate limit exceeded
⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. 📒 Files selected for processing (3)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
…scalation backend.js: kept writable/destroyed stream guard + try/catch over bare filter(Boolean) runewager-endpoint.service: kept SIGTERM→3s→SIGKILL escalation over direct kill -9 https://claude.ai/code/session_01WpEqAiDbpqnBywMjYXJHf4
This comment was marked as resolved.
This comment was marked as resolved.
|
CodeAnt AI finished reviewing your PR. |
prod-run.sh — pkill regex safety: Escape PROJECT_DIR with sed before interpolating into the pkill -f pattern. Spaces or regex metacharacters in the path (e.g. dots in /var/www) can cause unexpected matches or silent pattern failure. backend.js — rawBody missing response code: Change 500 → 400 when req.rawBody is absent. 500 caused webhook senders to treat the rejection as transient and retry; 400 signals a permanent bad-request so retries stop. The server-side misconfiguration is still logged as an error for visibility. https://claude.ai/code/session_01WpEqAiDbpqnBywMjYXJHf4
fuser without -t outputs "3001/tcp: 1234" — the full string was being passed to kill, causing it to fail silently and leaving the port holder alive (EADDRINUSE crash loop when lsof is unavailable). fuser -t outputs only the bare PID, matching lsof -t behaviour. https://claude.ai/code/session_01WpEqAiDbpqnBywMjYXJHf4
User description
Summary by Sourcery
Improve robustness and safety of backend process management, logging, and webhook handling, plus adjust CPU guard whitelisting.
Bug Fixes:
Enhancements:
CodeAnt-AI Description
Improve backend reliability: safer logging, strict webhook validation, cleaner restart behavior, and CPU-guard protections
What Changed
Impact
✅ Clearer webhook failure errors✅ Fewer endpoint crash-restart loops✅ Fewer lost or fatal log-write failures💡 Usage Guide
Checking Your Pull Request
Every time you make a pull request, our system automatically looks through it. We check for security issues, mistakes in how you're setting up your infrastructure, and common code problems. We do this to make sure your changes are solid and won't cause any trouble later.
Talking to CodeAnt AI
Got a question or need a hand with something in your pull request? You can easily get in touch with CodeAnt AI right here. Just type the following in a comment on your pull request, and replace "Your question here" with whatever you want to ask:
This lets you have a chat with CodeAnt AI about your pull request, making it easier to understand and improve your code.
Example
Preserve Org Learnings with CodeAnt
You can record team preferences so CodeAnt AI applies them in future reviews. Reply directly to the specific CodeAnt AI suggestion (in the same thread) and replace "Your feedback here" with your input:
This helps CodeAnt AI learn and adapt to your team's coding style and standards.
Example
Retrigger review
Ask CodeAnt AI to review the PR again, by typing:
Check Your Repository Health
To analyze the health of your code repository, visit our dashboard at https://app.codeant.ai. This tool helps you identify potential issues and areas for improvement in your codebase, ensuring your repository maintains high standards of code health.