google-gemini / google-gemini/gemini-cli
bug: shell exit-code mapping checks exitCode !== undefined where the value type is number | null
- Dominant language
- TypeScript
- Stars
- 107k
- Forks
- 14.6k
- Avg merge
- 2d 3h
- Merged PRs (30d)
- 45
Description
## What happened?
The shell tool's exit-status mapping checks `result.exitCode !== undefined`, but the shell execution result type declares `exitCode: number | null` (`packages/core/src/services/executionLifecycleService.ts:23`). Since `null !== undefined` is `true`, every signal-killed process (`exitCode === null`) enters the sandbox-denial heuristic even when that wasn't intended, while a hypothetical `undefined` exit code would be wrongly skipped. Three other sites in the same function use the correct `!== null` guard (e.g., lines ~812, ~856, ~1038), proving the inconsistency.
## Affected code
`packages/core/src/tools/shell.ts:866-869`:
```ts
if (
!!result.error ||
!!result.signal ||
(result.exitCode !== undefined && result.exitCode !== 0) ||
result.aborted
) {
```
## How can this be reproduced?
Run a command that gets terminated by a signal without a captured `signal` string (e.g., external kill of the child): `result.exitCode === null` passes the broken guard and the denial-detection branch executes spuriously on every such run.
## What did you expect to happen?
Consistent null-handling with the sibling checks in the same function.
## Impact
Low per-run impact but wrong semantics in an approval/denial heuristic path — the exact kind of inconsistency that becomes a real bug when the heuristic's behavior changes.
## Suggested direction
Change the guard to `(result.exitCode !== null && result.exitCode !== 0)` to match the rest of the file.
---
*Found by source audit on current `main` (commit `5411f113c`); platform-independent. No open issue/PR covering this was found (searched: shell exitCode null).*
Contributor guide
Research direction
Start with packages/core/src/tools/shell.ts around lines 866-869, then check the exitCode type in packages/core/src/services/executionLifecycleService.ts and the sibling null checks in the same function. Update the inconsistent guard to match the declared number-or-null type and verify that signal-killed results no longer enter this branch solely because exitCode is null.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- cli
- Issue type
- Bug
- Difficulty
- 1/5
- Estimated time
- Under an hour
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 90/100