Skip to content

Commit fcbe3a5

Browse files
fix(github): reject a malformed three-segment repoFullName in comments.ts
`createOrUpdateIssueCommentWithMarker` validated `repoFullName` with `const [owner, repo] = repoFullName.split("/")` + a truthiness check, so "owner/repo/extra" passed: the destructure silently dropped the extra segment and the GitHub call was issued against "owner/repo" — a repo the caller never specified. Add the missing `parts.length !== 2` segment-count check inline, matching the guard already present in parseRepoFullName (assignees.ts / labels.ts). No-slash and empty-segment inputs are still rejected exactly as before; whitespace handling is intentionally left unchanged (a separate issue covers that in a different file). Extends test/unit/github-comments.test.ts with a case asserting "owner/repo/extra" is rejected via createOrUpdatePrIntelligenceComment, mirroring the existing precedent in github-assignees.test.ts. Closes #6612
1 parent 42805e0 commit fcbe3a5

2 files changed

Lines changed: 15 additions & 2 deletions

File tree

src/github/comments.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,13 @@ async function createOrUpdateIssueCommentWithMarker(
5050
marker: string,
5151
options: { createIfMissing?: boolean | undefined; mode?: AgentActionMode } = {},
5252
): Promise<{ id: number; html_url?: string } | null> {
53-
const [owner, repo] = repoFullName.split("/");
54-
if (!owner || !repo) throw new Error(`Invalid repository full name: ${repoFullName}`);
53+
const parts = repoFullName.split("/");
54+
const owner = parts[0];
55+
const repo = parts[1];
56+
// Reject anything that is not exactly two non-empty segments -- "owner/repo/extra" would otherwise pass
57+
// (the destructure silently drops the extra segment), issuing a call against a repo the caller never
58+
// specified. Matches the segment-count guard in parseRepoFullName (assignees.ts / labels.ts).
59+
if (parts.length !== 2 || !owner || !repo) throw new Error(`Invalid repository full name: ${repoFullName}`);
5560

5661
return await withInstallationTokenRetry(env, installationId, async (token) => {
5762
// Non-live mode suppresses the comment create/update writes; the GET marker-search probe below still runs.

test/unit/github-comments.test.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -379,6 +379,14 @@ describe("GitHub PR intelligence comments", () => {
379379
it("rejects invalid repository names before calling GitHub", async () => {
380380
await expect(createOrUpdatePrIntelligenceComment(createTestEnv(), 123, "invalid", 12, "body")).rejects.toThrow(/Invalid repository full name/);
381381
});
382+
383+
it("rejects a malformed three-segment repository name instead of silently truncating it", async () => {
384+
// "owner/repo/extra" splits into three segments; the extra one must be rejected, not dropped, so no
385+
// GitHub call is ever made against the truncated "owner/repo".
386+
await expect(createOrUpdatePrIntelligenceComment(createTestEnv(), 123, "owner/repo/extra", 12, "body")).rejects.toThrow(
387+
/Invalid repository full name/,
388+
);
389+
});
382390
});
383391

384392
async function generatePrivateKeyPem(): Promise<string> {

0 commit comments

Comments
 (0)