mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-08 12:32:43 +00:00
Merge branch 'fix/v1439-jobs' into release/v1.43.9
This commit is contained in:
commit
897fb10c5b
2 files changed
+76
-4
No files matched your search
+22
-4
@@ -14,6 +14,7 @@ import {
|
||||
decryptCodexCreds,
|
||||
encryptAdminCodexCreds,
|
||||
decryptAdminCodexCreds,
|
||||
CodexRefreshError,
|
||||
type CodexCreds,
|
||||
} from "./codex-oauth";
|
||||
import { isPublicUrl } from "@/lib/validations/notifications";
|
||||
@@ -287,16 +288,33 @@ async function runCodexRefresh(
|
||||
// A sign-in replaced the token while the issuer refused the old one.
|
||||
return { fresh: now.creds };
|
||||
}
|
||||
if (!isDeadCodexSignIn(error)) return { failed: error };
|
||||
// `refresh_token_reused` is a dead grant here and only here: under the
|
||||
// lock, with the row still holding the very token just spent, no peer
|
||||
// of ours rotated it, so the issuer is refusing the whole family (a
|
||||
// revoked sign-in answers every refresh so). Outside the lock it is
|
||||
// the lost race it usually is (see DEAD_REFRESH_TOKEN_CODES).
|
||||
const refused =
|
||||
oauthErrorOf(error) === "refresh_token_reused"
|
||||
? new CodexRefreshError(401, "refresh_token_reused")
|
||||
: error;
|
||||
if (!isDeadCodexSignIn(refused)) return { failed: error };
|
||||
return {
|
||||
refused: error,
|
||||
refused,
|
||||
parked: (await store.park(tx, row.refreshEncrypted)) === 1,
|
||||
};
|
||||
}
|
||||
if ((await store.writeRotated(tx, row.refreshEncrypted, fresh)) === 0) {
|
||||
// A sign-in replaced the row meanwhile; it wins over this refresh.
|
||||
// A sign-in replaced the row meanwhile; it wins over this refresh. A
|
||||
// row with no usable credential left was disconnected meanwhile: the
|
||||
// person took Codex away, so nothing may be sent with it any more.
|
||||
const now = await store.read(tx);
|
||||
if (now?.creds) return { fresh: now.creds };
|
||||
if (now?.status === "connected" && now.creds) {
|
||||
return { fresh: now.creds };
|
||||
}
|
||||
return {
|
||||
refused: codexReconnectRequired("disconnected during refresh"),
|
||||
parked: false,
|
||||
};
|
||||
}
|
||||
return { fresh };
|
||||
},
|
||||
|
||||
@@ -319,3 +319,57 @@ describe("two refreshes of one Codex token", () => {
|
||||
expect(parkSignals("codex")).toHaveLength(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe("a Codex refresh under the lock", () => {
|
||||
it("parks a sign-in whose every refresh the issuer answers as reused", async () => {
|
||||
const user = await seedCodexUser();
|
||||
// The issuer revoked the token family: no peer rotated anything, yet each
|
||||
// refresh comes back reused.
|
||||
vi.mocked(refreshDeviceTokens).mockRejectedValue(
|
||||
new CodexRefreshError(400, "refresh_token_reused"),
|
||||
);
|
||||
|
||||
const chain = await resolveProviderChain(user.id);
|
||||
|
||||
expect(chain.map((p) => p.providerType)).not.toContain("codex");
|
||||
expect(
|
||||
(
|
||||
await prisma.user.findUniqueOrThrow({
|
||||
where: { id: user.id },
|
||||
select: { codexConnectionStatus: true },
|
||||
})
|
||||
).codexConnectionStatus,
|
||||
).toBe("expired");
|
||||
expect(parkSignals("codex")).toHaveLength(1);
|
||||
expect(parkSignals("codex")[0][0].meta?.oauth_error).toBe(
|
||||
"refresh_token_reused",
|
||||
);
|
||||
});
|
||||
|
||||
it("does not use Codex once more when the person disconnected it meanwhile", async () => {
|
||||
const user = await seedCodexUser();
|
||||
vi.mocked(refreshDeviceTokens).mockImplementation(async () => {
|
||||
await prisma.user.update({
|
||||
where: { id: user.id },
|
||||
data: {
|
||||
codexAccessTokenEncrypted: null,
|
||||
codexRefreshTokenEncrypted: null,
|
||||
codexConnectionStatus: "disconnected",
|
||||
},
|
||||
});
|
||||
return creds("rotated", 10 * HOUR_MS);
|
||||
});
|
||||
|
||||
const chain = await resolveProviderChain(user.id);
|
||||
|
||||
expect(chain.map((p) => p.providerType)).not.toContain("codex");
|
||||
expect(
|
||||
(
|
||||
await prisma.user.findUniqueOrThrow({
|
||||
where: { id: user.id },
|
||||
select: { codexConnectionStatus: true },
|
||||
})
|
||||
).codexConnectionStatus,
|
||||
).toBe("disconnected");
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user