Skip to content
Open
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
115 changes: 80 additions & 35 deletions sdk/typescript/tests-ts/release-automation.test.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import { spawnSync } from "node:child_process";
import { createHash } from "node:crypto";
import {
existsSync,
mkdirSync,
mkdtempSync,
readFileSync,
rmSync,
writeFileSync,
} from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { join, resolve } from "node:path";
import { fileURLToPath } from "node:url";
import { describe, expect, test } from "bun:test";

Expand Down Expand Up @@ -196,6 +197,34 @@ const releaseLabelsWorkflow = readFileSync(
),
"utf8",
);
const releaseTestBash = resolveReleaseTestBash();

function resolveReleaseTestBash(): string {
if (process.platform !== "win32") return "bash";

const gitExecPath = spawnSync("git", ["--exec-path"], {
encoding: "utf8",
timeout: 10_000,
windowsHide: true,
});
const executableDirectory = gitExecPath.stdout.trim();
if (gitExecPath.status !== 0 || executableDirectory === "") {
throw new Error("Unable to locate Git Bash for release automation tests.");
}

const executable = resolve(
executableDirectory,
"..",
"..",
"..",
"bin",
"bash.exe",
);
if (!existsSync(executable)) {
throw new Error(`Git Bash is unavailable at ${executable}.`);
}
return executable;
}

