mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-29 04:25:52 +01:00
Merge branch 'codex/agent-connection-api-parity' into codex/agent-connection-api-parity-maps
* codex/agent-connection-api-parity: Keep GitHub webhook secret rotation in human setup
This commit is contained in:
commit
ede4b768d0
3 files changed
+21
No files matched your search
@@ -647,6 +647,14 @@ describe("connection management with production default agents", () => {
|
||||
const imported = await f.request("POST", `/chat-endpoints/${created.body.id}/github/app`, { appId: String(appId), privateKey, webhookSecret: "fixture-webhook-secret", clientId: "fixture-client", clientSecret: "fixture-secret" });
|
||||
expect(imported, JSON.stringify(imported)).toMatchObject({ status: 200 });
|
||||
expect(JSON.stringify(imported.body)).not.toContain("PRIVATE KEY");
|
||||
const [beforeRotation] = await server.db.select().from(toolConnections).where(eq(toolConnections.id, created.body.connectionId));
|
||||
for (const token of [f.key.token, f.jwt]) {
|
||||
const rotation = await f.request("POST", `/chat-endpoints/${created.body.id}/setup-secret`, {}, token);
|
||||
expect(rotation, JSON.stringify(rotation)).toMatchObject({ status: 200, body: { status: "needs_user_action", endpointId: created.body.id } });
|
||||
expect(rotation.body).not.toHaveProperty("webhookSecret");
|
||||
}
|
||||
const [afterRotation] = await server.db.select().from(toolConnections).where(eq(toolConnections.id, created.body.connectionId));
|
||||
expect(afterRotation.credentialSecretRefs).toEqual(beforeRotation.credentialSecretRefs);
|
||||
const refreshed = await f.request("POST", `/chat-endpoints/${created.body.id}/github/repositories/refresh`, {});
|
||||
expect(refreshed, JSON.stringify(refreshed)).toMatchObject({ status: 200 });
|
||||
expect(JSON.stringify(refreshed.body)).toContain("fixture/repo");
|
||||
@@ -668,6 +676,11 @@ describe("connection management with production default agents", () => {
|
||||
expect((await humanRequest(callback)).status).toBe(403);
|
||||
const confirmed = await humanRequest(`/api/chat-endpoints/${created.body.id}/github/identity/confirm`, "POST", { githubUserId: "1357" });
|
||||
expect(confirmed.status, JSON.stringify(await confirmed.json())).toBe(200);
|
||||
const humanRotation = await humanRequest(`/api/chat-endpoints/${created.body.id}/setup-secret`, "POST", {});
|
||||
expect(humanRotation.status).toBe(201);
|
||||
expect(await humanRotation.json()).toEqual({ webhookSecret: expect.stringMatching(/^[a-f0-9]{64}$/) });
|
||||
const [humanRotated] = await server.db.select().from(toolConnections).where(eq(toolConnections.id, created.body.connectionId));
|
||||
expect(humanRotated.credentialSecretRefs).not.toEqual(beforeRotation.credentialSecretRefs);
|
||||
} finally { provider = null; }
|
||||
});
|
||||
|
||||
|
||||
@@ -429,6 +429,10 @@ export function chatChannelRoutes(db: Db, options: ChatChannelRouteOptions) {
|
||||
router.post("/chat-endpoints/:endpointId/setup-secret", managementGuard("connections:configure", "POST /chat-endpoints/:endpointId/setup-secret"), async (req, res) => {
|
||||
if (!(await assertEndpointManagementAccess(req, res))) return;
|
||||
res.set("Cache-Control", "no-store");
|
||||
if (req.actor.type === "agent") {
|
||||
res.json(await setupHandoff(req, "The responsible user must rotate and enter the webhook signing secret in GitHub."));
|
||||
return;
|
||||
}
|
||||
res
|
||||
.status(201)
|
||||
.json(
|
||||
|
||||
@@ -26,6 +26,7 @@ import type {
|
||||
|
||||
import {
|
||||
conflict,
|
||||
forbidden,
|
||||
notFound,
|
||||
unprocessable,
|
||||
} from "../../../errors.js";
|
||||
@@ -61,6 +62,9 @@ export function createGitHubSetupSecret(db: Db, options: GitHubSetupSecretOption
|
||||
managementContext?: ConnectionManagementContext,
|
||||
) {
|
||||
await managementContext?.reauthorize();
|
||||
if (managementContext?.actor.type === "agent") {
|
||||
throw forbidden("Webhook signing secrets require a human setup handoff");
|
||||
}
|
||||
const initial = await endpointRecord(endpointId);
|
||||
if (!initial) throw notFound("Chat endpoint not found");
|
||||
if (initial.endpoint.provider !== "github") {
|
||||
|
||||
Reference in new issue
Block a user