Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 11 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,23 +38,29 @@ Alternatively, you can install manually by following these steps:
To detect base images for local or remote images, use the following command:

```shell
$ docker base detect <image>
$ docker base detect <IMAGE>
```

`<image>` can either be a local image id or fully qualified image name from a remote registry.
`<IMAGE>` can either be a local image id or fully qualified image name from a remote registry.

### `docker base login`

To authenticate with the Atomist data plane, use the following command:

```shell
$ docker base login --workspace <workspace id> --api-key <api key>
$ docker base login <WORKSPACE ID>
```

For the security reasons the command does not accept an API key as command parameter. Instead, an API key can be passed
in via stdin with the parameter `--api-key-stdin`.

The `login` command will also check the legacy `ATOMIST_API_KEY` environment variable.

Authentication is not required. If not authenticated, the plugin will only use public data from Docker Official Images,
Docker Verified Publishers or Docker-sponsored Open Source.
Docker Verified Publishers or Docker-sponsored Open Source. Without authentication the `detect` command will not take
into account your own data on Docker Hub when searching for matching base images.

Visit [dso.docker.com](https://dso.docker.com/r/auth/integrations) to obtain a `workspace id` and `api key`.
Visit [dso.docker.com](https://dso.docker.com/r/auth/integrations) to obtain a `WORKSPACE ID` and `API KEY`.

### `docker base logout`

Expand Down
100 changes: 80 additions & 20 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,22 +17,27 @@
package main

import (
"bufio"
"fmt"
"io"
"os"
"strings"

"github.com/docker/base-cli-plugin/commands"
"github.com/docker/base-cli-plugin/internal"
"github.com/docker/base-cli-plugin/query"
"github.com/docker/cli/cli-plugins/manager"
"github.com/docker/cli/cli-plugins/plugin"
"github.com/docker/cli/cli/command"
"github.com/moby/term"
"github.com/pkg/errors"
"github.com/spf13/cobra"
)

func main() {
plugin.Run(func(dockerCli command.Cli) *cobra.Command {
var (
workspace, apiKey string
apiKeyStdin bool
)

logout := &cobra.Command{
Expand All @@ -46,23 +51,29 @@ func main() {
}

login := &cobra.Command{
Use: "login",
Short: "Authenticate with an Atomist workspace",
RunE: func(cmd *cobra.Command, _ []string) error {
if !query.CheckAuth(workspace, apiKey) {
return errors.New("login failed")
} else {
Use: "login WORKSPACE",
Short: "Authenticate with Atomist workspace",
RunE: func(cmd *cobra.Command, args []string) error {
workspace, err := readWorkspace(args, dockerCli)
if err != nil {
return err
}
apiKey, err := readApiKey(apiKeyStdin, dockerCli)
if err != nil {
return err
}
if query.CheckAuth(workspace, apiKey) {
Comment thread
cdupuis marked this conversation as resolved.
fmt.Println("Login successful")
dockerCli.ConfigFile().SetPluginConfig("base", "workspace", workspace)
dockerCli.ConfigFile().SetPluginConfig("base", "api-key", apiKey)
return dockerCli.ConfigFile().Save()
} else {
return errors.New("Login failed")
}
},
}
loginFlags := login.Flags()
loginFlags.StringVar(&workspace, "workspace", "", "Atomist workspace")
loginFlags.StringVar(&apiKey, "api-key", "", "Atomist API key")
login.MarkFlagRequired("workspace")
login.MarkFlagRequired("api-key")
loginFlags.BoolVar(&apiKeyStdin, "api-key-stdin", false, "Atomist API key")

base := &cobra.Command{
Use: "detect [OPTIONS] IMAGE",
Expand All @@ -74,19 +85,12 @@ func main() {
}
return fmt.Errorf(`"docker base detect" requires exactly 1 argument`)
}
if workspace == "" {
workspace, _ = dockerCli.ConfigFile().PluginConfig("base", "workspace")
}
if apiKey == "" {
apiKey, _ = dockerCli.ConfigFile().PluginConfig("base", "api-key")
}
workspace, _ := dockerCli.ConfigFile().PluginConfig("base", "workspace")
apiKey, _ := dockerCli.ConfigFile().PluginConfig("base", "api-key")

return commands.Detect(dockerCli, args[0], workspace, apiKey)
},
}
baseFlags := base.Flags()
baseFlags.StringVar(&workspace, "workspace", "", "Atomist workspace")
baseFlags.StringVar(&apiKey, "api-key", "", "Atomist API key")
base.MarkFlagRequired("image")

cmd := &cobra.Command{
Expand All @@ -103,3 +107,59 @@ func main() {
Version: internal.FromBuild().Version,
})
}

func readWorkspace(args []string, cli command.Cli) (string, error) {
var workspace string
if len(args) == 1 {
workspace = args[0]
} else {
fmt.Fprintf(cli.Out(), "Workspace: ")

workspace = readInput(cli.In(), cli.Out())
if workspace == "" {
return "", errors.Errorf("Error: Workspace required")
}
}
return workspace, nil
}

func readApiKey(apiKeyStdin bool, cli command.Cli) (string, error) {
var apiKey string

if apiKeyStdin {
contents, err := io.ReadAll(cli.In())
if err != nil {
return "", err
}

apiKey = strings.TrimSuffix(string(contents), "\n")
apiKey = strings.TrimSuffix(apiKey, "\r")
} else if v, ok := os.LookupEnv("ATOMIST_API_KEY"); v != "" && ok {
Comment thread
cdupuis marked this conversation as resolved.
apiKey = v
} else {
oldState, err := term.SaveState(cli.In().FD())
if err != nil {
return "", err
}
fmt.Fprintf(cli.Out(), "API key: ")
term.DisableEcho(cli.In().FD(), oldState)

apiKey = readInput(cli.In(), cli.Out())
fmt.Fprint(cli.Out(), "\n")
term.RestoreTerminal(cli.In().FD(), oldState)
if apiKey == "" {
return "", errors.Errorf("Error: API key required")
}
}
return apiKey, nil
}

func readInput(in io.Reader, out io.Writer) string {
reader := bufio.NewReader(in)
line, _, err := reader.ReadLine()
if err != nil {
fmt.Fprintln(out, err.Error())
os.Exit(1)
}
return string(line)
}