Skip to content

Claude/cpu guard script dn d8u - #130

Merged
gamblecodezcom merged 5 commits into
mainfrom
claude/cpu-guard-script-DnD8u
Mar 4, 2026
Merged

Claude/cpu guard script dn d8u#130
gamblecodezcom merged 5 commits into
mainfrom
claude/cpu-guard-script-DnD8u

Conversation

@gamblecodezcom

@gamblecodezcom gamblecodezcom commented Mar 4, 2026

Copy link
Copy Markdown
Owner

User description

Summary by Sourcery

Refine Telegram API rate-limiting bypass configuration and make QA artifact filesystem failures non-fatal while logging unexpected errors.

Enhancements:

  • Centralize and export Telegram callApi bypass method sets to avoid double-wrapping and support testing and future lifecycle additions.
  • Harden QA artifact directory and file creation so permission-related filesystem errors are treated as non-fatal while unexpected failures are logged as warnings.

CodeAnt-AI Description

Prevent Telegram long-poll timeouts and make QA artifact writes non-fatal

What Changed

  • Telegram API long-poll and lifecycle calls (including getUpdates, getMe, setWebhook, etc.) now bypass the global 15s timeout so long-polling no longer times out and the bot can start reliably; the bypass lists are exported for inspection/testing.
  • QA directory and file writes are treated as non-fatal: permission-related filesystem errors (EACCES/EPERM/EROFS/ EEXIST) are silently skipped, while unexpected write errors are logged as warnings so the bot does not crash on startup.
  • Systemd service sandboxing adjusted so the service can write under /var/www/html/Runewager (ProtectSystem=full, ProtectHome=false, UMask=0022, explicit ReadWritePaths), reducing permission-related startup failures.

Impact

✅ Stable long-polling without API call timeouts
✅ Bot no longer crashes on startup when QA files are unwritable
✅ Fewer systemd restart loops and permission-related startup 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:

@codeant-ai ask: Your question here

This lets you have a chat with CodeAnt AI about your pull request, making it easier to understand and improve your code.

Example

@codeant-ai ask: Can you suggest a safer alternative to storing this secret?

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:

@codeant-ai: Your feedback here

This helps CodeAnt AI learn and adapt to your team's coding style and standards.

Example

@codeant-ai: Do not flag unused imports.

Retrigger review

Ask CodeAnt AI to review the PR again, by typing:

@codeant-ai: review

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.

claude added 5 commits March 4, 2026 13:00
…eout

Telegraf's long-polling uses getUpdates with timeout=50 (Telegram holds
the connection for up to 50 seconds waiting for new updates). The callApi
patch was wrapping ALL methods — including getUpdates — with globalThrottle,
which has a hard 15-second race. This fired on every poll cycle, throwing
'rateLimiter: API call timed out after 15000ms', causing bot.launch() to
reject and systemd to enter an infinite restart loop.

Fix: add getUpdates (and Telegraf startup/lifecycle calls: getMe,
deleteWebhook, setWebhook, getWebhookInfo, close, logOut) to the _MANAGED
bypass set so they call the original callApi directly without the timeout
wrapper.

All 60 unit tests pass. Bot loads cleanly in CI mode.

https://claude.ai/code/session_01WpEqAiDbpqnBywMjYXJHf4
…hod sets

Two fixes:

1. index.js — ensureQaArtifacts(), persistQaProviderState(), ensureQaDirs():
   All QA file writes are now wrapped in try/catch and treated as non-fatal.
   The bot service runs as the 'runewager' system user but qa/ is owned by
   root, so writeFileSync was throwing EACCES on every startup, which was
   caught by startBot()'s outer try/catch and called process.exit(1).

2. telegramSafe.js — callApi bypass list refactored (code review feedback):
   The inline _MANAGED set is replaced with three named, exported constants:
   - LONG_POLL_METHODS    : getUpdates (must bypass 15 s timeout)
   - LIFECYCLE_METHODS    : getMe, deleteWebhook, setWebhook, etc.
   - INDIVIDUALLY_PATCHED_METHODS : sendMessage, sendPhoto, etc.
   Combined into CALLAPI_BYPASS_METHODS used by the callApi patch.
   All sets are exported so test suites can assert bypass membership without
   requiring a live Telegraf instance.

