Skip to content

fix: harden wrapper exits and matrix regressions#30

Open
ndycode wants to merge 2 commits intomainfrom
fix/wrapper-matrix-review-followups
Open

fix: harden wrapper exits and matrix regressions#30
ndycode wants to merge 2 commits intomainfrom
fix/wrapper-matrix-review-followups

Conversation

@ndycode
Copy link
Owner

@ndycode ndycode commented Mar 3, 2026

Summary

  • update scripts/codex.js to use structured main() flow and process.exitCode normalization for multi-auth paths
  • update scripts/codex-multi-auth.js to normalize non-integer exit codes to 1 while preserving integer exit propagation
  • remove stale matrix runner plumbing and align matrix execution with current CLI args in scripts/test-model-matrix.js
  • expand regression coverage for wrapper exit behavior, Windows shim guard stability, matrix command args, and .cmd fallback paths

Risk Notes

  • low runtime risk: wrapper change is limited to exit handling and startup guard behavior
  • matrix harness changes are scoped to script utilities and tests

Validation Evidence

  • npm test from D:\backup\projects\projects-nobuild\repo-projects\codex-multi-auth passed (100 files, 2325 tests)
  • npx vitest run test/test-model-matrix-script.test.ts test/codex-bin-wrapper.test.ts test/codex-multi-auth-bin-wrapper.test.ts passed (3 files, 20 tests)

Worktree

  • worktree path: D:\backup\projects\projects-nobuild\repo-projects\codex-multi-auth-wt-wrapper-matrix-review
  • base: origin/main at 46510fed4d25945f43c61226976ac59698d24a2a
  • branch: fix/wrapper-matrix-review-followups

note: greptile review for oc-chatgpt-multi-auth. cite files like lib/foo.ts:123. confirm regression tests + windows concurrency/token redaction coverage.

Greptile Summary

hardens wrapper exit handling and adds windows filesystem concurrency guards to survive antivirus locks and npm shim takeovers.

key changes:

  • adds runWithWindowsFsRetry with exponential backoff for EBUSY/EPERM/EACCES errors (addresses previous review comment about missing retry logic)
  • wraps all writeFileSync and mkdirSync calls in retry guards per project convention (scripts/repo-hygiene.js, scripts/copy-oauth-success.js)
  • restructures scripts/codex.js with main() flow and process.exitCode normalization
  • normalizes non-integer exit codes to 1 in scripts/codex-multi-auth.js while preserving integer propagation
  • removes stale matrix portStart plumbing, aligns with current cli args
  • adds regression tests for windows shim stability, exit propagation, matrix args, .cmd fallback paths

windows fs safety:
retry logic defends against antivirus file locks during shim writes. powershell profile upsert has benign toctou race (read-modify-write without lock), but acceptable since both processes write identical guard blocks. profile corruption risk is minimal (millisecond window, idempotent content).

test coverage:

  • test/codex-bin-wrapper.test.ts: windows shim guard installation, invocation-derived shim preference over PATH decoys, numeric-string exit code propagation
  • test/codex-multi-auth-bin-wrapper.test.ts: integer exit preservation, non-integer normalization
  • test/test-model-matrix-script.test.ts: .cmd parser fallback, matrix args with json/git-check-skip/variant config

missing coverage:
no tests for concurrent wrapper invocations or simulated EBUSY/EPERM failures (retry logic tested implicitly via CI windows runs).

Confidence Score: 4/5

  • safe to merge with low risk. addresses previous filesystem retry comment, adds structured exit handling, comprehensive test coverage.
  • windows fs retry guards properly handle EBUSY/EPERM/EACCES per project convention. exit normalization is idempotent and safe. toctou race in powershell profile upsert is benign (same content written). missing tests for concurrent invocations and simulated fs errors, but existing coverage validates happy paths thoroughly.
  • scripts/codex.js requires review of retry logic and shim installation flow. other files are straightforward.

