diff --git a/review-enrichment/src/analyzers/approval-integrity.ts b/review-enrichment/src/analyzers/approval-integrity.ts index af3837c308..a95054e9f2 100644 --- a/review-enrichment/src/analyzers/approval-integrity.ts +++ b/review-enrichment/src/analyzers/approval-integrity.ts @@ -14,6 +14,7 @@ import type { } from "../types.js"; import type { AnalysisContext } from "../analysis-context.js"; import { boundedFetchJson } from "../external-fetch.js"; +import { githubHeaders } from "../github-headers.js"; const GITHUB_API = "https://api.github.com"; const SLUG_RE = /^[A-Za-z0-9._-]+$/; @@ -46,14 +47,6 @@ interface LatestReview { submittedAt: string; } -function githubHeaders(token: string): Record { - return { - Authorization: `Bearer ${token}`, - Accept: "application/vnd.github+json", - "X-GitHub-Api-Version": "2022-11-28", - }; -} - async function fetchReviewsPage( owner: string, repo: string, diff --git a/review-enrichment/src/analyzers/asset-weight.ts b/review-enrichment/src/analyzers/asset-weight.ts index fd9a136606..dc95b06212 100644 --- a/review-enrichment/src/analyzers/asset-weight.ts +++ b/review-enrichment/src/analyzers/asset-weight.ts @@ -12,13 +12,13 @@ import type { } from "../types.js"; import type { AnalysisContext } from "../analysis-context.js"; import { boundedFetchJson } from "../external-fetch.js"; +import { githubHeaders } from "../github-headers.js"; import { isBinaryFileExtension } from "./binary-extensions.js"; const MAX_FINDINGS = 50; // keep the brief bounded after evaluating every changed binary candidate const MAX_PATH_SIZE_LOOKUPS = 50; // fallback Contents API calls when a recursive tree is truncated const THRESHOLD_BYTES = 100 * 1024; // flag a newly-added blob >= 100 KB, or growth >= 100 KB const GITHUB_API = "https://api.github.com"; -const GITHUB_API_VERSION = "2022-11-28"; interface ScanOptions { signal?: AbortSignal; @@ -48,15 +48,6 @@ export function basePathForGrowth(file: EnrichFile): string | null { return null; } -function githubHeaders(token: string): Record { - return { - Authorization: `Bearer ${token}`, - Accept: "application/vnd.github+json", - "X-GitHub-Api-Version": GITHUB_API_VERSION, - "User-Agent": "gittensory-review-enrichment", - }; -} - /** Percent-encode each segment of a repo path for a Contents API URL, rejecting (null) an empty path or any * empty / `.` / `..` segment so a crafted path can never traverse out of the tree. Pure. */ export function encodeRepoPath(path: string): string | null { diff --git a/review-enrichment/src/analyzers/blame-link.ts b/review-enrichment/src/analyzers/blame-link.ts index a47c17604b..a373513779 100644 --- a/review-enrichment/src/analyzers/blame-link.ts +++ b/review-enrichment/src/analyzers/blame-link.ts @@ -12,6 +12,7 @@ import type { } from "../types.js"; import type { AnalysisContext } from "../analysis-context.js"; import { boundedFetchJson } from "../external-fetch.js"; +import { githubHeaders } from "../github-headers.js"; import { isHistoryUninformativePath } from "./history-path.js"; const GITHUB_API = "https://api.github.com"; @@ -62,14 +63,6 @@ export function firstTouchedOldLine(patch: string): number | null { return null; } -function githubHeaders(token: string): Record { - return { - Authorization: `Bearer ${token}`, - Accept: "application/vnd.github+json", - "X-GitHub-Api-Version": "2022-11-28", - }; -} - async function fetchGithubJson( url: string, headers: Record, diff --git a/review-enrichment/src/analyzers/caller-impact.ts b/review-enrichment/src/analyzers/caller-impact.ts index 64f1da9400..d25617668f 100644 --- a/review-enrichment/src/analyzers/caller-impact.ts +++ b/review-enrichment/src/analyzers/caller-impact.ts @@ -27,12 +27,12 @@ import type { } from "../types.js"; import type { AnalysisContext } from "../analysis-context.js"; import { boundedFetchJson } from "../external-fetch.js"; +import { githubHeaders } from "../github-headers.js"; import { exportedNames, isPublicEntrypoint } from "./api-break.js"; import { isTestPath } from "./test-ratio.js"; import { DEFAULT_MAX_FINDINGS } from "./limits.js"; const GITHUB_API = "https://api.github.com"; -const GITHUB_API_VERSION = "2022-11-28"; const SLUG_RE = /^[A-Za-z0-9._-]+$/; const MAX_SYMBOLS = 6; // removed symbols searched per PR (Code Search rate budget) const MAX_SEARCHES = 6; // bounded Code Search queries per PR @@ -69,15 +69,6 @@ interface RemovedExport { line: number; } -function githubHeaders(token: string, raw = false): Record { - return { - Authorization: `Bearer ${token}`, - Accept: raw ? "application/vnd.github.raw" : "application/vnd.github+json", - "X-GitHub-Api-Version": GITHUB_API_VERSION, - "User-Agent": "gittensory-review-enrichment", - }; -} - function escapeRegExp(value: string): string { return value.replace(/[$.*+?^{}()|[\]\\]/g, "\\$&"); } @@ -287,7 +278,7 @@ async function fetchFileAtHead( const encoded = path.split("/").map(encodeURIComponent).join("/"); const resp = await fetchImpl( `${GITHUB_API}/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/contents/${encoded}?ref=${encodeURIComponent(headSha)}`, - { headers: githubHeaders(token, true), signal }, + { headers: githubHeaders(token, { raw: true }), signal }, ); if (!resp.ok) return null; return await readBoundedText(resp, signal); diff --git a/review-enrichment/src/analyzers/churn-hotspot.ts b/review-enrichment/src/analyzers/churn-hotspot.ts index 37608471f1..3f05fa535b 100644 --- a/review-enrichment/src/analyzers/churn-hotspot.ts +++ b/review-enrichment/src/analyzers/churn-hotspot.ts @@ -11,6 +11,7 @@ import type { } from "../types.js"; import type { AnalysisContext } from "../analysis-context.js"; import { boundedFetchJson } from "../external-fetch.js"; +import { githubHeaders } from "../github-headers.js"; import { isHistoryUninformativePath } from "./history-path.js"; const GITHUB_API = "https://api.github.com"; @@ -57,14 +58,6 @@ export function isHotspot(summary: { commitCount: number; fixFraction: number }) return summary.commitCount >= MIN_COMMITS && summary.fixFraction >= MIN_FIX_FRACTION; } -function githubHeaders(token: string): Record { - return { - Authorization: `Bearer ${token}`, - Accept: "application/vnd.github+json", - "X-GitHub-Api-Version": "2022-11-28", - }; -} - /** Fetch one page of commits touching `path` since `since`. Returns the list, or null on any error / non-200. */ async function fetchFileCommits( url: string, diff --git a/review-enrichment/src/analyzers/commit-hygiene.ts b/review-enrichment/src/analyzers/commit-hygiene.ts index 3aae789b25..a30eb7a361 100644 --- a/review-enrichment/src/analyzers/commit-hygiene.ts +++ b/review-enrichment/src/analyzers/commit-hygiene.ts @@ -16,6 +16,7 @@ import type { } from "../types.js"; import type { AnalysisContext } from "../analysis-context.js"; import { boundedFetchJson } from "../external-fetch.js"; +import { githubHeaders } from "../github-headers.js"; import { DEFAULT_MAX_FINDINGS } from "./limits.js"; const GITHUB_API = "https://api.github.com"; @@ -43,14 +44,6 @@ interface CommitListItem { parents?: Array<{ sha?: string }>; } -function githubHeaders(token: string): Record { - return { - Authorization: `Bearer ${token}`, - Accept: "application/vnd.github+json", - "X-GitHub-Api-Version": "2022-11-28", - }; -} - async function fetchPrCommits( owner: string, repo: string, diff --git a/review-enrichment/src/analyzers/commit-lint.ts b/review-enrichment/src/analyzers/commit-lint.ts index 51c7f55cd8..19026a3cea 100644 --- a/review-enrichment/src/analyzers/commit-lint.ts +++ b/review-enrichment/src/analyzers/commit-lint.ts @@ -12,6 +12,7 @@ import type { } from "../types.js"; import type { AnalysisContext } from "../analysis-context.js"; import { boundedFetchJson } from "../external-fetch.js"; +import { githubHeaders } from "../github-headers.js"; import { DEFAULT_MAX_FINDINGS } from "./limits.js"; const GITHUB_API = "https://api.github.com"; @@ -53,14 +54,6 @@ interface CommitListItem { commit?: { message?: string }; } -function githubHeaders(token: string): Record { - return { - Authorization: `Bearer ${token}`, - Accept: "application/vnd.github+json", - "X-GitHub-Api-Version": "2022-11-28", - }; -} - async function fetchPrCommits( owner: string, repo: string, diff --git a/review-enrichment/src/analyzers/commit-signature.ts b/review-enrichment/src/analyzers/commit-signature.ts index 287ef9504c..861a57163f 100644 --- a/review-enrichment/src/analyzers/commit-signature.ts +++ b/review-enrichment/src/analyzers/commit-signature.ts @@ -11,6 +11,7 @@ import type { } from "../types.js"; import type { AnalysisContext } from "../analysis-context.js"; import { boundedFetchJson } from "../external-fetch.js"; +import { githubHeaders } from "../github-headers.js"; const GITHUB_API = "https://api.github.com"; // Pull a bounded slice of recent commits — enough to decide "has any verified history" without paging the whole @@ -41,14 +42,6 @@ interface HistoryCommit { commit?: { verification?: { verified?: boolean } }; } -function githubHeaders(token: string): Record { - return { - Authorization: `Bearer ${token}`, - Accept: "application/vnd.github+json", - "X-GitHub-Api-Version": "2022-11-28", - }; -} - async function fetchGithubJson( url: string, headers: Record, diff --git a/review-enrichment/src/analyzers/coverage-delta.ts b/review-enrichment/src/analyzers/coverage-delta.ts index 0df409a081..c577bd132b 100644 --- a/review-enrichment/src/analyzers/coverage-delta.ts +++ b/review-enrichment/src/analyzers/coverage-delta.ts @@ -15,6 +15,7 @@ import type { } from "../types.js"; import type { AnalysisContext } from "../analysis-context.js"; import { boundedFetchJson } from "../external-fetch.js"; +import { githubHeaders } from "../github-headers.js"; const GITHUB_API = "https://api.github.com"; const SLUG_RE = /^[A-Za-z0-9._-]+$/; @@ -246,14 +247,6 @@ export function pathMatches(coveragePath: string, prFile: string): boolean { return c === p || c.endsWith(`/${p}`); } -function githubHeaders(token: string): Record { - return { - Authorization: `Bearer ${token}`, - Accept: "application/vnd.github+json", - "X-GitHub-Api-Version": "2022-11-28", - }; -} - /** Fetch + parse JSON with the shared bounded-fetch guard rails; returns the parsed body or null on any * error/non-200 so the caller degrades that one lookup rather than throwing. */ async function fetchGithubJson( diff --git a/review-enrichment/src/analyzers/duplication-scan.ts b/review-enrichment/src/analyzers/duplication-scan.ts index ff2d07ebbc..55289d21d5 100644 --- a/review-enrichment/src/analyzers/duplication-scan.ts +++ b/review-enrichment/src/analyzers/duplication-scan.ts @@ -15,10 +15,10 @@ import type { } from "../types.js"; import type { AnalysisContext } from "../analysis-context.js"; import { boundedFetchJson } from "../external-fetch.js"; +import { githubHeaders } from "../github-headers.js"; import { DEFAULT_MAX_FINDINGS } from "./limits.js"; const GITHUB_API = "https://api.github.com"; -const GITHUB_API_VERSION = "2022-11-28"; const MIN_RUN = 8; // a contiguous run of >= this many significant normalized lines is required to flag a duplicate const MAX_CANDIDATES = 40; // cap candidate files (closest-by-path first) we consider per scan @@ -48,15 +48,6 @@ interface ScanOptions { diagnostics?: AnalyzerDiagnostics; } -function githubHeaders(token: string): Record { - return { - Authorization: `Bearer ${token}`, - Accept: "application/vnd.github+json", - "X-GitHub-Api-Version": GITHUB_API_VERSION, - "User-Agent": "gittensory-review-enrichment", - }; -} - /** Parse `owner/repo`, rejecting anything that isn't exactly two safe segments (no traversal, no extra slashes) so a * hostile `repoFullName` cannot redirect the token-bearing request elsewhere. Returns null when unsafe. */ function parseRepo( diff --git a/review-enrichment/src/analyzers/exhaustiveness-drift.ts b/review-enrichment/src/analyzers/exhaustiveness-drift.ts index 30195a9f3b..e04a36c018 100644 --- a/review-enrichment/src/analyzers/exhaustiveness-drift.ts +++ b/review-enrichment/src/analyzers/exhaustiveness-drift.ts @@ -4,6 +4,7 @@ // pre-PR member set, and only reports high-confidence misses (explicit enum/union cases, no default branch). Bounded // file-fetch caps; fail-safe on missing token/headSha, bad slug, or fetch errors. import type { EnrichRequest, ExhaustivenessFinding } from "../types.js"; +import { githubHeaders } from "../github-headers.js"; import { reconstructOldContent } from "./doc-comment-drift.js"; import { isDiffFileHeaderLine } from "./diff-lines.js"; import { isTestPath } from "./test-ratio.js"; @@ -45,14 +46,6 @@ function isScannablePath(path: string): boolean { return SOURCE_RE.test(path) && !SKIP_RE.test(path) && !isTestPath(path); } -function githubHeaders(token: string): Record { - return { - Authorization: `Bearer ${token}`, - Accept: "application/vnd.github.raw", - "X-GitHub-Api-Version": "2022-11-28", - }; -} - async function readBoundedText(resp: Response, signal?: AbortSignal): Promise { const length = Number(resp.headers.get("content-length")); if (Number.isFinite(length) && length > MAX_FETCH_BYTES) return null; @@ -93,7 +86,7 @@ async function fetchFileAtHead( const encoded = path.split("/").map(encodeURIComponent).join("/"); const resp = await fetchFn( `${GITHUB_API}/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/contents/${encoded}?ref=${encodeURIComponent(headSha)}`, - { headers: githubHeaders(token), signal }, + { headers: githubHeaders(token, { raw: true }), signal }, ); if (!resp.ok) return null; return await readBoundedText(resp, signal); diff --git a/review-enrichment/src/analyzers/flaky-test.ts b/review-enrichment/src/analyzers/flaky-test.ts index d1b9abf7a7..c294f32ef0 100644 --- a/review-enrichment/src/analyzers/flaky-test.ts +++ b/review-enrichment/src/analyzers/flaky-test.ts @@ -10,6 +10,7 @@ import type { } from "../types.js"; import type { AnalysisContext } from "../analysis-context.js"; import { boundedFetchJson } from "../external-fetch.js"; +import { githubHeaders } from "../github-headers.js"; import { isTestPath } from "./test-ratio.js"; import { DEFAULT_MAX_FINDINGS } from "./limits.js"; @@ -53,14 +54,6 @@ interface RepoInfo { default_branch?: string; } -function githubHeaders(token: string): Record { - return { - Authorization: `Bearer ${token}`, - Accept: "application/vnd.github+json", - "X-GitHub-Api-Version": "2022-11-28", - }; -} - function markPartial(diagnostics: AnalyzerDiagnostics | undefined, reason: string): void { if (!diagnostics) return; diagnostics.partialStatus = "partial"; diff --git a/review-enrichment/src/analyzers/history.ts b/review-enrichment/src/analyzers/history.ts index 888bd36104..a9e73563d9 100644 --- a/review-enrichment/src/analyzers/history.ts +++ b/review-enrichment/src/analyzers/history.ts @@ -12,10 +12,10 @@ import type { AnalyzerDiagnostics, EnrichRequest, HistoryFinding } from "../types.js"; import type { AnalysisContext } from "../analysis-context.js"; import { boundedFetchJson } from "../external-fetch.js"; +import { githubHeaders } from "../github-headers.js"; import { isDiffFileHeaderLine } from "./diff-lines.js"; const GITHUB_API = "https://api.github.com"; -const GITHUB_API_VERSION = "2022-11-28"; const MAX_FILES_PROBED = 5; // bound the per-file commit-history fan-out const COMMITS_PER_FILE = 10; // recent commits to inspect per probed file const MAX_PR_LOOKUPS = 12; // global cap on commit→PR resolution calls @@ -179,15 +179,6 @@ export function parseRepo( return { owner: owner!, repo: repo! }; } -function githubHeaders(token: string): Record { - return { - Authorization: `Bearer ${token}`, - Accept: "application/vnd.github+json", - "X-GitHub-Api-Version": GITHUB_API_VERSION, - "User-Agent": "gittensory-review-enrichment", - }; -} - // ── Linked-issue alignment (no fetch — the issue text is in the envelope) ─────── /** Extract lowercased keyword tokens (length >= MIN_TOKEN_LENGTH, minus stopwords) from the issue's stated diff --git a/review-enrichment/src/analyzers/pending-review-requests.ts b/review-enrichment/src/analyzers/pending-review-requests.ts index ecf61a1992..c23b33a8d6 100644 --- a/review-enrichment/src/analyzers/pending-review-requests.ts +++ b/review-enrichment/src/analyzers/pending-review-requests.ts @@ -15,6 +15,7 @@ import type { } from "../types.js"; import type { AnalysisContext } from "../analysis-context.js"; import { boundedFetchJson } from "../external-fetch.js"; +import { githubHeaders } from "../github-headers.js"; const GITHUB_API = "https://api.github.com"; const SLUG_RE = /^[A-Za-z0-9._-]+$/; @@ -42,14 +43,6 @@ interface TimelineEvent { requested_team?: { slug?: string }; } -function githubHeaders(token: string): Record { - return { - Authorization: `Bearer ${token}`, - Accept: "application/vnd.github+json", - "X-GitHub-Api-Version": "2022-11-28", - }; -} - async function fetchRequestedReviewers( owner: string, repo: string, diff --git a/review-enrichment/src/analyzers/revert-recurrence.ts b/review-enrichment/src/analyzers/revert-recurrence.ts index ba6be8767d..a4e2ec8f8c 100644 --- a/review-enrichment/src/analyzers/revert-recurrence.ts +++ b/review-enrichment/src/analyzers/revert-recurrence.ts @@ -13,6 +13,7 @@ import type { } from "../types.js"; import type { AnalysisContext } from "../analysis-context.js"; import { boundedFetchJson } from "../external-fetch.js"; +import { githubHeaders } from "../github-headers.js"; import { isHistoryUninformativePath } from "./history-path.js"; import { DEFAULT_MAX_FINDINGS } from "./limits.js"; @@ -147,14 +148,6 @@ export function firstOverlap(left: Range[], right: Range[]): Range | null { return null; } -function githubHeaders(token: string): Record { - return { - Authorization: `Bearer ${token}`, - Accept: "application/vnd.github+json", - "X-GitHub-Api-Version": "2022-11-28", - }; -} - /** Fetch + parse JSON with the shared bounded-fetch guard rails. Returns the parsed body, or null on any * error / non-200 so the caller degrades that one lookup rather than throwing. */ async function fetchGithubJson( diff --git a/review-enrichment/src/analyzers/stale-branch.ts b/review-enrichment/src/analyzers/stale-branch.ts index 623835db2b..593360fcee 100644 --- a/review-enrichment/src/analyzers/stale-branch.ts +++ b/review-enrichment/src/analyzers/stale-branch.ts @@ -13,6 +13,7 @@ import type { } from "../types.js"; import type { AnalysisContext } from "../analysis-context.js"; import { boundedFetchJson } from "../external-fetch.js"; +import { githubHeaders } from "../github-headers.js"; const GITHUB_API = "https://api.github.com"; const SLUG_RE = /^[A-Za-z0-9._-]+$/; @@ -34,14 +35,6 @@ interface CompareResult { behind_by?: number; } -function githubHeaders(token: string): Record { - return { - Authorization: `Bearer ${token}`, - Accept: "application/vnd.github+json", - "X-GitHub-Api-Version": "2022-11-28", - }; -} - async function fetchDefaultBranch( owner: string, repo: string, diff --git a/review-enrichment/src/analyzers/unused-export.ts b/review-enrichment/src/analyzers/unused-export.ts index 971b2edce3..a8407017ba 100644 --- a/review-enrichment/src/analyzers/unused-export.ts +++ b/review-enrichment/src/analyzers/unused-export.ts @@ -12,12 +12,12 @@ import type { } from "../types.js"; import type { AnalysisContext } from "../analysis-context.js"; import { boundedFetchJson } from "../external-fetch.js"; +import { githubHeaders } from "../github-headers.js"; import { exportedSymbols, parseAddedExports } from "./undocumented-export.js"; import { isTestPath } from "./test-ratio.js"; import { DEFAULT_MAX_FINDINGS } from "./limits.js"; const GITHUB_API = "https://api.github.com"; -const GITHUB_API_VERSION = "2022-11-28"; const SLUG_RE = /^[A-Za-z0-9._-]+$/; const MAX_SYMBOLS = 10; const MAX_SEARCHES = 10; @@ -46,15 +46,6 @@ interface CodeSearchResponse { items?: CodeSearchItem[]; } -function githubHeaders(token: string, raw = false): Record { - return { - Authorization: `Bearer ${token}`, - Accept: raw ? "application/vnd.github.raw" : "application/vnd.github+json", - "X-GitHub-Api-Version": GITHUB_API_VERSION, - "User-Agent": "gittensory-review-enrichment", - }; -} - function escapeRegExp(value: string): string { return value.replace(/[$.*+?^{}()|[\]\\]/g, "\\$&"); } @@ -133,7 +124,7 @@ async function fetchFileAtHead( const encoded = path.split("/").map(encodeURIComponent).join("/"); const resp = await fetchImpl( `${GITHUB_API}/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/contents/${encoded}?ref=${encodeURIComponent(headSha)}`, - { headers: githubHeaders(token, true), signal }, + { headers: githubHeaders(token, { raw: true }), signal }, ); if (!resp.ok) return null; return await readBoundedText(resp, signal); diff --git a/review-enrichment/src/github-headers.ts b/review-enrichment/src/github-headers.ts new file mode 100644 index 0000000000..f47e7029d2 --- /dev/null +++ b/review-enrichment/src/github-headers.ts @@ -0,0 +1,21 @@ +// Shared outbound GitHub REST API request headers (#4609). Before this, 17 of 63 analyzer files hand-copied a +// private githubHeaders() helper that had drifted into 4 shapes: 11 sent no User-Agent, 3 added a User-Agent + +// a GITHUB_API_VERSION constant, 1 hardcoded Accept to raw-only (unable to ever request JSON), and 2 reinvented a +// raw-toggle param a 4th way. One export, one shape, used by every analyzer that talks to the GitHub API. +const GITHUB_API_VERSION = "2022-11-28"; +const USER_AGENT = "gittensory-review-enrichment"; + +/** Standard headers for an authenticated GitHub REST API request: `Authorization`, `X-GitHub-Api-Version`, and + * `User-Agent` are always present. `Accept` defaults to the structured-JSON media type; pass `{ raw: true }` + * when fetching raw file/blob content (e.g. the Contents API) instead of JSON metadata. Pure. */ +export function githubHeaders( + token: string, + opts?: { raw?: boolean }, +): Record { + return { + Authorization: `Bearer ${token}`, + Accept: opts?.raw ? "application/vnd.github.raw" : "application/vnd.github+json", + "X-GitHub-Api-Version": GITHUB_API_VERSION, + "User-Agent": USER_AGENT, + }; +} diff --git a/review-enrichment/test/github-headers.test.ts b/review-enrichment/test/github-headers.test.ts new file mode 100644 index 0000000000..30d9e29766 --- /dev/null +++ b/review-enrichment/test/github-headers.test.ts @@ -0,0 +1,36 @@ +import assert from "node:assert/strict"; +import { test } from "node:test"; + +import { githubHeaders } from "../dist/github-headers.js"; + +test("githubHeaders defaults to the structured-JSON Accept media type", () => { + const headers = githubHeaders("tok_abc123"); + assert.deepEqual(headers, { + Authorization: "Bearer tok_abc123", + Accept: "application/vnd.github+json", + "X-GitHub-Api-Version": "2022-11-28", + "User-Agent": "gittensory-review-enrichment", + }); +}); + +test("githubHeaders with no opts argument matches an explicit raw:false", () => { + assert.deepEqual(githubHeaders("tok_abc123"), githubHeaders("tok_abc123", { raw: false })); +}); + +test("githubHeaders switches Accept to the raw media type when opts.raw is true", () => { + const headers = githubHeaders("tok_abc123", { raw: true }); + assert.deepEqual(headers, { + Authorization: "Bearer tok_abc123", + Accept: "application/vnd.github.raw", + "X-GitHub-Api-Version": "2022-11-28", + "User-Agent": "gittensory-review-enrichment", + }); +}); + +test("githubHeaders with an empty opts object behaves like the default (JSON)", () => { + assert.deepEqual(githubHeaders("tok_abc123", {}), githubHeaders("tok_abc123")); +}); + +test("githubHeaders always embeds the caller's token verbatim in the Bearer value", () => { + assert.equal(githubHeaders("ghs_anotherToken999").Authorization, "Bearer ghs_anotherToken999"); +});