fix: expose web probe auth retry summary

This commit is contained in:
Codex
2026-06-16 05:59:07 +00:00
parent ef8a264064
commit be73e2b16e
3 changed files with 67 additions and 6 deletions
+65 -4
View File
@@ -3810,7 +3810,8 @@ async function authenticate(browserContext) {
async function authenticateWithApiRetries(browserContext) {
const loginUrl = new URL("/auth/login", baseUrl).toString();
const attempts = [];
for (let attempt = 1; attempt <= 3; attempt += 1) {
const maxAttempts = 3;
for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {
try {
const response = await browserContext.request.post(loginUrl, {
data: { username, password },
@@ -3819,10 +3820,12 @@ async function authenticateWithApiRetries(browserContext) {
});
const summary = await responseSummary(response);
const cookieState = await readAuthCookieState(browserContext);
const retryable = isRetryableAuthStatus(response.status());
const item = {
attempt,
method: "api",
...summary,
retryable,
cookiePresent: cookieState.cookiePresent,
cookieNames: cookieState.cookieNames,
};
@@ -3837,21 +3840,24 @@ async function authenticateWithApiRetries(browserContext) {
cookiePresent: true,
cookieNames: cookieState.cookieNames,
attempts,
retryCount: attempt - 1,
fallbackUsed: false,
valuesRedacted: true,
};
}
if (response.status() < 500 && response.status() !== 429) break;
if (!retryable) break;
} catch (error) {
attempts.push({
attempt,
method: "api",
status: 0,
statusText: "request-error",
retryable: true,
error: error instanceof Error ? error.message : String(error),
cookiePresent: false,
});
}
if (attempt < 3) await sleep(300 * attempt);
if (attempt < maxAttempts) await sleep(300 * attempt);
}
const cookieState = await readAuthCookieState(browserContext);
const last = attempts[attempts.length - 1] ?? null;
@@ -3864,6 +3870,9 @@ async function authenticateWithApiRetries(browserContext) {
cookiePresent: cookieState.cookiePresent,
cookieNames: cookieState.cookieNames,
attempts,
retryCount: retryCountFromAttempts(attempts),
fallbackUsed: false,
retryable: authAttemptsRetryable(attempts),
errorSummary: last,
valuesRedacted: true,
};
@@ -3896,6 +3905,9 @@ async function authenticateWithFormFallback(browserContext, apiAuth) {
cookiePresent: cookieState.cookiePresent,
cookieNames: cookieState.cookieNames,
attempts: apiAuth.attempts,
retryCount: apiAuth.retryCount ?? retryCountFromAttempts(apiAuth.attempts),
fallbackUsed: true,
retryable: apiAuth.retryable === true,
apiErrorSummary: apiAuth.errorSummary,
fallback,
valuesRedacted: true,
@@ -3938,6 +3950,9 @@ async function authenticateWithFormFallback(browserContext, apiAuth) {
cookiePresent: cookieState.cookiePresent,
cookieNames: cookieState.cookieNames,
attempts: apiAuth.attempts,
retryCount: apiAuth.retryCount ?? retryCountFromAttempts(apiAuth.attempts),
fallbackUsed: true,
retryable: apiAuth.retryable === true,
apiErrorSummary: apiAuth.errorSummary,
fallback,
valuesRedacted: true,
@@ -3955,6 +3970,9 @@ async function authenticateWithFormFallback(browserContext, apiAuth) {
cookiePresent: cookieState.cookiePresent,
cookieNames: cookieState.cookieNames,
attempts: apiAuth.attempts,
retryCount: apiAuth.retryCount ?? retryCountFromAttempts(apiAuth.attempts),
fallbackUsed: true,
retryable: apiAuth.retryable === true,
apiErrorSummary: apiAuth.errorSummary,
fallback,
valuesRedacted: true,
@@ -4451,6 +4469,19 @@ function boundedInteger(raw, fallback, min, max) {
return Math.max(min, Math.min(max, value));
}
function isRetryableAuthStatus(status) {
return status === 0 || status === 429 || status >= 500;
}
function retryCountFromAttempts(attempts) {
return Math.max(0, Array.isArray(attempts) ? attempts.length - 1 : 0);
}
function authAttemptsRetryable(attempts) {
if (!Array.isArray(attempts) || attempts.length === 0) return false;
return attempts.some((attempt) => attempt && typeof attempt === "object" && attempt.retryable === true);
}
async function responseSummary(response) {
const status = response.status();
let bodyPreview = null;
@@ -4498,22 +4529,52 @@ function sleep(ms) {
}
function publicAuth(value) {
const retryCount = Number.isInteger(value.retryCount) ? value.retryCount : retryCountFromAttempts(value.attempts);
const transientObserved = authAttemptsRetryable(value.attempts);
const ok = value.ok === true;
const retryable = ok ? false : value.retryable === true || transientObserved;
return {
ok: value.ok,
ok,
method: value.method ?? null,
origin: new URL(baseUrl).origin,
loginPath: value.loginUrl,
status: value.status,
statusText: value.statusText,
cookiePresent: value.cookiePresent,
cookieNames: value.cookieNames,
attempts: value.attempts ?? null,
retryCount,
fallbackUsed: value.fallbackUsed === true || value.method === "form-fallback",
fallback: value.fallback ?? null,
errorSummary: cloneSummary(value.errorSummary ?? value.apiErrorSummary ?? null),
degradedReason: ok ? null : "auth-login-failed",
retryable,
transientObserved,
commanderAction: ok
? null
: retryable
? "retry same web-probe command after short backoff; inspect target /auth/login and Cloud Web/API rollout if repeated"
: "inspect bootstrap admin credential source and target user state",
fingerprint: authSummaryFingerprint(value),
username,
valuesRedacted: true,
};
}
function authSummaryFingerprint(value) {
const payload = JSON.stringify({
origin: new URL(baseUrl).origin,
loginPath: value.loginUrl ?? null,
method: value.method ?? null,
status: value.status ?? null,
statusText: value.statusText ?? null,
cookiePresent: value.cookiePresent === true,
retryCount: Number.isInteger(value.retryCount) ? value.retryCount : retryCountFromAttempts(value.attempts),
fallbackUsed: value.fallbackUsed === true || value.method === "form-fallback",
});
return "sha256:" + createHash("sha256").update(payload).digest("hex").slice(0, 16);
}
function cloneSummary(value) {
if (!value || typeof value !== "object" || Array.isArray(value)) return value ?? null;
return { ...value };