mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-11-12 22:56:58 +01:00
fix(connectors): stop GitHub access refreshes from advancing agent runtimes (#19902)
This commit is contained in:
1 parent
eb7c7b083a
commit
0363ebec70
4 files changed
+165
-2
No files matched your search
@@ -6,8 +6,8 @@ import { randomUUID, generateKeyPairSync, verify, createHash, diffieHellman, hkd
|
||||
import { createServer, type Server } from "node:http";
|
||||
import { once } from "node:events";
|
||||
import { afterAll, afterEach, beforeAll, describe, expect, it, vi } from "vitest";
|
||||
import { eq, sql } from "drizzle-orm";
|
||||
import { applyPendingMigrations, companies, activityLog, companySecrets, connectionEventDeliveries, connectionGrants, createDb, EMBEDDED_POSTGRES_TEST_TIMEOUT_MS, toolApplications, toolConnections } from "@paperclipai/db";
|
||||
import { and, eq, sql } from "drizzle-orm";
|
||||
import { applyPendingMigrations, agents, companies, activityLog, companySecrets, connectionEventDeliveries, connectionGrants, createDb, EMBEDDED_POSTGRES_TEST_TIMEOUT_MS, resourceLifecycleEvents, toolApplications, toolConnections } from "@paperclipai/db";
|
||||
import { resolveExternalTestDatabaseUrl } from "./helpers/external-test-database.js";
|
||||
import { createGitHubGrantContinuity, githubGrantContinuityDeadline, githubContinuityRevision } from "../services/tool-access/github-grant-continuity.js";
|
||||
import { createPaperclipCloudConnector } from "../services/paperclip-cloud-connector.js";
|
||||
@@ -174,6 +174,32 @@ describeDatabase("GitHub coordinator with PostgreSQL and controlled Cloud HTTP (
|
||||
} finally { await ew.stop(); await cw.stop(); await coordinator.stop(); }
|
||||
});
|
||||
|
||||
it("rereads unchanged access on a scheduled refresh without advancing agent runtime revisions", async () => {
|
||||
const f = await fixture(["101"]);
|
||||
const agentId = randomUUID();
|
||||
await db.insert(agents).values({ id: agentId, companyId: f.company.id, name: "Runtime fixture", adapterType: "paperclip_runner" });
|
||||
vi.spyOn(globalThis, "fetch").mockImplementation((url, init) => String(url).startsWith("https://api.github.com")
|
||||
? realFetch(`${origin}${new URL(String(url)).pathname}${new URL(String(url)).search}`, init) : realFetch(url, init));
|
||||
const actor = { actorType: "system", actorId: "tool_health_sweep" } as const;
|
||||
const runtimeEvents = () => db.select().from(resourceLifecycleEvents).where(and(
|
||||
eq(resourceLifecycleEvents.companyId, f.company.id), eq(resourceLifecycleEvents.resourceType, "agent_runtime")));
|
||||
const grant = async () => (await db.select().from(connectionGrants).where(eq(connectionGrants.id, f.grant.id)))[0]!;
|
||||
try {
|
||||
// The first refresh records the repository list the fixture lacked.
|
||||
await f.service.refreshManagedGitHubGrantAccess(f.connection, f.grant, actor);
|
||||
const first = await grant();
|
||||
const before = await runtimeEvents();
|
||||
expect(before.length).toBeGreaterThan(0);
|
||||
await f.service.refreshManagedGitHubGrantAccess(f.connection, first, actor);
|
||||
const second = await grant();
|
||||
expect(second.providerTenant!.github!.accessRevision).not.toBe(first.providerTenant!.github!.accessRevision);
|
||||
expect(second.providerTenant!.github!.bindingSync).toBeUndefined();
|
||||
expect(bindings.filter(binding => binding.active === true)).toHaveLength(2);
|
||||
expect(await runtimeEvents()).toEqual(before);
|
||||
} finally {
|
||||
await db.delete(agents).where(eq(agents.id, agentId));
|
||||
}
|
||||
});
|
||||
it("failed binding removal persists retry/debt through restart, uses current lease deadline and settles without refetching GitHub metadata", async () => {
|
||||
const f = await fixture(["101"]); fakeClock();
|
||||
await db.update(connectionGrants).set({ providerTenant: { ...f.grant.providerTenant, github: { ...f.grant.providerTenant!.github!,
|
||||
|
||||
Reference in new issue
Block a user