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
16 changes: 16 additions & 0 deletions actions/setup/js/close_issue.test.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -486,6 +486,22 @@ describe("close_issue", () => {
expect(commentCalls[0].body).not.toContain("Default comment from config");
});

it("should pass shell metacharacters in a comment as API data", async () => {
const payload = "$(touch /tmp/gh-aw-command-injection); echo safe";
const handler = await main({ max: 10 });
const commentCalls = [];
mockGithub.rest.issues.createComment = async params => {
commentCalls.push(params);
return { data: { id: 999, html_url: "https://github.com/test-owner/test-repo/issues/100#issuecomment-999" } };
};

const result = await handler({ issue_number: 100, body: payload }, {});

expect(result.success).toBe(true);
expect(commentCalls).toHaveLength(1);
expect(commentCalls[0].body).toContain(payload);
});

it("should require body field when no config comment is set", async () => {
const handler = await main({ max: 10 });

Expand Down
10 changes: 10 additions & 0 deletions actions/setup/js/create_issue.test.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,16 @@ describe("create_issue", () => {
);
});

it("should pass shell metacharacters in the issue body as API data", async () => {
const payload = "$(touch /tmp/gh-aw-command-injection); echo safe";
const handler = await main({});

const result = await handler({ title: "Test Issue", body: payload });

expect(result.success).toBe(true);
expect(mockGithub.rest.issues.create.mock.calls[0][0].body).toContain(payload);
});

it("should append the configured body footer when the generated footer is disabled", async () => {
const handler = await main({
footer: false,
Expand Down
6 changes: 3 additions & 3 deletions actions/setup/js/create_pull_request.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -2096,7 +2096,7 @@ ${issueSafeFallbackFooter}`;

// Abort the failed git am before attempting any fallback
try {
await exec.exec("git am --abort");
await exec.exec("git", ["am", "--abort"]);
core.info("Aborted failed git am");
} catch (abortError) {
core.warning(`Failed to abort git am: ${getErrorMessage(abortError)}`);
Expand Down Expand Up @@ -2154,7 +2154,7 @@ ${issueSafeFallbackFooter}`;
core.warning(`Automatic add/add conflict recovery attempt failed during fallback: ${recoveredFallback.errorMessage}`);
}
try {
await exec.exec("git am --abort");
await exec.exec("git", ["am", "--abort"]);
} catch (abortFallbackError) {
core.warning(`Failed to abort fallback git am: ${getErrorMessage(abortFallbackError)}`);
}
Expand Down Expand Up @@ -2393,7 +2393,7 @@ ${issueSafeFallbackFooter}`;
// Push the branch with an empty commit to allow PR creation
try {
// Create an empty commit to ensure there's a commit difference
await exec.exec(`git commit --allow-empty -m "Initialize"`);
await exec.exec("git", ["commit", "--allow-empty", "-m", "Initialize"]);
core.info("Created empty commit");

const forkCwd = process.cwd();
Expand Down
12 changes: 12 additions & 0 deletions actions/setup/js/create_pull_request_sanitization.test.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,18 @@ describe("create_pull_request - body sanitization", () => {
expect(createCall.body).not.toMatch(/(?<![`])@another-user(?![`])/);
});

it("should pass shell metacharacters in PR content as API data", async () => {
const payload = "$(touch /tmp/gh-aw-command-injection); echo safe";
const { main } = require("./create_pull_request.cjs");
const handler = await main({ allow_empty: true });

await handler({ title: "Test PR", body: payload }, {});

const createCall = global.github.rest.pulls.create.mock.calls[0]?.[0];
expect(createCall.body).toContain(payload);
expect(JSON.stringify(global.exec.exec.mock.calls)).not.toContain(payload);
});

it("should expose hidden markdown link title XPIA payloads in PR body (closing the XPIA channel)", async () => {
const { main } = require("./create_pull_request.cjs");
const handler = await main({ allow_empty: true });
Expand Down
Loading