fix(web): install a step-up's command retry only when its prompt opens
Copilot round 6. `handleCommandScopedAuthRecovery` wrote `pendingStepUpRetryRef` before calling `trySetPendingStepUp`, which REFUSES a second prompt while one is already open — so the refused command's operation replaced the open prompt's, and authorizing that prompt ran the command the user had just been told could not start. The retry now goes in only on a prompt that actually opened, which makes the pairing hold in both directions: the prompt and its retry are installed together, and the EMA branch takes them out together. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Quk1hBUtyhkXowwMXzAnAY Signed-off-by: cliffhall <cliff@futurescale.com>
This commit is contained in:
parent
1634437b69
commit
6f2e1faed2
2 changed files with 43 additions and 8 deletions
|
|
@ -2059,6 +2059,32 @@ describe("useOAuthRecovery", () => {
|
|||
expect(firstRetry).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("keeps the open prompt's retry when a second step-up is refused", async () => {
|
||||
// `trySetPendingStepUp` refuses the second prompt, so the second
|
||||
// command's operation must not replace the first's — authorizing the
|
||||
// open prompt would otherwise run the command the user was just told
|
||||
// could not start (#2165).
|
||||
const client = fakeClient({
|
||||
handleAuthChallenge: vi.fn().mockResolvedValue({ kind: "satisfied" }),
|
||||
});
|
||||
const h = harness({
|
||||
servers: [entry("a", {}, true)],
|
||||
activeServerId: "a",
|
||||
client,
|
||||
});
|
||||
const firstRetry = vi.fn().mockResolvedValue(undefined);
|
||||
const refusedRetry = vi.fn().mockResolvedValue(undefined);
|
||||
await openStepUp(h, "tool", firstRetry);
|
||||
await openStepUp(h, "prompt", refusedRetry);
|
||||
expect(toastTitles()).toContain("Step-up authorization in progress");
|
||||
|
||||
await act(async () => {
|
||||
await h.api().handleStepUpAuthorize();
|
||||
});
|
||||
expect(firstRetry).toHaveBeenCalledTimes(1);
|
||||
expect(refusedRetry).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("cancels back to the panel that asked", async () => {
|
||||
const client = fakeClient();
|
||||
const h = harness({ servers: [entry("a")], activeServerId: "a", client });
|
||||
|
|
|
|||
|
|
@ -690,14 +690,23 @@ export function useOAuthRecovery({
|
|||
) {
|
||||
return true;
|
||||
}
|
||||
pendingStepUpRetryRef.current = options.retryOperation ?? null;
|
||||
trySetPendingStepUp({
|
||||
challenge: error.authChallenge,
|
||||
authorizationUrl: error.authorizationUrl,
|
||||
serverId: options.serverId,
|
||||
source: options.source,
|
||||
enterpriseManaged: isEmaStepUp(error.authChallenge, server),
|
||||
});
|
||||
// The retry belongs to the prompt, so it is installed only once the
|
||||
// prompt is actually open (#2165). `trySetPendingStepUp` REFUSES a
|
||||
// second prompt while one is already up — writing the ref first meant
|
||||
// the refused command's operation replaced the open prompt's, and
|
||||
// authorizing that prompt then ran the command the user was just told
|
||||
// could not start.
|
||||
if (
|
||||
trySetPendingStepUp({
|
||||
challenge: error.authChallenge,
|
||||
authorizationUrl: error.authorizationUrl,
|
||||
serverId: options.serverId,
|
||||
source: options.source,
|
||||
enterpriseManaged: isEmaStepUp(error.authChallenge, server),
|
||||
})
|
||||
) {
|
||||
pendingStepUpRetryRef.current = options.retryOperation ?? null;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue