mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-29 04:25:52 +01:00
Authorize background project Git with explicit Connector consent (#17798)
This commit is contained in:
1 parent
6874fed05c
commit
baec3abd67
37 files changed
+1265
-156
No files matched your search
@@ -1,3 +1,4 @@
|
||||
import { githubCredentialsFixture } from "./helpers/github-credentials-fixture.js";
|
||||
import { createNativeGitHubAccess } from "../services/native-runtime/native-github-access.js";
|
||||
import express from "express";
|
||||
import request from "supertest";
|
||||
@@ -71,129 +72,7 @@ const support = await getEmbeddedPostgresTestSupport();
|
||||
await database?.cleanup();
|
||||
vi.unstubAllEnvs();
|
||||
}, 60_000);
|
||||
async function seed() {
|
||||
const companyId = randomUUID(),
|
||||
agentId = randomUUID(),
|
||||
runId = randomUUID(),
|
||||
issueId = randomUUID();
|
||||
await db.insert(companies).values({
|
||||
id: companyId,
|
||||
name: companyId,
|
||||
issuePrefix: companyId.slice(0, 8),
|
||||
});
|
||||
await db.insert(agents).values({
|
||||
id: agentId,
|
||||
companyId,
|
||||
name: "Shared",
|
||||
role: "engineer",
|
||||
adapterType: "codex_local",
|
||||
});
|
||||
await db
|
||||
.insert(issues)
|
||||
.values({ id: issueId, companyId, title: "Identity test" });
|
||||
await db.insert(heartbeatRuns).values({
|
||||
id: runId,
|
||||
companyId,
|
||||
agentId,
|
||||
status: "running",
|
||||
contextSnapshot: { issueId },
|
||||
});
|
||||
await db.insert(companyMemberships).values(
|
||||
["A", "B"].map((principalId) => ({
|
||||
companyId,
|
||||
principalType: "user",
|
||||
principalId,
|
||||
status: "active",
|
||||
membershipRole: "member",
|
||||
})),
|
||||
);
|
||||
await initializeRunIdentity(db, {
|
||||
companyId,
|
||||
runId,
|
||||
responsibleUserId: "A",
|
||||
cause: "instruction",
|
||||
});
|
||||
return { companyId, agentId, runId, issueId };
|
||||
}
|
||||
async function grant(
|
||||
input: Awaited<ReturnType<typeof seed>>,
|
||||
user: string,
|
||||
dedicated = false,
|
||||
) {
|
||||
const applicationId = randomUUID(),
|
||||
connectionId = randomUUID(),
|
||||
secretId = randomUUID(),
|
||||
definitionId = randomUUID(),
|
||||
id = randomUUID();
|
||||
await db.insert(toolApplications).values({
|
||||
id: applicationId,
|
||||
companyId: input.companyId,
|
||||
name: applicationId,
|
||||
type: "mcp_http",
|
||||
});
|
||||
await db.insert(toolConnections).values({
|
||||
id: connectionId,
|
||||
companyId: input.companyId,
|
||||
applicationId,
|
||||
name: connectionId,
|
||||
uid: connectionId,
|
||||
transport: "mcp_remote",
|
||||
status: "active",
|
||||
enabled: true,
|
||||
credentialPolicy: dedicated ? "per_agent" : "per_user",
|
||||
config: { sourceTemplateKey: "github" },
|
||||
});
|
||||
await db.insert(toolConnectionInstalls).values({
|
||||
companyId: input.companyId,
|
||||
connectionId,
|
||||
targetType: "agent",
|
||||
targetId: input.agentId,
|
||||
});
|
||||
if (!dedicated)
|
||||
await db.insert(userSecretDefinitions).values({
|
||||
id: definitionId,
|
||||
companyId: input.companyId,
|
||||
key: definitionId,
|
||||
name: "Test GitHub",
|
||||
});
|
||||
await db.insert(companySecrets).values({
|
||||
id: secretId,
|
||||
companyId: input.companyId,
|
||||
key: secretId,
|
||||
name: `Test token ${secretId}`,
|
||||
scope: dedicated ? "company" : "user",
|
||||
ownerUserId: dedicated ? null : user,
|
||||
userSecretDefinitionId: dedicated ? null : definitionId,
|
||||
});
|
||||
await db.insert(connectionGrants).values({
|
||||
id,
|
||||
companyId: input.companyId,
|
||||
connectionId,
|
||||
kind: dedicated ? "agent" : "user",
|
||||
subjectUserId: dedicated ? null : user,
|
||||
subjectAgentId: dedicated ? input.agentId : null,
|
||||
status: "active",
|
||||
credentialSecretRefs: [
|
||||
{
|
||||
secretId,
|
||||
configPath: "oauth.access_token",
|
||||
versionSelector: "latest",
|
||||
},
|
||||
],
|
||||
providerTenant: {
|
||||
github: {
|
||||
userId: user,
|
||||
login: user,
|
||||
installationCount: 1,
|
||||
repositoryCount: 1,
|
||||
repositorySelection: "selected",
|
||||
installationIds: ["1"],
|
||||
installationOwnerLogins: [user],
|
||||
},
|
||||
},
|
||||
});
|
||||
return { id, connectionId, secretId, definitionId };
|
||||
}
|
||||
const { seed, grant, switchTo } = githubCredentialsFixture(() => db);
|
||||
it.each(["config", "transportConfig"] as const)("reads only current GitHub identity connections via %s", async location => {
|
||||
const input = await seed(), selected = await grant(input, "A");
|
||||
const [connection] = await db.select().from(toolConnections).where(eq(toolConnections.id, selected.connectionId));
|
||||
@@ -260,24 +139,6 @@ const support = await getEmbeddedPostgresTestSupport();
|
||||
} finally { capture.flush(); await observed.$client.end(); }
|
||||
});
|
||||
|
||||
async function switchTo(
|
||||
input: Awaited<ReturnType<typeof seed>>,
|
||||
user: string,
|
||||
) {
|
||||
const id = randomUUID();
|
||||
await db.insert(issueComments).values({
|
||||
id,
|
||||
companyId: input.companyId,
|
||||
issueId: input.issueId,
|
||||
authorUserId: user,
|
||||
body: "Next instruction",
|
||||
});
|
||||
const context = await reserveSteeredIdentity(db, {
|
||||
...input,
|
||||
messageId: id,
|
||||
});
|
||||
await acceptSteeredIdentity(db, context!);
|
||||
}
|
||||
it("resolves A → B → A without retaining tokens, and records only redacted diagnostics", async () => {
|
||||
const input = await seed();
|
||||
await grant(input, "A");
|
||||
|
||||
Reference in new issue
Block a user