Repository navigation
fix: skip empty source values for flags that cannot parse them - #2451
Conversation
PostParse already refused to parse an empty value for any flag that is
not a string or a bool, since there is nothing to parse, but it still
marked the flag as set. That left the flag in a half state:
- Required was satisfied with a zero value. A required port read from
an empty PORT came back as 0 instead of failing, which is what
Docker Compose and Kubernetes hand over for an undefined variable.
- IsSet reported true for a flag that only held its default.
- An empty variable earlier in the chain hid a later one, so with
EnvVars("LEGACY_PORT", "PORT"), LEGACY_PORT="" and PORT=8080 the flag
kept its default of 80.
Walk the source chain and skip an empty value for those flags, so it is
treated like an unset variable. String flags still take the empty value
and bool flags still read it as false, as before. A non-empty value
that fails to parse is still an error.
Five cases fail before the fix: Required satisfied by an empty int or duration, IsSet true for an int or string slice that kept its default, and an empty variable hiding a later one. Three guard cases pass before and after: an unparsable value still errors, and string and bool flags still treat an empty value as set.
Juneezee
left a comment
There was a problem hiding this comment.
Thanks, the fix looks right to me. The five new cases fail on main (f6f38ed) and pass here, and go test ./... passes.
- This conflicts with main now that #2449 is merged. Keeping both lines resolves it:
f.hasBeenSet = true
f.fromSource = true
breakLines 158 to 159 in f6f38ed
I tried that merge locally and go test ./... passes. I can push it to this branch if that is easier for you.
- The skip covers every source, not only env vars, since the loop checks
val == ""for anything inSources.Chain:
Lines 149 to 153 in 4d537c9
For example, an empty file now leaves a required int flag unset too:
p := filepath.Join(t.TempDir(), "port")
os.WriteFile(p, nil, 0o600)
cmd := &cli.Command{
Flags: []cli.Flag{&cli.IntFlag{Name: "port", Required: true, Sources: cli.Files(p)}},
}
err := cmd.Run(context.Background(), []string{"app"})
// main: err is nil, port is 0, IsSet is true
// this PR: Required flag "port" not setI think that is the right behavior, but the docs paragraph is under "Values from the Environment" and the release note only mentions environment variables. GenericFlag is also affected (IsSet goes from true to false) but is not in the release note's list. Could you word both as something like "an empty value from any source is skipped for flags other than string and bool"?
cli/docs/v3/examples/flags/value-sources.md
Lines 65 to 68 in 4d537c9
…not-set # Conflicts: # flag_impl.go
The skip applies to every source in the chain, so a required int read from an empty file now fails like one read from an empty environment variable. Fails on main, where the flag is set to 0 with no error.
…ables Move the paragraph from the environment section to the general note on Sources order, since an empty file is skipped the same way.
|
Thanks for checking it so carefully.
|
Juneezee
left a comment
There was a problem hiding this comment.
urfave/cli v3.14.0 skips an empty source value for a flag that cannot parse it (urfave/cli#2451), so such a variable no longer marks the flag as set. That reaches three flags: --workers, --download-workers and --ignore-signature-status-code. An exported-empty GO_GALAXY_WORKERS or GO_GALAXY_DOWNLOAD_WORKERS now leaves the [tool.go-galaxy] key in charge instead of forcing the built-in default, and an exported-empty GO_GALAXY_IGNORE_SIGNATURE_STATUS_CODE no longer hides ANSIBLE_GALAXY_IGNORE_SIGNATURE_STATUS_CODES behind it in the chain. String and bool flags keep their reading: exported empty, they count as set. The workers test that pinned the old reading now pins the new one, and a download-workers row and a surface test of the ignore list join it; all three fail against v3.13.0. The comment on the --workers Value keeps the one reason that still holds: applyWorkers takes an unset flag's Value without the range check. The configuration reference, two internals pages and Upgrading say what changed, Upgrading with the one exit code it moves, 10 to 0 under a required count of all or +all. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This PR contains the following updates: | Package | Type | Update | Change | OpenSSF | |---|---|---|---|---| | [github.com/urfave/cli/v3](https://github.com/urfave/cli) | require | minor | `v3.10.1` → `v3.14.0` | [](https://securityscorecards.dev/viewer/?uri=github.com/urfave/cli) | --- >⚠️ **Warning** > > Some dependencies could not be looked up. Check the [Dependency Dashboard](issues/23) for more information. --- ### Release Notes <details> <summary>urfave/cli (github.com/urfave/cli/v3)</summary> ### [`v3.14.0`](https://github.com/urfave/cli/releases/tag/v3.14.0) [Compare Source](urfave/cli@v3.13.0...v3.14.0) #### What's Changed - chore(deps): bump mkdocs-git-revision-date-localized-plugin from 1.5.4 to 1.6.0 in the python-packages group by [@​dependabot](https://github.com/dependabot)\[bot] in [#​2436](urfave/cli#2436) - fix: set BoolWithInverseFlag in a short option group by [@​lazerg](https://github.com/lazerg) in [#​2440](urfave/cli#2440) - Keep arguments after a bare dash by [@​official-burak](https://github.com/official-burak) in [#​2419](urfave/cli#2419) - fix: handle a multi-byte flag at the end of a short option group by [@​SulimanAbdulrazzaq](https://github.com/SulimanAbdulrazzaq) in [#​2438](urfave/cli#2438) - fix: complete persistent flags in shell completion by [@​sb123sb123](https://github.com/sb123sb123) in [#​2437](urfave/cli#2437) - fix: restore Unwrap on the error returned by Exit by [@​fadiroot](https://github.com/fadiroot) in [#​2444](urfave/cli#2444) - fix: reject a parent's Local flag inside a short option group by [@​fadiroot](https://github.com/fadiroot) in [#​2445](urfave/cli#2445) - fix: report a flag that needs an argument but is not last in a short group by [@​yu2971512385-ui](https://github.com/yu2971512385-ui) in [#​2443](urfave/cli#2443) - Use prefixFor so flag suggestions agree with help on rune count by [@​januththedev](https://github.com/januththedev) in [#​2448](urfave/cli#2448) - fix: reject duplicate flag names by [@​deepakganesh78](https://github.com/deepakganesh78) in [#​2396](urfave/cli#2396) - fix: date a time-only timestamp today when Timezone is not UTC by [@​breken-ai](https://github.com/breken-ai) in [#​2450](urfave/cli#2450) - fix: let a subcommand's command-line value replace a persistent flag's env/file value by [@​breken-ai](https://github.com/breken-ai) in [#​2449](urfave/cli#2449) - Add urfave_cli_no_template build tag by [@​kolyshkin](https://github.com/kolyshkin) in [#​2441](urfave/cli#2441) - fix: skip empty source values for flags that cannot parse them by [@​abo3losh1](https://github.com/abo3losh1) in [#​2451](urfave/cli#2451) #### New Contributors - [@​lazerg](https://github.com/lazerg) made their first contribution in [#​2440](urfave/cli#2440) - [@​official-burak](https://github.com/official-burak) made their first contribution in [#​2419](urfave/cli#2419) - [@​SulimanAbdulrazzaq](https://github.com/SulimanAbdulrazzaq) made their first contribution in [#​2438](urfave/cli#2438) - [@​sb123sb123](https://github.com/sb123sb123) made their first contribution in [#​2437](urfave/cli#2437) - [@​fadiroot](https://github.com/fadiroot) made their first contribution in [#​2444](urfave/cli#2444) - [@​yu2971512385-ui](https://github.com/yu2971512385-ui) made their first contribution in [#​2443](urfave/cli#2443) - [@​januththedev](https://github.com/januththedev) made their first contribution in [#​2448](urfave/cli#2448) - [@​deepakganesh78](https://github.com/deepakganesh78) made their first contribution in [#​2396](urfave/cli#2396) - [@​breken-ai](https://github.com/breken-ai) made their first contribution in [#​2450](urfave/cli#2450) - [@​abo3losh1](https://github.com/abo3losh1) made their first contribution in [#​2451](urfave/cli#2451) **Full Changelog**: <urfave/cli@v3.13.0...v3.14.0> ### [`v3.13.0`](https://github.com/urfave/cli/releases/tag/v3.13.0) [Compare Source](urfave/cli@v3.12.0...v3.13.0) #### What's Changed - Trim the key of a map flag when TrimSpace is set by [@​youdie006](https://github.com/youdie006) in [#​2431](urfave/cli#2431) - Fix inverse bool flag counting with an external counter by [@​jakezwang](https://github.com/jakezwang) in [#​2432](urfave/cli#2432) - feat: add Deprecated field to flags and commands by [@​anandghegde](https://github.com/anandghegde) in [#​2429](urfave/cli#2429) - fix: parse single-rune Unicode flags by [@​znnnnnnn-wil](https://github.com/znnnnnnn-wil) in [#​2434](urfave/cli#2434) #### New Contributors - [@​jakezwang](https://github.com/jakezwang) made their first contribution in [#​2432](urfave/cli#2432) - [@​anandghegde](https://github.com/anandghegde) made their first contribution in [#​2429](urfave/cli#2429) - [@​znnnnnnn-wil](https://github.com/znnnnnnn-wil) made their first contribution in [#​2434](urfave/cli#2434) **Full Changelog**: <urfave/cli@v3.12.0...v3.13.0> ### [`v3.12.0`](https://github.com/urfave/cli/releases/tag/v3.12.0) [Compare Source](urfave/cli@v3.11.0...v3.12.0) #### What's Changed - feat: add Command.ArgValidator for tree-wide argument validation by [@​dearchap](https://github.com/dearchap) in [#​2377](urfave/cli#2377) - Single-value arguments can be marked as required by [@​idelchi](https://github.com/idelchi) in [#​2393](urfave/cli#2393) - docs: clarify that named Arguments are excluded from cmd.Args() by [@​dearchap](https://github.com/dearchap) in [#​2411](urfave/cli#2411) - fix: never run command action on shell completion past a double dash by [@​dearchap](https://github.com/dearchap) in [#​2412](urfave/cli#2412) - chore(deps): bump github.com/stretchr/testify from 1.11.1 to 1.12.0 by [@​app/dependabot](https://github.com/app/dependabot) in [#​2413](urfave/cli#2413) - Support custom FlagStringer for MutuallyExclusiveFlags by [@​SHIVANSHGARG07](https://github.com/SHIVANSHGARG07) in [#​2414](urfave/cli#2414) - Add TextFlag for encoding.TextMarshaler/TextUnmarshaler values by [@​ChrisJr404](https://github.com/ChrisJr404) in [#​2415](urfave/cli#2415) - chore(deps): bump github.com/stretchr/testify from 1.12.0 to 1.12.1 by [@​app/dependabot](https://github.com/app/dependabot) in [#​2416](urfave/cli#2416) - chore(deps): bump the python-packages group with 2 updates by [@​app/dependabot](https://github.com/app/dependabot) in [#​2417](urfave/cli#2417) - Show inherited persistent flags in child help by [@​justadityaraj](https://github.com/justadityaraj) in [#​2421](urfave/cli#2421) - fix: preserve whitespace in positional arguments by [@​lenamonj](https://github.com/lenamonj) in [#​2423](urfave/cli#2423) - fix: preserve whitespace in equals-form flag values by [@​BenYang12](https://github.com/BenYang12) in [#​2425](urfave/cli#2425) - fix: complete subcommand flags after positional arguments by [@​fzlzjerry](https://github.com/fzlzjerry) in [#​2426](urfave/cli#2426) - Fix a year-less timestamp layout losing January 1 by [@​youdie006](https://github.com/youdie006) in [#​2427](urfave/cli#2427) - docs: add go-size-analyzer, module version, and reflection by [@​imsumedhaa](https://github.com/imsumedhaa) in [#​2428](urfave/cli#2428) #### New Contributors - [@​idelchi](https://github.com/idelchi) made their first contribution in [#​2393](urfave/cli#2393) - [@​SHIVANSHGARG07](https://github.com/SHIVANSHGARG07) made their first contribution in [#​2414](urfave/cli#2414) - [@​ChrisJr404](https://github.com/ChrisJr404) made their first contribution in [#​2415](urfave/cli#2415) - [@​justadityaraj](https://github.com/justadityaraj) made their first contribution in [#​2421](urfave/cli#2421) - [@​lenamonj](https://github.com/lenamonj) made their first contribution in [#​2423](urfave/cli#2423) - [@​BenYang12](https://github.com/BenYang12) made their first contribution in [#​2425](urfave/cli#2425) - [@​youdie006](https://github.com/youdie006) made their first contribution in [#​2427](urfave/cli#2427) - [@​imsumedhaa](https://github.com/imsumedhaa) made their first contribution in [#​2428](urfave/cli#2428) **Full Changelog**: <urfave/cli@v3.11.0...v3.12.0> ### [`v3.11.0`](https://github.com/urfave/cli/releases/tag/v3.11.0) [Compare Source](urfave/cli@v3.10.1...v3.11.0) #### What's Changed - fix: correct a typo in the help message for the powershell autocompletion by [@​suzuki-shunsuke](https://github.com/suzuki-shunsuke) in [#​2383](urfave/cli#2383) - Escape backslashes in fish completion descriptions by [@​mahirhir](https://github.com/mahirhir) in [#​2378](urfave/cli#2378) - chore(deps): bump actions/setup-go from 6 to 7 by [@​dependabot](https://github.com/dependabot)\[bot] in [#​2389](urfave/cli#2389) - chore(deps): bump mkdocs-material from 9.7.6 to 9.7.7 in the python-packages group by [@​dependabot](https://github.com/dependabot)\[bot] in [#​2391](urfave/cli#2391) - chore(deps): bump actions/setup-python from 6 to 7 by [@​dependabot](https://github.com/dependabot)\[bot] in [#​2390](urfave/cli#2390) - fix: skip all hidden flags in shell completion, not just bool flags by [@​vidigoat](https://github.com/vidigoat) in [#​2388](urfave/cli#2388) - Fix nil pointer dereference for interface-typed flag values by [@​mrueg](https://github.com/mrueg) in [#​2400](urfave/cli#2400) - Fix index out of range panic when Run is given no arguments by [@​mrueg](https://github.com/mrueg) in [#​2401](urfave/cli#2401) - fix: honor BoolWithInverseFlag DefaultText by [@​fzlzjerry](https://github.com/fzlzjerry) in [#​2403](urfave/cli#2403) - Fix Issue [#​2385](urfave/cli#2385) by [@​BrandonIrizarry](https://github.com/BrandonIrizarry) in [#​2386](urfave/cli#2386) - fix: inherit HideHelpCommand in subcommands by [@​utkarshalpha](https://github.com/utkarshalpha) in [#​2395](urfave/cli#2395) - test: cover Run-with-no-arguments paths ([#​2406](urfave/cli#2406)) by [@​dearchap](https://github.com/dearchap) in [#​2407](urfave/cli#2407) - test: add shell-completion case for hidden BoolWithInverseFlag by [@​dearchap](https://github.com/dearchap) in [#​2408](urfave/cli#2408) - test: fix ineffective mutex error-string assertion and add mirror cases by [@​dearchap](https://github.com/dearchap) in [#​2410](urfave/cli#2410) #### New Contributors - [@​mahirhir](https://github.com/mahirhir) made their first contribution in [#​2378](urfave/cli#2378) - [@​vidigoat](https://github.com/vidigoat) made their first contribution in [#​2388](urfave/cli#2388) - [@​fzlzjerry](https://github.com/fzlzjerry) made their first contribution in [#​2403](urfave/cli#2403) - [@​BrandonIrizarry](https://github.com/BrandonIrizarry) made their first contribution in [#​2386](urfave/cli#2386) - [@​utkarshalpha](https://github.com/utkarshalpha) made their first contribution in [#​2395](urfave/cli#2395) **Full Changelog**: <urfave/cli@v3.10.1...v3.11.0> </details> --- ### Configuration 📅 **Schedule**: (UTC) - Branch creation - At 12:00 AM through 04:59 AM and 10:00 PM through 11:59 PM, Monday through Friday (`* 0-4,22-23 * * 1-5`) - Only on Sunday and Saturday (`* * * * 0,6`) - Automerge - At any time (no schedule defined) 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box --- This PR has been generated by [Mend Renovate CLI](https://github.com/renovatebot/renovate). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0NC4xNTEuMiIsInVwZGF0ZWRJblZlciI6IjQ0LjE1MS4yIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJLaW5kL0RlcGVuZGVuY2llcyJdfQ==--> Reviewed-on: https://altlinux.space/stapler/stplr/pulls/503
What type of PR is this?
What this PR does / why we need it:
An environment variable that is set but empty marks a flag as set even when the flag cannot use the empty value.
PostParsealready skips parsing""for anything that is not a string or a bool, since there is nothing to parse, but it still setshasBeenSet. So the flag ends up marked as set while holding only its default:Before:
0 true, no error. After:Required flag "port" not set.The same applies to every source in the chain, so an empty file behaves like an empty environment variable. This has three visible effects for any flag other than string and bool (int, uint, float, duration, timestamp, slice, map and
GenericFlag):Requiredis satisfied with a zero value. Docker Compose and Kubernetes pass an undefined variable through as an empty one, so a required port silently becomes0exactly when the config is missing.IsSetreturns true for a flag that only holds its default.EnvVars("LEGACY_PORT", "PORT"),LEGACY_PORT=""andPORT=8080, the flag keeps its default of80.Changes:
flag_impl.go:PostParsewalksSources.Chainitself and skips an empty value for flags that cannot parse it, so it behaves like an unset variable and the next source gets a turn. String flags still take""and bool flags still read it asfalse, so c.IsSet returns true for empty env vars #517 / Consider empty environment variables as set #530 (an empty string variable counts as set) is unchanged. A non-empty value that fails to parse is still an error, rather than being skipped.flag_test.go:TestFlagsFromEmptyEnv, a table test run throughCommand.Run, andTestFlagFromEmptyFileSourcefor an empty file.docs/v3/examples/flags/value-sources.md: one paragraph, under the general note onSourcesorder, on how an empty value from any source is treated.With a single source the flag's value never changes, only
IsSetandRequirednow agree with it.Which issue(s) this PR fixes:
No open issue. Related history: #517 and #530 decided that an empty variable counts as set for a string flag. That still holds; this only covers flag types that have no way to hold an empty value.
Special notes for your reviewer:
#2449 added
f.fromSource = truenext tof.hasBeenSet = truein the same block ofPostParse.mainis merged into this branch with both lines kept inside the loop, and the tests from #2449 pass.Testing
TestFlagFromEmptyFileSourcefails onmain, where the flag is set to 0 with no error.TestFlagsFromEmptyEnv: five cases fail onmain(required int, required duration, IsSet for an int and a string slice that kept their defaults, and the shadowed second variable). Three guard cases pass before and after: an unparsable value still errors, and string and bool flags still treat an empty value as set.go vet ./...andgo test ./...pass, andv3diffshows no public API change.Release Notes