Problem
builtins.FlagSet is a type alias for pflag.FlagSet. Every builtin that
registers boolean flags with BoolP/Bool inherits pflag's NoOptDefVal="true"
behavior, which accepts the explicit-value form: head --verbose=false file,
rm --force=false target, truncate --no-create=true file, etc.
GNU coreutils documents these as no-argument options and rejects the =value
form before touching any operand:
$ head --verbose=false file
head: option '--verbose' doesn't allow an argument
(exit 1)
We silently accept it. This is a GNU-compat divergence affecting ~25 builtins.
Existing precedent
df already solves this with private noArgBool / noArgSentinel (a NUL-byte
sentinel that's unforgeable through execve) + registerNoArgBool, plus a pentest
test asserting df --all=false is rejected. See builtins/df/df.go.
Proposed fix
- Promote
noArgBool / noArgSentinel / registerNoArgBool from the df
package into the shared builtins package.
- Migrate all builtins with boolean flags to the shared helper.
- Delete df's private copy.
- Add bash-comparison scenario coverage for the
--flag=value rejection.
Affected builtins
cat, cd, cut, du, grep, head, help, ip, ls, ping, ps, pwd, read, rm, sed,
sort, ss, strings, tail, tr, truncate, uname, uniq, wc, xargs
(df already handled)
Context
Surfaced in #537 (rm builtin review). This issue
tracks the systemic migration for the rest.
Originally posted by @chatgpt-codex-connector[bot] in #537 (comment)
Problem
builtins.FlagSetis a type alias forpflag.FlagSet. Every builtin thatregisters boolean flags with
BoolP/Boolinherits pflag'sNoOptDefVal="true"behavior, which accepts the explicit-value form:
head --verbose=false file,rm --force=false target,truncate --no-create=true file, etc.GNU coreutils documents these as no-argument options and rejects the
=valueform before touching any operand:
We silently accept it. This is a GNU-compat divergence affecting ~25 builtins.
Existing precedent
dfalready solves this with privatenoArgBool/noArgSentinel(a NUL-bytesentinel that's unforgeable through execve) +
registerNoArgBool, plus a pentesttest asserting
df --all=falseis rejected. See builtins/df/df.go.Proposed fix
noArgBool/noArgSentinel/registerNoArgBoolfrom thedfpackage into the shared
builtinspackage.--flag=valuerejection.Affected builtins
cat, cd, cut, du, grep, head, help, ip, ls, ping, ps, pwd, read, rm, sed,
sort, ss, strings, tail, tr, truncate, uname, uniq, wc, xargs
(df already handled)
Context
Surfaced in #537 (rm builtin review). This issue
tracks the systemic migration for the rest.
Originally posted by @chatgpt-codex-connector[bot] in #537 (comment)