Important Files Changed

Filename Overview
scripts/codex.js adds windows fs retry guards and structured main() with exit normalization. retry logic addresses previous EBUSY/EPERM comment. minor toctou race in powershell profile upsert is benign.
scripts/codex-multi-auth.js adds cli version hydration and exit code normalization. clean, minimal change.
scripts/test-model-matrix.js refactors executeModelCase to extract buildModelCaseArgs, removes stale portStart param. clean alignment with current cli args.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    Start([codex wrapper invoked]) --> Hydrate[hydrate CLI version env]
    Hydrate --> CheckPlatform{windows?}
    CheckPlatform -->|yes| InstallGuards[ensureWindowsShellShimGuards]
    CheckPlatform -->|no| ParseArgs
    InstallGuards --> RetryBatch[writeFileSyncWithWindowsRetry<br/>codex.bat/cmd/ps1]
    RetryBatch -->|EBUSY/EPERM| Backoff[exponential backoff<br/>50ms, 100ms, 200ms]
    Backoff --> RetryBatch
    RetryBatch -->|success| ProfileGuard[upsertPowerShellProfileGuard]
    ProfileGuard --> ParseArgs[parse args]
    ParseArgs --> CheckBypass{bypass or<br/>!shouldHandle<br/>MultiAuth?}
    CheckBypass -->|no bypass,<br/>handle multi-auth| LoadMulti[loadRunCodexMultiAuthCli]
    CheckBypass -->|bypass or<br/>forward| FindReal[resolveRealCodexBin]
    LoadMulti --> RunMulti[runCodexMultiAuthCli]
    RunMulti --> NormalizeMulti[normalizeExitCode]
    NormalizeMulti --> TopNormalize
    FindReal --> AutoSync[autoSyncManagerActiveSelection]
    AutoSync --> Forward[forwardToRealCodex]
    Forward --> TopNormalize[normalizeExitCode at top level]
    TopNormalize --> Exit([process.exitCode set])
Loading

Last reviewed commit: 8ae183f

Context used:

  • Rule from dashboard - What: Every code change must explain how it defends against Windows filesystem concurrency bugs and ... (source)

Co-authored-by: Codex <noreply@openai.com>
@ndycode ndycode closed this Mar 3, 2026
@ndycode ndycode deleted the fix/wrapper-matrix-review-followups branch March 3, 2026 12:12
Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

6 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

@ndycode ndycode restored the fix/wrapper-matrix-review-followups branch March 3, 2026 12:18
@ndycode ndycode reopened this Mar 3, 2026
Co-authored-by: Codex <noreply@openai.com>
@coderabbitai
Copy link

coderabbitai bot commented Mar 3, 2026

📝 Walkthrough

This PR hardens wrapper exit handling and matrix test regressions through refactored scripts, Windows shell guard infrastructure, and expanded test coverage. Severity: Medium (maintenance/hardening). Risk is low per the author's assessment; all 2,325 existing tests pass locally, and 20 new regression tests were added across 3 test files covering exit code normalization, Windows shim behavior, and matrix command args. A follow-up commit explicitly addresses a reviewable concern—adding filesystem retry guards (EBUSY/EPERM/EACCES) for Windows shim file writes to align with project conventions.

Key architectural changes:

  • Exit normalization: scripts/codex-multi-auth.js normalizes non-integer exit codes to 1 while preserving integer codes; also adds version environment hydration.
  • Windows shell guards: scripts/codex.js (~374 lines added) introduces shim guard installation (batch, cmd, PowerShell) with filesystem resilience helpers and profile guard insertion; runs at startup before CLI processing.
  • Matrix refactor: scripts/test-model-matrix.js extracts buildModelCaseArgs() helper, removes stale portStart plumbing, adds skip-git-repo-check flag, and exports a test-facing helper for argument verification.

Test additions verify integer exit code propagation, non-integer normalization, Windows shim precedence over PATH decoys, and .cmd fallback to shell mode. No public API changes or data-loss concerns identified.