function publishedMetadata(): ReleaseMetadata {
return {
Expand Down Expand Up @@ -1417,6 +1446,18 @@ describe("idempotent GitHub release verification", () => {
});

describe("GitHub release workflow safeguards", () => {
test("uses Git Bash for shell fragments on Windows", () => {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Route every shell test through the resolved Git Bash

On Windows systems where C:\Windows\System32\bash.exe resolves to WSL before Git Bash, this regression check passes because it invokes releaseTestBash, but the release-workflow tests at lines 1588 and 1735 still call unqualified spawnSync("bash", ...). The parameterized version-history test can therefore enter WSL and mishandle its Windows GITHUB_OUTPUT path, leaving the suite broken in precisely the configuration this change targets; replace those remaining call sites or make this check detect unqualified Bash invocations.

Useful? React with 👍 / 👎.

if (process.platform !== "win32") return;

const result = spawnSync(releaseTestBash, ["-c", "uname -s"], {
encoding: "utf8",
timeout: 10_000,
});

expect(result.status).toBe(0);
expect(result.stdout.trim()).toMatch(/^MINGW/u);
});

test("requires a real tag for protected npm publication", () => {
expect(protectedReleaseWorkflow).toContain("release-tag");
expect(protectedReleaseWorkflow).toContain('"$GITHUB_REF_TYPE"');
Expand Down Expand Up @@ -1454,7 +1495,7 @@ describe("GitHub release workflow safeguards", () => {
"git() { return 0; }",
"npm() { printf '%s\\n' '[\"0.1.1\",\"999999999999999999999999.0.0\"]'; }",
].join("\n");
const result = spawnSync("bash", ["-c", `${mocks}\n${script}`], {
const result = spawnSync(releaseTestBash, ["-c", `${mocks}\n${script}`], {
cwd: fileURLToPath(new URL("../../../", import.meta.url)),
encoding: "utf8",
env: {
Expand Down Expand Up @@ -1640,7 +1681,7 @@ describe("GitHub release workflow safeguards", () => {
" return 1",
"}",
].join("\n");
const result = spawnSync("bash", ["-c", `${mocks}\n${script}`], {
const result = spawnSync(releaseTestBash, ["-c", `${mocks}\n${script}`], {
cwd: fileURLToPath(new URL("../../../", import.meta.url)),
encoding: "utf8",
env: {
Expand Down Expand Up @@ -1759,7 +1800,7 @@ describe("GitHub release workflow safeguards", () => {
" printf 'created exact release tag\\n'",
"}",
].join("\n");
const result = spawnSync("bash", ["-c", `${mock}\n${script}`], {
const result = spawnSync(releaseTestBash, ["-c", `${mock}\n${script}`], {
encoding: "utf8",
env: {
...process.env,
Expand Down Expand Up @@ -1835,7 +1876,7 @@ describe("GitHub release workflow safeguards", () => {
" esac",
"}",
].join("\n");
const result = spawnSync("bash", ["-c", `${mock}\n${script}`], {
const result = spawnSync(releaseTestBash, ["-c", `${mock}\n${script}`], {
encoding: "utf8",
env: {
...process.env,
Expand Down Expand Up @@ -1934,7 +1975,7 @@ describe("GitHub release workflow safeguards", () => {
" esac",
"}",
].join("\n");
const result = spawnSync("bash", ["-c", `${mock}\n${script}`], {
const result = spawnSync(releaseTestBash, ["-c", `${mock}\n${script}`], {
encoding: "utf8",
env: {
...process.env,
Expand Down Expand Up @@ -1978,7 +2019,7 @@ describe("GitHub release workflow safeguards", () => {
"git() { return 0; }",
"sfw() { printf '%s\\n' '[\"0.1.1\",\"999999999999999999999999.0.0\"]'; }",
].join("\n");
const result = spawnSync("bash", ["-c", `${mocks}\n${script}`], {
const result = spawnSync(releaseTestBash, ["-c", `${mocks}\n${script}`], {
cwd: fileURLToPath(new URL("../../../", import.meta.url)),
encoding: "utf8",
env: {
Expand Down Expand Up @@ -2013,7 +2054,7 @@ describe("GitHub release workflow safeguards", () => {
"git() { return 0; }",
`sfw() { printf '%s\\n' '["0.1.0","${checkedOutVersion}"]'; }`,
].join("\n");
const result = spawnSync("bash", ["-c", `${mocks}\n${script}`], {
const result = spawnSync(releaseTestBash, ["-c", `${mocks}\n${script}`], {
cwd: fileURLToPath(new URL("../../../", import.meta.url)),
encoding: "utf8",
env: {
Expand Down Expand Up @@ -2100,7 +2141,7 @@ describe("GitHub release workflow safeguards", () => {
" esac",
"}",
].join("\n");
const result = spawnSync("bash", ["-c", `${mock}\n${script}`], {
const result = spawnSync(releaseTestBash, ["-c", `${mock}\n${script}`], {
encoding: "utf8",
env: {
...process.env,
Expand Down Expand Up @@ -2165,7 +2206,7 @@ describe("GitHub release workflow safeguards", () => {
" esac",
"}",
].join("\n");
const result = spawnSync("bash", ["-c", `${mocks}\n${script}`], {
const result = spawnSync(releaseTestBash, ["-c", `${mocks}\n${script}`], {
encoding: "utf8",
env: {
...process.env,
Expand Down Expand Up @@ -2209,7 +2250,7 @@ describe("GitHub release workflow safeguards", () => {
" esac",
"}",
].join("\n");
const result = spawnSync("bash", ["-c", `${mocks}\n${script}`], {
const result = spawnSync(releaseTestBash, ["-c", `${mocks}\n${script}`], {
encoding: "utf8",
env: {
...process.env,
Expand Down Expand Up @@ -2350,7 +2391,7 @@ describe("GitHub release workflow safeguards", () => {
" fi",
"}",
].join("\n");
const result = spawnSync("bash", [], {
const result = spawnSync(releaseTestBash, [], {
input: `${mocks}\n${script}`,
encoding: "utf8",
env: {
Expand Down Expand Up @@ -2516,24 +2557,28 @@ describe("GitHub release workflow safeguards", () => {
" esac",
"}",
].join("\n");
const result = spawnSync("bash", ["-c", `${mocks}\n${script}`], {
cwd: workspace,
encoding: "utf8",
env: {
...process.env,
GITHUB_OUTPUT: "/dev/null",
GITHUB_REPOSITORY: "test/codex-security",
MOCK_EXACT_PROVENANCE: exact ? "1" : "0",
MOCK_ORIGINAL_COMMIT: originalCommit,
MOCK_ORIGINAL_RUN_ID: "30481596228",
MOCK_RECOVERY_CONCLUSION: recoveryConclusion,
RELEASE_RUN_ID: releaseRun,
RELEASE_SHA: releaseCommit,
RELEASE_TAG: "npm-v0.1.2",
RELEASE_VERSION: "0.1.2",
const result = spawnSync(
releaseTestBash,
["-c", `${mocks}\n${script}`],
{
cwd: workspace,
encoding: "utf8",
env: {
...process.env,
GITHUB_OUTPUT: "/dev/null",
GITHUB_REPOSITORY: "test/codex-security",
MOCK_EXACT_PROVENANCE: exact ? "1" : "0",
MOCK_ORIGINAL_COMMIT: originalCommit,
MOCK_ORIGINAL_RUN_ID: "30481596228",
MOCK_RECOVERY_CONCLUSION: recoveryConclusion,
RELEASE_RUN_ID: releaseRun,
RELEASE_SHA: releaseCommit,
RELEASE_TAG: "npm-v0.1.2",
RELEASE_VERSION: "0.1.2",
},
timeout: 10_000,
},
timeout: 10_000,
});
);

expect(result.status).toBe(status);
if (status === 0) {
Expand Down Expand Up @@ -2828,7 +2873,7 @@ describe("GitHub release workflow safeguards", () => {
' command node "$@"',
"}",
].join("\n");
const result = spawnSync("bash", [], {
const result = spawnSync(releaseTestBash, [], {
input: `${mocks}\n${script}`,
encoding: "utf8",
env: {
Expand Down Expand Up @@ -2979,7 +3024,7 @@ describe("GitHub release workflow safeguards", () => {
" esac",
"}",
].join("\n");
const result = spawnSync("bash", ["-c", `${mock}\n${script}`], {
const result = spawnSync(releaseTestBash, ["-c", `${mock}\n${script}`], {
encoding: "utf8",
env: {
...process.env,
Expand Down Expand Up @@ -3052,7 +3097,7 @@ describe("GitHub release workflow safeguards", () => {
" esac",
"}",
].join("\n");
const result = spawnSync("bash", ["-c", `${mock}\n${script}`], {
const result = spawnSync(releaseTestBash, ["-c", `${mock}\n${script}`], {
encoding: "utf8",
env: {
...process.env,
Expand Down Expand Up @@ -3113,7 +3158,7 @@ describe("GitHub release workflow safeguards", () => {
" esac",
"}",
].join("\n");
const result = spawnSync("bash", ["-c", `${mock}\n${script}`], {
const result = spawnSync(releaseTestBash, ["-c", `${mock}\n${script}`], {
encoding: "utf8",
env: {
...process.env,
Expand Down Expand Up @@ -3190,7 +3235,7 @@ describe("GitHub release workflow safeguards", () => {
" esac",
"}",
].join("\n");
const result = spawnSync("bash", ["-c", `${mock}\n${script}`], {
const result = spawnSync(releaseTestBash, ["-c", `${mock}\n${script}`], {
encoding: "utf8",
env: {
...process.env,
Expand Down Expand Up @@ -3243,7 +3288,7 @@ describe("GitHub release workflow safeguards", () => {
" esac",
"}",
].join("\n");
const result = spawnSync("bash", ["-c", `${mock}\n${script}`], {
const result = spawnSync(releaseTestBash, ["-c", `${mock}\n${script}`], {
encoding: "utf8",
env: {
...process.env,
Expand Down