Skip to content

Where people and agents ship software together. The open-source git platform for the whole job: issues, agents, checks and deploys to the edge.

g1t.sh
143 linesCodeBlameRaw

Pick any line to see why it is the way it is: the commit, the pull request and issue it came from, and what the agent was thinking.

Merge branch 'worktree-agent-a6da31375506fc440'1// node --test "scripts/deploy/*.test.mjs" (npm run test:deploy)
2//
3// Invite a friend's statements, run as identity runs them: read out of
4// services/identity/src (the constants there are written out in full) and
5// run on SQLite, which D1 is, against identity's migrations applied in
6// order. Twenty invites each; a revoked one comes back, a used one is
7// spent; signing up from the link spends it and records who invited whom.
8import assert from "node:assert/strict";
9import { readFileSync, readdirSync } from "node:fs";
10import { join } from "node:path";
11import { DatabaseSync } from "node:sqlite";
12import { test } from "node:test";
13
14import { ROOT } from "./stack.mjs";
15
16const SRC = join(ROOT, "services", "identity", "src");
17
18/** Every `const NAME: &str = r#"…"#;` in `file`, by name. */
19function statements(file) {
20 const text = readFileSync(join(SRC, file), "utf8");
21 const found = {};
22 for (const match of text.matchAll(/const (\w+): &str =\s*r#"([\s\S]*?)"#;/g)) found[match[1]] = match[2];
23 return found;
24}
25
26const SQL = { ...statements("invites.rs"), ...statements(join("invites", "friends.rs")) };
27
28function migrated() {
29 const db = new DatabaseSync(":memory:");
30 const dir = join(ROOT, "services", "identity", "migrations");
31 for (const file of readdirSync(dir).filter((name) => name.endsWith(".sql")).sort()) {
32 db.exec(readFileSync(join(dir, file), "utf8"));
33 }
34 return db;
35}
36
37const LIMIT = 20;
38const LATER = "2099-01-01T00:00:00.000Z";
39const EARLIER = "2000-01-01T00:00:00.000Z";
40let next = 0;
41
42/** Makes an invite to g1t for `inviter` the way `create_invite` does: within the allowance. */
43function invite(db, inviter, email, { limit = LIMIT, expiresAt = LATER } = {}) {
44 const id = `inv_${++next}`;
45 const row = db
46 .prepare(SQL.INSERT_WITHIN_ALLOWANCE)
47 .get(id, `hash_${id}`, "g1t-abcd", null, email, "account", null, inviter, null, "user", EARLIER, expiresAt, null, null, inviter, limit);
48 return row?.id ?? null;
49}
50
51const used = (db, inviter) => db.prepare(SQL.USED).get(inviter).n;
52
53test("the statements are all there", () => {
54 for (const name of ["INSERT", "INSERT_WITHIN_ALLOWANCE", "USED", "GRANTED", "PENDING_FOR", "REVOKE", "SPEND_CODE", "INSERT_USER_WITH_CODE"]) {
55 assert.ok(SQL[name], `${name} not found`);
56 }
57});
58
59test("twenty invites each: the twenty-first is refused in the statement that writes", () => {
60 const db = migrated();
61 for (let n = 1; n <= LIMIT; n++) assert.ok(invite(db, "usr_bo", `friend${n}@example.com`), `invite ${n}`);
62 assert.equal(used(db, "usr_bo"), LIMIT);
63 assert.equal(invite(db, "usr_bo", "one-too-many@example.com"), null);
64 // Somebody else's are their own.
65 assert.ok(invite(db, "usr_cy", "friend1@example.com"));
66 // Invitations into a workspace never count.
67 db.prepare(SQL.INSERT).run("inv_ws", "hash_ws", "g1t-wxyz", null, "x@example.com", "account", "wsp_1", "usr_bo", null, "none", EARLIER, LATER, null, "member");
68 assert.equal(used(db, "usr_bo"), LIMIT);
69});
70
71test("revoking an unused invite gives it back; an expired one never counted", () => {
72 const db = migrated();
73 const ids = [];
74 for (let n = 1; n <= LIMIT; n++) ids.push(invite(db, "usr_bo", `friend${n}@example.com`));
75 const revoked = db.prepare(SQL.REVOKE).get("usr_bo", ids[0]);
76 assert.equal(revoked?.id, ids[0]);
77 assert.equal(used(db, "usr_bo"), LIMIT - 1);
78 assert.ok(invite(db, "usr_bo", "another@example.com"));
79 // Someone else cannot revoke it.
80 assert.equal(db.prepare(SQL.REVOKE).get("usr_eve", ids[1]), undefined);
81 // An expired, never used invite is not counted.
82 const db2 = migrated();
83 invite(db2, "usr_bo", "late@example.com", { expiresAt: EARLIER });
84 assert.equal(used(db2, "usr_bo"), 0);
85});
86
87test("a used invite is spent: revoking it does nothing and it still counts", () => {
88 const db = migrated();
89 const id = invite(db, "usr_bo", "ada@example.com");
90 db.prepare(SQL.SPEND_CODE).run("usr_ada", id);
91 db.prepare("UPDATE invites SET applied_at = ? WHERE id = ?").run(EARLIER, id);
92 assert.equal(db.prepare(SQL.REVOKE).get("usr_bo", id), undefined);
93 assert.equal(used(db, "usr_bo"), 1);
94 // Revoked while its account was still confirming: stopped, and still spent.
95 const waiting = invite(db, "usr_bo", "cy@example.com");
96 db.prepare(SQL.SPEND_CODE).run("usr_cy", waiting);
97 assert.equal(db.prepare(SQL.REVOKE).get("usr_bo", waiting)?.id, waiting);
98 assert.equal(used(db, "usr_bo"), 2);
99});
100
101test("a pending invite for the same address is found; a revoked one is not", () => {
102 const db = migrated();
103 const id = invite(db, "usr_bo", "ada@example.com");
104 assert.equal(db.prepare(SQL.PENDING_FOR).get("usr_bo", "ada@example.com").n, 1);
105 assert.equal(db.prepare(SQL.PENDING_FOR).get("usr_cy", "ada@example.com").n, 0);
106 db.prepare(SQL.REVOKE).get("usr_bo", id);
107 assert.equal(db.prepare(SQL.PENDING_FOR).get("usr_bo", "ada@example.com").n, 0);
108});
109
110test("staff grants add to the twenty and can take some back", () => {
111 const db = migrated();
112 const grant = db.prepare("INSERT INTO invite_grants (id, target_kind, target_id, amount, note, granted_by, created_at) VALUES (?, 'user', ?, ?, ?, ?, ?)");
113 grant.run("igr_1", "usr_bo", 10, "launch partner", "staff@example.com", EARLIER);
114 grant.run("igr_2", "usr_bo", -3, null, "staff@example.com", EARLIER);
115 grant.run("igr_3", "usr_cy", 50, null, "staff@example.com", EARLIER);
116 assert.equal(db.prepare(SQL.GRANTED).get("usr_bo").n, 7);
117 assert.equal(db.prepare(SQL.GRANTED).get("usr_dee").n, 0);
118});
119
120test("signing up from the link spends the invite once and records who invited whom", () => {
121 const db = migrated();
122 const id = invite(db, "usr_bo", "ada@example.com");
123 db.prepare(SQL.SPEND_CODE).run("usr_ada", id);
124 db.prepare(SQL.INSERT_USER_WITH_CODE).run("usr_ada", "ada", "ada@example.com", "hash", 1, id);
125 const user = db.prepare("SELECT username, email_verified_at FROM users WHERE id = 'usr_ada'").get();
126 assert.equal(user.username, "ada");
127 // From the email's own link: the address starts confirmed.
128 assert.ok(user.email_verified_at);
129 const row = db.prepare("SELECT inviter_id, redeemed_by, redeemed_at, sealed_code FROM invites WHERE id = ?").get(id);
130 assert.equal(row.inviter_id, "usr_bo");
131 assert.equal(row.redeemed_by, "usr_ada");
132 assert.ok(row.redeemed_at);
133 // A second sign-up with the same code spends nothing and makes no account.
134 db.prepare(SQL.SPEND_CODE).run("usr_eve", id);
135 db.prepare(SQL.INSERT_USER_WITH_CODE).run("usr_eve", "eve", "eve@example.com", "hash", 0, id);
136 assert.equal(db.prepare("SELECT count(*) AS n FROM users WHERE id = 'usr_eve'").get().n, 0);
137 assert.equal(db.prepare("SELECT redeemed_by FROM invites WHERE id = ?").get(id).redeemed_by, "usr_ada");
138 // Without the proof the address waits to be confirmed like any other.
139 const other = invite(db, "usr_bo", "dee@example.com");
140 db.prepare(SQL.SPEND_CODE).run("usr_dee", other);
141 db.prepare(SQL.INSERT_USER_WITH_CODE).run("usr_dee", "dee", "dee@example.com", "hash", 0, other);
142 assert.equal(db.prepare("SELECT email_verified_at FROM users WHERE id = 'usr_dee'").get().email_verified_at, null);
143});

This file's history is long; its oldest lines are credited to the oldest commit read.