Skip to content

feat(utils): add helper managers and release automation hardening#31

Merged
rolling-codes merged 4 commits intomainfrom
codex/fixed-version
Apr 29, 2026
Merged

feat(utils): add helper managers and release automation hardening#31
rolling-codes merged 4 commits intomainfrom
codex/fixed-version

Conversation

@rolling-codes
Copy link
Copy Markdown
Owner

@rolling-codes rolling-codes commented Apr 28, 2026

Summary

Ship a small-but-useful helper release that shortens common EasyCord setup and response patterns while also tightening workflow safety and release automation.

Release Impact

  • Patch (release:patch)
  • Minor (release:minor)
  • Major (release:major)

Quality Checklist

  • Tests added or updated for behavior changes
  • pytest passes locally
  • ruff check . passes locally
  • Docs updated (README/API/docstrings) for public API changes
  • No local/debug/temp files included

Notes for Reviewers

Highlights in this release:

  • new helper utilities: Paginator, EasyEmbed, SecurityManager, and FrameworkManager
  • new convenience composer presets for secure defaults and faster bootstraps
  • reliability fixes for webhook retry, emoji file validation, SQLite decode safety, middleware bucket cleanup, and AI limiter pruning
  • hardened GitHub workflows for tests, auto-fix, release publishing, issue triage, and PR governance
  • version bump and release notes for 4.2.0

Validation

  • pytest tests -q -> 612 passed
  • python -m build succeeded

Summary by CodeRabbit

  • New Features

    • Added EasyEmbed for quick Discord embed status messages (success, error, info, warning)
    • Added Paginator for interactive embed pagination with page navigation
    • Added SecurityManager and FrameworkManager for simplified bot and middleware configuration
    • Added prompt length validation for AI commands
  • Bug Fixes

    • Improved stale webhook recovery and recreation
    • Enhanced emoji validation with file size and path checks
  • Improvements

    • Better database error handling and resilience
    • Expanded GitHub Actions automation for quality and release workflows

@sourcery-ai
Copy link
Copy Markdown

sourcery-ai Bot commented Apr 28, 2026

Reviewer's Guide

Adds prompt-length guarding and stale rate-limit bucket pruning to the OpenClaude AI plugin, hardens the auto-fix workflow security, and introduces new release automation plus corresponding tests and release notes for v4.1.1.

Sequence diagram for updated ask flow with prompt limit and stale bucket pruning

sequenceDiagram
    actor User
    participant Discord
    participant OpenClaudePlugin
    participant RateLimiter

    User->>Discord: Slash command ask(prompt)
    Discord->>OpenClaudePlugin: ask(ctx, prompt)
    OpenClaudePlugin->>OpenClaudePlugin: Check len(prompt) <= _max_prompt_chars
    alt Prompt too long
        OpenClaudePlugin-->>Discord: ctx.respond("ai.prompt_too_long", ephemeral)
        Discord-->>User: Error message
    else Prompt within limit
        OpenClaudePlugin->>OpenClaudePlugin: _prune_old_request_buckets(time.monotonic())
        OpenClaudePlugin->>RateLimiter: _rate_limit_retry_after(ctx)
        alt Rate limited
            RateLimiter-->>OpenClaudePlugin: retry_after
            OpenClaudePlugin-->>Discord: ctx.respond("ai.rate_limited", ephemeral)
            Discord-->>User: Retry after message
        else Allowed
            RateLimiter-->>OpenClaudePlugin: None
            OpenClaudePlugin->>OpenClaudePlugin: Call Claude API and build reply
            OpenClaudePlugin-->>Discord: ctx.respond(answer)
            Discord-->>User: AI response
        end
    end
Loading

Class diagram for updated AIPlugin and OpenClaudePlugin prompt and rate-limit behavior

