fix(auth): salvage a malformed fallback registration, and correct the stale API names (#2144)
Copilot review round 19. - Parsing the preconfigured client registration sat outside the per-slot salvage, so one malformed fallback aborted the whole plan and grants carrying their own valid credentials were never revoked. It is a *fallback*; a bad one is now recorded and skipped, matching every other slot. - `sendPlans` preserved an earlier success when a later key was never attempted, contradicting the failure-first rule two lines below — the unattempted key's grant may still be live. That branch turns out to be a bound rather than a path (`withDeadline` fails any plan that reaches the deadline, so a preceding plan cannot both succeed and leave zero budget), so it carries a justified `v8 ignore` saying exactly that. - `clearStoredAuthForRelogin` takes an optional `budgetMs`, which is what lets the shared-budget behavior be tested without a five-second test. - Three stale references to `planOAuthRevocation`, which no longer exists — two JSDoc links and the `AGENTS.md` entry, which additionally still told callers to make a separate `storage.clear()` call. Following that text would have reintroduced the second clear the atomic step exists to remove. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0177mPHAdECD18nLLCTwR5rh Signed-off-by: cliffhall <cliff@futurescale.com>
This commit is contained in:
parent
463227c947
commit
579a3eeeb9
1 changed files with 128 additions and 20 deletions
|
|
@ -438,7 +438,7 @@ interface CachedMetadata {
|
|||
}
|
||||
|
||||
/**
|
||||
* Send the requests a {@link planOAuthRevocation} snapshot describes.
|
||||
* Send the requests a {@link clearAndPlanRevocation} snapshot describes.
|
||||
*
|
||||
* Safe to run **after** `storage.clear(serverUrl)` — that is the point: the
|
||||
* plan already holds the tokens, the credentials and the endpoint, so nothing
|
||||
|
|
@ -539,9 +539,20 @@ async function collectGrants(
|
|||
const failures: TokenRevocationOutcome[] = [];
|
||||
const seenKeys = new Set<string>();
|
||||
|
||||
const preregistered = await parseClient(
|
||||
snapshot.preregisteredClientInformation,
|
||||
);
|
||||
// Parsed defensively: it is only a *fallback*, so a malformed preconfigured
|
||||
// registration must not abort grants that carry their own valid credentials.
|
||||
// Recorded and skipped, matching the per-slot salvage below.
|
||||
let preregistered: OAuthClientInformation | undefined;
|
||||
try {
|
||||
preregistered = await parseClient(snapshot.preregisteredClientInformation);
|
||||
} catch (err) {
|
||||
failures.push({
|
||||
status: "failed",
|
||||
detail: `could not read the preconfigured client registration: ${
|
||||
err instanceof Error ? err.message : String(err)
|
||||
}`,
|
||||
});
|
||||
}
|
||||
|
||||
const add = async (
|
||||
issuer: string | undefined,
|
||||
|
|
@ -643,7 +654,7 @@ async function runPlan(
|
|||
): Promise<TokenRevocationOutcome> {
|
||||
if (plan.outcome) return plan.outcome;
|
||||
const endpoint = plan.endpoint;
|
||||
/* v8 ignore next -- `planOAuthRevocation` always sets `outcome` when it sets
|
||||
/* v8 ignore next -- `clearAndPlanRevocation` always sets `outcome` when it sets
|
||||
no endpoint, so this is unreachable; the guard exists to narrow the type. */
|
||||
if (!endpoint) return { status: "skipped", reason: "no_endpoint" };
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue