flagon-io/g1t

public

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/apps/status/src/subscribers.test.ts

105 lines6,176 bytesCodeBlame
1import assert from "node:assert/strict";
2import { test } from "node:test";
3
4import { alertLetter, bindingSender, confirmLetter, memorySender, render, unsubscribeHeaders, updateLetter } from "./email.ts";
5import { atom, feedItems, jsonFeed } from "./feed.ts";
6import { chosenParts, hashToken, newToken, normalizeEmail, parseParts, readUnsubscribeToken, unsubscribeToken, wants } from "./subscribers.ts";
7
8test("addresses are trimmed, lowercased and checked", () => {
9 assert.equal(normalizeEmail(" Ana@Example.COM "), "ana@example.com");
10 assert.equal(normalizeEmail("nope"), null);
11 assert.equal(normalizeEmail("a@b"), null);
12 assert.equal(normalizeEmail("a b@example.com"), null);
13 assert.equal(normalizeEmail(42), null);
14});
15
16test("confirmation tokens: random, and only their hash is kept", async () => {
17 const a = newToken();
18 assert.match(a, /^[A-Za-z0-9_-]{43}$/);
19 assert.notEqual(newToken(), a);
20 const hash = await hashToken(a);
21 assert.match(hash, /^[0-9a-f]{64}$/);
22 assert.equal(await hashToken(a), hash, "the same token hashes the same");
23 assert.ok(!hash.includes(a));
24});
25
26test("unsubscribe links are signed, not stored, and refuse tampering", async () => {
27 const token = await unsubscribeToken("secret", "sub-1");
28 assert.ok(token.startsWith("sub-1."));
29 assert.equal(await readUnsubscribeToken("secret", token), "sub-1");
30 assert.equal(await readUnsubscribeToken("other", token), null, "another secret");
31 assert.equal(await readUnsubscribeToken("secret", token.replace("sub-1", "sub-2")), null, "another subscriber");
32 assert.equal(await readUnsubscribeToken("secret", `${token}x`), null);
33 assert.equal(await readUnsubscribeToken("secret", "garbage"), null);
34});
35
36test("per-part subscriptions", () => {
37 assert.equal(chosenParts([], ["git", "api"]), null, "none chosen is everything");
38 assert.equal(chosenParts(["git", "api"], ["git", "api"]), null, "all chosen is everything");
39 assert.deepEqual(chosenParts(["git", "git", "zzz"], ["git", "api"]), ["git"]);
40 assert.equal(parseParts(null), null);
41 assert.deepEqual(parseParts('["git"]'), ["git"]);
42 assert.equal(parseParts("not json"), null);
43 assert.equal(wants(null, ["api"]), true);
44 assert.equal(wants(["git"], ["api"]), false);
45 assert.equal(wants(["git"], ["api", "git"]), true);
46 assert.equal(wants(["git"], []), true, "news about no part in particular goes to everyone");
47});
48
49test("letters: escaped HTML, plain text, and an unsubscribe link in every update", () => {
50 const { text, html } = render(updateLetter({ heading: "Identified: <Pushes>", text: "A bad deploy.", url: "https://status.g1t.sh/incidents/a", affects: ["Git"], unsubscribe: "https://status.g1t.sh/unsubscribe?token=x" }));
51 assert.ok(html.includes("Identified: &lt;Pushes&gt;") && !html.includes("<Pushes>"));
52 assert.ok(text.includes("Unsubscribe: https://status.g1t.sh/unsubscribe?token=x"));
53 assert.ok(text.includes("Affects: Git."));
54 assert.equal(unsubscribeHeaders("https://u")["List-Unsubscribe-Post"], "List-Unsubscribe=One-Click");
55 assert.ok(render(confirmLetter("https://c", ["Git"])).text.includes("affecting Git"));
56 assert.ok(render(alertLetter({ title: "Detected: API not answering", lines: ["API has not answered on 3 checks in a row since 5 Oct 12:00 UTC."], link: "https://sudo.g1t.sh/incidents/x" })).text.includes("https://sudo.g1t.sh/incidents/x"));
57});
58
59test("senders: the binding when there is one, none otherwise", async () => {
60 assert.equal(bindingSender(undefined), null);
61 const calls: unknown[] = [];
62 const sender = bindingSender({ send: async (m) => void calls.push(m) }, "Status <s@g1t.sh>");
63 await sender!.send({ to: "a@b.co", subject: "Hi", text: "t", html: "h" });
64 assert.deepEqual(calls, [{ to: "a@b.co", from: "Status <s@g1t.sh>", subject: "Hi", text: "t", html: "h" }]);
65 const memory = memorySender();
66 await memory.send({ to: "a@b.co", subject: "Hi", text: "t", html: "h" });
67 assert.equal(memory.sent.length, 1);
68});
69
70test("feeds: every public update and maintenance notice, newest first, in Atom and JSON Feed", () => {
71 const incidents = [
72 {
73 id: "a",
74 title: "Pushes & pulls failing",
75 impact: "down" as const,
76 status: "resolved" as const,
77 components: ["git"],
78 component_impacts: [{ key: "git", impact: "major_outage" as const }],
79 started_at: "2026-10-05T11:00:00Z",
80 resolved_at: "2026-10-05T12:00:00Z",
81 url: "https://status.g1t.sh/incidents/a",
82 postmortem_published_at: null,
83 updates: [
84 { id: "u2", at: "2026-10-05T12:00:00Z", status: "resolved" as const, text: "Fixed." },
85 { id: "u1", at: "2026-10-05T11:05:00Z", status: "investigating" as const, text: "Looking <now>." },
86 ],
87 },
88 ];
89 const maintenance = [
90 { id: "m", title: "Upgrade", message: "m", components: ["git"], starts_at: "2026-10-06T02:00:00Z", ends_at: "2026-10-06T03:00:00Z", state: "scheduled" as const, url: "https://status.g1t.sh/maintenance/m", updates: [{ id: "mu", at: "2026-10-05T11:30:00Z", text: "Scheduled." }] },
91 ];
92 const items = feedItems(incidents, maintenance);
93 assert.deepEqual(items.map((i) => i.title), ["Resolved: Pushes & pulls failing", "Maintenance: Upgrade", "Investigating: Pushes & pulls failing"]);
94 assert.equal(items[0]!.url, "https://status.g1t.sh/incidents/a#update-u2");
95 const xml = atom(items, { origin: "https://status.g1t.sh", title: "g1t status", updated: "2026-10-05T13:00:00Z" });
96 assert.ok(xml.startsWith('<?xml version="1.0" encoding="utf-8"?>\n<feed xmlns="http://www.w3.org/2005/Atom">'));
97 assert.ok(xml.includes("<title>Resolved: Pushes &amp; pulls failing</title>"));
98 assert.ok(xml.includes("Looking &lt;now&gt;."));
99 assert.ok(xml.includes("<updated>2026-10-05T12:00:00Z</updated>"));
100 assert.equal((xml.match(/<entry>/g) ?? []).length, 3);
101 const json = jsonFeed(items, { origin: "https://status.g1t.sh", title: "g1t status", updated: "" }) as { version: string; items: { id: string; content_text: string }[] };
102 assert.equal(json.version, "https://jsonfeed.org/version/1.1");
103 assert.equal(json.items[2]!.content_text, "Looking <now>.");
104 assert.equal(feedItems(incidents, maintenance, 1).length, 1);
105});