classDiagram
    class AIPlugin {
        -int _rate_limit
        -float _rate_window
        -str _thinking_key
        -int _max_prompt_chars
        -dict _requests
        +__init__(client, db, guild_id, logger, client_session, authorizer, model, rate_limit, rate_window, thinking_key, max_prompt_chars)
        +ask(ctx, prompt)
        -_rate_limit_retry_after(ctx) float
        -_prune_old_request_buckets(now) void
    }

    class OpenClaudePlugin {
        +__init__(client, db, guild_id, logger, client_session, authorizer, model, rate_limit, rate_window, max_prompt_chars)
    }

    OpenClaudePlugin --|> AIPlugin
Loading

File-Level Changes

Change Details Files
Add maximum prompt length enforcement and stale rate-limit bucket pruning to the AI plugin and cover them with tests.
  • Extend AIPlugin and OpenClaude plugin constructors to accept a max_prompt_chars parameter and store it on the instance.
  • Add an early guard in AIPlugin.ask that rejects prompts exceeding the configured max length with an ephemeral localized response and skips provider calls.
  • Introduce a _prune_old_request_buckets helper that removes request buckets whose timestamps all fall outside the current rate window, and invoke it before rate limiting.
  • Add async tests to verify overlong prompts are rejected without calling the provider and that stale request buckets are pruned based on time.monotonic().
easycord/plugins/openclaude.py
tests/test_openclaude_plugin.py
Harden the auto-fix workflow to restrict fix-command execution and limit who can trigger the /fix-issues comment handler.
  • Validate the workflow_dispatch fix_command input with a regex so that only python scripts under scripts/ with .py suffix are allowed, failing the job otherwise.
  • Refactor branch and fix_command handling to use validated inputs for workflow_dispatch events.
  • On issue_comment events, fetch the commenter’s repository permission level and fail the job if they are not a collaborator with admin, maintain, or write access, before running any fixes.
.github/workflows/auto-fix-issues.yml
Document and automate the v4.1.1 release process, including Git tag-based releases and a helper script.
  • Add v4.1.1 entry to the main release notes summarizing security hardening, AI plugin safeguards, and release automation changes.
  • Create a detailed RELEASE_v4.1.1.md file describing changes, rationale, and testing for this patch release.
  • Introduce a GitHub Actions release workflow that automatically creates a GitHub Release when a vX.Y.Z tag is pushed.
  • Add a PowerShell script that validates a version string, constructs a vX.Y.Z tag, and pushes it to origin to trigger the release workflow.
RELEASES.md
RELEASE_v4.1.1.md
.github/workflows/release.yml
release.ps1

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

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 28, 2026

Warning

Rate limit exceeded

@rolling-codes has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 53 minutes and 16 seconds before requesting another review.

To keep reviews running without waiting, you can enable usage-based add-on for your organization. This allows additional reviews beyond the hourly cap. Account admins can enable it under billing.

⌛ 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.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: bd8893a0-eac5-4e48-b860-aa166e6a035a

📥 Commits

Reviewing files that changed from the base of the PR and between f9a9834 and f689ef4.

⛔ Files ignored due to path filters (6)
  • README.md is excluded by none and included by none
  • RELEASES.md is excluded by none and included by none
  • RELEASE_v4.1.1.md is excluded by none and included by none
  • RELEASE_v4.2.0.md is excluded by none and included by none
  • pyproject.toml is excluded by none and included by none
  • release.ps1 is excluded by none and included by none
📒 Files selected for processing (16)
  • .github/workflows/auto-fix-issues.yml
  • .github/workflows/release.yml
  • easycord/__init__.py
  • easycord/_bot_guild.py
  • easycord/composer.py
  • easycord/database.py
  • easycord/managers.py
  • easycord/middleware.py
  • easycord/plugins/openclaude.py
  • easycord/utils/easy_embed.py
  • tests/test_bot.py
  • tests/test_composer.py
  • tests/test_database.py
  • tests/test_features.py
  • tests/test_managers.py
  • tests/test_openclaude_plugin.py

