Diffinery

codician/diffinerypublic

Open-source, agent-first GitHub and GitHub Actions alternative that runs on your own Cloudflare account: git hosting, pull requests, code review and drop-in GitHub Actions YAML on Workers, Durable Objects, R2 and Containers.

Extension unit tests in two files, so CI's two test shards each get one

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VQ3j7radTeNPDXuJ936W3K
Claude authored signed1 parent 313fb0ecommit 12e2ca0e6894fdca13e662b389da6c1ce522efe4Browse files
3 files changed+101−96
addedapps/vscode/test/repos.test.ts+61−0View file
@@ -1,0 +1,61 @@
1+import { describe, expect, it } from "vitest";
2+import { compareVersions, credentialInput, dedupe, matches, nextLink, repoNameFrom, repoRef, type RepoJson } from "../src/util";
3+
4+
5+const S = "https://diffinery.com";
6+const repo = (full: string, description: string | null = null): RepoJson => ({
7+ full_name: full,
8+ name: full.split("/")[1]!,
9+ owner: { login: full.split("/")[0]! },
10+ description,
11+ private: true,
12+ clone_url: `${S}/${full}.git`,
13+ html_url: `${S}/${full}`,
14+});
15+
16+describe("repositories", () => {
17+ it("reads owner/repo from names and URLs on this server only", () => {
18+ expect(repoRef(S, "codician/diffinery")).toEqual({ owner: "codician", repo: "diffinery" });
19+ expect(repoRef(S, "https://diffinery.com/codician/diffinery.git")).toEqual({ owner: "codician", repo: "diffinery" });
20+ expect(repoRef(S, "https://diffinery.com/codician/diffinery/tree/main/src")).toEqual({ owner: "codician", repo: "diffinery" });
21+ expect(repoRef(S, "https://github.com/codician/diffinery")).toBeNull();
22+ expect(repoRef(S, "diffinery")).toBeNull();
23+ expect(repoRef(S, "a/b/c")).toBeNull();
24+ expect(repoRef(S, "a b/c")).toBeNull();
25+ expect(repoRef("http://localhost:8787", "http://localhost:8787/ada/x.git")).toEqual({ owner: "ada", repo: "x" });
26+ });
27+
28+ it("matches every word, merges without duplicates", () => {
29+ const a = repo("codician/diffinery", "A git forge for agents");
30+ const b = repo("codician/tactfolio", "Backtesting");
31+ expect(matches(a, "forge DIFF")).toBe(true);
32+ expect(matches(b, "forge")).toBe(false);
33+ expect(dedupe([a], [b, repo("Codician/Diffinery")]).map((r) => r.full_name)).toEqual(["codician/diffinery", "codician/tactfolio"]);
34+ });
35+
36+ it("follows Link headers", () => {
37+ expect(nextLink('<https://diffinery.com/api/v3/user/repos?page=2>; rel="next", <https://diffinery.com/api/v3/user/repos?page=5>; rel="last"')).toBe("https://diffinery.com/api/v3/user/repos?page=2");
38+ expect(nextLink('<https://x/?page=1>; rel="prev"')).toBeNull();
39+ expect(nextLink(null)).toBeNull();
40+ });
41+
42+ it("names a repository after a folder", () => {
43+ expect(repoNameFrom("My Project (old)")).toBe("My-Project-old");
44+ expect(repoNameFrom("...")).toBe("repository");
45+ });
46+});
47+
48+describe("updates and Git", () => {
49+ it("compares versions", () => {
50+ expect(compareVersions("0.2.0", "0.1.9")).toBe(1);
51+ expect(compareVersions("0.1.0", "0.1.0")).toBe(0);
52+ expect(compareVersions("0.1.0", "0.1.10")).toBe(-1);
53+ expect(compareVersions("1.0.0-beta", "1.0.0")).toBe(-1);
54+ });
55+
56+ it("writes what git credential approve reads", () => {
57+ expect(credentialInput(S, "ada", "dfy_x", 1_800_000_000_500)).toBe("protocol=https\nhost=diffinery.com\nusername=ada\npassword=dfy_x\npassword_expiry_utc=1800000000\n\n");
58+ expect(credentialInput("http://localhost:8787", "ada", "t")).toBe("protocol=http\nhost=localhost:8787\nusername=ada\npassword=t\n\n");
59+ expect(() => credentialInput(S, "ada\nhost=evil", "t")).toThrow();
60+ });
61+});
addedapps/vscode/test/signin.test.ts+40−0View file
@@ -1,0 +1,40 @@
1+import { createHash } from "node:crypto";
2+import { describe, expect, it } from "vitest";
3+import { authorizeUrl, clientId, editorRedirect, normalizeServer, pkce, readCallback } from "../src/util";
4+
5+const S = "https://diffinery.com";
6+
7+describe("server and OAuth", () => {
8+ it("normalizes the server setting", () => {
9+ expect(normalizeServer(undefined)).toBe(S);
10+ expect(normalizeServer(" https://diffinery.com/ ")).toBe(S);
11+ expect(normalizeServer("diffinery.example.org")).toBe("https://diffinery.example.org");
12+ expect(normalizeServer("http://localhost:8787")).toBe("http://localhost:8787");
13+ expect(() => normalizeServer("http://diffinery.com")).toThrow(/https/);
14+ expect(() => normalizeServer("https://")).toThrow(/valid URL/);
15+ });
16+
17+ it("returns to the editor by its own scheme when the server knows it", () => {
18+ expect(editorRedirect("vscode")).toBe("vscode://codician.diffinery/oauth");
19+ expect(editorRedirect("cursor")).toBe("cursor://codician.diffinery/oauth");
20+ expect(editorRedirect("some-fork")).toBeNull();
21+ expect(clientId(S)).toBe("https://diffinery.com/oauth/clients/editor.json");
22+ });
23+
24+ it("makes a PKCE pair and an authorization URL", () => {
25+ const p = pkce();
26+ expect(p.challenge).toBe(createHash("sha256").update(p.verifier).digest("base64url"));
27+ const u = new URL(authorizeUrl(S, "cursor://codician.diffinery/oauth", p.challenge, p.state));
28+ expect(u.origin + u.pathname).toBe(`${S}/oauth/authorize`);
29+ expect(Object.fromEntries(u.searchParams)).toEqual({ response_type: "code", client_id: clientId(S), redirect_uri: "cursor://codician.diffinery/oauth", code_challenge: p.challenge, code_challenge_method: "S256", state: p.state, scope: "write" });
30+ });
31+
32+ it("accepts only the callback of this sign-in, from this server", () => {
33+ const expect_ = { state: "st", server: S };
34+ expect(readCallback(`code=dfa_1&state=st&iss=${encodeURIComponent(S)}`, expect_)).toEqual({ code: "dfa_1" });
35+ expect(readCallback("code=dfa_1&state=other", expect_)).toHaveProperty("error");
36+ expect(readCallback("code=dfa_1&state=st&iss=https%3A%2F%2Fevil.example", expect_)).toEqual({ error: expect.stringMatching(/evil\.example/) });
37+ expect(readCallback("error=access_denied&state=st", expect_)).toEqual({ error: "Sign-in was cancelled in the browser." });
38+ expect(readCallback("state=st", expect_)).toHaveProperty("error");
39+ });
40+});
deletedapps/vscode/test/util.test.ts+0−96
@@ -1,96 +1,0 @@
1-import { createHash } from "node:crypto";
2-import { describe, expect, it } from "vitest";
3-import { authorizeUrl, clientId, compareVersions, credentialInput, dedupe, editorRedirect, matches, nextLink, normalizeServer, pkce, readCallback, repoNameFrom, repoRef, type RepoJson } from "../src/util";
4-
5-const S = "https://diffinery.com";
6-const repo = (full: string, description: string | null = null): RepoJson => ({
7- full_name: full,
8- name: full.split("/")[1]!,
9- owner: { login: full.split("/")[0]! },
10- description,
11- private: true,
12- clone_url: `${S}/${full}.git`,
13- html_url: `${S}/${full}`,
14-});
15-
16-describe("server and OAuth", () => {
17- it("normalizes the server setting", () => {
18- expect(normalizeServer(undefined)).toBe(S);
19- expect(normalizeServer(" https://diffinery.com/ ")).toBe(S);
20- expect(normalizeServer("diffinery.example.org")).toBe("https://diffinery.example.org");
21- expect(normalizeServer("http://localhost:8787")).toBe("http://localhost:8787");
22- expect(() => normalizeServer("http://diffinery.com")).toThrow(/https/);
23- expect(() => normalizeServer("https://")).toThrow(/valid URL/);
24- });
25-
26- it("returns to the editor by its own scheme when the server knows it", () => {
27- expect(editorRedirect("vscode")).toBe("vscode://codician.diffinery/oauth");
28- expect(editorRedirect("cursor")).toBe("cursor://codician.diffinery/oauth");
29- expect(editorRedirect("some-fork")).toBeNull();
30- expect(clientId(S)).toBe("https://diffinery.com/oauth/clients/editor.json");
31- });
32-
33- it("makes a PKCE pair and an authorization URL", () => {
34- const p = pkce();
35- expect(p.challenge).toBe(createHash("sha256").update(p.verifier).digest("base64url"));
36- const u = new URL(authorizeUrl(S, "cursor://codician.diffinery/oauth", p.challenge, p.state));
37- expect(u.origin + u.pathname).toBe(`${S}/oauth/authorize`);
38- expect(Object.fromEntries(u.searchParams)).toEqual({ response_type: "code", client_id: clientId(S), redirect_uri: "cursor://codician.diffinery/oauth", code_challenge: p.challenge, code_challenge_method: "S256", state: p.state, scope: "write" });
39- });
40-
41- it("accepts only the callback of this sign-in, from this server", () => {
42- const expect_ = { state: "st", server: S };
43- expect(readCallback(`code=dfa_1&state=st&iss=${encodeURIComponent(S)}`, expect_)).toEqual({ code: "dfa_1" });
44- expect(readCallback("code=dfa_1&state=other", expect_)).toHaveProperty("error");
45- expect(readCallback("code=dfa_1&state=st&iss=https%3A%2F%2Fevil.example", expect_)).toEqual({ error: expect.stringMatching(/evil\.example/) });
46- expect(readCallback("error=access_denied&state=st", expect_)).toEqual({ error: "Sign-in was cancelled in the browser." });
47- expect(readCallback("state=st", expect_)).toHaveProperty("error");
48- });
49-});
50-
51-describe("repositories", () => {
52- it("reads owner/repo from names and URLs on this server only", () => {
53- expect(repoRef(S, "codician/diffinery")).toEqual({ owner: "codician", repo: "diffinery" });
54- expect(repoRef(S, "https://diffinery.com/codician/diffinery.git")).toEqual({ owner: "codician", repo: "diffinery" });
55- expect(repoRef(S, "https://diffinery.com/codician/diffinery/tree/main/src")).toEqual({ owner: "codician", repo: "diffinery" });
56- expect(repoRef(S, "https://github.com/codician/diffinery")).toBeNull();
57- expect(repoRef(S, "diffinery")).toBeNull();
58- expect(repoRef(S, "a/b/c")).toBeNull();
59- expect(repoRef(S, "a b/c")).toBeNull();
60- expect(repoRef("http://localhost:8787", "http://localhost:8787/ada/x.git")).toEqual({ owner: "ada", repo: "x" });
61- });
62-
63- it("matches every word, merges without duplicates", () => {
64- const a = repo("codician/diffinery", "A git forge for agents");
65- const b = repo("codician/tactfolio", "Backtesting");
66- expect(matches(a, "forge DIFF")).toBe(true);
67- expect(matches(b, "forge")).toBe(false);
68- expect(dedupe([a], [b, repo("Codician/Diffinery")]).map((r) => r.full_name)).toEqual(["codician/diffinery", "codician/tactfolio"]);
69- });
70-
71- it("follows Link headers", () => {
72- expect(nextLink('<https://diffinery.com/api/v3/user/repos?page=2>; rel="next", <https://diffinery.com/api/v3/user/repos?page=5>; rel="last"')).toBe("https://diffinery.com/api/v3/user/repos?page=2");
73- expect(nextLink('<https://x/?page=1>; rel="prev"')).toBeNull();
74- expect(nextLink(null)).toBeNull();
75- });
76-
77- it("names a repository after a folder", () => {
78- expect(repoNameFrom("My Project (old)")).toBe("My-Project-old");
79- expect(repoNameFrom("...")).toBe("repository");
80- });
81-});
82-
83-describe("updates and Git", () => {
84- it("compares versions", () => {
85- expect(compareVersions("0.2.0", "0.1.9")).toBe(1);
86- expect(compareVersions("0.1.0", "0.1.0")).toBe(0);
87- expect(compareVersions("0.1.0", "0.1.10")).toBe(-1);
88- expect(compareVersions("1.0.0-beta", "1.0.0")).toBe(-1);
89- });
90-
91- it("writes what git credential approve reads", () => {
92- expect(credentialInput(S, "ada", "dfy_x", 1_800_000_000_500)).toBe("protocol=https\nhost=diffinery.com\nusername=ada\npassword=dfy_x\npassword_expiry_utc=1800000000\n\n");
93- expect(credentialInput("http://localhost:8787", "ada", "t")).toBe("protocol=http\nhost=localhost:8787\nusername=ada\npassword=t\n\n");
94- expect(() => credentialInput(S, "ada\nhost=evil", "t")).toThrow();
95- });
96-});