mirror of
https://github.com/morluto/rea.git
synced 2026-11-10 00:36:35 +00:00
fa0fcf35ce5b2c0fb51678f8ae40756eebbddf47
2
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
7a1d89a801 |
fix(javascript): reject child-process option literals Node refuses at the call site (#9594)
* fix(javascript): reject a spawn stdio string Node refuses at the call site
`node:child_process` validates a literal `stdio` string before it creates anything, so a
bad value throws from the call itself and no child process exists. The analysis reported the
raw string as `stdioMode` and kept the spawn.
Measured on Node 24.22.1:
| `stdio` | outcome |
| --- | --- |
| `"pipe"`, `"overlapped"`, `"inherit"`, `"ignore"` | child starts |
| `"ipc"`, `"PIPE"`, `"pipe "`, `"pipeline"`, `"stream"`, `"stdio"` | THREW `ERR_INVALID_ARG_VALUE` |
The accepted set is exact and case-sensitive, so it is a closed list rather than a pattern.
`"ipc"` is the interesting one: it is valid as an array element but refused as the scalar
shorthand, which is the shape a caller reaches for when they mean the array form.
`fork` differs on one value because it appends `"ipc"` to a string and splits it, so `""`
becomes the lone element `"ipc"` and is refused:
| call | outcome |
| --- | --- |
| `spawn(..., {stdio: ""})` | child starts |
| `fork(..., {stdio: ""})` | THREW `ERR_INVALID_ARG_VALUE` |
`exec` is left alone, because it spreads its options and validates none of them. A number,
boolean or object `stdio` is also refused by Node, but `stdioMode` already reports those as
`"dynamic"`; deciding them here would claim more than the reported mode explains, so only
the string case is decided.
18 cases, 9 failing before this commit. `src/domain/javascript`: 5106 to 5124 passing.
`tsc` 0; `build` 0; `npm run format:check` 0; `npm run lint` 0 errors.
* fix(javascript): reject a non-string cwd or argv0 Node refuses at the call site
The same call-site validation the `stdio` string gets applies to `cwd` and `argv0`:
Node checks them before the child exists, so a non-string literal throws
`ERR_INVALID_ARG_TYPE` and the analysis still reported a spawn.
Measured on Node 24.22.1, identical on `spawn`, `fork`, `execFile` and `exec`:
| `cwd` / `argv0` | outcome |
| --- | --- |
| `"/tmp"` / `"x"` | child starts |
| `null` | child starts |
| `5`, `0`, `true`, `{}`, `[]` | THREW `ERR_INVALID_ARG_TYPE` |
`env` is deliberately not in the set: Node accepts any `env` value, including `5` and
`"x"`, so a non-object `env` is not a call-site failure.
Only an exactly readable literal is decided; a binding, a call or a member read stays
undecided, because its value is not settled by this expression.
The test file is renamed from `spawn_stdio_literal` to `spawn_option_literals` because it
now covers all three members. 16 cases added; reverting this check fails 9 of them.
`src/domain/javascript`: 5124 to 5140 passing. `tsc` 0; `build` 0;
`npm run format:check` 0; `npm run lint` 0 errors.
* fix(javascript): read the stdio and path options by value, not by AST kind
Seven review findings, each measured on Node 24.22.1. All seven were real, and two of them
were removing real children.
**`execFile` does not forward `stdio`.** Async `execFile` never passes `options.stdio` to its
underlying `spawn`, so `execFile(process.execPath, ["-e", ""], {stdio: "bad"})` returns a
real child — `stdioMode` already forces it to `"default"`. The new filter rejected it anyway
and dropped the spawn plus its linked interactions. `execFile` is now exempt, like `exec`.
**A no-substitution template literal is the same string to Node.** `readExactJavaScriptLiteral`
already resolves it, but the filter tested `t.isStringLiteral`, so ``{stdio: `ipc`}`` kept a
spawn Node refuses while ``{cwd: `/tmp`}`` — a valid path — was rejected because the same
branch called `readExactJavaScriptLiteral` and treated any hit as a non-string. Both sides
now read the value and test its type:
| call | Node 24.22.1 |
| --- | --- |
| ``spawn(..., {stdio: `ipc`})`` | THREW `ERR_INVALID_ARG_VALUE` |
| ``spawn(..., {stdio: `pipe`})`` | child starts |
| ``spawn(..., {cwd: `/tmp`})`` | child starts |
| ``spawn(..., {argv0: `x`})`` | child starts |
**A shape the literal owner does not price still has a settled type.** `{cwd: 1n}`,
`{cwd: /x/}`, `{cwd: () => {}}`, `{cwd: class {}}` and `{cwd: new String("x")}` all throw
`ERR_INVALID_ARG_TYPE`, and none matched the previous object/array/boolean arms.
**The `fork` explanation was wrong.** Node's `stdioStringToArray` rejects `stdio: ""` with an
explicit check before anything is appended; it does not split the string and it never builds
an IPC-only array. The rejection was right, the reason was not, so the comment now states the
real rule.
44 cases; reverting the `execFile` exemption fails 1, reverting the value-based read fails 1,
and reverting the extended non-string arms fails 6.
`src/domain/javascript`: 5158 to 5168 passing. `tsc` 0; `build` 0;
`npm run format:check` 0; `npm run lint` 0 errors.
* fix(javascript): keep a path-shaped cwd that Node accepts
`cwd` is a path, so Node takes a byte array or a file `URL` there, not only a string. The
blanket `NewExpression` arm rejected every constructor for both members, which dropped real
children.
Measured on Node 24.22.1, identical on `spawn`, `fork`, `execFile` and `exec`:
| `cwd` | outcome |
| --- | --- |
| `new Uint8Array([47, 116, 109, 112])` | child starts |
| `new Buffer("/tmp")` | child starts |
| `new URL("file:///C:/tmp/")` | child starts |
| `new String("/tmp")`, `new Number(1)`, `new Foo("/tmp")` | THREW `ERR_INVALID_ARG_TYPE` |
`argv0` is different: it is an argument string only, so `new Uint8Array([120])` and
`new URL(...)` both throw there. `isPathConstructor` names the constructors that can produce
a path, and only `cwd` consults it.
`URL` stays undecided rather than accepted, because whether a file URL resolves is a
platform property: `new URL("file:///tmp/")` throws `ERR_INVALID_FILE_URL_PATH` on Windows
while a drive-qualified path does not. Syntax alone cannot settle that, so the answer is
left open instead of guessed.
8 cases added; reverting the arm fails 3 of them.
`src/domain/javascript`: 5168 to 5176 passing. `tsc` 0; `build` 0;
`npm run format:check` 0; `npm run lint` 0 errors.
* test(javascript): distinguish package scope in route fixtures
* test(apple): separate identity and refusal fixture groups
* fix(javascript): keep unresolved cwd constructors unknown
* refactor(javascript): name process option admission by its contract
---------
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
|
||
|
|
b46f4fcebd |
fix(javascript): preserve loader authority for exact suffixes (#9477)
* fix(javascript): require exact loader suffix case * fix(javascript): share exact loader mode across import resolution * test(process): align symlink fixture with filesystem checkpoints * test(javascript): normalize the module resolution oracle path separators * test(frida): assert the CLI spawn Evidence contract * test(mcp): use an unsupported analysis-view parent * test(browser): separate source-location line bounds from parity * fix(javascript): preserve uncertain loader provenance * test(javascript): cover uncertain require resolution * fix(javascript): retain conditional Electron evidence * fix(javascript): preserve timed semantic provenance * fix(javascript): retain conditional builtin effects * test(javascript): distinguish bundled host authority * fix(javascript): preserve nested loader invocation identity * test(javascript): qualify Electron fixture authority * fix(javascript): preserve loader invocation authority * fix(javascript): respect source order for resolver escapes * fix(javascript): check nested loader callable mutations * fix(javascript): retain conditional constructor requests * fix(reference): retain constructor loader relationships * fix(reference): follow nested loader callable paths * refactor(javascript): share callable mutation interpretation * fix(javascript): require exact package loader suffixes * refactor(javascript): unify conditional relation evidence * refactor(javascript): unify conditional node evidence * fix(javascript): retain unknown authority for mixed case sources * fix(javascript): preserve loader uncertainty for dotfiles * fix(reference): classify javascript suffix dotfiles * test(reference): cover suffix dotfiles through cli * fix(javascript): retain equivalent conditional built-in origins * fix(javascript): preserve wrapped resolver operation * fix(javascript): retain nested conditional built-in receivers * test(javascript): declare CommonJS in native addon fixtures * fix(javascript): retain wrapped resolver candidates * style: format merged native command schema * fix(javascript): preserve uncertain loader authority * test(javascript): require candidate preload evidence * test(javascript): cover reference loader member writes --------- Co-authored-by: ShuaixinHuang <1836656514@qq.com> |