Walkthrough

Adds multiple GitHub Actions workflows (auto-fix, release, issue-triage, PR governance, PR Quality), enhances AI plugin prompt-length checks and rate-limiter cleanup, introduces manager/composer helpers, utilities (Paginator, EasyEmbed), and various bot/database/middleware robustness fixes plus corresponding tests.

Changes

Cohort / File(s) Summary
GitHub Actions workflows
.github/workflows/auto-fix-issues.yml, .github/workflows/release.yml, .github/workflows/issue-triage.yml, .github/workflows/pr-governance.yml, .github/workflows/tests.yml
Added/updated multiple CI workflows: scoped concurrency, input validation and commenter permission gate for auto-fix; new release workflow for tag pushes; issue triage labeling flow; PR governance title/label enforcement; renamed/updated tests workflow with Ruff lint step.
AI plugin & tests
easycord/plugins/openclaude.py, tests/test_openclaude_plugin.py
Added max_prompt_chars to AIPlugin/OpenClaudePlugin, early rejection with ephemeral message for overlong prompts, stale limiter bucket pruning; tests cover rejection and limiter cleanup.
Core managers & composer
easycord/managers.py, easycord/composer.py, tests/test_managers.py, tests/test_composer.py
New SecurityManager and FrameworkManager module, plus Composer.secure_defaults and Composer.convenience_framework; tests validate middleware composition and bootstrap/build flows.
Utilities: paginator & embeds
easycord/utils/__init__.py, easycord/utils/paginator.py, easycord/utils/easy_embed.py, tests/test_features.py
Added Paginator interactive embed paginator and EasyEmbed factory; package re-exports; tests for pagination and embed colors/behavior.
Bot guild fixes & tests
easycord/_bot_guild.py, tests/test_bot.py
send_webhook retries when cached webhook raises discord.NotFound by recreating; create_emoji validates file existence and 256 KiB limit and reads via Path; tests updated/added for webhook and emoji error cases.
Database & tests
easycord/database.py, tests/test_database.py
SQLiteDatabase._decode_data now catches JSON/type errors and returns {} for invalid/falsy payloads; tests added for malformed inputs.
Middleware rate limiting
easycord/middleware.py
Rate-limit middleware now prunes empty user entries, uses local user_hits copy for checks, and ensures setdefault when recording timestamps.
Package exports
easycord/__init__.py
Re-exported EasyEmbed, FrameworkManager, Paginator, and SecurityManager via package __all__.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested labels

codex

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 36.36% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat(utils): add helper managers and release automation hardening' accurately and specifically summarizes the main changes: new utilities and workflow improvements, matching the primary content of the PR.
Description check ✅ Passed The description follows the template structure with all required sections completed: summary, release impact (Minor selected), quality checklist with most items checked, and comprehensive notes for reviewers covering highlights and validation results.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/fixed-version

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
Review rate limit: 0/1 reviews remaining, refill in 53 minutes and 16 seconds.

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

@qodo-code-review
Copy link
Copy Markdown

Review Summary by Qodo

Security hardening and release automation improvements

✨ Enhancement 🧪 Tests

Grey Divider

Walkthroughs

Description
• Add prompt length validation and stale bucket pruning to AIPlugin
• Harden auto-fix workflow with command validation and permission checks
• Add tag-triggered GitHub Release workflow automation
• Add v4.1.1 release notes and PowerShell release script
Diagram
flowchart LR
  A["AIPlugin"] -->|"add max_prompt_chars"| B["Prompt validation"]
  A -->|"add _prune_old_request_buckets"| C["Memory management"]
  D["auto-fix workflow"] -->|"validate command"| E["Security hardening"]
  D -->|"check permissions"| E
  F["release.yml"] -->|"tag trigger"| G["GitHub Release"]
  H["release.ps1"] -->|"create tag"| G
Loading

