-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Refactor content_trust cli/flags handling #929
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -52,18 +52,20 @@ type Cli interface { | |
| DefaultVersion() string | ||
| ManifestStore() manifeststore.Store | ||
| RegistryClient(bool) registryclient.RegistryClient | ||
| ContentTrustEnabled() bool | ||
| } | ||
|
|
||
| // DockerCli is an instance the docker command line client. | ||
| // Instances of the client can be returned from NewDockerCli. | ||
| type DockerCli struct { | ||
| configFile *configfile.ConfigFile | ||
| in *InStream | ||
| out *OutStream | ||
| err io.Writer | ||
| client client.APIClient | ||
| serverInfo ServerInfo | ||
| clientInfo ClientInfo | ||
| configFile *configfile.ConfigFile | ||
| in *InStream | ||
| out *OutStream | ||
| err io.Writer | ||
| client client.APIClient | ||
| serverInfo ServerInfo | ||
| clientInfo ClientInfo | ||
| contentTrust bool | ||
| } | ||
|
|
||
| // DefaultVersion returns api.defaultVersion or DOCKER_API_VERSION if specified. | ||
|
|
@@ -121,6 +123,12 @@ func (cli *DockerCli) ClientInfo() ClientInfo { | |
| return cli.clientInfo | ||
| } | ||
|
|
||
| // ContentTrustEnabled returns if content trust has been enabled by an | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: reads a bit odd, perhaps could be |
||
| // environment variable. | ||
| func (cli *DockerCli) ContentTrustEnabled() bool { | ||
| return cli.contentTrust | ||
| } | ||
|
|
||
| // ManifestStore returns a store for local manifests | ||
| func (cli *DockerCli) ManifestStore() manifeststore.Store { | ||
| // TODO: support override default location from config file | ||
|
|
@@ -237,8 +245,8 @@ func (c ClientInfo) HasKubernetes() bool { | |
| } | ||
|
|
||
| // NewDockerCli returns a DockerCli instance with IO output and error streams set by in, out and err. | ||
| func NewDockerCli(in io.ReadCloser, out, err io.Writer) *DockerCli { | ||
| return &DockerCli{in: NewInStream(in), out: NewOutStream(out), err: err} | ||
| func NewDockerCli(in io.ReadCloser, out, err io.Writer, isTrusted bool) *DockerCli { | ||
| return &DockerCli{in: NewInStream(in), out: NewOutStream(out), err: err, contentTrust: isTrusted} | ||
| } | ||
|
|
||
| // NewAPIClientFromFlags creates a new APIClient from command line flags | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -67,6 +67,7 @@ type buildOptions struct { | |||||||||||||||||||||||||||||||||||||
| imageIDFile string | ||||||||||||||||||||||||||||||||||||||
| stream bool | ||||||||||||||||||||||||||||||||||||||
| platform string | ||||||||||||||||||||||||||||||||||||||
| untrusted bool | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| // dockerfileFromStdin returns true when the user specified that the Dockerfile | ||||||||||||||||||||||||||||||||||||||
|
|
@@ -137,7 +138,7 @@ func NewBuildCommand(dockerCli command.Cli) *cobra.Command { | |||||||||||||||||||||||||||||||||||||
| flags.StringVar(&options.target, "target", "", "Set the target build stage to build.") | ||||||||||||||||||||||||||||||||||||||
| flags.StringVar(&options.imageIDFile, "iidfile", "", "Write the image ID to the file") | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| command.AddTrustVerificationFlags(flags) | ||||||||||||||||||||||||||||||||||||||
| command.AddTrustVerificationFlags(flags, &options.untrusted, dockerCli.ContentTrustEnabled()) | ||||||||||||||||||||||||||||||||||||||
| command.AddPlatformFlag(flags, &options.platform) | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| flags.BoolVar(&options.squash, "squash", false, "Squash newly built layers into a single new layer") | ||||||||||||||||||||||||||||||||||||||
|
|
@@ -285,18 +286,18 @@ func runBuild(dockerCli command.Cli, options buildOptions) error { | |||||||||||||||||||||||||||||||||||||
| defer cancel() | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| var resolvedTags []*resolvedTag | ||||||||||||||||||||||||||||||||||||||
| if command.IsTrusted() { | ||||||||||||||||||||||||||||||||||||||
| if !options.untrusted { | ||||||||||||||||||||||||||||||||||||||
| translator := func(ctx context.Context, ref reference.NamedTagged) (reference.Canonical, error) { | ||||||||||||||||||||||||||||||||||||||
| return TrustedReference(ctx, dockerCli, ref, nil) | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
| // if there is a tar wrapper, the dockerfile needs to be replaced inside it | ||||||||||||||||||||||||||||||||||||||
| if buildCtx != nil { | ||||||||||||||||||||||||||||||||||||||
| // Wrap the tar archive to replace the Dockerfile entry with the rewritten | ||||||||||||||||||||||||||||||||||||||
| // Dockerfile which uses trusted pulls. | ||||||||||||||||||||||||||||||||||||||
| buildCtx = replaceDockerfileTarWrapper(ctx, buildCtx, relDockerfile, translator, &resolvedTags) | ||||||||||||||||||||||||||||||||||||||
| buildCtx = replaceDockerfileForContentTrust(ctx, buildCtx, relDockerfile, translator, &resolvedTags) | ||||||||||||||||||||||||||||||||||||||
| } else if dockerfileCtx != nil { | ||||||||||||||||||||||||||||||||||||||
| // if there was not archive context still do the possible replacements in Dockerfile | ||||||||||||||||||||||||||||||||||||||
| newDockerfile, _, err := rewriteDockerfileFrom(ctx, dockerfileCtx, translator) | ||||||||||||||||||||||||||||||||||||||
| newDockerfile, _, err := rewriteDockerfileFrom(ctx, dockerfileCtx, translator, !options.untrusted) | ||||||||||||||||||||||||||||||||||||||
| if err != nil { | ||||||||||||||||||||||||||||||||||||||
| return err | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
|
|
@@ -460,7 +461,7 @@ func runBuild(dockerCli command.Cli, options buildOptions) error { | |||||||||||||||||||||||||||||||||||||
| return err | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
| if command.IsTrusted() { | ||||||||||||||||||||||||||||||||||||||
| if !options.untrusted { | ||||||||||||||||||||||||||||||||||||||
| // Since the build was successful, now we must tag any of the resolved | ||||||||||||||||||||||||||||||||||||||
| // images from the above Dockerfile rewrite. | ||||||||||||||||||||||||||||||||||||||
| for _, resolved := range resolvedTags { | ||||||||||||||||||||||||||||||||||||||
|
|
@@ -503,7 +504,7 @@ type resolvedTag struct { | |||||||||||||||||||||||||||||||||||||
| // "FROM <image>" instructions to a digest reference. `translator` is a | ||||||||||||||||||||||||||||||||||||||
| // function that takes a repository name and tag reference and returns a | ||||||||||||||||||||||||||||||||||||||
| // trusted digest reference. | ||||||||||||||||||||||||||||||||||||||
| func rewriteDockerfileFrom(ctx context.Context, dockerfile io.Reader, translator translatorFunc) (newDockerfile []byte, resolvedTags []*resolvedTag, err error) { | ||||||||||||||||||||||||||||||||||||||
| func rewriteDockerfileFrom(ctx context.Context, dockerfile io.Reader, translator translatorFunc, istrusted bool) (newDockerfile []byte, resolvedTags []*resolvedTag, err error) { | ||||||||||||||||||||||||||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Looks like the whole reason this So, actually, looks like that's already what's done; it's only called in that case, so we can just remove the boolean (and check). This is the only location this function is called: cli/cli/command/image/build.go Lines 288 to 305 in 82a8085
|
||||||||||||||||||||||||||||||||||||||
| scanner := bufio.NewScanner(dockerfile) | ||||||||||||||||||||||||||||||||||||||
| buf := bytes.NewBuffer(nil) | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
|
|
@@ -520,7 +521,7 @@ func rewriteDockerfileFrom(ctx context.Context, dockerfile io.Reader, translator | |||||||||||||||||||||||||||||||||||||
| return nil, nil, err | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
| ref = reference.TagNameOnly(ref) | ||||||||||||||||||||||||||||||||||||||
| if ref, ok := ref.(reference.NamedTagged); ok && command.IsTrusted() { | ||||||||||||||||||||||||||||||||||||||
| if ref, ok := ref.(reference.NamedTagged); ok && istrusted { | ||||||||||||||||||||||||||||||||||||||
| trustedRef, err := translator(ctx, ref) | ||||||||||||||||||||||||||||||||||||||
| if err != nil { | ||||||||||||||||||||||||||||||||||||||
| return nil, nil, err | ||||||||||||||||||||||||||||||||||||||
|
|
@@ -543,11 +544,10 @@ func rewriteDockerfileFrom(ctx context.Context, dockerfile io.Reader, translator | |||||||||||||||||||||||||||||||||||||
| return buf.Bytes(), resolvedTags, scanner.Err() | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| // replaceDockerfileTarWrapper wraps the given input tar archive stream and | ||||||||||||||||||||||||||||||||||||||
| // replaces the entry with the given Dockerfile name with the contents of the | ||||||||||||||||||||||||||||||||||||||
| // new Dockerfile. Returns a new tar archive stream with the replaced | ||||||||||||||||||||||||||||||||||||||
| // Dockerfile. | ||||||||||||||||||||||||||||||||||||||
| func replaceDockerfileTarWrapper(ctx context.Context, inputTarStream io.ReadCloser, dockerfileName string, translator translatorFunc, resolvedTags *[]*resolvedTag) io.ReadCloser { | ||||||||||||||||||||||||||||||||||||||
| // replaceDockerfileForContentTrust wraps the given input tar archive stream and | ||||||||||||||||||||||||||||||||||||||
| // uses the translator to replace the Dockerfile which uses a trusted reference. | ||||||||||||||||||||||||||||||||||||||
| // Returns a new tar archive stream with the replaced Dockerfile. | ||||||||||||||||||||||||||||||||||||||
| func replaceDockerfileForContentTrust(ctx context.Context, inputTarStream io.ReadCloser, dockerfileName string, translator translatorFunc, resolvedTags *[]*resolvedTag) io.ReadCloser { | ||||||||||||||||||||||||||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We could rename these functions to, e.g. |
||||||||||||||||||||||||||||||||||||||
| pipeReader, pipeWriter := io.Pipe() | ||||||||||||||||||||||||||||||||||||||
| go func() { | ||||||||||||||||||||||||||||||||||||||
| tarReader := tar.NewReader(inputTarStream) | ||||||||||||||||||||||||||||||||||||||
|
|
@@ -574,7 +574,7 @@ func replaceDockerfileTarWrapper(ctx context.Context, inputTarStream io.ReadClos | |||||||||||||||||||||||||||||||||||||
| // generated from a directory on the local filesystem, the | ||||||||||||||||||||||||||||||||||||||
| // Dockerfile will only appear once in the archive. | ||||||||||||||||||||||||||||||||||||||
| var newDockerfile []byte | ||||||||||||||||||||||||||||||||||||||
| newDockerfile, *resolvedTags, err = rewriteDockerfileFrom(ctx, content, translator) | ||||||||||||||||||||||||||||||||||||||
| newDockerfile, *resolvedTags, err = rewriteDockerfileFrom(ctx, content, translator, true) | ||||||||||||||||||||||||||||||||||||||
| if err != nil { | ||||||||||||||||||||||||||||||||||||||
| pipeWriter.CloseWithError(err) | ||||||||||||||||||||||||||||||||||||||
| return | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
way cleaner! 👍