5 Commits

Author SHA1 Message Date
Christian Dupuis
c4fb3dbee0 Merge pull request #3 from docker/atomist/gofmt-main
Go format fixes
2022-09-19 16:57:40 +02:00
Atomist Bot
424469a2b1 Run go mod tidy
[atomist:generated]
 [atomist-skill:atomist/go-format-skill]

Signed-off-by: Christian Dupuis <christian@atomist.com>
2022-09-19 14:42:00 +00:00
Christian Dupuis
f0e36ec311 Merge pull request #2 from docker/issue-1
Remove `--api-key` parameter
2022-09-19 16:41:47 +02:00
Christian Dupuis
12098e0f6e Remove --api-key parameter
fixes #1

Signed-off-by: Christian Dupuis <cd@atomist.com>
2022-09-19 16:39:53 +02:00
Christian Dupuis
1b78e08fca Add another line break
Signed-off-by: Christian Dupuis <cd@atomist.com>
2022-09-16 17:58:54 +02:00
4 changed files with 94 additions and 28 deletions

View File

@@ -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>
```
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.
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`.
Visit [dso.docker.com](https://dso.docker.com/r/auth/integrations) to obtain a `workspace id` and `api key`.
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. 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`.
### `docker base logout`

View File

@@ -103,7 +103,7 @@ func Detect(dockerCli command.Cli, image string, workspace string, apiKey string
bi[ix] = e
}
s.Stop()
fmt.Printf("Base image for %s\n%s\n\n", label, strings.Join(bi, "\n"))
fmt.Printf("Base image for %s\n%s\n\n", label, strings.Join(bi, "\n\n"))
}
}
return nil

2
go.mod
View File

@@ -7,6 +7,7 @@ require (
github.com/docker/cli v20.10.17+incompatible
github.com/fatih/color v1.13.0
github.com/google/go-containerregistry v0.5.1
github.com/moby/term v0.0.0-20220808134915-39b0c02b01ae
github.com/opencontainers/go-digest v1.0.0
github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799
github.com/pkg/errors v0.9.1
@@ -40,7 +41,6 @@ require (
github.com/miekg/pkcs11 v1.0.3 // indirect
github.com/moby/sys/mount v0.3.3 // indirect
github.com/moby/sys/mountinfo v0.6.2 // indirect
github.com/moby/term v0.0.0-20220808134915-39b0c02b01ae // indirect
github.com/morikuni/aec v1.0.0 // indirect
github.com/prometheus/client_golang v1.7.1 // indirect
github.com/prometheus/client_model v0.2.0 // indirect

100
main.go
View File

@@ -17,7 +17,11 @@
package main
import (
"bufio"
"fmt"
"io"
"os"
"strings"
"github.com/docker/base-cli-plugin/commands"
"github.com/docker/base-cli-plugin/internal"
@@ -25,6 +29,7 @@ import (
"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"
)
@@ -32,7 +37,7 @@ import (
func main() {
plugin.Run(func(dockerCli command.Cli) *cobra.Command {
var (
workspace, apiKey string
apiKeyStdin bool
)
logout := &cobra.Command{
@@ -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) {
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",
@@ -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{
@@ -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 {
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)
}