Grey Divider

File Changes

1. easycord/plugins/openclaude.py ✨ Enhancement +27/-0

Add prompt validation and memory management to AIPlugin

• Add max_prompt_chars parameter to AIPlugin and OpenClaude plugin constructors
• Implement prompt length validation in ask() method with user-friendly error response
• Add _prune_old_request_buckets() method to prevent unbounded memory growth from stale rate-limit
 entries
• Call pruning method during each request to maintain bounded in-memory state

easycord/plugins/openclaude.py


2. tests/test_openclaude_plugin.py 🧪 Tests +40/-0

Add tests for prompt validation and bucket pruning

• Add test for prompt length rejection when exceeding configured maximum
• Add test for stale rate-limit bucket pruning over time
• Verify ephemeral response and no provider query on oversized prompts
• Verify old buckets are removed while recent ones are retained

tests/test_openclaude_plugin.py


3. .github/workflows/auto-fix-issues.yml Security +23/-2

Harden auto-fix workflow security and validation

• Add regex validation for fix_command input to ensure it starts with python scripts/<name>.py
• Add permission check for issue-comment trigger to restrict execution to collaborators with
 admin/maintain/write access
• Validate that PR head repository matches current repository before allowing auto-fix
• Fail workflow with clear error messages on validation failures

.github/workflows/auto-fix-issues.yml


View more (4)
4. .github/workflows/release.yml ✨ Enhancement +20/-0

Add tag-triggered GitHub Release workflow

• Create new workflow triggered on semantic version tags (v*.*.*)
• Use softprops/action-gh-release to automatically generate GitHub Releases
• Enable auto-generated release notes from commit history
• Set appropriate permissions for release creation

.github/workflows/release.yml


5. RELEASES.md 📝 Documentation +12/-0

Add v4.1.1 release notes index entry

• Add v4.1.1 release entry with highlights section
• Link to detailed release notes in RELEASE_v4.1.1.md
• Document security hardening, AI plugin safety, and release automation improvements

RELEASES.md


6. RELEASE_v4.1.1.md 📝 Documentation +29/-0

Add detailed v4.1.1 release notes

• Document workflow security hardening with command validation and permission restrictions
• Document AI plugin safety improvements including prompt length guard and bucket pruning
• Document release automation additions including release.yml and release.ps1
• Include testing instructions for validation

RELEASE_v4.1.1.md


7. release.ps1 ✨ Enhancement +17/-0

Add PowerShell release tag creation script

• Create PowerShell script to simplify semantic version tag creation and pushing
• Accept version parameter in X.Y.Z or vX.Y.Z format
• Validate version format matches semantic versioning pattern
• Create and push git tag in single command

release.ps1


Grey Divider

Qodo Logo

@qodo-code-review
Copy link
Copy Markdown

qodo-code-review Bot commented Apr 28, 2026

Code Review by Qodo

🐞 Bugs (4) 📘 Rule violations (0)

Grey Divider


Action required

1. fix_command injection still possible 🐞 Bug ⛨ Security
Description
The workflow_dispatch regex allows arbitrary trailing text after the .py path ((?:\s+.*)?), so
inputs like python scripts/fix_issues.py && <cmd> will pass validation and then be executed
verbatim by the Apply fixes step. This enables arbitrary command execution in the workflow context
(with contents: write) when using workflow_dispatch.
Code

.github/workflows/auto-fix-issues.yml[R41-45]

+              // Keep command execution constrained to a known safe prefix.
+              if (!/^python\s+scripts\/[A-Za-z0-9._/-]+\.py(?:\s+.*)?$/.test(inputCommand)) {
+                core.setFailed("fix_command must start with `python scripts/<name>.py`.");
+                return;
+              }
Evidence
The workflow validates fix_command with a regex that allows any characters after the script name,
and then executes the resulting value directly in a run: step. Because run: executes the
provided string as a shell command line, metacharacters included in the allowed suffix are
interpreted by the shell rather than treated as Python arguments.

