119 lines
5.2 KiB
TypeScript
119 lines
5.2 KiB
TypeScript
import { afterEach, describe, expect, test } from "bun:test";
|
|
import { mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
import { join } from "node:path";
|
|
import { resolveToken, type GitHubYamlAuthConfig } from "./gh/auth-and-safety";
|
|
import { resolvePositionalIssueReference, resolvePositionalPrReference } from "./gh/refs";
|
|
import type { GitHubOptions, GitHubResolvedNumberReference } from "./gh/types";
|
|
|
|
const originalGhToken = process.env.GH_TOKEN;
|
|
const originalGithubToken = process.env.GITHUB_TOKEN;
|
|
const temporaryRoots: string[] = [];
|
|
|
|
afterEach(() => {
|
|
if (originalGhToken === undefined) delete process.env.GH_TOKEN;
|
|
else process.env.GH_TOKEN = originalGhToken;
|
|
if (originalGithubToken === undefined) delete process.env.GITHUB_TOKEN;
|
|
else process.env.GITHUB_TOKEN = originalGithubToken;
|
|
while (temporaryRoots.length > 0) rmSync(temporaryRoots.pop()!, { recursive: true, force: true });
|
|
});
|
|
|
|
function testAuthConfig(): GitHubYamlAuthConfig {
|
|
const root = mkdtempSync("/tmp/unidesk-gh-token-override-");
|
|
temporaryRoots.push(root);
|
|
writeFileSync(join(root, "global-token.txt"), "global-token\n");
|
|
writeFileSync(join(root, "selfmedia-token.txt"), "selfmedia-token\n");
|
|
return {
|
|
tokenSource: {
|
|
enabled: true,
|
|
priority: "before-env",
|
|
root,
|
|
sourceRef: "global-token.txt",
|
|
sourceKey: "GH_TOKEN",
|
|
format: "raw-token",
|
|
scope: "global",
|
|
configRef: "test#github.auth.tokenSource",
|
|
},
|
|
repositoryOverrides: [{
|
|
repository: "pikainc/selfmedia",
|
|
priority: "before-env",
|
|
root,
|
|
sourceRef: "selfmedia-token.txt",
|
|
sourceKey: "GH_TOKEN",
|
|
format: "raw-token",
|
|
scope: "repository-override",
|
|
configRef: "test#github.auth.repositoryOverrides[0]",
|
|
}],
|
|
};
|
|
}
|
|
|
|
function options(repo: string): GitHubOptions {
|
|
return { repo } as GitHubOptions;
|
|
}
|
|
|
|
function resolvedRepo(value: GitHubResolvedNumberReference | { ok: boolean }): string {
|
|
if (!("number" in value)) throw new Error("expected a resolved positional reference");
|
|
return value.repo;
|
|
}
|
|
|
|
describe("GitHub repository token overrides", () => {
|
|
test("selects the exact repository override without affecting global repositories", () => {
|
|
delete process.env.GH_TOKEN;
|
|
delete process.env.GITHUB_TOKEN;
|
|
const authConfig = testAuthConfig();
|
|
|
|
const selfmedia = resolveToken("pikainc/selfmedia", false, authConfig);
|
|
const unidesk = resolveToken("pikasTech/unidesk", false, authConfig);
|
|
const other = resolveToken("owner/other", false, authConfig);
|
|
|
|
expect(selfmedia.token).toBe("selfmedia-token");
|
|
expect(selfmedia.probe).toMatchObject({ scope: "repository-override", sourceRef: "selfmedia-token.txt", sourceKey: "GH_TOKEN", valuesPrinted: false });
|
|
expect(unidesk.token).toBe("global-token");
|
|
expect(other.token).toBe("global-token");
|
|
expect(unidesk.probe).toMatchObject({ scope: "global", sourceRef: "global-token.txt", valuesPrinted: false });
|
|
expect(other.probe).toMatchObject({ scope: "global", sourceRef: "global-token.txt", valuesPrinted: false });
|
|
expect(selfmedia.probe.tokenFingerprint).not.toBe(unidesk.probe.tokenFingerprint);
|
|
});
|
|
|
|
test("keeps before-env repository overrides ahead of global environment tokens", () => {
|
|
process.env.GH_TOKEN = "environment-token";
|
|
process.env.GITHUB_TOKEN = "secondary-environment-token";
|
|
|
|
const selected = resolveToken("pikainc/selfmedia", false, testAuthConfig());
|
|
|
|
expect(selected.token).toBe("selfmedia-token");
|
|
expect(selected.probe).toMatchObject({ source: "yaml-token-source", scope: "repository-override", yamlSourcePriority: "before-env" });
|
|
});
|
|
|
|
test("matches repository overrides without case sensitivity", () => {
|
|
delete process.env.GH_TOKEN;
|
|
delete process.env.GITHUB_TOKEN;
|
|
const authConfig = testAuthConfig();
|
|
|
|
for (const repo of ["PikaInc/selfmedia", "pikainc/SELFMEDIA", "PIKAINC/SELFMEDIA"]) {
|
|
const selected = resolveToken(repo, false, authConfig);
|
|
expect(selected.token).toBe("selfmedia-token");
|
|
expect(selected.probe).toMatchObject({ scope: "repository-override", sourceRef: "selfmedia-token.txt", valuesPrinted: false });
|
|
}
|
|
|
|
const global = resolveToken("PikasTech/UniDesk", false, authConfig);
|
|
expect(global.token).toBe("global-token");
|
|
expect(global.probe).toMatchObject({ scope: "global", sourceRef: "global-token.txt", valuesPrinted: false });
|
|
});
|
|
|
|
test("uses the final positional repository for issue and PR token selection", () => {
|
|
delete process.env.GH_TOKEN;
|
|
delete process.env.GITHUB_TOKEN;
|
|
const authConfig = testAuthConfig();
|
|
const issueRef = resolvePositionalIssueReference(["issue", "edit", "pikainc/selfmedia#12"], 2, "issue edit", options("pikasTech/unidesk"));
|
|
const prRef = resolvePositionalPrReference(["pr", "comment", "pikainc/selfmedia#34"], 2, "pr comment", options("pikasTech/unidesk"));
|
|
|
|
const issueToken = resolveToken(resolvedRepo(issueRef), false, authConfig);
|
|
const prToken = resolveToken(resolvedRepo(prRef), false, authConfig);
|
|
const defaultToken = resolveToken("pikasTech/unidesk", false, authConfig);
|
|
|
|
expect(issueToken.token).toBe("selfmedia-token");
|
|
expect(prToken.token).toBe("selfmedia-token");
|
|
expect(defaultToken.token).toBe("global-token");
|
|
});
|
|
});
|