Walkthrough

adds Windows-specific filesystem resilience and shell-guard infrastructure to the Codex multi-auth CLI wrapper. CLI version is hydrated into environment at startup, guards are installed before command processing, and exit codes are properly propagated through the wrapper layers.

Changes

Cohort / File(s) Summary
CLI Version Hydration
scripts/codex-multi-auth.js, scripts/codex.js
Reads package.json via createRequire and sets CODEX_MULTI_AUTH_CLI_VERSION env var at startup. Both files implement this with try/catch fallback.
Windows Shell Guard Infrastructure
scripts/codex.js
Introduces filesystem helpers with retry logic (write/mkdir), batch/cmd/PowerShell shim guards, detection/installation logic, and PowerShell profile mutations to route multi-auth through shims. Runs ensureWindowsShellShimGuards() before normal command processing.
Model Matrix Test Argument Building
scripts/test-model-matrix.js
Extracts token and argument construction into buildModelCaseArgs(). Adds test-facing __buildModelCaseArgsForTests export. Consolidates server cleanup state (stopCodexServersQueue, spawnedCodexPids) at module top level.
Windows Guard Test Coverage
test/codex-bin-wrapper.test.ts
New helper runWrapperScript for custom environment execution. Validates Windows shell guard installation, invocation-derived shim precedence over PATH, and numeric exit code propagation from multi-auth CLI.
Multi-Auth Wrapper Integration Tests
test/codex-multi-auth-bin-wrapper.test.ts
New test suite verifying integer exit codes propagate directly and non-integer codes normalize to 1. Includes temporary fixture creation, mock dist/lib/codex-manager.js, and retryable directory cleanup.
Model Matrix Argument Tests
test/test-model-matrix-script.test.ts
New tests for resolveCodexExecutable shell mode fallback and __buildModelCaseArgsForTests covering JSON output, git check skip, and variant configurations with -c flags.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

the Windows shell guard infrastructure in scripts/codex.js:+374/-2 introduces dense logic across filesystem helpers, PowerShell profile mutations, and shim detection. the refactoring of test model matrix arguments requires understanding the new control flow. distributed test coverage across three new test suites adds scope. however, changes are mostly additive with limited cross-file interdependencies.

flagged concerns:

  • scripts/codex.js: PowerShell profile writes and shim guard installation lack concurrency protection. parallel invocations could corrupt profile or leave guards in partial states.
  • scripts/test-model-matrix.js: portStart parameter removal from scenario calls—verify existing test scenarios don't depend on specific port allocation.
  • test/codex-multi-auth-bin-wrapper.test.ts: removeDirectoryWithRetry handles EBUSY/EPERM, but Windows has other transient FS conditions (file locks, antivirus scans) that may not retry sufficiently.
  • scripts/codex.js: hydrateCliVersionEnv() catches all errors silently—no regression tests verify behavior when package.json is malformed or unreadable.
  • test/codex-bin-wrapper.test.ts: Windows shim guard tests assume consistent filesystem ordering and timing. no tests cover concurrent wrapper invocations.

Suggested labels

bug

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description covers summary, changes, and validation evidence with test results. However, the docs/governance checklist and risk/rollback sections are missing or incomplete per the template. Complete the docs/governance checklist, explicitly state risk level and rollback plan, and verify README/docs alignment if behavior is user-visible.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The PR title follows conventional commits format with type fix and a clear, concise summary under 72 chars describing the main changes to wrapper exits and matrix regressions.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/wrapper-matrix-review-followups