.github/workflows/auto-fix-issues.yml[37-45]
.github/workflows/auto-fix-issues.yml[100-102]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`workflow_dispatch` accepts a `fix_command` string that is later executed via a `run:` step. The current validation regex permits arbitrary trailing content after the script path (`(?:\s+.*)?`), which allows shell metacharacters like `&&`, `;`, `|`, backticks, `$()`, etc. This can lead to command injection.

### Issue Context
Even with the “safe prefix” requirement, the suffix is effectively unrestricted and will be interpreted by the shell when executed.

### Fix Focus Areas
- .github/workflows/auto-fix-issues.yml[37-45]
- .github/workflows/auto-fix-issues.yml[100-102]

### Recommended fix
- Restrict `fix_command` to a *whitelist* of allowed scripts (e.g., exactly `python scripts/fix_issues.py`) OR remove support for arbitrary commands.
- If arguments must be supported, parse and validate them strictly (e.g., split into tokens and reject any token containing shell metacharacters) and/or avoid shell evaluation by switching to a safer execution pattern (e.g., set outputs for `script_path` and `args` separately and build a fixed `python` invocation without allowing shell operators).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

2. Unvalidated target_branch ref 🐞 Bug ⛨ Security
Description
workflow_dispatch takes target_branch verbatim and uses it as both the checkout ref and the
destination in git push origin "HEAD:${branch}", allowing pushes to unintended refs (e.g.,
refs/tags/... or other namespaces). This can accidentally or intentionally update non-branch refs
using the workflow token.
Code

.github/workflows/auto-fix-issues.yml[R38-49]

+              const inputBranch = core.getInput("target_branch");
+              const inputCommand = core.getInput("fix_command");
+
+              // Keep command execution constrained to a known safe prefix.
+              if (!/^python\s+scripts\/[A-Za-z0-9._/-]+\.py(?:\s+.*)?$/.test(inputCommand)) {
+                core.setFailed("fix_command must start with `python scripts/<name>.py`.");
+                return;
+              }
+
+              core.setOutput("branch", inputBranch);
+              core.setOutput("fix_command", inputCommand);
              core.setOutput("commit_message", core.getInput("commit_message"));
Evidence
The workflow sets the branch output directly from the target_branch input with no validation,
then uses that output in both checkout and push. This makes the workflow sensitive to ref namespace
tricks and user error (pushing to tags/other refs instead of branches).

.github/workflows/auto-fix-issues.yml[37-49]
.github/workflows/auto-fix-issues.yml[86-91]
.github/workflows/auto-fix-issues.yml[109-121]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`target_branch` is used as a raw git ref for checkout and push. Without validation, this can target non-branch refs (e.g., `refs/tags/v1.2.3`) and update them.

### Issue Context
This is in the `workflow_dispatch` path and uses `contents: write` token permissions.

### Fix Focus Areas
- .github/workflows/auto-fix-issues.yml[37-49]
- .github/workflows/auto-fix-issues.yml[86-91]
- .github/workflows/auto-fix-issues.yml[109-121]

### Recommended fix
- Validate `target_branch` against an allowed branch-name pattern (and reject inputs containing `refs/`, `..`, `~`, `^`, `:`, or whitespace).
- Optionally resolve and verify the branch exists via GitHub API.
- When pushing, force the namespace: `git push origin "HEAD:refs/heads/${branch}"` (after stripping any `refs/heads/` prefix).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Prune runs on every ask 🐞 Bug ➹ Performance
Description
AIPlugin.ask now prunes stale rate-limit buckets by scanning the entire _requests map on every
command invocation. For bots with many historical users, this adds O(number of buckets) overhead per
request and can become a performance bottleneck.
Code

easycord/plugins/openclaude.py[R83-92]

