Skip to content

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

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

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

Conversation

@JoaoMarcos44

@JoaoMarcos44 JoaoMarcos44 commented Oct 28, 2026 •

Copy link
Copy Markdown

When allowNegative: true and strict: true, an explicit no-logfile boolean currently passes validation and then writes false into logfile, even if logfile is a string option. An explicit negative option can also write to an undeclared destination.

This change validates the effective negation target in checkOptionUsage() after the existing option/value checks. Actual negations must target a declared boolean, otherwise parsing throws ERR_PARSE_ARGS_UNKNOWN_OPTION. storeOption() is unchanged.

const { parseArgs } = require('node:util');

parseArgs({
  args: ['--logfile', 'out.log', '--no-logfile'],
  allowNegative: true,
  strict: true,
  options: {
    logfile: { type: 'string' },
    'no-logfile': { type: 'boolean' },
  },
}).values;
// Before: { logfile: false }
// After: ERR_PARSE_ARGS_UNKNOWN_OPTION

Explicit negative boolean options without a declared destination also become errors in strict mode. This is an observable behavior change, limited to strict validation.

The existing negative boolean short aliases discussed in #53107 remain supported. The update also preserves strict: false, allowNegative: false, literal no-* string options with values, double negation, multiple, defaults, and negated tokens.

Added 18 regression and compatibility cases. The tests already present on the base branch are retained unchanged.

Visual Overview

Strict validation of parseArgs negation targets

Validation

  • On Node v24.22.1, 126 API tests passed against the edited JavaScript module, including the 18 new cases.
  • The same API tests against the base module produced the six expected regression failures and 120 passes.
  • The API run uses the existing test bodies, omits the CLI/default-argument suite, and loads the edited module with the installed Node internals.
  • The unmodified test entry point was attempted but stopped in test/common because this environment cannot enumerate network interfaces. A rebuilt Node binary and the full native CI suite have not been run.
  • The repository ESLint checks passed for both changed files; git diff --check also passed.

AI assistance: Codex prepared the implementation, new tests, descriptions, and infographic. The source was compared with the base and checked locally as described above; full native CI remains required.

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 <[email protected]>
@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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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.

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

3 participants