Skip to content

feat(api): add installation-scoped bulk agent pause/dry-run endpoint - #8144

Merged
loopover-orb[bot] merged 1 commit into
mainfrom
feat/tenant-quota-job-dispatch-enforcement
Jul 23, 2026
Merged

feat(api): add installation-scoped bulk agent pause/dry-run endpoint#8144
loopover-orb[bot] merged 1 commit into
mainfrom
feat/tenant-quota-job-dispatch-enforcement

Conversation

@JSONbored

Copy link
Copy Markdown
Owner

Summary

  • Adds PUT /v1/app/installations/:id/agent/bulk-settings, applying agentPaused/agentDryRun across every currently-installed repo in a tenant's installation in one call — previously only strictly per-repo via PUT /v1/repos/:owner/:repo/settings.
  • Reuses this route family's existing tenant-scoping exactly (resolveAppInstallationScope/installationRecordInScope): an operator can write any installation; a non-operator session only their own — enforced before any write.
  • Distinct from the global operator kill-switch (getGlobalAgentFrozenState), untouched by this.
  • Own audit-trail event (installation.agent_bulk_settings_updated), distinct from both per-repo edits (repo.settings_updated) and the kill-switch's own event.

Closes #7676.

Test plan

  • New tests in test/integration/app-installations-selfservice.test.ts: auth/role rejection, invalid installation id / unknown installation / malformed body (incl. genuinely unparseable JSON) / unrecognized field, tenant-isolation (never lets tenant A touch tenant B's installation, enforced pre-write), applies across every installed repo and only those repos, partial-field updates preserve the other flag, no-op for zero-repo installations, operator bypass with its own audit event.
  • npx tsc --noEmit
  • Targeted coverage check — 100% line/branch/function coverage on every new line
  • npm run ui:openapi:check / npm run ui:openapi:settings-parity — clean
  • npm run test:coverage (unsharded, full suite) — clean
  • npm audit --audit-level=moderate — 0 vulnerabilities
  • npm run engine-parity:drift-check / npm run manifest:drift-check — clean

A hosted tenant with multiple repos under one installation had no way
to pause/dry-run all of them at once -- only the strictly per-repo
PUT /v1/repos/:owner/:repo/settings existed. Adds PUT /v1/app/
installations/:id/agent/bulk-settings, applying agentPaused/
agentDryRun across every currently-installed repo in the installation
in one call. Reuses the existing /v1/app/installations* tenant-scoping
(resolveAppInstallationScope / installationRecordInScope), so a tenant
can never bulk-write another tenant's installation. Distinct from the
global operator kill-switch, which stays untouched.

Closes #7676.
@JSONbored JSONbored self-assigned this Jul 23, 2026
@superagent-security

Copy link
Copy Markdown
Contributor

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

@codecov

codecov Bot commented Jul 23, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 90.11%. Comparing base (4578fef) to head (896de6a).
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #8144      +/-   ##
==========================================
- Coverage   92.03%   90.11%   -1.92%     
==========================================
  Files         764       98     -666     
  Lines       77520    25151   -52369     
  Branches    23430     4702   -18728     
==========================================
- Hits        71346    22665   -48681     
+ Misses       5062     2214    -2848     
+ Partials     1112      272     -840     
Flag Coverage Δ
shard-1 29.85% <100.00%> (-27.81%) ⬇️
shard-2 43.32% <10.00%> (-7.57%) ⬇️
shard-3 70.72% <10.00%> (+16.25%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
src/api/routes.ts 95.27% <100.00%> (+0.03%) ⬆️

... and 666 files with indirect coverage changes

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

loopover-orb Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Tip

✅ LoopOver review result - approve/merge recommended

Review updated: 2026-07-23 04:53:11 UTC

2 files · 1 AI reviewer · no blockers · readiness 100/100 · CI green · clean

✅ Suggested Action - Approve/Merge

  • safe to merge

Review summary
This adds `PUT /v1/app/installations/:id/agent/bulk-settings`, reusing the existing `resolveAppInstallationScope`/`installationRecordInScope` tenant-isolation pattern from the health/repair routes and applying `agentPaused`/`agentDryRun` across every installed repo in an installation via a `.strict()` picked-field schema. The forbidden-installation check runs before body parsing and before any write, and partial-field updates correctly preserve the other flag by merging into `getRepositorySettings` first. Test coverage is thorough (auth, scope, malformed/unparseable JSON, strict-extra-field rejection, partial update, zero-repo no-op, operator bypass with distinct audit event) and closes the linked #7676.

Nits — 6 non-blocking
  • src/api/routes.ts: the `Promise.all` over `repoFullNames.map` fires one `getRepositorySettings` + `upsertRepositorySettings` pair concurrently per installed repo with no batching/limit — fine for typical tenant sizes but worth a comment or cap if an installation can have hundreds of repos.
  • src/api/routes.ts: an empty body `{}` passes `.safeParse` (all fields optional) and still performs a full write pass across every repo plus a `recordAuditEvent` call for a functionally no-op change — consider short-circuiting when `Object.keys(changes).length === 0`.
  • The four inline HTTP status literals (400/403/404) flagged by tooling match this file's existing per-route convention (see the sibling health/repair routes), so no change needed there.
  • Consider adding a quick `Object.keys(changes).length === 0` early-return to skip the repo fan-out and audit write for a genuinely empty body.
  • If installations can have very large repo counts, consider chunking the `Promise.all` to bound concurrent D1 writes.
  • 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.

Decision drivers

  • ✅ Code review — No blockers (1 reviewer)
  • ✅ Gate result — Passing (No configured blocker found.)
Context & advisory signals — never blocks the verdict
Signal Result Evidence
Linked issue ✅ Linked #7676
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 (1 linked issue).
Validation posture ✅ 25/25 PR body includes validation/test evidence.
Contributor workload ✅ 10/10 Author activity: 14 registered-repo PR(s), 14 merged, 228 issue(s).
Contributor context ✅ Confirmed Gittensor contributor JSONbored; Gittensor profile; 14 PR(s), 228 issue(s).
Improvement ✅ Minor risk: clean · value: minor · LLM: significant
Linked issue satisfaction

Addressed
The PR adds a new installation-scoped PUT /v1/app/installations/:id/agent/bulk-settings endpoint that applies agentPaused/agentDryRun across all repos in an installation with proper tenant-scoping, and records a distinct audit event (installation.agent_bulk_settings_updated) separate from per-repo edits and the global kill-switch, matching all stated deliverables and boundaries.

Review context
  • Author: JSONbored
  • Role context: owner (maintainer lane)
  • Public audience mode: oss maintainer
  • Lane context: Repository is configured for direct PR review.
  • Public profile languages: Python, TypeScript, Ruby, Go, JavaScript, MDX, Shell, Solidity
  • Official Gittensor activity: 14 PR(s), 228 issue(s).
  • PR-specific overlap: none found.
Contributor next steps
  • Start here: Treat this as maintainer-lane context rather than normal contributor-lane activity.
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.
🧪 Chat with LoopOver

Ask LoopOver a question about this PR directly in a comment — grounded only in the same cached, public-safe facts shown above, never a new claim.

  • @loopover ask &lt;question&gt; answers contribution-quality Q&A with source citations and freshness.
  • @loopover chat &lt;question&gt; answers in natural prose from cached decision-pack facts via local inference (maintainer/collaborator; read-only).
  • A plain-language @loopover mention with a real question is routed to the closest matching read-only command automatically — no exact syntax required.

Full command reference: https://loopover.ai/docs/loopover-commands

🧪 Experimental — new and may change.

🟩 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 LoopOver, a quiet PR intelligence layer for OSS maintainers.

  • Re-run LoopOver review

@loopover-orb loopover-orb Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LoopOver approves — the gate is satisfied and CI is green.

@loopover-orb
loopover-orb Bot merged commit b3cb3c9 into main Jul 23, 2026
14 checks passed
@loopover-orb
loopover-orb Bot deleted the feat/tenant-quota-job-dispatch-enforcement branch July 23, 2026 04:53
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.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add installation-scoped bulk pause/dry-run endpoint (currently strictly per-repo)

1 participant