+    def _prune_old_request_buckets(self, now: float) -> None:
+        # Keep the in-memory limiter bounded over long uptimes.
+        stale_before = now - self._rate_window
+        stale_keys = [
+            key
+            for key, values in self._requests.items()
+            if not any(stamp > stale_before for stamp in values)
+        ]
+        for key in stale_keys:
+            del self._requests[key]
Evidence
The new pruning helper iterates over all entries in _requests, and ask() calls it
unconditionally before rate limiting. That means each /ask performs work proportional to the total
number of tracked buckets, not just the current user.

easycord/plugins/openclaude.py[83-92]
easycord/plugins/openclaude.py[105-117]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`ask()` prunes stale rate limit buckets on every request by scanning the full `_requests` dict. This can degrade performance for large bots.

### Issue Context
The change is helpful for bounding memory, but doing a full scan per request is avoidable.

### Fix Focus Areas
- easycord/plugins/openclaude.py[83-92]
- easycord/plugins/openclaude.py[105-117]

### Recommended fix
- Track `self._last_prune` and only prune every N seconds (e.g., once per `rate_window` or once per 60s).
- Alternatively, only prune when `len(self._requests)` exceeds a threshold.
- Keep the existing test by patching time and triggering prune based on the new schedule/threshold.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


4. Release tag glob too broad 🐞 Bug ☼ Reliability
Description
The release workflow triggers on v*.*.*, which also matches pre-release/build tags like
v1.2.3-rc1, potentially publishing releases unintentionally. Without an in-workflow validation
gate, any matching tag push will create a GitHub Release.
Code

.github/workflows/release.yml[R3-7]

+on:
+  push:
+    tags:
+      - "v*.*.*"
+
Evidence
The workflow uses a permissive tag glob and does not validate github.ref_name before running the
release action, so non-stable tags that still match the glob will publish releases.

.github/workflows/release.yml[3-7]
.github/workflows/release.yml[11-20]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
The workflow triggers on a broad glob that can match non-stable tags (e.g., `v1.2.3-rc1`). This may create unintended GitHub Releases.

### Issue Context
GitHub tag patterns are glob-based, so you typically need an explicit validation step.

### Fix Focus Areas
- .github/workflows/release.yml[3-7]
- .github/workflows/release.yml[11-20]

### Recommended fix
- Add a first step that validates `github.ref_name` with a strict SemVer regex (e.g., `^v[0-9]+\.[0-9]+\.[0-9]+$`) and fails or exits early if it doesn’t match.
- Optionally add a `job.if:` guard using `contains()` checks to exclude `-` / `+` as a quick filter, but still prefer regex validation in a shell step.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Qodo Logo

Copy link
Copy Markdown

@sourcery-ai sourcery-ai Bot left a comment

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:

  • The fix_command regex in auto-fix-issues.yml still allows path traversal (e.g., python scripts/../../foo.py); consider constraining it to disallow .. segments (e.g., by using a path component pattern like [A-Za-z0-9._-]+(/...)* without dots-only segments).
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The `fix_command` regex in `auto-fix-issues.yml` still allows path traversal (e.g., `python scripts/../../foo.py`); consider constraining it to disallow `..` segments (e.g., by using a path component pattern like `[A-Za-z0-9._-]+(/...)*` without dots-only segments).

## Individual Comments

