Skip to content

g1t/services/runner/src/bump.test.ts

159 lines8,401 bytesCodeBlame

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.

Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily1import assert from "node:assert/strict";
2import { test } from "node:test";
3
4import type { BumpArgs } from "@g1t/contracts";
5
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar6import { bumpEnv, bumpProblem, bumpSandboxName, isBranchName, isSystem, registryHosts, systemActor } from "./bump.ts";
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily7import { buildHosts } from "./egress.ts";
8
9const PREFIX = "g1t/security/";
10
11const args: BumpArgs = {
12 repo: { namespace: "Acme", name: "site" },
13 ecosystem: "npm",
14 package: "@babel/traverse",
15 version: "7.23.2",
16 lockfiles: ["package-lock.json", "web/package-lock.json"],
17 branch: "g1t/security/babel-traverse-7.23.2",
18 message: "Update @babel/traverse to 7.23.2",
19};
20
21test("a well-formed update can start", () => {
22 assert.equal(bumpProblem(args, PREFIX), null);
23 for (const ecosystem of ["crates.io", "Go", "PyPI"]) {
24 assert.equal(bumpProblem({ ...args, ecosystem }, PREFIX), null, ecosystem);
25 }
26});
27
28test("the branch must be a security update's", () => {
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar29 for (const branch of ["main", "g1t/security/", "feature/g1t/security/x", "g1t/security/a..b", "g1t/security/a b", "g1t/security/a:b", "g1t/security/x.lock"]) {
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily30 assert.match(bumpProblem({ ...args, branch }, PREFIX) ?? "", /starts with g1t\/security\//, branch);
31 }
32});
33
34test("names, versions and lockfiles are checked before anything starts", () => {
35 assert.match(bumpProblem({ ...args, ecosystem: "RubyGems" }, PREFIX) ?? "", /cannot update RubyGems/);
36 assert.match(bumpProblem({ ...args, package: "--registry=evil" }, PREFIX) ?? "", /package's name/);
37 assert.match(bumpProblem({ ...args, version: "1.0; rm -rf /" }, PREFIX) ?? "", /version/);
38 assert.match(bumpProblem({ ...args, lockfiles: [] }, PREFIX) ?? "", /between 1 and/);
39 assert.match(bumpProblem({ ...args, lockfiles: ["../Cargo.lock"] }, PREFIX) ?? "", /not a path inside/);
40 assert.match(bumpProblem({ ...args, lockfiles: ["/etc/Cargo.lock"] }, PREFIX) ?? "", /not a path inside/);
41 assert.match(bumpProblem({ ...args, repo: { namespace: "", name: "site" } }, PREFIX) ?? "", /repository/);
42 assert.match(bumpProblem(null, PREFIX) ?? "", /arguments/);
43});
44
45test("g1t acts as itself, a member of the workspace", () => {
46 const actor = systemActor("Acme");
47 assert.deepEqual(actor, { id: "g1t", username: "g1t", kind: "system", verified: true, workspaces: [{ slug: "acme", role: "member" }] });
48 assert.equal(isSystem(actor), true);
49 assert.equal(isSystem({ id: "usr_1", username: "ada" }), false);
50 assert.equal(isSystem(null), false);
51});
52
53test("the sandbox is given what bump mode reads", () => {
54 const env = bumpEnv(args, "main", "g1t_token");
55 assert.deepEqual(env, {
56 MODE: "bump",
57 G1T_USER: "acme",
58 G1T_TOKEN: "g1t_token",
59 GIT_REMOTE: "https://g1t.sh/Acme/site.git",
60 GIT_BRANCH_BASE: "main",
61 GIT_BRANCH: "g1t/security/babel-traverse-7.23.2",
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar62 BUMP_KIND: "security",
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily63 BUMP_ECOSYSTEM: "npm",
64 BUMP_PACKAGE: "@babel/traverse",
65 BUMP_VERSION: "7.23.2",
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar66 BUMP_PACKAGES: '[{"package":"@babel/traverse","version":"7.23.2"}]',
67 BUMP_STRATEGY: "increase",
68 BUMP_FORCE: "0",
69 BUMP_REGISTRIES: "[]",
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily70 BUMP_LOCKFILES: '["package-lock.json","web/package-lock.json"]',
71 COMMIT_MESSAGE: "Update @babel/traverse to 7.23.2",
72 });
73 assert.equal(bumpEnv({ ...args, message: " " }, "main", "t").COMMIT_MESSAGE, "Update @babel/traverse to 7.23.2");
74 assert.equal(bumpSandboxName(args), "bump:acme/site:g1t/security/babel-traverse-7.23.2");
75});
76
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar77const update: BumpArgs = {
78 ...args,
79 kind: "version",
80 package: "lodash",
81 version: "4.17.21",
82 packages: [
83 { package: "lodash", version: "4.17.21" },
84 { package: " vitest ", version: "1.6.0" },
85 ],
86 branch: "deps/npm/lodash",
87 message: "Bump lodash and vitest",
88 strategy: "widen",
89 force: true,
90 registries: [{ type: "npm-registry", url: "https://npm.acme.dev/", token: "s3cret", scopes: ["@acme"] }],
91};
92
93test("a version update names any branch git takes", () => {
94 assert.equal(bumpProblem(update, PREFIX), null);
95 for (const branch of ["main", "dependabot/npm/lodash-4.17.21", "deps"]) {
96 assert.equal(bumpProblem({ ...update, branch }, PREFIX), null, branch);
97 }
98 for (const branch of ["", "a b", "a..b", "a~1", "a^", "a:b", "a?", "a*", "a[b", "a\\b", "a@{1}", "-x", "/x", "refs/heads/x", "x/", "x.lock", "x".repeat(201)]) {
99 assert.match(bumpProblem({ ...update, branch }, PREFIX) ?? "", /not a branch name/, branch);
100 }
101 assert.equal(isBranchName("deps/npm/lodash"), true);
102 assert.equal(isBranchName(undefined), false);
103});
104
105test("a version update's packages, strategy and registries are checked", () => {
106 assert.match(bumpProblem({ ...update, kind: "major" as "version" }, PREFIX) ?? "", /cannot make a major update/);
107 assert.match(bumpProblem({ ...update, package: "" }, PREFIX) ?? "", /A version update needs the package's name/);
108 assert.match(bumpProblem({ ...update, packages: [{ package: "--evil", version: "1" }] }, PREFIX) ?? "", /each package's name/);
109 assert.match(bumpProblem({ ...update, packages: [{ package: "lodash", version: "1 2" }] }, PREFIX) ?? "", /raise lodash to/);
110 const many = Array.from({ length: 51 }, (_, i) => ({ package: `p${i}`, version: "1.0.0" }));
111 assert.match(bumpProblem({ ...update, packages: many }, PREFIX) ?? "", /at most 50 packages/);
112 for (const strategy of ["increase", "increase-if-necessary", "widen", "lockfile-only"]) {
113 assert.equal(bumpProblem({ ...update, strategy }, PREFIX), null, strategy);
114 }
115 assert.match(bumpProblem({ ...update, strategy: "auto" }, PREFIX) ?? "", /not a versioning strategy/);
116 const registry = update.registries![0]!;
117 assert.match(bumpProblem({ ...update, registries: [{ ...registry, type: "maven-repository" }] }, PREFIX) ?? "", /cannot read a maven-repository registry/);
118 for (const url of ["http://npm.acme.dev", "npm.acme.dev", "https://", "https:// x"]) {
119 assert.match(bumpProblem({ ...update, registries: [{ ...registry, url }] }, PREFIX) ?? "", /starts with https/, url);
120 }
121 assert.match(bumpProblem({ ...update, registries: [{ ...registry, token: "x".repeat(2001) }] }, PREFIX) ?? "", /credentials/);
122 assert.match(bumpProblem({ ...update, registries: [{ ...registry, scopes: ["acme"] }] }, PREFIX) ?? "", /not an npm scope/);
123 assert.match(bumpProblem({ ...update, registries: Array.from({ length: 21 }, () => registry) }, PREFIX) ?? "", /at most 20 private registries/);
124 for (const type of ["cargo-registry", "python-index", "goproxy-server"]) {
125 assert.equal(bumpProblem({ ...update, registries: [{ type, url: "https://r.acme.dev/x", username: "u", password: "p", replacesBase: true }] }, PREFIX), null, type);
126 }
127});
128
129test("a version update's sandbox is told what to raise, how and from where", () => {
130 const env = bumpEnv(update, "main", "t");
131 assert.equal(env.BUMP_KIND, "version");
132 assert.equal(env.GIT_BRANCH, "deps/npm/lodash");
133 assert.equal(env.BUMP_PACKAGE, "lodash");
134 assert.equal(env.BUMP_VERSION, "4.17.21");
135 assert.equal(env.BUMP_PACKAGES, '[{"package":"lodash","version":"4.17.21"},{"package":"vitest","version":"1.6.0"}]');
136 assert.equal(env.BUMP_STRATEGY, "widen");
137 assert.equal(env.BUMP_FORCE, "1");
138 assert.deepEqual(JSON.parse(env.BUMP_REGISTRIES!), update.registries);
139 assert.equal(env.COMMIT_MESSAGE, "Bump lodash and vitest");
140 assert.equal(bumpEnv({ ...update, message: "" }, "main", "t").COMMIT_MESSAGE, "Update lodash and 1 more");
141 const one = bumpEnv({ ...update, packages: [], strategy: undefined, force: undefined, registries: undefined }, "main", "t");
142 assert.equal(one.BUMP_PACKAGES, '[{"package":"lodash","version":"4.17.21"}]');
143 assert.equal(one.BUMP_STRATEGY, "increase");
144 assert.equal(one.BUMP_FORCE, "0");
145 assert.equal(one.BUMP_REGISTRIES, "[]");
146});
147
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily148test("a security update reaches the package registries and nothing else builds get", () => {
149 const hosts = buildHosts("bump");
150 for (const host of ["registry.npmjs.org", "repo.yarnpkg.com", "index.crates.io", "static.crates.io", "proxy.golang.org", "sum.golang.org", "pypi.org", "files.pythonhosted.org"]) {
151 assert.ok(hosts.includes(host), host);
152 }
153 for (const host of ["github.com", "api.cloudflare.com", "ghcr.io"]) assert.ok(!hosts.includes(host), host);
154});
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar155
156test("an update's private registries are reachable from its sandbox", () => {
157 assert.deepEqual(registryHosts(update), [...new Set((update.registries ?? []).map((registry) => new URL(registry.url).host))]);
158 assert.deepEqual(registryHosts(args), []);
159});