Tip

Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs).
Share your feedback on Discord.


Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@scripts/codex-multi-auth.js`:
- Around line 17-18: The wrapper currently treats only integer-typed values as
valid (using Number.isInteger on exitCode), so numeric strings like "7" are
downgraded to 1; fix this in the codex-multi-auth wrapper by coercing the
returned exitCode from runCodexMultiAuthCli into a Number first (e.g., const
numeric = Number(exitCode)) and then setting process.exitCode to numeric if
Number.isInteger(numeric) otherwise fallback to 1; update the logic around the
exitCode variable and the process.exitCode assignment to mirror the
normalization used in codex.js while referencing runCodexMultiAuthCli and the
exitCode variable.

In `@test/codex-bin-wrapper.test.ts`:
- Around line 188-289: These two Windows-only tests ("installs Windows codex
shell guards to survive shim takeover" and "prefers invocation-derived shim
directory over PATH-decoy shim entries") currently return early on non-win32 and
can pass with zero assertions; add a guard to force a failure (or explicit skip)
when not running on Windows by inserting expect.hasAssertions() at the top of
each test (before the current if (process.platform !== "win32") return;) so a
non-Windows run cannot silently succeed, or alternatively replace the
early-return with an explicit test skip (vitest.test.skip for the whole case) —
update the test bodies that call runWrapper and runWrapperScript accordingly so
the unique test names and calls to runWrapper/runWrapperScript remain covered.

In `@test/codex-multi-auth-bin-wrapper.test.ts`:
- Around line 14-20: The isRetriableFsError function currently returns true only
for "EBUSY" and "EPERM" and should also treat "EACCES" as retriable to handle
transient Windows FS locks; update the function (isRetriableFsError) to include
code === "EACCES" in the return condition (or add it to the list of retriable
codes) so cleanup tests become deterministic on Windows while keeping the same
type-guard logic and error shape check.
- Around line 91-107: Add a regression test that covers the numeric-string exit
path: create a new test in test/codex-multi-auth-bin-wrapper.test.ts that
mirrors the existing non-integer test but writes codex-manager.js to export
runCodexMultiAuthCli returning the string "7" (instead of a number or
non-integer), then call runWrapper(fixtureRoot, ["auth","status"]) and assert
result.status is 7; this ensures the behavior referenced at
lib/scripts/codex-multi-auth.js:18 correctly propagates numeric-string exits.
Ensure you use createWrapperFixture and runWrapper just like the existing tests
so it remains deterministic under vitest.

ℹ️ Review info

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between d36b04f and 8ae183f.

📒 Files selected for processing (6)
  • scripts/codex-multi-auth.js
  • scripts/codex.js
  • scripts/test-model-matrix.js
  • test/codex-bin-wrapper.test.ts
  • test/codex-multi-auth-bin-wrapper.test.ts
  • test/test-model-matrix-script.test.ts
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Greptile Review
🧰 Additional context used
📓 Path-based instructions (1)
test/**

⚙️ CodeRabbit configuration file

tests must stay deterministic and use vitest. demand regression cases that reproduce concurrency bugs, token refresh races, and windows filesystem behavior. reject changes that mock real secrets or skip assertions.

Files:

  • test/test-model-matrix-script.test.ts
  • test/codex-multi-auth-bin-wrapper.test.ts
  • test/codex-bin-wrapper.test.ts
🧬 Code graph analysis (4)
scripts/codex-multi-auth.js (1)
scripts/codex.js (4)
  • require (13-13)
  • require (78-78)
  • pkg (14-14)
  • version (15-15)
test/codex-multi-auth-bin-wrapper.test.ts (2)
scripts/codex.js (3)
  • code (209-209)
  • code (222-222)
  • attempt (218-218)
lib/utils.ts (1)
  • sleep (65-67)
scripts/codex.js (2)
scripts/codex-multi-auth.js (3)
  • require (7-7)
  • pkg (8-8)
  • version (9-9)
lib/utils.ts (1)
  • sleep (65-67)
test/codex-bin-wrapper.test.ts (1)
scripts/codex.js (4)
  • shimDir (271-271)
  • codexBatchPath (446-446)
  • scriptDir (86-86)
  • scriptDir (265-265)
🔇 Additional comments (7)
scripts/codex-multi-auth.js (1)

6-15: good best-effort version hydration.

the startup env hydration is safe and non-blocking in lib/scripts/codex-multi-auth.js:6.

scripts/test-model-matrix.js (2)

133-182: cleanup serialization looks solid.

the queueing in lib/scripts/test-model-matrix.js:176 prevents overlapping pid cleanup and reduces race risk for concurrent runs.


247-269: good extraction for model-case arg construction.

lib/scripts/test-model-matrix.js:247 cleanly centralizes args/token building and supports deterministic verification through the test hook.

test/test-model-matrix-script.test.ts (1)

66-119: nice regression coverage expansion here.

the new assertions in test/test-model-matrix-script.test.ts:66 and test/test-model-matrix-script.test.ts:91 validate fallback behavior and command-arg construction directly.

test/codex-bin-wrapper.test.ts (1)

348-367: good regression for numeric-string exit propagation.

the assertion in test/codex-bin-wrapper.test.ts:348 closes an important wrapper-exit edge case.

scripts/codex.js (2)

194-243: windows fs retry hardening is well done.

the retry wrapper in lib/scripts/codex.js:213 covers transient lock codes and uses bounded backoff, which is the right guardrail for shim/profile writes.


516-553: startup sequencing for guard install is strong.

running guard installation before command routing in lib/scripts/codex.js:550 reduces post-update shim drift and keeps wrapper behavior stable.

Comment on lines 17 to 18
const exitCode = await runCodexMultiAuthCli(process.argv.slice(2));
process.exitCode = Number.isInteger(exitCode) ? exitCode : 1;
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

fix numeric-string exit propagation in this wrapper.

lib/scripts/codex-multi-auth.js:18 treats only integer-typed numbers as valid, so "7" is downgraded to 1. this breaks wrapper exit semantics and diverges from the normalization pattern used in lib/scripts/codex.js:183.

proposed fix
-const exitCode = await runCodexMultiAuthCli(process.argv.slice(2));
-process.exitCode = Number.isInteger(exitCode) ? exitCode : 1;
+const exitCode = await runCodexMultiAuthCli(process.argv.slice(2));
+const parsedExitCode =
+	typeof exitCode === "number" && Number.isInteger(exitCode)
+		? exitCode
+		: Number(exitCode);
+process.exitCode = Number.isInteger(parsedExitCode) ? parsedExitCode : 1;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const exitCode = await runCodexMultiAuthCli(process.argv.slice(2));
process.exitCode = Number.isInteger(exitCode) ? exitCode : 1;
const exitCode = await runCodexMultiAuthCli(process.argv.slice(2));
const parsedExitCode =
typeof exitCode === "number" && Number.isInteger(exitCode)
? exitCode
: Number(exitCode);
process.exitCode = Number.isInteger(parsedExitCode) ? parsedExitCode : 1;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/codex-multi-auth.js` around lines 17 - 18, The wrapper currently
treats only integer-typed values as valid (using Number.isInteger on exitCode),
so numeric strings like "7" are downgraded to 1; fix this in the
codex-multi-auth wrapper by coercing the returned exitCode from
runCodexMultiAuthCli into a Number first (e.g., const numeric =
Number(exitCode)) and then setting process.exitCode to numeric if
Number.isInteger(numeric) otherwise fallback to 1; update the logic around the
exitCode variable and the process.exitCode assignment to mirror the
normalization used in codex.js while referencing runCodexMultiAuthCli and the
exitCode variable.

Comment on lines +188 to +289
it("installs Windows codex shell guards to survive shim takeover", () => {
if (process.platform !== "win32") {
return;
}

const fixtureRoot = createWrapperFixture();
const fakeBin = createFakeCodexBin(fixtureRoot);
const shimDir = join(fixtureRoot, "shim-bin");
mkdirSync(shimDir, { recursive: true });
writeFileSync(
join(shimDir, "codex-multi-auth.cmd"),
"@ECHO OFF\r\nREM fixture codex-multi-auth shim\r\n",
"utf8",
);
writeFileSync(
join(shimDir, "codex.cmd"),
'@ECHO OFF\r\necho "%dp0%\\node_modules\\@openai\\codex\\bin\\codex.js"\r\n',
"utf8",
);
writeFileSync(
join(shimDir, "codex.ps1"),
'Write-Output "$basedir/node_modules/@openai/codex/bin/codex.js"' + "\r\n",
"utf8",
);

const result = runWrapper(fixtureRoot, ["--version"], {
CODEX_MULTI_AUTH_REAL_CODEX_BIN: fakeBin,
CODEX_MULTI_AUTH_WINDOWS_BATCH_SHIM_GUARD: "1",
PATH: `${shimDir}${delimiter}${process.env.PATH ?? ""}`,
USERPROFILE: fixtureRoot,
HOME: fixtureRoot,
});
expect(result.status).toBe(0);

const codexBatchPath = join(shimDir, "codex.bat");
expect(readFileSync(codexBatchPath, "utf8")).toContain(
"codex-multi-auth windows shim guardian v1",
);
const codexCmdPath = join(shimDir, "codex.cmd");
expect(readFileSync(codexCmdPath, "utf8")).toContain(
"codex-multi-auth windows shim guardian v1",
);
expect(readFileSync(codexCmdPath, "utf8")).toContain(
"node_modules\\codex-multi-auth\\scripts\\codex.js",
);
const codexPs1Path = join(shimDir, "codex.ps1");
expect(readFileSync(codexPs1Path, "utf8")).toContain(
"codex-multi-auth windows shim guardian v1",
);
expect(readFileSync(codexPs1Path, "utf8")).toContain(
"node_modules/codex-multi-auth/scripts/codex.js",
);
const pwshProfilePath = join(
fixtureRoot,
"Documents",
"PowerShell",
"Microsoft.PowerShell_profile.ps1",
);
expect(readFileSync(pwshProfilePath, "utf8")).toContain(
"# >>> codex-multi-auth shell guard >>>",
);
expect(readFileSync(pwshProfilePath, "utf8")).toContain("CodexMultiAuthShim");
});