All 60 unit tests pass. Module loads cleanly in CI mode.

https://claude.ai/code/session_01WpEqAiDbpqnBywMjYXJHf4
…e conflict

Addresses code review feedback:

index.js:
- Added QA_FS_SUPPRESS constant (EACCES, EPERM, EROFS, EEXIST) — the set of
  expected error codes when qa/ is owned by root but the service runs as the
  runewager user. Defined once, shared by all three QA helpers.
- ensureQaDirs: replace silent catch-all with per-directory loop; unexpected
  error codes (e.g. ENOENT, ENOMEM) are logged as warnings so they remain
  visible; permission codes are silently skipped.
- persistQaProviderState: catch checks err.code — returns silently for
  permission errors, logs a warning for any other code (e.g. JSON failure).
- ensureQaArtifacts: same pattern — unexpected errors are logged at warn level;
  permission errors (EACCES/EPERM/EROFS) are intentionally silent.

telegramSafe.js:
- Resolved merge conflict: kept the CALLAPI_BYPASS_METHODS module-level
  constants introduced in the previous commit; dropped the inline _MANAGED
  block that arrived from main during the merge.

All 60 unit tests pass.

https://claude.ai/code/session_01WpEqAiDbpqnBywMjYXJHf4
External code or tests could accidentally mutate the exported Sets
(LONG_POLL_METHODS, LIFECYCLE_METHODS, etc.) which would silently
alter runtime bypass behavior in callApi.

Export frozen array snapshots instead — callers can still iterate and
use .includes() for membership checks; the internal module-level Sets
remain mutable for runtime use by the callApi patch.

All 60 unit tests pass.

https://claude.ai/code/session_01WpEqAiDbpqnBywMjYXJHf4
…=false, UMask=0022

ProtectSystem=strict makes the ENTIRE filesystem read-only (including /var),
requiring every directory Node.js touches to be explicitly listed in
ReadWritePaths.  This caused silent crashes under systemd while manual
`node index.js` worked fine (no sandbox).

Changes:
- ProtectSystem=strict → full
    /usr, /boot, /etc stay read-only; /var (where the app lives) is fully
    writable.  No more brittle per-directory ReadWritePaths maintenance.
- ProtectHome=true → false
    Service runs as root; /root is root's home.  Node/npm use /root for
    internal caches and temp files — blocking it caused subtle startup
    failures that only appeared under systemd sandboxing.
- UMask=0077 → 0022
    0077 (owner-only) made log files mode 600, unreadable by log-tailing
    utilities running as non-root.  0022 gives the standard 644/755.
- ReadWritePaths kept as belt-and-suspenders documentation; functionally
    redundant under ProtectSystem=full but makes intent explicit and guards
    against future tightening.
- Expanded inline comments explain each directive's rationale so the next
    operator understands the trade-off before changing settings.

All 60 unit tests pass.

https://claude.ai/code/session_01WpEqAiDbpqnBywMjYXJHf4
@codeant-ai

codeant-ai Bot commented Mar 4, 2026

Copy link
Copy Markdown

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 ·
Reddit ·
LinkedIn

@gamblecodezcom
gamblecodezcom merged commit c15864f into main Mar 4, 2026
3 checks passed
@gamblecodezcom
gamblecodezcom deleted the claude/cpu-guard-script-DnD8u branch March 4, 2026 13:20
@coderabbitai

coderabbitai Bot commented Mar 4, 2026

Copy link
Copy Markdown

Warning

Rate limit exceeded

@gamblecodezcom has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 11 minutes and 40 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

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.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: df839171-789d-4be1-b8f1-31cde6a18979

📥 Commits

Reviewing files that changed from the base of the PR and between b1cb5d7 and 90742a6.

📒 Files selected for processing (3)
  • index.js
  • runewager.service
  • telegramSafe.js
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch claude/cpu-guard-script-DnD8u

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@sourcery-ai

sourcery-ai Bot commented Mar 4, 2026

Copy link
Copy Markdown

Reviewer's Guide

Refactors Telegram callApi rate-limiter bypass logic into reusable, exported method sets, and makes QA artifact directory/file creation fault-tolerant by handling permission-related filesystem errors gracefully while logging unexpected failures.

Sequence diagram for updated Telegram tg.callApi rate-limiter bypass

sequenceDiagram
    participant Caller
    participant TelegrafBot
    participant TgContext as TgContext_tg
    participant GlobalThrottle
    participant TelegramAPI

    Caller->>TelegrafBot: invoke_telegraf_method
    TelegrafBot->>TgContext: callApi(method, data, signal)
    alt method in CALLAPI_BYPASS_METHODS
        TgContext->>TelegramAPI: original_callApi(method, data, signal)
        TelegramAPI-->>TgContext: response
        TgContext-->>TelegrafBot: response
        TelegrafBot-->>Caller: response
    else method not in CALLAPI_BYPASS_METHODS
        TgContext->>GlobalThrottle: schedule(original_callApi, method, data, signal)
        GlobalThrottle->>TelegramAPI: original_callApi(method, data, signal)
        TelegramAPI-->>GlobalThrottle: response
        GlobalThrottle-->>TgContext: response
        TgContext-->>TelegrafBot: response
        TelegrafBot-->>Caller: response
    end
Loading

Flow diagram for QA directory creation with suppressed filesystem errors

flowchart TD
    A[start ensureQaDirs] --> B[dir in qaContextDir, qaStateDir, qaLogsDir]
    B --> C["fs.mkdirSync(dir, recursive true)"]
    C --> D{error thrown?}
    D -- no --> E[continue to next dir]
    D -- yes --> F{e.code in QA_FS_SUPPRESS?}
    F -- yes --> E
    F -- no --> G[logEvent warn ensureQaDirs: unexpected error]
    G --> E
    E --> H{more dirs?}
    H -- yes --> B
    H -- no --> I[end ensureQaDirs]

    subgraph QA_FS_SUPPRESS_values
      J[EACCES]
      K[EPERM]
      L[EROFS]
      M[EEXIST]
    end
Loading

Flow diagram for fault-tolerant QA artifact persistence

flowchart TD
    A[start ensureQaArtifacts] --> B[try block]
    B --> C[ensureQaDirs]
    C --> D[write qaRepoInfoFile]
    D --> E[write qaCapabilitiesFile]
    E --> F[persistQaProviderState]
    F --> G[end ensureQaArtifacts]

    B -->|error e| H{e.code in QA_FS_SUPPRESS?}
    H -- yes --> G
    H -- no --> I[logEvent warn ensureQaArtifacts: unexpected error]
    I --> G

    subgraph persistQaProviderState_logic
      J[start persistQaProviderState] --> K[try block]
      K --> L[ensureQaDirs]
      L --> M[write qaProviderStateFile]
      M --> N[end persistQaProviderState]
      K -->|error e| O{e.code in QA_FS_SUPPRESS?}
      O -- yes --> N
      O -- no --> P[logEvent warn persistQaProviderState: unexpected error]
      P --> N
    end
Loading

File-Level Changes

Change Details Files
Centralized and exported Telegram callApi rate-limiter bypass method sets to avoid double-wrapping and support testing.
  • Introduced LONG_POLL_METHODS, LIFECYCLE_METHODS, INDIVIDUALLY_PATCHED_METHODS, and combined CALLAPI_BYPASS_METHODS Sets near the top of the Telegram helper module.
  • Updated the tg.callApi wrapper in init() to consult CALLAPI_BYPASS_METHODS instead of a locally-scoped _MANAGED Set.
  • Exported frozen array versions of the bypass method sets for external inspection and tests while preventing mutation of internal Sets.
telegramSafe.js
Hardened QA artifacts directory and file creation to tolerate permission issues while logging unexpected filesystem errors.
  • Added QA_FS_SUPPRESS Set of expected filesystem error codes representing permission or read-only failures for QA paths.
  • Wrapped ensureQaDirs directory creation loop in try/catch and suppressed known permission-related errors while logging unexpected ones as warnings.
  • Wrapped persistQaProviderState writes in try/catch to ignore expected permission errors and log unexpected failures as warnings.
  • Wrapped ensureQaArtifacts in try/catch so QA artifact generation becomes non-fatal, silently skipping expected permission problems and logging unexpected errors as warnings.
index.js

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@codeant-ai codeant-ai Bot added the size:L This PR changes 100-499 lines, ignoring generated files label Mar 4, 2026

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 1 issue, and left some high level feedback:

  • In the QA filesystem handling, QA_FS_SUPPRESS is documented as covering permission-related cases but also includes EEXIST, which is not a permission error; consider either updating the comment to reflect this or dropping EEXIST from the suppression set so unexpected EEXIST cases continue to be logged.
  • In the fs error handlers you assume e has code and message fields; if there is any chance a non-Error value bubbles up, it may be safer to guard those accesses (e.g., e && e.code) or fall back to a generic message to avoid secondary failures during logging.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In the QA filesystem handling, `QA_FS_SUPPRESS` is documented as covering permission-related cases but also includes `EEXIST`, which is not a permission error; consider either updating the comment to reflect this or dropping `EEXIST` from the suppression set so unexpected `EEXIST` cases continue to be logged.
- In the `fs` error handlers you assume `e` has `code` and `message` fields; if there is any chance a non-Error value bubbles up, it may be safer to guard those accesses (e.g., `e && e.code`) or fall back to a generic message to avoid secondary failures during logging.

## Individual Comments

### Comment 1
<location path="index.js" line_range="4832-4833" />
<code_context>
   writeFileAtomic(filePath, JSON.stringify(data, null, 2));
 }

+// Expected error codes when the service user cannot write to qa/ (created as root).
+const QA_FS_SUPPRESS = new Set(['EACCES', 'EPERM', 'EROFS', 'EEXIST']);
+
 function ensureQaDirs() {
</code_context>
<issue_to_address>
**issue (bug_risk):** Suppressing EEXIST for mkdir can hide a real configuration problem when a qa path is a file rather than a directory.

With `fs.mkdirSync`, `EEXIST` also covers the case where a file already exists at the target path (e.g. `qa/` or `qa/logs` is a file, not a directory). In that case we likely *do* want to surface an error, since QA artifacts will never be written and this will be hard to debug. Consider either removing `EEXIST` from `QA_FS_SUPPRESS`, or only suppressing it after verifying the existing path is a directory (e.g. via `fs.statSync`).
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread index.js
Comment on lines +4832 to +4833
// Expected error codes when the service user cannot write to qa/ (created as root).
const QA_FS_SUPPRESS = new Set(['EACCES', 'EPERM', 'EROFS', 'EEXIST']);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (bug_risk): Suppressing EEXIST for mkdir can hide a real configuration problem when a qa path is a file rather than a directory.

With fs.mkdirSync, EEXIST also covers the case where a file already exists at the target path (e.g. qa/ or qa/logs is a file, not a directory). In that case we likely do want to surface an error, since QA artifacts will never be written and this will be hard to debug. Consider either removing EEXIST from QA_FS_SUPPRESS, or only suppressing it after verifying the existing path is a directory (e.g. via fs.statSync).

@codeant-ai

codeant-ai Bot commented Mar 4, 2026

Copy link
Copy Markdown

Nitpicks 🔍

🔒 No security issues identified
⚡ Recommended areas for review

  • File permission exposure
    Changing UMask to 0022 and making files world-readable increases the risk that logs or artifacts under the service's writable paths expose sensitive data (tokens, secrets, user data). Consider minimizing world-readable artifacts, limiting the directories writable by the service, and/or running the service as a non-root dedicated user.

  • Bypass set correctness
    The new LONG_POLL / LIFECYCLE / INDIVIDUALLY_PATCHED sets are used to bypass the callApi rate-limiter. Ensure the method names listed exactly match the 'method' string passed to Telegraf's callApi at runtime (casing, aliases, and any namespaced forms). Otherwise legitimate calls may be incorrectly queued/killed or bypassed.

@codeant-ai

codeant-ai Bot commented Mar 4, 2026

Copy link
Copy Markdown

CodeAnt AI finished reviewing your PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L This PR changes 100-499 lines, ignoring generated files

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants