Skip to content

feat(review): add review-evasion protection#3414

Merged
JSONbored merged 3 commits into
mainfrom
claude/gracious-wiles-e380a0
Jul 5, 2026
Merged

feat(review): add review-evasion protection#3414
JSONbored merged 3 commits into
mainfrom
claude/gracious-wiles-e380a0

Conversation

@JSONbored

Copy link
Copy Markdown
Owner

Summary

  • Contributors were closing or converting a PR to draft immediately after Gittensory started reviewing it, dodging the one-shot terminal decision (a free review, or an escape from an active gate verdict).
  • Adds durable active-review tracking (active_review_tracking, one row per repo/PR, scoped to the reviewed head) that starts right before cost-bearing AI-review work begins and terminalizes when the pass concludes, the head changes, the PR closes, or evasion enforcement completes.
  • When a contributor closes their own PR (or converts it to draft) while that tracking is still active, Gittensory now reopens (if needed, self-close only) and re-closes it as the App -- a close the contributor cannot themselves reopen (existing one-shot-reopen guard) -- posts an explanation comment, applies the configured label, and records a review_evasion moderation strike, but only once the enforcement close actually succeeds.
  • Extracts the moderation-rules escalation (label/ban/auto-blacklist) into a shared applyModerationEscalationForRule helper so both the existing planner-driven path and these new direct webhook handlers use identical logic.
  • Wires review_evasion into the moderation-rules engine (own event type, includable/excludable via global or per-repo moderationRules) and adds reviewEvasionProtection / reviewEvasionLabel / reviewEvasionComment as full config-as-code settings (DB column + Drizzle schema, RepositorySettings type, DB row parse/write, .gittensory.yml resolver, OpenAPI schema, documented .gittensory.yml.example block). Off by default -- zero behavior change for an install that hasn't opted in.

No issue linked: this is a new capability (anti-abuse protection), not a bug fix, and there is no existing open issue tracking it.

Scope

  • The PR title follows type(scope): short summary Conventional Commit format, for example fix(api): restore profile access checks.
  • This PR is focused and does not mix unrelated backend, UI, MCP, docs, dependency, and deploy changes.
  • This follows CONTRIBUTING.md and does not reintroduce GitHub Pages, VitePress, site/, or CNAME.
  • I linked an issue, or this is small enough that the summary explains why an issue is not needed.

Validation

  • git diff --check
  • npm run actionlint
  • npm run typecheck
  • npm run test:coverage locally; codecov/patch requires ≥99% coverage of the lines AND branches you changed (aim for 100% on your diff so CI variance does not fail near the threshold). Global coverage is a non-blocking trend with a loose 90% backstop, not the gate.
  • npm run test:workers
  • npm run build:mcp
  • npm run test:mcp-pack
  • npm run ui:openapi:check
  • npm run ui:lint
  • npm run ui:typecheck
  • npm run ui:build
  • npm audit --audit-level=moderate
  • New or changed behavior has unit/integration tests for new branches, fallback paths, and sanitizer boundaries

All of the above ran green via npm run test:ci plus npm audit --audit-level=moderate, both locally and after rebasing onto the latest main.

Safety

  • No secrets, wallet details, hotkeys, coldkeys, user PATs, private keys, raw trust scores, private rankings, or private maintainer evidence are exposed.
  • Public GitHub text stays sanitized, low-noise, and does not imply compensation guarantees or optimization tactics.
  • Auth, cookie, CORS, GitHub App, Cloudflare, or session changes include negative-path tests.
  • API/OpenAPI/MCP behavior is updated and tested where needed.
  • UI changes use live API data or real empty/error/loading states, not production mock/demo fallbacks. (n/a -- no UI changes)
  • Visible UI changes include a UI Evidence section below with screenshots. (n/a -- backend-only change, no visible UI)
  • Public docs/changelogs are updated where needed; changelogs are only edited for release-prep PRs. (.gittensory.yml.example documents the new settings; CHANGELOG.md intentionally untouched)

Notes

  • New test coverage: test/unit/queue.test.ts (self-close and converted_to_draft evasion handlers, including lock contention, dry-run, pause/freeze, write-permission denial, live-freshness staleness, reopen/close API failure, redelivery idempotency, and the interaction with the existing one-shot reopen guard), test/unit/agent-action-executor.test.ts (the shared applyModerationEscalationForRule helper), test/unit/db-persistence.test.ts and test/unit/moderation-config-db.test.ts (the new active_review_tracking repository functions and the new settings' DB round-trip), test/unit/moderation-rules.test.ts and test/unit/focus-manifest.test.ts (the new rule type and yml parsing), test/unit/github-pr-actions.test.ts (reopenPullRequest).

@superagent-security

Copy link
Copy Markdown

Superagent didn't find any vulnerabilities or security issues in this PR.

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jul 5, 2026

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
gittensory-ui 65cd80a Commit Preview URL

Branch Preview URL
Jul 05 2026, 08:15 AM

@codecov

codecov Bot commented Jul 5, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 99.38650% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 93.04%. Comparing base (65de78e) to head (65cd80a).
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
src/queue/processors.ts 99.19% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3414      +/-   ##
==========================================
+ Coverage   93.01%   93.04%   +0.03%     
==========================================
  Files         297      297              
  Lines       31038    31193     +155     
  Branches    11319    11383      +64     
==========================================
+ Hits        28870    29024     +154     
  Misses       1513     1513              
- Partials      655      656       +1     
Files with missing lines Coverage Δ
src/db/repositories.ts 96.50% <100.00%> (+0.02%) ⬆️
src/db/schema.ts 70.68% <100.00%> (+0.68%) ⬆️
src/github/pr-actions.ts 100.00% <100.00%> (ø)
src/openapi/schemas.ts 100.00% <ø> (ø)
src/services/agent-action-executor.ts 96.80% <100.00%> (ø)
src/settings/agent-actions.ts 96.15% <100.00%> (+0.02%) ⬆️
src/settings/moderation-rules.ts 100.00% <100.00%> (ø)
src/signals/focus-manifest.ts 98.69% <100.00%> (+0.01%) ⬆️
src/queue/processors.ts 93.38% <99.19%> (+0.28%) ⬆️
🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@gittensory-orb gittensory-orb Bot added the gittensor:feature Gittensor-scored feature linked to a feature issue — scores a 1.25x multiplier. label Jul 5, 2026
@gittensory-orb

gittensory-orb Bot commented Jul 5, 2026

Copy link
Copy Markdown

Important

🟪🟪🟪🟪🟪🟪🟪🟪🟪🟪🟪🟪

🔍 Gittensory is reviewing…

AI analysis is in progress. This comment will update when the review is complete.

🟩 Safe / merged · 🟦 Advisory · 🟨 Held for review · 🟥 Blocked / closed · 🟪 Reviewing

JSONbored added 3 commits July 5, 2026 01:06
Contributors were closing or converting PRs to draft immediately after
Gittensory started reviewing them, dodging the one-shot terminal
decision. Track when a fresh review pass starts against a PR's head,
and when a contributor closes or drafts their own PR while that
tracking is still active, reopen (if needed) and re-close it as the
App -- a close the contributor cannot themselves reopen -- post an
explanation, apply the configured label, and record a review_evasion
moderation strike once the enforcement close actually succeeds.

Wires review_evasion into the shared moderation-rules engine and adds
reviewEvasionProtection/reviewEvasionLabel/reviewEvasionComment
config-as-code settings (DB, types, resolver, OpenAPI, .gittensory.yml).

Validated with npm run test:coverage, npm run test:ci, and npm audit
--audit-level=moderate.
The draft-conversion handler only checked pr.authorLogin against the
maintainer/owner/bot exemptions -- it never compared the webhook
sender to the author, so a maintainer converting a CONTRIBUTOR's PR to
draft during an active review was wrongly treated as self-evasion and
enforced against the author who didn't do it. Require
sender.login === authorLogin before enforcing, matching the self-close
handler's existing actor check.

Also keeps the migration's already-updated ISO-8601 strftime defaults
(matching src/db/schema.ts's nowIso() convention) and adds a v8-ignore
for terminalizeActiveReviewTracking's defensive D1-metadata fallback.

Validated with npm run test:ci and npm audit --audit-level=moderate.
closeReviewEvasionSelfCloseIfActive audited an error and returned
normally when reopenPullRequest succeeded but the subsequent
closePullRequest call failed, silently leaving the PR OPEN on
GitHub -- worse than the contributor's original close, and the exact
outcome this enforcement exists to prevent. Propagate the error
instead so the queue's own retry/backoff re-processes the job; the
live freshness check already in this handler sees the PR as open
(current) on retry and re-attempts the close, converging once it
succeeds.

Also tightens patch coverage: v8-ignore annotations on two provably
unreachable branches, and named intermediate variables for the
comment-gating checks in both evasion handlers.

Validated with npm run test:ci and npm audit --audit-level=moderate.
@JSONbored JSONbored force-pushed the claude/gracious-wiles-e380a0 branch from e9c401f to 65cd80a Compare July 5, 2026 08:13
@JSONbored JSONbored merged commit c860b1f into main Jul 5, 2026
13 checks passed
@JSONbored JSONbored deleted the claude/gracious-wiles-e380a0 branch July 5, 2026 08:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

gittensor:feature Gittensor-scored feature linked to a feature issue — scores a 1.25x multiplier. manual-review Gittensor contributor context

Development

Successfully merging this pull request may close these issues.

1 participant