Skip to content

Commit f3f70ed

Browse files
committed
fix: order managed auth checkpoint events
1 parent d786e5d commit f3f70ed

2 files changed

Lines changed: 48 additions & 5 deletions

File tree

src/lib/mcp/tools/managed-auth-state.ts

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -219,10 +219,19 @@ async function waitFromCheckpoint(
219219
);
220220
}
221221
const events = await authFlowEvents(client, latest.id);
222-
const event =
223-
checkpoint.kind === "event"
224-
? events.find((candidate) => candidate.id === checkpoint.eventId)
225-
: events.find((candidate) => candidate.id !== checkpoint.eventId);
222+
let event: ManagedAuthTimelineEvent | undefined;
223+
if (checkpoint.kind === "event") {
224+
event = events.find((candidate) => candidate.id === checkpoint.eventId);
225+
} else if (checkpoint.eventId === null) {
226+
event = events[0];
227+
} else {
228+
// Timelines are newest-first. Only entries before the baseline were created
229+
// after the checkpoint; an absent baseline must fail closed.
230+
const baselineIndex = events.findIndex(
231+
(candidate) => candidate.id === checkpoint.eventId,
232+
);
233+
event = baselineIndex > 0 ? events.slice(0, baselineIndex)[0] : undefined;
234+
}
226235
if (!event || event.status === "IN_PROGRESS") {
227236
return { state: "pending", connection: latest };
228237
}

src/lib/mcp/tools/managed-auth-wait.test.ts

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,14 @@ describe("managed-auth wait", () => {
157157
});
158158
const staleClient = waitClient({
159159
states: [authenticated],
160-
events: [oldEvent],
160+
events: [
161+
oldEvent,
162+
timelineEvent({
163+
id: "flow_older",
164+
type: "reauth",
165+
status: "SUCCESS",
166+
}),
167+
],
161168
}).client;
162169
const selector = {
163170
connectionId: authenticated.id,
@@ -188,6 +195,33 @@ describe("managed-auth wait", () => {
188195
).toBe("authenticated");
189196
});
190197

198+
test("after-checkpoint fails closed when its baseline is absent", async () => {
199+
const authenticated = connection({
200+
status: "AUTHENTICATED",
201+
flow_status: "SUCCESS",
202+
flow_type: "REAUTH",
203+
});
204+
const { client } = waitClient({
205+
states: [authenticated],
206+
events: [
207+
timelineEvent({
208+
id: "flow_historical",
209+
type: "reauth",
210+
status: "SUCCESS",
211+
}),
212+
],
213+
});
214+
const result = await waitForAuthConnection(
215+
client,
216+
{
217+
connectionId: authenticated.id,
218+
flowCheckpoint: checkpoint("after", "flow_missing"),
219+
},
220+
{ timeoutMs: 0 },
221+
);
222+
expect(result.state).toBe("pending");
223+
});
224+
191225
test("explicitly empty baseline catches the first flow's terminal failure", async () => {
192226
const failed = connection({
193227
flow_status: "FAILED",

0 commit comments

Comments
 (0)