Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions actions/setup/js/push_repo_memory.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -368,9 +368,16 @@ async function main() {

core.info("Changes detected, committing and pushing...");

// Stage all changes
// Stage all changes.
// --sparse: "Allow updating index entries outside of the sparse-checkout cone.
// Normally, git add refuses to update index entries whose paths do not fit
// within the sparse-checkout cone, since those files might be removed from the
// working tree without warning." (git-add(1))
// This is required because "git checkout --orphan" can re-activate
// sparse-checkout, causing a plain "git add ." to silently skip or reject
// files on the first run for a new memory branch.
try {
execGitSync(["add", "."], { stdio: "inherit" });
execGitSync(["add", "--sparse", "."], { stdio: "inherit" });
} catch (error) {
core.setFailed(`Failed to stage changes: ${getErrorMessage(error)}`);
return;
Expand Down
23 changes: 23 additions & 0 deletions actions/setup/js/push_repo_memory.test.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -1057,6 +1057,29 @@ describe("push_repo_memory.cjs - shell injection security tests", () => {
expect(scriptContent).toContain("fs.rmSync(");
});

it("should use git add --sparse to handle sparse-checkout on orphan branch creation", () => {
// Regression test for: push_repo_memory fails with sparse-checkout error on first run.
//
// Root cause: "git checkout --orphan" can re-activate sparse-checkout behaviour.
// A plain "git add ." then fails because the files fall outside the sparse-checkout
// definition.
//
// Fix: use "git add --sparse ." so files are staged regardless of whether
// sparse-checkout is active.

const fs = require("fs");
const path = require("path");

const scriptPath = path.join(import.meta.dirname, "push_repo_memory.cjs");
const scriptContent = fs.readFileSync(scriptPath, "utf8");

// Must use "git add --sparse ." to stage files regardless of sparse-checkout state.
expect(scriptContent).toContain('"add", "--sparse", "."');

// Must NOT use plain "git add ." which breaks under sparse-checkout.
expect(scriptContent).not.toContain('"add", "."');
});

it("should safely handle malicious branch names", () => {
// Test that malicious branch names would be rejected by git, not executed as shell commands
const maliciousBranchNames = [
Expand Down
Loading