Skip to content
File

Blob: test/pat-last-used.worker.test.ts

typescript83 lines
1import { beforeAll, describe, expect, it } from "vitest";
2import { env } from "cloudflare:workers";
3 
4import {
5 PAT_LAST_USED_READ_THROTTLE_MS,
6 generatePatPlaintext,
7 hashPatPlaintext,
8 shouldTouchPatLastUsedAt,
9} from "@/worker/auth/pat";
10import { newPrefixedId } from "@/worker/common";
11import { createDb } from "@/worker/db/d1/client";
12import { findPatByPrefix, insertPatWithGrants, updatePatLastUsedAt } from "@/worker/db/d1/dal";
13 
14import { ensureD1Migrations } from "./util/d1Setup";
15import { seedRepo } from "./util/repoSeed";
16 
17beforeAll(async () => {
18 await ensureD1Migrations(env);
19});
20 
21describe("shouldTouchPatLastUsedAt", () => {
22 it("write op always returns true regardless of lastUsedAt", () => {
23 expect(shouldTouchPatLastUsedAt(null, "write")).toBe(true);
24 expect(shouldTouchPatLastUsedAt(Date.now(), "write")).toBe(true);
25 });
26 
27 it("read op returns true when lastUsedAt is null", () => {
28 expect(shouldTouchPatLastUsedAt(null, "read")).toBe(true);
29 });
30 
31 it("read op returns false when lastUsedAt is fresh", () => {
32 const now = Date.now();
33 expect(shouldTouchPatLastUsedAt(now - 1000, "read", now)).toBe(false);
34 expect(shouldTouchPatLastUsedAt(now - PAT_LAST_USED_READ_THROTTLE_MS + 1, "read", now)).toBe(
35 false
36 );
37 });
38 
39 it("read op returns true when lastUsedAt is older than the throttle window", () => {
40 const now = Date.now();
41 expect(shouldTouchPatLastUsedAt(now - PAT_LAST_USED_READ_THROTTLE_MS, "read", now)).toBe(true);
42 expect(shouldTouchPatLastUsedAt(now - PAT_LAST_USED_READ_THROTTLE_MS - 1, "read", now)).toBe(
43 true
44 );
45 });
46});
47 
48describe("updatePatLastUsedAt", () => {
49 it("writes the supplied timestamp to the row", async () => {
50 const seed = await seedRepo(env, {
51 namespaceSlug: `pat-touch-${Math.random().toString(36).slice(2, 8)}`,
52 repoSlug: "site",
53 });
54 const db = createDb(env.DB);
55 const generated = generatePatPlaintext();
56 const patId = newPrefixedId("pat");
57 await insertPatWithGrants(db, {
58 pat: {
59 id: patId,
60 userId: seed.userId,
61 name: "ci",
62 prefix: generated.publicPrefix,
63 hash: await hashPatPlaintext(generated.plaintext),
64 createdAt: Date.now(),
65 expiresAt: null,
66 revokedAt: null,
67 lastUsedAt: null,
68 },
69 namespaceGrants: [],
70 repoGrants: [{ patId, repoId: seed.repositoryId, level: "push" }],
71 });
72 
73 const before = await findPatByPrefix(db, generated.publicPrefix);
74 expect(before?.lastUsedAt).toBeNull();
75 
76 const stamp = 1_700_000_000_000;
77 await updatePatLastUsedAt(db, patId, stamp);
78 
79 const after = await findPatByPrefix(db, generated.publicPrefix);
80 expect(after?.lastUsedAt).toBe(stamp);
81 });
82});