diff --git a/.github/workflows/mcp-inspector.lock.yml b/.github/workflows/mcp-inspector.lock.yml index a6c476a93e1..ad1d4a64f61 100644 --- a/.github/workflows/mcp-inspector.lock.yml +++ b/.github/workflows/mcp-inspector.lock.yml @@ -996,7 +996,7 @@ jobs: "url": "https://mcp.datadoghq.com/api/unstable/mcp-server/mcp?toolsets=core", "headers": { "DD_API_KEY": "\${DD_API_KEY}", - "DD_APPLICATION_KEY": "\${DD_APP_KEY}", + "DD_APPLICATION_KEY": "\${DD_APPLICATION_KEY}", "DD_SITE": "\${DD_SITE}" }, "tools": [ diff --git a/.github/workflows/smoke-otel-backends.lock.yml b/.github/workflows/smoke-otel-backends.lock.yml index 878ea3a0c79..59f8342c061 100644 --- a/.github/workflows/smoke-otel-backends.lock.yml +++ b/.github/workflows/smoke-otel-backends.lock.yml @@ -769,7 +769,7 @@ jobs: "url": "https://mcp.datadoghq.com/api/unstable/mcp-server/mcp?toolsets=core", "headers": { "DD_API_KEY": "\${DD_API_KEY}", - "DD_APPLICATION_KEY": "\${DD_APP_KEY}", + "DD_APPLICATION_KEY": "\${DD_APPLICATION_KEY}", "DD_SITE": "\${DD_SITE}" }, "tools": [ diff --git a/actions/setup/js/push_signed_commits.cjs b/actions/setup/js/push_signed_commits.cjs index 31643b5d842..458c0d40c25 100644 --- a/actions/setup/js/push_signed_commits.cjs +++ b/actions/setup/js/push_signed_commits.cjs @@ -360,7 +360,7 @@ async function pushSignedCommits({ githubClient, owner, repo, branch, baseRef, c core.info(`pushSignedCommits: using chained OID from previous mutation: ${expectedHeadOid}`); } else { // First commit: check whether the branch already exists on the remote. - const { stdout: oidOut } = await exec.getExecOutput("git", ["ls-remote", "origin", `refs/heads/${branch}`], { cwd }); + const { stdout: oidOut } = await exec.getExecOutput("git", ["ls-remote", "origin", `refs/heads/${branch}`], { cwd, env: { ...process.env, ...(gitAuthEnv || {}) } }); expectedHeadOid = oidOut.trim().split(/\s+/)[0]; if (!expectedHeadOid) { // Branch does not exist on the remote yet. diff --git a/actions/setup/js/push_signed_commits.test.cjs b/actions/setup/js/push_signed_commits.test.cjs index f07d65bd27b..dfccf271cde 100644 --- a/actions/setup/js/push_signed_commits.test.cjs +++ b/actions/setup/js/push_signed_commits.test.cjs @@ -730,6 +730,177 @@ describe("push_signed_commits integration tests", () => { }); }); + describe("git auth environment propagation", () => { + it("should pass gitAuthEnv to ls-remote in the signed-commit path", async () => { + const gitAuthEnv = { + GIT_CONFIG_COUNT: "1", + GIT_CONFIG_KEY_0: "http.https://github.com/.extraheader", + GIT_CONFIG_VALUE_0: "Authorization: basic test-token", + }; + const sentinelKey = "PUSH_SIGNED_COMMITS_ENV_SENTINEL_1"; + const sentinelValue = "sentinel-1"; + const previousSentinel = process.env[sentinelKey]; + process.env[sentinelKey] = sentinelValue; + + const getExecOutput = vi.fn(async (_program, args) => { + if (args[0] === "rev-list") { + return { + exitCode: 0, + stdout: "1111111111111111111111111111111111111111 0000000000000000000000000000000000000000\n", + stderr: "", + }; + } + if (args[0] === "diff-tree") { + return { + exitCode: 0, + stdout: ":100644 100644 0000000000000000000000000000000000000000 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa M\tmemory.json\n", + stderr: "", + }; + } + if (args[0] === "ls-remote") { + return { + exitCode: 0, + stdout: "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef\trefs/heads/auth-check-branch\n", + stderr: "", + }; + } + if (args[0] === "log") { + return { exitCode: 0, stdout: "Auth check commit\n", stderr: "" }; + } + throw new Error(`Unexpected git command: ${args.join(" ")}`); + }); + + const execProgram = vi.fn(async (_program, args, opts = {}) => { + if (args[0] === "cat-file" && args[1] === "blob") { + opts.listeners?.stdout?.(Buffer.from("memory data\n")); + return 0; + } + throw new Error(`Unexpected exec command: ${args.join(" ")}`); + }); + + global.exec = { + getExecOutput, + exec: execProgram, + }; + + const githubClient = makeMockGithubClient(); + + try { + await pushSignedCommits({ + githubClient, + owner: "test-owner", + repo: "test-repo", + branch: "auth-check-branch", + baseRef: "origin/main", + cwd: workDir, + gitAuthEnv, + }); + } finally { + if (previousSentinel === undefined) { + delete process.env[sentinelKey]; + } else { + process.env[sentinelKey] = previousSentinel; + } + } + + const lsRemoteCall = getExecOutput.mock.calls.find(call => call[1][0] === "ls-remote"); + expect(lsRemoteCall).toBeDefined(); + expect(lsRemoteCall[2]).toEqual( + expect.objectContaining({ + cwd: workDir, + env: expect.objectContaining({ + ...gitAuthEnv, + [sentinelKey]: sentinelValue, + }), + }) + ); + }); + + it("should include auth env on ls-remote getExecOutput git call", async () => { + const gitAuthEnv = { + GIT_CONFIG_COUNT: "1", + GIT_CONFIG_KEY_0: "http.https://github.com/.extraheader", + GIT_CONFIG_VALUE_0: "Authorization: basic test-token", + }; + const sentinelKey = "PUSH_SIGNED_COMMITS_ENV_SENTINEL_2"; + const sentinelValue = "sentinel-2"; + const previousSentinel = process.env[sentinelKey]; + process.env[sentinelKey] = sentinelValue; + + const getExecOutput = vi.fn(async (_program, args) => { + if (args[0] === "rev-list") { + return { + exitCode: 0, + stdout: "2222222222222222222222222222222222222222 1111111111111111111111111111111111111111\n", + stderr: "", + }; + } + if (args[0] === "diff-tree") { + return { + exitCode: 0, + stdout: ":100644 100644 0000000000000000000000000000000000000000 bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb M\tmemory.json\n", + stderr: "", + }; + } + if (args[0] === "ls-remote") { + return { + exitCode: 0, + stdout: "cafebabecafebabecafebabecafebabecafebabe\trefs/heads/auth-check-branch\n", + stderr: "", + }; + } + if (args[0] === "log") { + return { exitCode: 0, stdout: "Auth guard commit\n", stderr: "" }; + } + throw new Error(`Unexpected git command: ${args.join(" ")}`); + }); + + global.exec = { + getExecOutput, + exec: async (_program, args, opts = {}) => { + if (args[0] === "cat-file" && args[1] === "blob") { + opts.listeners?.stdout?.(Buffer.from("memory data\n")); + return 0; + } + throw new Error(`Unexpected exec command: ${args.join(" ")}`); + }, + }; + + const githubClient = makeMockGithubClient(); + + try { + await pushSignedCommits({ + githubClient, + owner: "test-owner", + repo: "test-repo", + branch: "auth-check-branch", + baseRef: "origin/main", + cwd: workDir, + gitAuthEnv, + }); + } finally { + if (previousSentinel === undefined) { + delete process.env[sentinelKey]; + } else { + process.env[sentinelKey] = previousSentinel; + } + } + + const networkGitCalls = getExecOutput.mock.calls.filter(call => call[1][0] === "ls-remote"); + expect(networkGitCalls).toHaveLength(1); + for (const call of networkGitCalls) { + expect(call[2]).toEqual( + expect.objectContaining({ + env: expect.objectContaining({ + ...gitAuthEnv, + [sentinelKey]: sentinelValue, + }), + }) + ); + } + }); + }); + // ────────────────────────────────────────────────────── // Commit message – multi-line body // ──────────────────────────────────────────────────────