diff --git a/tests/integration/acting-account-resolver.test.ts b/tests/integration/acting-account-resolver.test.ts index 0c61815a4..923088189 100644 --- a/tests/integration/acting-account-resolver.test.ts +++ b/tests/integration/acting-account-resolver.test.ts @@ -282,21 +282,30 @@ describe("acting-account resolver — the decision is never cached", () => { const owner = await makeUser("owner"); const delegate = await makeUser("delegate"); await seedWeight(owner.id, 81); + // Far enough ahead that accepting, signing in and switching cannot + // outrun it on a loaded runner, and well inside the session's minute. + const expiresAt = new Date(Date.now() + 30_000); const invited = await inviteGrant({ grantorId: owner.id, granteeId: delegate.id, access: "READ", scope: null, - expiresAt: new Date(Date.now() + 400), + expiresAt, }); await acceptGrant({ grantId: invited.id, granteeId: delegate.id }); const session = await signIn(delegate.id); await switchTo(session.id, owner.id); expect((await call()).status).toBe(200); - await new Promise((resolve) => setTimeout(resolve, 500)); - // The row did not change. Only the clock the resolver reads moved. - expect((await call()).status).toBe(403); + // The row does not change. Only the clock the resolver reads moves, to + // the instant the grant names: the first one it no longer holds. + vi.useFakeTimers({ toFake: ["Date"] }); + try { + vi.setSystemTime(expiresAt); + expect((await call()).status).toBe(403); + } finally { + vi.useRealTimers(); + } }); it("refuses the moment the grant is only pending", async () => { diff --git a/tests/integration/encryption-key-check.test.ts b/tests/integration/encryption-key-check.test.ts index eae7d1f87..f7d1a8ea5 100644 --- a/tests/integration/encryption-key-check.test.ts +++ b/tests/integration/encryption-key-check.test.ts @@ -44,6 +44,41 @@ vi.mock("@/lib/db-compat", () => ({ ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), })); +/** + * The start-up probe is bounded in time on purpose: ten seconds in all and + * two per query, so a host with a huge table still starts. Those bounds are + * not what this file asks about. On a loaded runner a probe query can take + * longer than two seconds, and the check then answers "inconclusive" + * (`incomplete`) where the data says "mismatch", which is the right answer + * for a slow host and the wrong one for a test of the verdicts. So the check + * runs here with time to finish, unless a case passes its own budget or + * sampler: the cases that test the bounds themselves do. + */ +vi.mock("@/lib/crypto/canary", async (importOriginal) => { + const actual = await importOriginal(); + return { + ...actual, + checkEncryptionKeyCanaries: ( + client: Parameters[0], + options: Parameters[1] = {}, + ) => { + let sampler; + try { + sampler = actual.sqlColumnSampler(client, { + statementTimeoutMs: 60_000, + }); + } catch { + // A client the sampler cannot use: the check reports that itself. + } + return actual.checkEncryptionKeyCanaries(client, { + probeBudgetMs: 120_000, + ...(sampler ? { sampler } : {}), + ...options, + }); + }, + }; +}); + import { _resetCryptoCacheForTests, encrypt,