mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-15 20:53:23 +02:00
Keep completed connections outside pending OAuth quotas
Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
1 parent
fb7946a4b8
commit
d17bdce7a9
3 files changed
+14
-2
No files matched your search
+1
-1
@@ -172,6 +172,6 @@ catalog to implement them.
|
||||
Registration also enforces shared source quotas (6 per minute and 30 unconsented
|
||||
clients) using a resource-bound hash of the trusted request IP; raw addresses are
|
||||
not stored. Configure trusted proxies correctly. Authorization starts atomically
|
||||
remove expired requests and enforce 10 retained requests per client and 1,000
|
||||
remove expired requests and enforce 10 pending-consent requests per client and 1,000
|
||||
instance-wide, independently of further client registrations. Existing grants
|
||||
remain usable when anonymous registration or authorization is throttled.
|
||||
@@ -309,4 +309,16 @@ describe.skipIf(!support.supported)("public MCP OAuth and tool boundary", () =>
|
||||
expect(await db.select().from(mcpOauthRequests).where(eq(mcpOauthRequests.clientId, client.client_id))).toHaveLength(1);
|
||||
});
|
||||
|
||||
it("does not charge completed connections against a shared client's pending consent quota", async () => {
|
||||
const f = await fixture();
|
||||
const input = { client_id: f.client.client_id, redirect_uri: redirectUri, response_type: "code", resource: config.resource, code_challenge: challenge, code_challenge_method: "S256" };
|
||||
for (let i = 0; i < 12; i++) {
|
||||
const id = (await oauth.authorize(input)).split("/").at(-1)!;
|
||||
const consent = await oauth.consent(id, f.actor, { decision: "approve", companyId: f.company.id, allowWrites: false });
|
||||
const code = new URL(consent.redirectUrl).searchParams.get("code")!;
|
||||
await expect(oauth.token({ grant_type: "authorization_code", client_id: f.client.client_id, redirect_uri: redirectUri, resource: config.resource, code, code_verifier: verifier })).resolves.toHaveProperty("access_token");
|
||||
}
|
||||
await expect(oauth.authorize(input)).resolves.toContain("/mcp-connect/");
|
||||
});
|
||||
|
||||
});
|
||||
@@ -144,7 +144,7 @@ export function createPublicMcpOAuth(db: Db, config: PublicMcpConfig) {
|
||||
await tx.delete(mcpOauthRequests).where(lt(mcpOauthRequests.expiresAt, now));
|
||||
const [counts] = await tx.select({ total: sql<number>`count(*)::int`,
|
||||
client: sql<number>`(count(*) FILTER (WHERE ${mcpOauthRequests.clientId} = ${client.id}))::int`,
|
||||
}).from(mcpOauthRequests);
|
||||
}).from(mcpOauthRequests).where(isNull(mcpOauthRequests.decidedAt));
|
||||
if (!counts || counts.total >= 1000 || counts.client >= 10) {
|
||||
throw new McpOAuthError("temporarily_unavailable", "Too many pending connection requests. Retry later.", 429);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user