-
Notifications
You must be signed in to change notification settings - Fork 2
feat(moderation): comprehensive warning system with severity, decay, and expiry #251
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
ca4a580
feat(moderation): comprehensive warning system with severity, decay, …
5391fd6
📝 Add docstrings to `feat/issue-250-warning-system`
coderabbitai[bot] e31417b
feat(dashboard): add warning system config to moderation section
6ada6e2
feat(dashboard): add escalation threshold editor
d1dffe0
📝 Add docstrings to `feat/issue-250-warning-system`
coderabbitai[bot] 6705986
fix: address all PR #251 review comments
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -42,3 +42,4 @@ web/tsconfig.tsbuildinfo | |
| openclaw-studio/ | ||
| .codex/ | ||
| .turbo/ | ||
| worktrees/ | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -9,7 +9,8 @@ | |
| "!coverage", | ||
| "!logs", | ||
| "!data", | ||
| "!feat-issue-164" | ||
| "!feat-issue-164", | ||
| "!worktrees" | ||
| ] | ||
| }, | ||
| "linter": { | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,60 @@ | ||
| /** | ||
| * Migration: Comprehensive Warning System | ||
| * | ||
| * Adds a dedicated `warnings` table that tracks individual warnings with | ||
| * severity, points, expiry (auto-removal after a configurable period), | ||
| * and decay (points reduce over time). Warnings reference the parent | ||
| * mod_case for traceability. | ||
| * | ||
| * Also adds an index on mod_cases for active-warning escalation queries. | ||
| * | ||
| * @see https://github.com/VolvoxLLC/volvox-bot/issues/250 | ||
| */ | ||
|
|
||
| 'use strict'; | ||
|
|
||
| /** @param {import('node-pg-migrate').MigrationBuilder} pgm */ | ||
| exports.up = (pgm) => { | ||
| // ── warnings table ───────────────────────────────────────────────── | ||
| pgm.sql(` | ||
| CREATE TABLE IF NOT EXISTS warnings ( | ||
| id SERIAL PRIMARY KEY, | ||
| guild_id TEXT NOT NULL, | ||
| user_id TEXT NOT NULL, | ||
| moderator_id TEXT NOT NULL, | ||
| moderator_tag TEXT NOT NULL, | ||
| reason TEXT, | ||
| severity TEXT NOT NULL DEFAULT 'low' | ||
| CHECK (severity IN ('low', 'medium', 'high')), | ||
| points INTEGER NOT NULL DEFAULT 1, | ||
| active BOOLEAN NOT NULL DEFAULT TRUE, | ||
| expires_at TIMESTAMPTZ, | ||
| removed_at TIMESTAMPTZ, | ||
| removed_by TEXT, | ||
| removal_reason TEXT, | ||
| case_id INTEGER REFERENCES mod_cases(id) ON DELETE SET NULL, | ||
| created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), | ||
| updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() | ||
| ) | ||
| `); | ||
|
|
||
| // Fast lookup: all warnings for a user in a guild | ||
| pgm.sql( | ||
| 'CREATE INDEX IF NOT EXISTS idx_warnings_guild_user ON warnings(guild_id, user_id, created_at DESC)', | ||
| ); | ||
|
|
||
| // Fast lookup: active warnings only (for escalation + /warnings display) | ||
| pgm.sql( | ||
| 'CREATE INDEX IF NOT EXISTS idx_warnings_active ON warnings(guild_id, user_id) WHERE active = TRUE', | ||
| ); | ||
|
|
||
| // Expiry polling: find warnings that need to be deactivated | ||
| pgm.sql( | ||
| 'CREATE INDEX IF NOT EXISTS idx_warnings_expires ON warnings(expires_at) WHERE active = TRUE AND expires_at IS NOT NULL', | ||
| ); | ||
| }; | ||
|
|
||
| /** @param {import('node-pg-migrate').MigrationBuilder} pgm */ | ||
| exports.down = (pgm) => { | ||
| pgm.sql('DROP TABLE IF EXISTS warnings CASCADE'); | ||
| }; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Check failure
Code scanning / CodeQL
Missing rate limiting High
Copilot Autofix
AI about 1 month ago
In general, the fix is to introduce a rate-limiting middleware (e.g., using
express-rate-limit) and apply it to the affected routes so that even authenticated clients cannot make unbounded numbers of expensive requests. This middleware should be added without altering existing authentication or audit behavior.The best single approach here is to (1) import
express-rate-limit, (2) define a small set of limiter instances (for example, a “public” limiter and an “authenticated” limiter) in this file, and (3) apply the appropriate limiter to the router mounts. Specifically, for the issue CodeQL flagged on the/warningsroute, we add the authenticated limiter into the middleware chain directly beforerequireAuth()or immediately after it. To keep behavior consistent and improve security more broadly, we can also rate-limit other authenticated routes in the same router, and optionally add a lighter limiter to public routes such as/authand/community. All changes should be made insidesrc/api/index.js: add the import at the top, define the limiters near the router creation, and then update therouter.use(...)lines to include those limiters in the middleware lists, keeping the rest of the logic and ordering intact.Concretely:
src/api/index.js, addimport rateLimit from 'express-rate-limit';.const router = Router();, define e.g.:const publicLimiter = rateLimit({ windowMs: 60_000, max: 60 });const authLimiter = rateLimit({ windowMs: 60_000, max: 120 });router.use('/warnings', requireAuth(), auditLogMiddleware(), warningsRouter);to includeauthLimiter(e.g.,router.use('/warnings', authLimiter, requireAuth(), auditLogMiddleware(), warningsRouter);).authLimiterto all the authenticated routes in this file andpublicLimiterto public routes like/authand/community.