feat(orb): gate APR repo-transfer requests on idea completion - #8000
feat(orb): gate APR repo-transfer requests on idea completion#8000jsdevninja wants to merge 1 commit into
Conversation
Adds the customer-facing request-only path for APR transfers (JSONbored#7742): evaluateAprRepoTransferRequestEligibility + requestAprRepoTransfer wrap initiateAprRepoTransfer so GitHub is only contacted when the JSONbored#7591 completion signal is true, and expose POST /v1/loop/request-apr-transfer. No automatic or proactive offer.
| const body = await c.req.json().catch(() => null); | ||
| const parsed = requestAprTransferSchema.safeParse(body); | ||
| if (!parsed.success) return c.json({ error: "invalid_request_apr_transfer_request", issues: parsed.error.issues }, 400); | ||
| const result = await requestAprRepoTransfer(c.env, parsed.data); |
There was a problem hiding this comment.
P1: ideaComplete security gate is trivially bypassable because it is caller-supplied
The ideaComplete boolean comes from the request body, so any caller can set it to true and bypass the completion gate.
Look up idea completion from a server-side persisted source instead of trusting caller input.
AI prompt
Check if this security scanner issue is valid. If so, understand the root cause and fix it. If appropriate, update or add tests. Keep the change focused and preserve intended behavior.
<file name="src/api/routes.ts">
<violation number="1" location="src/api/routes.ts:3749">
<priority>P1</priority>
<title>`ideaComplete` security gate is trivially bypassable because it is caller-supplied</title>
<evidence>The `ideaComplete` boolean is accepted directly from the request body (`ideaComplete: z.boolean()`) and passed to `requestAprRepoTransfer`, which uses it as the sole input to `evaluateAprRepoTransferRequestEligibility`. Since the caller controls this value, they can set `ideaComplete: true` to bypass the completion gate entirely, defeating the #7742 policy that repo transfers should only be available after idea completion.</evidence>
<recommendation>Look up the idea completion status from a trusted server-side source (#7591) instead of trusting the caller. If a persisted lookup is not yet available, reject all transfer requests or verify completion via an internal service call that the caller cannot influence. The route should not accept `ideaComplete` from the request body.</recommendation>
</violation>
</file>
|
Caution 🛑 LoopOver review result - fixes requiredReview updated: 2026-07-22 05:50:38 UTC
Review summary Nits — 5 non-blocking
CI checks failing
Decision drivers
Context & advisory signals — never blocks the verdict
Linked issue satisfactionAddressed Review context
Contributor next steps
Signal definitions
🧪 Chat with LoopOverAsk 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.
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.
|
|
LoopOver is closing this pull request on the maintainer's behalf (CI is failing (Superagent Security Scan)). This is an automated maintenance action — to pursue this change, please open a new pull request with the issues resolved. Closed PRs may be analyzed later to improve review accuracy, but they are not automatically reopened or re-reviewed. |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #8000 +/- ##
==========================================
- Coverage 91.92% 89.79% -2.14%
==========================================
Files 740 96 -644
Lines 75933 24341 -51592
Branches 23040 4578 -18462
==========================================
- Hits 69803 21857 -47946
+ Misses 5037 2214 -2823
+ Partials 1093 270 -823
Flags with carried forward coverage won't be shown. Click here to find out more.
|
Closes #7742
Summary
evaluateAprRepoTransferRequestEligibility+requestAprRepoTransferinsrc/orb/apr-repo-transfer.ts. The request wrapper gates onideaCompletebefore calling the existinginitiateAprRepoTransfer; incomplete ideas never touch GitHub.POST /v1/loop/request-apr-transfer(same private API auth as the other/v1/loop/*Rent-a-Loop routes). Responses:202initiated (still pending recipient acceptance),409idea not complete,502GitHub rejected the transfer,400invalid body.Test plan
response.text()rejection fallbacknpm run typecheckorb-apr-repo-transfer+routes-request-apr-transfer(17 passing)