fix(slack): recover rejected grants and consume creation confirmations

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
DottaandPaperclip committed 2026-10-09 10:18:40 -05:00
1 parent 61d199b086
commit 34ffc905ea
5 files changed
+77 -6

No files matched your search

@@ -4236,6 +4236,16 @@ describeEmbeddedPostgres("chat channel control-plane integration", () => {
expect((await f.service.get(f.endpoint.id)).setup.slackRegistration?.status).toBe("configured");
expect(f.provider.mock.calls.filter(([url]) => String(url).endsWith("apps.manifest.create"))).toHaveLength(1);
});
it("reconnects a rejected manager token without losing pending manifest configuration", async () => {
const f = await managedFixture(); f.state.failManifestUpdate = true; await f.provision();
expect((await f.service.get(f.endpoint.id)).setup.slackRegistration?.errorCode).toBe("slack_manifest_update_pending");
expect((await f.grants.choices(f.companyId, actor)).workspaces).toEqual([]);
expect((await f.grants.get(f.grantId, f.companyId, actor)).status).toBe("reauthorize");
await f.grants.complete(await f.authorize(), "new-claim", null, actor);
f.state.failManifestUpdate = false; await f.provision();
expect((await f.service.get(f.endpoint.id)).setup.slackRegistration?.status).toBe("configured");
expect(f.provider.mock.calls.filter(([url]) => String(url).endsWith("apps.manifest.create"))).toHaveLength(1);
});
it("does not restore a revoked grant when an in-flight refresh returns", async () => {
const f = await managedFixture();
await db.update(chatSlackManagerGrants).set({ expiresAt: new Date(0) }).where(eq(chatSlackManagerGrants.id, f.grantId));
@@ -236,15 +236,20 @@ export function createSlackManagerGrants(store: SlackRegistrationStore) {
await tx.execute(sql`select pg_advisory_xact_lock(hashtextextended(${`slack-manager-refresh:${id}`}, 0))`);
const peers = await tx.select().from(chatSlackManagerGrants).where(and(eq(chatSlackManagerGrants.companyId, companyId), eq(chatSlackManagerGrants.managerAppId, grant.managerAppId), eq(chatSlackManagerGrants.workspaceId, grant.workspaceId))).orderBy(chatSlackManagerGrants.id);
if (peers.some(peer => Date.parse(peer.rateLimits[method] ?? "") > Date.now())) return { error: providerFailure("slack_setup_rate_limited") };
if ((await readGrant(tx, id, companyId, actor)).status !== "active") return { error: providerFailure("slack_manager_reauthorize") };
try { return { value: await api(method, fields, authorized.token) }; }
const current = await readGrant(tx, id, companyId, actor);
if (current.status !== "active") return { error: providerFailure("slack_manager_reauthorize") };
try { return { value: await api(method, fields, await secret(current, current.accessSecretId, tx)) }; }
catch (error) {
const details = object(object(error).details);
if (details.code === "slack_setup_rate_limited") {
const until = new Date(Date.now() + Math.min(Number(details.retryAfterSeconds) || 60, 86_400) * 1000).toISOString();
for (const peer of peers) await tx.update(chatSlackManagerGrants).set({ rateLimits: sql`${chatSlackManagerGrants.rateLimits} || ${JSON.stringify({ [method]: until })}::jsonb` }).where(eq(chatSlackManagerGrants.id, peer.id));
}
return { error: details.code === "slack_configuration_token_invalid" ? providerFailure("slack_manager_reauthorize") : error };
if (details.code === "slack_configuration_token_invalid") {
await tx.update(chatSlackManagerGrants).set({ status: "reauthorize", revision: current.revision + 1, updatedAt: new Date() }).where(eq(chatSlackManagerGrants.id, id));
return { error: providerFailure("slack_manager_reauthorize") };
}
return { error };
}
});
if ("error" in result) throw result.error;