Skip to content

util: validate parseArgs negation targets in strict mode - #67086

Open
JoaoMarcos44 wants to merge 5 commits into
nodejs:mainfrom
JoaoMarcos44:fix-parse-args-allow-negative
Open

JoaoMarcos44 wants to merge 5 commits into
nodejs:mainfrom
JoaoMarcos44:fix-parse-args-allow-negative

Conversation

@JoaoMarcos44

@JoaoMarcos44 JoaoMarcos44 commented Oct 28, 2026 •

Copy link
Copy Markdown

With strict: true and allowNegative: true, an explicitly declared negative boolean can overwrite a string option with false or write to an undeclared destination. This change validates those cases while preserving supported boolean negation and short aliases.

The configuration conflict check runs in the existing per-option validation loop, reusing the validated optionType. It rejects an enumerable own no-X: boolean declaration paired with an own X: string option, even with args: []. A separate usage check rejects an applied negation whose destination is not a declared boolean. An isolated no-alpha declaration can still be negated through --no-no-alpha.

storeOption() is unchanged. No new public option, dependency, cache, or abstraction is introduced. The additional pass over own property names has been removed.

Compatibility

  • The configuration check follows the existing loop's enumeration scope. A non-enumerable negative declaration is not rejected while unused, but applying it to a string destination is still rejected by the usage check. An own non-enumerable destination is checked when the negative declaration is enumerable.
  • A conflict can be reported before an invalid declaration that appears later. Each negative declaration's own fields are validated before checking its conflict.
  • The negative declaration's validated type is reused; the destination is still read. This change does not guarantee getter or proxy evaluation counts.
  • strict: false, allowNegative: false, valid boolean aliases, tokens, defaults, multiple, and literal negative string options retain their behavior in the covered cases.

Validation

  • 176/176 tests passed on Node v22.16.0 and v24.22.1, including CLI cases, with no skips.
  • All 117 tests from the upstream base are retained unchanged. Added coverage exercises conflicting declarations, missing destinations, invalid target configurations, aliases, double negation, and the enumeration behavior described above.
  • Against the base module, the same suite produced 156 passes and 20 expected regression failures, checked by name and count. Against the previous PR revision, it produced 172 passes and the four expected differences.
  • Repository ESLint (with the Windows linebreak-style exception), Markdown lint, and git diff --check passed.

The full parseArgs test entry point and original common helpers ran against the edited JavaScript module loaded with the installed runtimes' internals. These results are not from a rebuilt Node binary. A native build and the official CI remain pending.

AI assistance: Codex assisted with implementation, tests, review, and documentation.

Fixes: #67085

@nodejs-github-bot nodejs-github-bot added needs-ci PRs that need a full CI run. util Issues and PRs related to the built-in util module. labels Oct 28, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Welcome to Node.js, and thank you for your first contribution!

Before review, please take a moment to read:

Please make sure every commit is signed off. For a first pull request, GitHub Actions require collaborator approval and Jenkins CI must be started by a collaborator or triager, so an initial wait is normal.

@JoaoMarcos44
JoaoMarcos44 force-pushed the fix-parse-args-allow-negative branch from 10ec1ef to 287de8b Compare October 28, 2026 17:17
@JoaoMarcos44
JoaoMarcos44 requested a review from a team as a code owner October 28, 2026 17:17
@JoaoMarcos44
JoaoMarcos44 force-pushed the fix-parse-args-allow-negative branch 2 times, most recently from 9b0f403 to 1365d32 Compare October 28, 2026 18:16
When `allowNegative` is enabled in `util.parseArgs()`, `storeOption()`
previously stripped the `no-` prefix unconditionally, even when the
option itself was explicitly defined in `options` (for example
`'no-logfile'` or `'no-warnings'`).

Check `!ObjectHasOwn(options, longOption)` before stripping `no-`,
matching `checkOptionUsage()`, and avoid negating configured `'string'`
options or `'__proto__'` in `strict: false` mode.

Fixes: nodejs#67085
Signed-off-by: JoaoMarcos44 <joaomarcosdias444@gmail.com>
@JoaoMarcos44
JoaoMarcos44 force-pushed the fix-parse-args-allow-negative branch from 1365d32 to 956b79a Compare October 28, 2026 18:17
@ljharb

ljharb commented Oct 28, 2026

Copy link
Copy Markdown
Member

As I commented in the issue, I think the existing behavior is expected, intentional, and desired. Having a --no-x option without also supporting an --x option is wildly unintuitive and confusing, and I think it's fine if node chooses not to enable that.

Cover explicit negative options with string or missing destinations.
Preserve boolean aliases, tokens, defaults, multiple values, literal
string options, and permissive parsing.

Refs: nodejs#67085
Signed-off-by: JoaoMarcos44 <joaomarcosdias444@gmail.com>
Assisted-by: Codex
Validate the destination of an applied negative option after checking
its original declaration and argument. Reject string and undeclared
destinations with ERR_PARSE_ARGS_UNKNOWN_OPTION in strict mode.

Keep storeOption unchanged to preserve negative boolean aliases and
permissive parsing.

Fixes: nodejs#67085
Signed-off-by: JoaoMarcos44 <joaomarcosdias444@gmail.com>
Assisted-by: Codex
JoaoMarcos44 added a commit to JoaoMarcos44/node that referenced this pull request Oct 28, 2026
Show strict negation target validation and preserved boolean aliases.
Retain permissive parsing behavior and remove the earlier claims about
preserving every negative option and prototype pollution.

Refs: nodejs#67086
Signed-off-by: JoaoMarcos44 <joaomarcosdias444@gmail.com>
Assisted-by: Codex
@JoaoMarcos44 JoaoMarcos44 changed the title util: do not negate explicit no-* options in parseArgs util: validate parseArgs negation targets in strict mode Oct 28, 2026
@JoaoMarcos44

Copy link
Copy Markdown
Author

@ljharb I've narrowed this PR in 3d3d676. storeOption() now matches the base, so the established negative boolean alias behavior is preserved.

The change is confined to checkOptionUsage() in strict mode. After validating the original option and its argument, it checks the destination of an actual negation. A string or undeclared destination now throws ERR_PARSE_ARGS_UNKNOWN_OPTION. This also rejects explicit negative boolean options without a declared destination, rather than returning an undeclared key. strict: false, allowNegative: false, and literal no-* string options with values keep their existing behavior.

Added 18 regression and compatibility cases. Local verification against the edited JavaScript module passed all 126 API cases; the base fails the six new regressions. Repository ESLint and whitespace checks passed. The full rebuilt Node CI remains pending; the local test-runner limitation is documented in the description.

The issue description and infographic have also been updated to reflect this scope. AI assistance and the verification limits are disclosed in the PR description.

@ljharb

ljharb commented Oct 28, 2026

Copy link
Copy Markdown
Member

It should not be possible by default with allowNegatives to reject --x and allow --no-x. That would be a poor API design, and something you should do on your own after parseArgs completes.

@shadowspawn

shadowspawn commented Oct 31, 2026 •

Copy link
Copy Markdown
Member

checkOptionUsage is a runtime check that an option is being used as intended on the command line, so checking the arguments being parsed.

I think the restriction that declared explicitly negated booleans must not have a declared positive string option when allowNegative: true belongs in parseArgs() where the configuration is checked.

See the code following this line:

// Validate input configuration.

Reject explicit boolean no-* options that target a string option during
strict configuration validation, before arguments are tokenized.

Keep missing negation targets as usage errors, preserving valid double
negation, boolean aliases, and permissive parsing. Check own option names
including non-enumerable declarations without reading a negative getter
when its own target is absent.

Add regression coverage and document the strict configuration contract.

Refs: nodejs#67086
Assisted-by: Codex
Signed-off-by: JoaoMarcos44 <joaomarcosdias444@gmail.com>
@JoaoMarcos44

Copy link
Copy Markdown
Author

Thanks, @shadowspawn and @ljharb. I've updated the PR in cdda2e3b.

The explicit no-X: boolean / X: string conflict is now checked during configuration validation, after the existing validators and before tokenization. It throws ERR_INVALID_ARG_VALUE even with args: []. The check remains under strict && allowNegative to preserve permissive parsing.

The missing-destination check stays in usage validation. Declaring no-alpha alone can still be valid for --no-no-alpha, while using --no-alpha without a declared alpha is rejected in strict mode. This keeps the two responsibilities separate and preserves both goals of the PR.

Application-specific logging behavior and normalization remain outside parseArgs(). There is no new coercion API or configuration flag; valid boolean aliases, tokens, defaults, and multiple remain covered.

Local verification passed all 167 parseArgs tests, including CLI cases, on Node v22.16.0 and v24.22.1. These runs loaded the edited JavaScript module with the installed runtime's internals; they were not rebuilt Node binaries. Repository ESLint and Markdown lint also passed. A native build and official CI remain pending.

Check conflicting negative declarations in the existing validation loop
and reuse the validated option type. Remove the additional traversal of
own property names while retaining the negation usage check.

Follow the existing loop's enumeration scope and error ordering. Keep
guards for invalid target configurations, update regression coverage,
and document the enumerable declaration requirement.

Refs: nodejs#67086
Assisted-by: Codex
Signed-off-by: JoaoMarcos44 <joaomarcosdias444@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs-ci PRs that need a full CI run. util Issues and PRs related to the built-in util module.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

util: parseArgs strict validation accepts non-boolean negation targets

4 participants