Skip to content

feat(agent-actions): add an account-age throttle for ban-evasion#2642

Merged
JSONbored merged 3 commits into
mainfrom
feat/account-age-throttle
Jul 2, 2026
Merged

feat(agent-actions): add an account-age throttle for ban-evasion#2642
JSONbored merged 3 commits into
mainfrom
feat/account-age-throttle

Conversation

@JSONbored

@JSONbored JSONbored commented Jul 2, 2026

Copy link
Copy Markdown
Owner

Summary

  • The contributor blacklist matches by exact login string; the contributor cap counts open items per repo. Neither has any signal for how OLD a GitHub account is — the classic ban-evasion gap: a banned login gets a fresh account the same day and gets full trust until it independently trips the cap on its own in ONE repo.
  • Adds accountAgeThresholdDays: a PR from an account younger than the threshold gets the new-account label AND a tightened effective contributorOpenPrCap (half, rounded up, minimum 1) — friction/visibility only, never an automatic close on account age alone. PR-path only for now (the issue-path cap enforcement doesn't read this setting yet).
  • Fetches created_at via GET /users/{login} — already classified as a cached "metadata" GitHub response (src/github/client.ts's resolveGitHubCacheClass), so this reuses the existing response-cache infra with zero new caching mechanism.
  • Off by default (null threshold). Never fires for the repo owner, admin logins, automation bots, or a repo-scoped autoCloseExemptLogins entry — same standing exemption as every other anti-abuse mechanism (blacklist, contributor cap, review-nag). The label mutation itself is additionally gated behind label autonomy being "auto", matching every other label write.
  • Full config-as-code chain wired (migration + Drizzle schema + RepositorySettings type + db/repositories.ts resolver + .gittensory.yml parsing + OpenAPI schema + .gittensory.yml.example docs).

Closes #2561.

Scope

  • The PR title follows type(scope): short summary Conventional Commit format.
  • 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 (via npm run test:ci)
  • npm run db:migrations:check — migration 0096 (rebased/renumbered after a main-side collision), contiguous, no new duplicates
  • npm run typecheck
  • npm run test:coverage locally — tests covering: a below-threshold account gets the label AND the tightened cap trips a close a raw-cap check wouldn't; an above-threshold account is fully unaffected; the repo owner's own PR is never labeled even on a brand-new account; getGithubUserCreatedAt fetches/parses/fails-open on error; .gittensory.yml parsing (set/override/clear-via-null/omitted/invalid).
  • npm run test:workers (via npm run test:ci)
  • npm run build:mcp (via npm run test:ci)
  • npm run test:mcp-pack (via npm run test:ci)
  • npm run ui:openapi:check — regenerated and committed apps/gittensory-ui/public/openapi.json
  • npm run ui:lint (via npm run test:ci)
  • npm run ui:typecheck (via npm run test:ci)
  • npm run ui:build (via npm run test:ci)
  • npm audit --audit-level=moderate
  • New or changed behavior has unit/integration tests for new branches, fallback paths, and sanitizer boundaries

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. — N/A, no auth/session/CORS surface touched.
  • API/OpenAPI/MCP behavior is updated and tested where needed. — RepositorySettings's new fields added to the OpenAPI schema and regenerated.
  • UI changes use live API data or real empty/error/loading states, not production mock/demo fallbacks. — N/A, no UI change.
  • Visible UI changes include a UI Evidence section below with screenshots. — N/A, no UI change.
  • Public docs/changelogs are updated where needed; changelogs are only edited for release-prep PRs. — .gittensory.yml.example documents the new settings.

Notes

  • Fourth of a batch of independent maintainer-only roadmap items being worked one PR at a time.

@dosubot dosubot Bot added the size:L label Jul 2, 2026
@loopover-orb

loopover-orb Bot commented Jul 2, 2026

Copy link
Copy Markdown

Warning

🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨

⏸️ Gittensory review result - manual review recommended

Review updated: 2026-07-02 23:42:54 UTC

13 files · 1 AI reviewer · 1 blocker · readiness 100/100 · CI pending · blocked

⏸️ Suggested Action - Manual Review

  • Possible leaked secret in the diff (generic_secret_assignment) — Remove the secret from the diff, rotate the exposed credential, then re-run the gate.

Review summary
The change wires a default-off account-age setting through schema, migration, repository settings, config-as-code, OpenAPI, and the PR maintenance path. The PR path is coherent: it fails open on lookup errors, respects label autonomy for the visibility label, and only tightens an already-configured contributor cap rather than closing solely on account age. The main remaining concerns are policy/documentation alignment around exemptions and the explicitly PR-only scope.

Nits — 6 non-blocking
  • nit: src/queue/processors.ts:1986 does not consult autoCloseExemptLogins before applying the new-account label, so confirm whether the shared anti-abuse exemption list is intentionally ignored for this visibility throttle.
  • nit: src/github/app.ts:425 returns any string created_at value; explicitly rejecting unparseable date strings would keep the fail-open behavior local to the GitHub helper instead of relying on Date.parse(...)=NaN in the processor.
  • nit: src/types.ts:672 documents the feature as PR-path only while the PR description says PR/issue, so align the public contract or add the issue-path wiring in a follow-up.
  • nit: test/unit/queue.test.ts:6707 covers the owner exemption but not the admin or automation-bot exemptions that the processor condition also promises.
  • In src/queue/processors.ts:1986, either add the same repo-scoped exemption check used by the anti-abuse planner or document why account-age labeling is deliberately outside autoCloseExemptLogins.
  • PR author also opened the linked issue — Link an issue that was opened by a different contributor, or provide a rationale for why this self-authored issue represents genuine discovery work.

Concerns raised — review before merging

  • Possible leaked secret in the diff (generic_secret_assignment) — Remove the secret from the diff, rotate the exposed credential, then re-run the gate.
Signal Result Evidence
Code review ❌ 1 blocker 1 reviewer
Linked issue ✅ Linked #2561
Related work ✅ No active overlap found No same-issue or scoped active PR overlap found.
Change scope ✅ 20/20 Low review scope from cached public metadata (size label size:L; 1 linked issue).
Validation posture ✅ 25/25 PR body includes validation/test evidence.
Contributor workload ✅ 10/10 Author activity: 64 registered-repo PR(s), 55 merged, 522 issue(s).
Contributor context ✅ Confirmed Gittensor contributor JSONbored; Gittensor profile; 64 PR(s), 522 issue(s).
Gate result ❌ Blocking Repo-configured hard blocker found.
Review context
  • Author: JSONbored
  • Role context: owner (maintainer lane)
  • Public audience mode: oss maintainer
  • Lane context: Repository registration is not available in the local Gittensory cache.
  • Public profile languages: not available
  • Official Gittensor activity: 64 PR(s), 522 issue(s).
  • PR-specific overlap: none found.
Contributor next steps
  • Treat this as maintainer-lane context rather than normal contributor-lane activity.
  • No action.
Signal definitions
  • Related work = same linked issue, overlapping active PRs, or title/path similarity.
  • Change scope = cached public metadata such as size labels, draft state, and review-burden hints.
  • Validation posture = whether the PR provides enough public validation/test evidence for maintainer review.
  • Contributor workload = public contributor activity and cleanup pressure, not a repo-wide quality failure.
  • Contributor context = public GitHub/Gittensor identity context; non-Gittensor status is not a blocker.

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


💰 Earn for open-source contributions like this. Gittensor lets GitHub contributors earn for the work they already do — register to start earning →.

Checked by Gittensory, a quiet PR intelligence layer for OSS maintainers.

  • Re-run Gittensory review

@codecov

codecov Bot commented Jul 2, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 92.59259% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 96.09%. Comparing base (3bee887) to head (315f547).
⚠️ Report is 5 commits behind head on main.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
src/queue/processors.ts 83.33% 0 Missing and 2 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2642      +/-   ##
==========================================
- Coverage   96.09%   96.09%   -0.01%     
==========================================
  Files         237      237              
  Lines       26448    26474      +26     
  Branches     9589     9602      +13     
==========================================
+ Hits        25416    25440      +24     
  Misses        425      425              
- Partials      607      609       +2     
Files with missing lines Coverage Δ
src/db/repositories.ts 96.58% <100.00%> (+<0.01%) ⬆️
src/db/schema.ts 69.46% <ø> (ø)
src/github/app.ts 98.16% <100.00%> (+0.06%) ⬆️
src/openapi/schemas.ts 100.00% <ø> (ø)
src/signals/focus-manifest.ts 99.27% <100.00%> (+<0.01%) ⬆️
src/queue/processors.ts 92.39% <83.33%> (-0.06%) ⬇️
🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jul 2, 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 315f547 Commit Preview URL

Branch Preview URL
Jul 02 2026, 11:44 PM

JSONbored added 3 commits July 2, 2026 16:40
The contributor blacklist matches by exact login string; the contributor
cap counts open items per repo. Neither has any signal for how old a
GitHub account is -- the classic ban-evasion gap: a banned login gets a
fresh account the same day and gets full trust until it independently
trips the cap on its own.

Adds accountAgeThresholdDays: a PR/issue from an account younger than the
threshold gets the new-account label AND a tightened effective contributor
cap (half, rounded up) -- friction/visibility, never an automatic close on
account age alone. Fetches created_at via GET /users/{login}, already
classified as a cached "metadata" GitHub response (client.ts), so this
reuses the existing response cache with no new caching infra. Off by
default. Never fires for the repo owner, admin logins, or automation bots.

Closes #2561.
The account-age throttle applied its label directly, bypassing the
label-autonomy opt-in every other label mutation goes through — a repo
with label autonomy still at the default "observe" would get labels
written anyway. Also narrows the docs to PR-only (issue-path
enforcement isn't wired yet) and hardens getGithubUserCreatedAt against
a non-string created_at field.

Addresses gate review findings on #2561.
main independently merged 0095_pull_request_detail_sync_pr_state.sql,
colliding with this branch's own 0095_account_age_throttle.sql after
rebase.
@JSONbored
JSONbored force-pushed the feat/account-age-throttle branch from 5f73109 to 315f547 Compare July 2, 2026 23:42
@JSONbored
JSONbored merged commit 33b4cbf into main Jul 2, 2026
12 checks passed
@JSONbored
JSONbored deleted the feat/account-age-throttle branch July 2, 2026 23:46
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 0.25x multiplier.

Development

Successfully merging this pull request may close these issues.

feat(agent-actions): add an account-age throttle for ban-evasion

1 participant