Run checkout auth cleanup when API commit signing is enabled (#1597)

* Run checkout auth cleanup when API commit signing is enabled

* Derive git-config test expectations from GITHUB_SERVER_URL

No-Verification-Needed: test-only change
This commit is contained in:
Ashwin Bhat
2026-08-06 10:18:34 -07:00
committed by GitHub
parent e1fc925862
commit 96e281f4d9
6 changed files with 391 additions and 4 deletions
+63 -1
View File
@@ -16,28 +16,35 @@ describe("Agent Mode", () => {
let exportVariableSpy: any;
let setOutputSpy: any;
let configureGitAuthSpy: any;
let replaceCheckoutCredentialsSpy: any;
beforeEach(() => {
exportVariableSpy = spyOn(core, "exportVariable").mockImplementation(
() => {},
);
setOutputSpy = spyOn(core, "setOutput").mockImplementation(() => {});
// Mock configureGitAuth to prevent actual git commands from running
// Mock git configuration to prevent actual git commands from running
configureGitAuthSpy = spyOn(
gitConfig,
"configureGitAuth",
).mockImplementation(async () => {
// Do nothing - prevent actual git config modifications
});
replaceCheckoutCredentialsSpy = spyOn(
gitConfig,
"replaceCheckoutCredentials",
).mockImplementation(async () => {});
});
afterEach(() => {
exportVariableSpy?.mockClear();
setOutputSpy?.mockClear();
configureGitAuthSpy?.mockClear();
replaceCheckoutCredentialsSpy?.mockClear();
exportVariableSpy?.mockRestore();
setOutputSpy?.mockRestore();
configureGitAuthSpy?.mockRestore();
replaceCheckoutCredentialsSpy?.mockRestore();
});
test("prepareAgentMode is exported as a function", () => {
@@ -257,4 +264,59 @@ describe("Agent Mode", () => {
// Should be empty or just whitespace when no MCP servers are included
expect(result.claudeArgs).not.toContain("--mcp-config");
});
describe("git credential configuration", () => {
const mockOctokit = {
rest: {
users: {
getByUsername: mock(() =>
Promise.resolve({
data: { login: "test-user", id: 12345, type: "User" },
}),
),
},
},
} as any;
test("uses full git auth on the non-signing path", async () => {
const context = createMockAutomationContext({
eventName: "workflow_dispatch",
});
await prepareAgentMode({
context,
octokit: mockOctokit,
githubToken: "test-token",
});
expect(configureGitAuthSpy).toHaveBeenCalledTimes(1);
expect(configureGitAuthSpy).toHaveBeenCalledWith("test-token", context, {
login: context.inputs.botName,
id: parseInt(context.inputs.botId),
});
// configureGitAuth performs the credential replacement itself; the mock
// stands in for it here, so the standalone helper is not invoked.
expect(replaceCheckoutCredentialsSpy).not.toHaveBeenCalled();
});
test("still replaces the checkout credential when API commit signing is enabled", async () => {
const context = createMockAutomationContext({
eventName: "workflow_dispatch",
inputs: { useCommitSigning: true },
});
await prepareAgentMode({
context,
octokit: mockOctokit,
githubToken: "test-token",
});
expect(configureGitAuthSpy).not.toHaveBeenCalled();
expect(replaceCheckoutCredentialsSpy).toHaveBeenCalledTimes(1);
expect(replaceCheckoutCredentialsSpy).toHaveBeenCalledWith(
"test-token",
context,
);
});
});
});
+92 -1
View File
@@ -1,8 +1,99 @@
import { describe, test, expect } from "bun:test";
import { describe, test, expect, beforeEach, afterEach, spyOn } from "bun:test";
import { prepareTagMode } from "../../src/modes/tag";
import { mockIssueCommentContext } from "../mockContext";
import * as actor from "../../src/github/validation/actor";
import * as createInitial from "../../src/github/operations/comments/create-initial";
import * as fetcher from "../../src/github/data/fetcher";
import * as branch from "../../src/github/operations/branch";
import * as createPrompt from "../../src/create-prompt";
import * as mcp from "../../src/mcp/install-mcp-server";
import * as gitConfig from "../../src/github/operations/git-config";
describe("Tag Mode", () => {
test("prepareTagMode is exported as a function", () => {
expect(typeof prepareTagMode).toBe("function");
});
describe("git credential configuration", () => {
let spies: Array<{ mockRestore: () => void }>;
let configureGitAuthSpy: any;
let replaceCheckoutCredentialsSpy: any;
beforeEach(() => {
configureGitAuthSpy = spyOn(
gitConfig,
"configureGitAuth",
).mockImplementation(async () => {});
replaceCheckoutCredentialsSpy = spyOn(
gitConfig,
"replaceCheckoutCredentials",
).mockImplementation(async () => {});
spies = [
configureGitAuthSpy,
replaceCheckoutCredentialsSpy,
spyOn(actor, "checkHumanActor").mockImplementation(async () => {}),
spyOn(createInitial, "createInitialComment").mockImplementation(
async () => ({ id: 42 }) as any,
),
spyOn(fetcher, "fetchGitHubData").mockImplementation(
async () => ({}) as any,
),
spyOn(branch, "setupBranch").mockImplementation(
async () =>
({
baseBranch: "main",
claudeBranch: "claude/test",
currentBranch: "claude/test",
}) as any,
),
spyOn(createPrompt, "createPrompt").mockImplementation(async () => {}),
spyOn(mcp, "prepareMcpConfig").mockImplementation(async () => "{}"),
];
});
afterEach(() => {
for (const spy of spies) {
spy.mockRestore();
}
});
test("uses full git auth on the non-signing path", async () => {
const context = { ...mockIssueCommentContext };
await prepareTagMode({
context,
octokit: {} as any,
githubToken: "test-token",
});
expect(configureGitAuthSpy).toHaveBeenCalledTimes(1);
expect(configureGitAuthSpy).toHaveBeenCalledWith("test-token", context, {
login: context.inputs.botName,
id: parseInt(context.inputs.botId),
});
// configureGitAuth performs the credential replacement itself; the mock
// stands in for it here, so the standalone helper is not invoked.
expect(replaceCheckoutCredentialsSpy).not.toHaveBeenCalled();
});
test("still replaces the checkout credential when API commit signing is enabled", async () => {
const context = {
...mockIssueCommentContext,
inputs: { ...mockIssueCommentContext.inputs, useCommitSigning: true },
};
await prepareTagMode({
context,
octokit: {} as any,
githubToken: "test-token",
});
expect(configureGitAuthSpy).not.toHaveBeenCalled();
expect(replaceCheckoutCredentialsSpy).toHaveBeenCalledTimes(1);
expect(replaceCheckoutCredentialsSpy).toHaveBeenCalledWith(
"test-token",
context,
);
});
});
});