From e151efe7818bc9d24b36dd4c1ced50b21549d122 Mon Sep 17 00:00:00 2001 From: Sam Lanning Date: Wed, 7 May 2025 19:51:30 +0100 Subject: [PATCH 1/2] Add test for executable files --- src/test/integration/git.test.ts | 57 ++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/src/test/integration/git.test.ts b/src/test/integration/git.test.ts index c8403ce..53a38c7 100644 --- a/src/test/integration/git.test.ts +++ b/src/test/integration/git.test.ts @@ -82,6 +82,7 @@ const makeFileChanges = async ( repoDirectory: string, changegroup: | "standard" + | "with-executable-file" | "with-ignored-symlink" | "with-included-valid-symlink" | "with-included-invalid-symlink", @@ -120,6 +121,17 @@ const makeFileChanges = async ( path.join(repoDirectory, "coverage", "foo", "bar"), "This file should be ignored", ); + if (changegroup === "with-executable-file") { + // Add an executable file + await fs.promises.writeFile( + path.join(repoDirectory, "executable-file.sh"), + "#!/bin/bash\necho hello", + ); + await fs.promises.chmod( + path.join(repoDirectory, "executable-file.sh"), + 0o755, + ); + } if (changegroup === "with-ignored-symlink") { // node_modules is ignored in this repo await fs.promises.mkdir(path.join(repoDirectory, "node_modules"), { @@ -341,6 +353,51 @@ describe("git", () => { }); }); + it(`should throw appropriate error when executable file is present`, async () => { + const branch = `${TEST_BRANCH_PREFIX}-executable-file`; + branches.push(branch); + + await fs.promises.mkdir(testDir, { recursive: true }); + const repoDirectory = path.join(testDir, `repo-executable-file`); + + // Clone the git repo locally using the git cli and child-process + await new Promise((resolve, reject) => { + const p = execFile( + "git", + ["clone", process.cwd(), `repo-executable-file`], + { cwd: testDir }, + (error) => { + if (error) { + reject(error); + } else { + resolve(); + } + }, + ); + p.stdout?.pipe(process.stdout); + p.stderr?.pipe(process.stderr); + }); + + await makeFileChanges(repoDirectory, "with-executable-file"); + + // Push the changes + await expect(() => + commitChangesFromRepo({ + octokit, + ...REPO, + branch, + message: { + headline: "Test commit", + body: "This is a test commit", + }, + repoDirectory, + log, + }), + ).rejects.toThrow( + "Unexpected executable file at executable-file.sh, GitHub API only supports non-executable files and directories. You may need to add this file to .gitignore", + ); + }); + it("should correctly be able to base changes off specific commit", async () => { const branch = `${TEST_BRANCH_PREFIX}-specific-base`; branches.push(branch); From eebc770a27af4374ddef5792887958fbabbf2e01 Mon Sep 17 00:00:00 2001 From: Sam Lanning Date: Wed, 7 May 2025 19:55:02 +0100 Subject: [PATCH 2/2] Throw an error when executable files are found --- .changeset/lazy-icons-cheer.md | 5 +++++ src/git.ts | 5 +++++ 2 files changed, 10 insertions(+) create mode 100644 .changeset/lazy-icons-cheer.md diff --git a/.changeset/lazy-icons-cheer.md b/.changeset/lazy-icons-cheer.md new file mode 100644 index 0000000..ca9d5d5 --- /dev/null +++ b/.changeset/lazy-icons-cheer.md @@ -0,0 +1,5 @@ +--- +"@changesets/ghcommit": minor +--- + +Throw an error when executable files are encountered diff --git a/src/git.ts b/src/git.ts index 1d56a14..30b6b94 100644 --- a/src/git.ts +++ b/src/git.ts @@ -68,6 +68,11 @@ export const commitChangesFromRepo = async ({ `Unexpected symlink at ${filepath}, GitHub API only supports files and directories. You may need to add this file to .gitignore`, ); } + if ((await workdir?.mode()) === FILE_MODES.executableFile) { + throw new Error( + `Unexpected executable file at ${filepath}, GitHub API only supports non-executable files and directories. You may need to add this file to .gitignore`, + ); + } const prevOid = await commit?.oid(); const currentOid = await workdir?.oid(); // Don't include files that haven't changed, and exist in both trees