it("prefers invocation-derived shim directory over PATH-decoy shim entries", () => {
if (process.platform !== "win32") {
return;
}

const fixtureRoot = mkdtempSync(join(tmpdir(), "codex-wrapper-invoke-fixture-"));
createdDirs.push(fixtureRoot);
const globalShimDir = join(fixtureRoot, "global-bin");
const scriptDir = join(globalShimDir, "node_modules", "codex-multi-auth", "scripts");
mkdirSync(scriptDir, { recursive: true });
copyFileSync(join(repoRootDir, "scripts", "codex.js"), join(scriptDir, "codex.js"));
copyFileSync(join(repoRootDir, "scripts", "codex-routing.js"), join(scriptDir, "codex-routing.js"));
writeFileSync(
join(globalShimDir, "codex-multi-auth.cmd"),
"@ECHO OFF\r\nREM real shim\r\n",
"utf8",
);
const decoyShimDir = join(fixtureRoot, "decoy-bin");
mkdirSync(decoyShimDir, { recursive: true });
writeFileSync(
join(decoyShimDir, "codex-multi-auth.cmd"),
"@ECHO OFF\r\nREM decoy shim\r\n",
"utf8",
);
const fakeBin = createFakeCodexBin(fixtureRoot);
const scriptPath = join(scriptDir, "codex.js");
const result = runWrapperScript(scriptPath, ["--version"], {
CODEX_MULTI_AUTH_REAL_CODEX_BIN: fakeBin,
PATH: `${decoyShimDir}${delimiter}${globalShimDir}${delimiter}${process.env.PATH ?? ""}`,
USERPROFILE: fixtureRoot,
HOME: fixtureRoot,
});
expect(result.status).toBe(0);
expect(readFileSync(join(globalShimDir, "codex.bat"), "utf8")).toContain(
"codex-multi-auth windows shim guardian v1",
);
expect(() => readFileSync(join(decoyShimDir, "codex.bat"), "utf8")).toThrow();
});
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

avoid silent no-assert passes for windows-only tests.

test/codex-bin-wrapper.test.ts:189 and test/codex-bin-wrapper.test.ts:253 return early on non-windows, so these tests can pass with zero assertions. that leaves lib/scripts/codex.js:516 windows guard behavior unprotected on common runners.

suggested test-shape update
-it("installs Windows codex shell guards to survive shim takeover", () => {
-	if (process.platform !== "win32") {
-		return;
-	}
+it.skipIf(process.platform !== "win32")("installs Windows codex shell guards to survive shim takeover", () => {
   // ...
 });

-it("prefers invocation-derived shim directory over PATH-decoy shim entries", () => {
-	if (process.platform !== "win32") {
-		return;
-	}
+it.skipIf(process.platform !== "win32")("prefers invocation-derived shim directory over PATH-decoy shim entries", () => {
   // ...
 });

also make a required windows ci lane for this suite so these regressions are always exercised.

As per coding guidelines "test/**: tests must stay deterministic and use vitest. demand regression cases that reproduce concurrency bugs, token refresh races, and windows filesystem behavior. reject changes that mock real secrets or skip assertions."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/codex-bin-wrapper.test.ts` around lines 188 - 289, These two
Windows-only tests ("installs Windows codex shell guards to survive shim
takeover" and "prefers invocation-derived shim directory over PATH-decoy shim
entries") currently return early on non-win32 and can pass with zero assertions;
add a guard to force a failure (or explicit skip) when not running on Windows by
inserting expect.hasAssertions() at the top of each test (before the current if
(process.platform !== "win32") return;) so a non-Windows run cannot silently
succeed, or alternatively replace the early-return with an explicit test skip
(vitest.test.skip for the whole case) — update the test bodies that call
runWrapper and runWrapperScript accordingly so the unique test names and calls
to runWrapper/runWrapperScript remain covered.

Comment on lines +14 to +20
function isRetriableFsError(error: unknown): boolean {
if (!error || typeof error !== "object" || !("code" in error)) {
return false;
}
const { code } = error as { code?: unknown };
return code === "EBUSY" || code === "EPERM";
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

include eacces in retriable cleanup errors.

test/codex-multi-auth-bin-wrapper.test.ts:19 omits EACCES, which is a common transient windows fs lock code and can make cleanup flaky.

proposed fix
-	return code === "EBUSY" || code === "EPERM";
+	return code === "EBUSY" || code === "EPERM" || code === "EACCES";

As per coding guidelines "test/**: tests must stay deterministic and use vitest. demand regression cases that reproduce concurrency bugs, token refresh races, and windows filesystem behavior. reject changes that mock real secrets or skip assertions."

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
function isRetriableFsError(error: unknown): boolean {
if (!error || typeof error !== "object" || !("code" in error)) {
return false;
}
const { code } = error as { code?: unknown };
return code === "EBUSY" || code === "EPERM";
}
function isRetriableFsError(error: unknown): boolean {
if (!error || typeof error !== "object" || !("code" in error)) {
return false;
}
const { code } = error as { code?: unknown };
return code === "EBUSY" || code === "EPERM" || code === "EACCES";
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/codex-multi-auth-bin-wrapper.test.ts` around lines 14 - 20, The
isRetriableFsError function currently returns true only for "EBUSY" and "EPERM"
and should also treat "EACCES" as retriable to handle transient Windows FS
locks; update the function (isRetriableFsError) to include code === "EACCES" in
the return condition (or add it to the list of retriable codes) so cleanup tests
become deterministic on Windows while keeping the same type-guard logic and
error shape check.

Comment on lines +91 to +107
it("normalizes non-integer exit codes to 1", () => {
const fixtureRoot = createWrapperFixture();
const distLibDir = join(fixtureRoot, "dist", "lib");
mkdirSync(distLibDir, { recursive: true });
writeFileSync(
join(distLibDir, "codex-manager.js"),
[
"export async function runCodexMultiAuthCli() {",
'\treturn "ok";',
"}",
].join("\n"),
"utf8",
);

const result = runWrapper(fixtureRoot, ["auth", "status"]);
expect(result.status).toBe(1);
});
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

add a numeric-string exit regression test here.

this suite validates integer and non-integer exits, but it misses the numeric-string path that should propagate (e.g. "7"). this gap leaves the behavior in lib/scripts/codex-multi-auth.js:18 unguarded.

proposed test addition
+	it("propagates numeric-string exit codes", () => {
+		const fixtureRoot = createWrapperFixture();
+		const distLibDir = join(fixtureRoot, "dist", "lib");
+		mkdirSync(distLibDir, { recursive: true });
+		writeFileSync(
+			join(distLibDir, "codex-manager.js"),
+			[
+				"export async function runCodexMultiAuthCli() {",
+				'\treturn "7";',
+				"}",
+			].join("\n"),
+			"utf8",
+		);
+
+		const result = runWrapper(fixtureRoot, ["auth", "status"]);
+		expect(result.status).toBe(7);
+	});

As per coding guidelines "test/**: tests must stay deterministic and use vitest. demand regression cases that reproduce concurrency bugs, token refresh races, and windows filesystem behavior. reject changes that mock real secrets or skip assertions."

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
it("normalizes non-integer exit codes to 1", () => {
const fixtureRoot = createWrapperFixture();
const distLibDir = join(fixtureRoot, "dist", "lib");
mkdirSync(distLibDir, { recursive: true });
writeFileSync(
join(distLibDir, "codex-manager.js"),
[
"export async function runCodexMultiAuthCli() {",
'\treturn "ok";',
"}",
].join("\n"),
"utf8",
);
const result = runWrapper(fixtureRoot, ["auth", "status"]);
expect(result.status).toBe(1);
});
it("normalizes non-integer exit codes to 1", () => {
const fixtureRoot = createWrapperFixture();
const distLibDir = join(fixtureRoot, "dist", "lib");
mkdirSync(distLibDir, { recursive: true });
writeFileSync(
join(distLibDir, "codex-manager.js"),
[
"export async function runCodexMultiAuthCli() {",
'\treturn "ok";',
"}",
].join("\n"),
"utf8",
);
const result = runWrapper(fixtureRoot, ["auth", "status"]);
expect(result.status).toBe(1);
});
it("propagates numeric-string exit codes", () => {
const fixtureRoot = createWrapperFixture();
const distLibDir = join(fixtureRoot, "dist", "lib");
mkdirSync(distLibDir, { recursive: true });
writeFileSync(
join(distLibDir, "codex-manager.js"),
[
"export async function runCodexMultiAuthCli() {",
'\treturn "7";',
"}",
].join("\n"),
"utf8",
);
const result = runWrapper(fixtureRoot, ["auth", "status"]);
expect(result.status).toBe(7);
});
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/codex-multi-auth-bin-wrapper.test.ts` around lines 91 - 107, Add a
regression test that covers the numeric-string exit path: create a new test in
test/codex-multi-auth-bin-wrapper.test.ts that mirrors the existing non-integer
test but writes codex-manager.js to export runCodexMultiAuthCli returning the
string "7" (instead of a number or non-integer), then call
runWrapper(fixtureRoot, ["auth","status"]) and assert result.status is 7; this
ensures the behavior referenced at lib/scripts/codex-multi-auth.js:18 correctly
propagates numeric-string exits. Ensure you use createWrapperFixture and
runWrapper just like the existing tests so it remains deterministic under
vitest.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant