Files
docker-cli/cli/command/registry/search.go
Sebastiaan van Stijn c88268681e prevent login prompt on registry operations with no TTY attached
When pulling or pushing images, the CLI could prompt for a password
if the push/pull failed and the registry returned a 401 (Unauthorized)

Ironically, this feature did not work when using Docker Hub (and possibly
other registries using basic auth), due to some custom error handling added
in [moby@19a93a6e3d42], which also discards the registry's status code,
changing it to a 404;

    curl -v -XPOST --unix-socket /var/run/docker.sock 'http://localhost/v1.50/images/create?fromImage=docker.io%2Fexample%2Fprivate&tag=latest'
    ...
    < HTTP/1.1 404 Not Found
    < Content-Type: application/json
    ...
    {"message":"pull access denied for example/private, repository does not exist or may require 'docker login'"}

And due to a bug, other registries (not using basic auth) returned a generic
error, which resulted in a 500 Internal Server Error. That bug was fixed in
docker 28.2, now returning the upstream status code and trigger an interactive
prompt;

    docker pull icr.io/my-ns/my-image:latest
    Please login prior to pull:
    Username:

This prompt would be triggered unconditionally, also if the CLI was run
non-interactively and no TTY attached;

    docker pull icr.io/my-ns/my-image:latest < /dev/null
    Please login prior to pull:
    Username:

With this PR, no prompt is shown ;

    # without STDIN attached
    docker pull icr.io/my-ns/my-image:latest < /dev/null
    Error response from daemon: error from registry: Authorization required. See https://cloud.ibm.com/docs/Registry?topic=Registry-troubleshoot-auth-req - Authorization required. See https://cloud.ibm.com/docs/Registry?topic=Registry-troubleshoot-auth-req

For now, the prompt is still shown otherwise;

    docker pull icr.io/my-ns/my-image:latest

    Login prior to pull:
    Username: ^C

[moby@19a93a6e3d42]: 19a93a6e3d

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-06-19 10:25:27 +02:00

87 lines
2.5 KiB
Go

package registry
import (
"context"
"fmt"
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/formatter"
"github.com/docker/cli/opts"
registrytypes "github.com/docker/docker/api/types/registry"
"github.com/docker/docker/registry"
"github.com/spf13/cobra"
)
type searchOptions struct {
format string
term string
noTrunc bool
limit int
filter opts.FilterOpt
}
// NewSearchCommand creates a new `docker search` command
func NewSearchCommand(dockerCli command.Cli) *cobra.Command {
options := searchOptions{filter: opts.NewFilterOpt()}
cmd := &cobra.Command{
Use: "search [OPTIONS] TERM",
Short: "Search Docker Hub for images",
Args: cli.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
options.term = args[0]
return runSearch(cmd.Context(), dockerCli, options)
},
Annotations: map[string]string{
"category-top": "10",
},
}
flags := cmd.Flags()
flags.BoolVar(&options.noTrunc, "no-trunc", false, "Don't truncate output")
flags.VarP(&options.filter, "filter", "f", "Filter output based on conditions provided")
flags.IntVar(&options.limit, "limit", 0, "Max number of search results")
flags.StringVar(&options.format, "format", "", "Pretty-print search using a Go template")
return cmd
}
func runSearch(ctx context.Context, dockerCli command.Cli, options searchOptions) error {
if options.filter.Value().Contains("is-automated") {
_, _ = fmt.Fprintln(dockerCli.Err(), `WARNING: the "is-automated" filter is deprecated, and searching for "is-automated=true" will not yield any results in future.`)
}
indexInfo, err := registry.ParseSearchIndexInfo(options.term)
if err != nil {
return err
}
authConfig := command.ResolveAuthConfig(dockerCli.ConfigFile(), indexInfo)
encodedAuth, err := registrytypes.EncodeAuthConfig(authConfig)
if err != nil {
return err
}
var requestPrivilege registrytypes.RequestAuthConfig
if dockerCli.In().IsTerminal() {
requestPrivilege = command.RegistryAuthenticationPrivilegedFunc(dockerCli, indexInfo, "search")
}
results, err := dockerCli.Client().ImageSearch(ctx, options.term, registrytypes.SearchOptions{
RegistryAuth: encodedAuth,
PrivilegeFunc: requestPrivilege,
Filters: options.filter.Value(),
Limit: options.limit,
})
if err != nil {
return err
}
searchCtx := formatter.Context{
Output: dockerCli.Out(),
Format: NewSearchFormat(options.format),
Trunc: !options.noTrunc,
}
return SearchWrite(searchCtx, results)
}