### Comment 1
<location path=".github/workflows/auto-fix-issues.yml" line_range="42" />
<code_context>
+              const inputCommand = core.getInput("fix_command");
+
+              // Keep command execution constrained to a known safe prefix.
+              if (!/^python\s+scripts\/[A-Za-z0-9._/-]+\.py(?:\s+.*)?$/.test(inputCommand)) {
+                core.setFailed("fix_command must start with `python scripts/<name>.py`.");
+                return;
</code_context>
<issue_to_address>
**🚨 issue (security):** The `fix_command` regex still allows path traversal via `scripts/../...` despite the intended restriction.

The pattern `[A-Za-z0-9._/-]+` still accepts values like `scripts/../foo.py`, which can escape the intended directory. Tighten this by disallowing `..` segments and redundant slashes, e.g.:

```js
/^python\sscripts\/[A-Za-z0-9_/-]+\.py(?:\s+.*)?$/
```

plus an explicit guard:

```js
if (inputCommand.includes("..")) {
  core.setFailed("fix_command may not contain '..' path segments.");
  return;
}
```

or encode the path shape more strictly, e.g. `scripts/[A-Za-z0-9_-]+(?:/[A-Za-z0-9_-]+)*\.py`. This keeps execution aligned with the stated safety constraint.
</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 .github/workflows/auto-fix-issues.yml Outdated
@augmentcode
Copy link
Copy Markdown

augmentcode Bot commented Apr 28, 2026

🤖 Augment PR Summary

Summary: This PR hardens automation around issue triage and releases, and adds safety guards to the OpenClaude/AI plugin.

Changes:

  • Hardened auto-fix-issues workflow by validating workflow_dispatch fix_command input and restricting /fix-issues issue-comment triggers to collaborators with write-level access.
  • Added a tag-triggered GitHub Release workflow (vX.Y.Z) that publishes releases with generated notes.
  • Added max_prompt_chars enforcement in AIPlugin.ask and introduced stale rate-limit bucket pruning to keep limiter state bounded over long uptimes.
  • Extended .gitignore to cover additional pytest/temp directories.
  • Added release notes for v4.1.1 and a PowerShell helper (release.ps1) to create/push version tags.
  • Added tests covering overlong prompt rejection and stale limiter-bucket pruning.

Technical Notes: The OpenClaude wrapper now forwards max_prompt_chars into the shared AIPlugin; rate limiting state is pruned on each /ask invocation to avoid unbounded memory growth.

🤖 Was this summary useful? React with 👍 or 👎

Copy link
Copy Markdown

@augmentcode augmentcode Bot left a comment

Choose a reason for hiding this comment

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

Review completed. 1 suggestion posted.

Fix All in Augment

Comment augment review to trigger a new review at any time.

Comment thread .github/workflows/auto-fix-issues.yml Outdated
Comment thread .github/workflows/auto-fix-issues.yml Outdated
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
easycord/plugins/openclaude.py (1)

83-116: ⚠️ Potential issue | 🟡 Minor

Run cleanup before the early return.

The new overlong-prompt branch returns before _prune_old_request_buckets() runs, so stale request buckets can linger indefinitely if a user only sends rejected prompts.

♻️ Proposed fix
-        if self._max_prompt_chars > 0 and len(prompt) > self._max_prompt_chars:
-            await ctx.respond(
-                ctx.t(
-                    "ai.prompt_too_long",
-                    default="Prompt is too long. Maximum length is {limit} characters.",
-                    limit=self._max_prompt_chars,
-                ),
-                ephemeral=True,
-            )
-            return
-
         self._prune_old_request_buckets(time.monotonic())
+        if self._max_prompt_chars > 0 and len(prompt) > self._max_prompt_chars:
+            await ctx.respond(
+                ctx.t(
+                    "ai.prompt_too_long",
+                    default="Prompt is too long. Maximum length is {limit} characters.",
+                    limit=self._max_prompt_chars,
+                ),
+                ephemeral=True,
+            )
+            return
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@easycord/plugins/openclaude.py` around lines 83 - 116, The early-return in
ask prevents _prune_old_request_buckets from running when prompts exceed
_max_prompt_chars; call self._prune_old_request_buckets(time.monotonic()) at the
start of ask (or immediately before any return on the overlong-prompt branch) so
the request limiter is always cleaned up, ensuring stale keys are removed even
for rejected prompts (update the ask method to run _prune_old_request_buckets
before the length check or duplicate the call just before the existing return).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.github/workflows/auto-fix-issues.yml:
- Around line 42-48: The current validation for inputCommand (used to set
fix_command) allows arbitrary trailing shell content and is command-injection
vulnerable; tighten the regex to only permit the script path plus safe tokenized
arguments (e.g. change /^[^... ]/ to something like matching
/^python\s+scripts\/[A-Za-z0-9._/-]+\.py(?:\s+[A-Za-z0-9._\-/]+)*$/) or
explicitly reject shell metacharacters (reject if inputCommand contains
characters like ;&|$`<>), and prefer validating tokens instead of allowing ".*";
update the validation around inputCommand/fix_command accordingly so only safe
filenames and alphanumeric/flag-style args are accepted before the command is
later executed by the bash runner.

In @.github/workflows/release.yml:
- Around line 8-10: The workflow currently sets workflow-level permission
"contents: write", which is overly broad; remove or change that top-level
"permissions: contents: write" entry and instead grant "contents: write" only on
the specific release job by adding a job-level permissions block (e.g., under
the release job definition) so other jobs do not inherit write access; locate
the top-level "permissions: contents: write" and the release job name to make
this change and ensure other jobs either inherit default read-only permissions
or are given explicit scoped permissions as needed.
- Line 16: The workflow currently references the mutable tag
"softprops/action-gh-release@v2"; replace that with the action's immutable
commit SHA to prevent tag retargeting—locate the step using "uses:
softprops/action-gh-release@v2" and update it to "uses:
softprops/action-gh-release@<commit-sha>" where <commit-sha> is the full commit
hash from the softprops/action-gh-release repository (choose the desired release
commit), commit the change, and verify the workflow runs against the pinned SHA.

In `@tests/test_openclaude_plugin.py`:
- Around line 546-583: Remove the redundant `@pytest.mark.asyncio` decorators from
the async test functions test_aiplugin_rejects_overlong_prompt and
test_aiplugin_prunes_stale_request_buckets in tests/test_openclaude_plugin.py;
these tests are already async and the project uses asyncio_mode="auto", so
delete the decorator lines above those two function definitions and keep the
async function signatures, fixtures, and assertions unchanged.

---

Outside diff comments:
In `@easycord/plugins/openclaude.py`:
- Around line 83-116: The early-return in ask prevents
_prune_old_request_buckets from running when prompts exceed _max_prompt_chars;
call self._prune_old_request_buckets(time.monotonic()) at the start of ask (or
immediately before any return on the overlong-prompt branch) so the request
limiter is always cleaned up, ensuring stale keys are removed even for rejected
prompts (update the ask method to run _prune_old_request_buckets before the
length check or duplicate the call just before the existing return).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: ffcf35c0-cf7a-4d24-b2df-5295c70c79da

📥 Commits

Reviewing files that changed from the base of the PR and between cd4bf3e and 84f60d3.

⛔ Files ignored due to path filters (4)
  • .gitignore is excluded by none and included by none
  • RELEASES.md is excluded by none and included by none
  • RELEASE_v4.1.1.md is excluded by none and included by none
  • release.ps1 is excluded by none and included by none
📒 Files selected for processing (4)
  • .github/workflows/auto-fix-issues.yml
  • .github/workflows/release.yml
  • easycord/plugins/openclaude.py
  • tests/test_openclaude_plugin.py

Comment thread .github/workflows/auto-fix-issues.yml Outdated
Comment thread .github/workflows/release.yml
Comment thread .github/workflows/release.yml Outdated
Comment thread tests/test_openclaude_plugin.py Outdated
@rolling-codes rolling-codes changed the title Codex/fixed version feat(utils): add helper managers and release automation hardening Apr 29, 2026
@rolling-codes rolling-codes merged commit 8dc8cae into main Apr 29, 2026
1 of 3 checks passed
@rolling-codes rolling-codes deleted the codex/fixed-version branch April 29, 2026 10:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants