Skip to content

fix: skip all hidden flags in shell completion, not just bool flags#2388

Open
vidigoat wants to merge 1 commit into
urfave:mainfrom
vidigoat:fix/hidden-flag-completion
Open

fix: skip all hidden flags in shell completion, not just bool flags#2388
vidigoat wants to merge 1 commit into
urfave:mainfrom
vidigoat:fix/hidden-flag-completion

Conversation

@vidigoat

@vidigoat vidigoat commented Jul 9, 2026

Copy link
Copy Markdown

What type of PR is this?

  • bug

What this PR does / why we need it:

printFlagSuggestions (used by the default shell-completion handler) is supposed to skip hidden flags, but it only skips hidden *BoolFlag values:

if bflag, ok := flag.(*BoolFlag); ok && bflag.Hidden {
    continue
}

The type assertion is to the concrete *BoolFlag type, so a hidden flag of any other type (*StringFlag, *IntFlag, *DurationFlag, ...) fails the assertion and is emitted into the completion output anyway. That exposes flags the author explicitly marked Hidden: true whenever a user hits <TAB>.

Repro (hidden *StringFlag):

cmd := &cli.Command{
    Name:                  "app",
    EnableShellCompletion: true,
    Commands: []*cli.Command{{
        Name: "sub",
        Flags: []cli.Flag{
            &cli.StringFlag{Name: "secret", Hidden: true},
            &cli.StringFlag{Name: "visible"},
        },
        Action: func(context.Context, *cli.Command) error { return nil },
    }},
}

app sub -<TAB> prints --secret alongside --visible, even though secret is hidden. A hidden *BoolFlag in the same list is correctly omitted.

Changes:

  • help.go: replace the *BoolFlag-specific check with the existing VisibleFlag interface (IsVisible), which every flag type implements via FlagBase. This is the same mechanism visibleFlags and the flag-category code already use, so all hidden flags are now skipped regardless of concrete type.

Which issue(s) this PR fixes:

NONE

Testing

Added typical-flag-suggestion-hidden-non-bool to TestDefaultCompleteWithFlags, mirroring the existing typical-flag-suggestion-hidden-bool case but with a hidden *StringFlag. It fails on main (completion emits the hidden flag) and passes with this change. go test ./..., go vet ./..., and gofmt are clean.

Release Notes

Hidden flags of non-boolean types are no longer offered in shell completion (previously only hidden bool flags were skipped).

printFlagSuggestions only skipped hidden *BoolFlag values because it
type-asserted to the concrete *BoolFlag type. Any other hidden flag
(*StringFlag, *IntFlag, *DurationFlag, etc.) still leaked into shell
completion output.

Use the existing VisibleFlag interface (IsVisible) the same way
visibleFlags and the flag-category code already do, so every hidden
flag is skipped regardless of its concrete type.
@vidigoat vidigoat requested a review from a team as a code owner July 9, 2026 11:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant