pr_01m47d24b0e6n91zwymwxg0vpx/services/runner/src/credentials.test.ts

75 lines3,239 bytesCodeBlame
1import assert from "node:assert/strict";
2import { createHash } from "node:crypto";
3import { test } from "node:test";
4
5import { credentialHashes, holdCredentials, pushGrant, remotePath, revokeCredentials, sha256Hex } from "./credentials.ts";
6
7test("a remote names its repository", () => {
8 assert.deepEqual(remotePath("https://g1t.sh/acme/rocket.git"), { namespace: "acme", name: "rocket" });
9 assert.deepEqual(remotePath("https://g1t.sh/pulls/pul_01abc.git"), { namespace: "pulls", name: "pul_01abc" });
10 assert.equal(remotePath("https://g1t.sh/acme"), null);
11});
12
13test("a fork is the pull request's own; a branch of the repository is not", () => {
14 const repo = { namespace: "acme", name: "rocket" };
15 assert.deepEqual(pushGrant(repo, { namespace: "pulls", name: "pul_1" }, "main"), {
16 repo: { namespace: "pulls", name: "pul_1" },
17 branch: null,
18 });
19 assert.deepEqual(pushGrant(repo, { namespace: "Acme", name: "Rocket" }, "fix-login"), {
20 repo: { namespace: "Acme", name: "Rocket" },
21 branch: "fix-login",
22 });
23});
24
25test("tokens are hashed the way identity stores them", async () => {
26 const token = "g1t_0123456789abcdef";
27 assert.equal(await sha256Hex(token), createHash("sha256").update(token).digest("hex"));
28 const hashes = await credentialHashes({ G1T_TOKEN: token, G1T_AGENT_TOKEN: "g1t_x", OTHER: "g1t_y", CHECK_TOKEN: "c" });
29 assert.equal(hashes.length, 2);
30 assert.ok(hashes.every((hash) => /^[0-9a-f]{64}$/.test(hash)));
31});
32
33/** Identity, as far as the credentials' lifecycle uses it. */
34function fakeIdentity() {
35 const calls: { method: string; body: unknown }[] = [];
36 return {
37 calls,
38 fetch: async (url: string, init?: RequestInit) => {
39 calls.push({ method: url.split("/rpc/")[1], body: JSON.parse(String(init?.body)) });
40 return new Response("true");
41 },
42 };
43}
44
45function memoryStorage() {
46 const map = new Map<string, unknown>();
47 return {
48 map,
49 put: async (key: string, value: unknown) => void map.set(key, value),
50 get: async <T>(key: string) => map.get(key) as T | undefined,
51 delete: async (key: string) => map.delete(key),
52 };
53}
54
55test("a sandbox's credentials are bound to its run and revoked once when it stops", async () => {
56 const identity = fakeIdentity();
57 const storage = memoryStorage();
58 await holdCredentials(identity, storage, { G1T_TOKEN: "g1t_a", G1T_AGENT_TOKEN: "g1t_b" }, "run_1");
59 assert.equal(identity.calls[0].method, "bind_run_credentials");
60 assert.deepEqual((identity.calls[0].body as { runId: string }).runId, "run_1");
61 await revokeCredentials(identity, storage);
62 await revokeCredentials(identity, storage);
63 const revokes = identity.calls.filter((call) => call.method === "revoke_run_credentials");
64 assert.equal(revokes.length, 1);
65 assert.equal((revokes[0].body as { tokenHashes: string[] }).tokenHashes.length, 2);
66});
67
68test("a sandbox with no run record still has its credentials revoked", async () => {
69 const identity = fakeIdentity();
70 const storage = memoryStorage();
71 await holdCredentials(identity, storage, { G1T_TOKEN: "g1t_a" }, null);
72 assert.equal(identity.calls.length, 0);
73 await revokeCredentials(identity, storage);
74 assert.equal(identity.calls[0].method, "revoke_run_credentials");
75});