Skip to content

Commit

Permalink
Merge pull request moby#14980 from jlhawn/build_tag_resolved_digests
Browse files Browse the repository at this point in the history
[api/client] Tag resolved digest from Dockerfile
  • Loading branch information
Arnaud Porterie committed Jul 29, 2015
2 parents 887882c + bb2e6c7 commit d94aeb2
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 11 deletions.
50 changes: 41 additions & 9 deletions api/client/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,8 +114,9 @@ func (cli *DockerCli) CmdBuild(args ...string) error {
}

// Resolve the FROM lines in the Dockerfile to trusted digest references
// using Notary.
newDockerfile, err := rewriteDockerfileFrom(filepath.Join(contextDir, relDockerfile), cli.trustedReference)
// using Notary. On a successful build, we must tag the resolved digests
// to the original name specified in the Dockerfile.
newDockerfile, resolvedTags, err := rewriteDockerfileFrom(filepath.Join(contextDir, relDockerfile), cli.trustedReference)
if err != nil {
return fmt.Errorf("unable to process Dockerfile: %v", err)
}
Expand Down Expand Up @@ -290,7 +291,20 @@ func (cli *DockerCli) CmdBuild(args ...string) error {
}
return Cli.StatusError{Status: jerr.Message, StatusCode: jerr.Code}
}
return err

if err != nil {
return err
}

// Since the build was successful, now we must tag any of the resolved
// images from the above Dockerfile rewrite.
for _, resolved := range resolvedTags {
if err := cli.tagTrusted(resolved.repoInfo, resolved.digestRef, resolved.tagRef); err != nil {
return err
}
}

return nil
}

// getDockerfileRelPath uses the given context directory for a `docker build`
Expand Down Expand Up @@ -486,14 +500,21 @@ func (td *trustedDockerfile) Close() error {
return os.Remove(td.File.Name())
}

// resolvedTag records the repository, tag, and resolved digest reference
// from a Dockerfile rewrite.
type resolvedTag struct {
repoInfo *registry.RepositoryInfo
digestRef, tagRef registry.Reference
}

// rewriteDockerfileFrom rewrites the given Dockerfile by resolving images in
// "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(dockerfileName string, translator func(string, registry.Reference) (registry.Reference, error)) (newDockerfile *trustedDockerfile, err error) {
func rewriteDockerfileFrom(dockerfileName string, translator func(string, registry.Reference) (registry.Reference, error)) (newDockerfile *trustedDockerfile, resolvedTags []*resolvedTag, err error) {
dockerfile, err := os.Open(dockerfileName)
if err != nil {
return nil, fmt.Errorf("unable to open Dockerfile: %v", err)
return nil, nil, fmt.Errorf("unable to open Dockerfile: %v", err)
}
defer dockerfile.Close()

Expand All @@ -502,7 +523,7 @@ func rewriteDockerfileFrom(dockerfileName string, translator func(string, regist
// Make a tempfile to store the rewritten Dockerfile.
tempFile, err := ioutil.TempFile("", "trusted-dockerfile-")
if err != nil {
return nil, fmt.Errorf("unable to make temporary trusted Dockerfile: %v", err)
return nil, nil, fmt.Errorf("unable to make temporary trusted Dockerfile: %v", err)
}

trustedFile := &trustedDockerfile{
Expand All @@ -528,29 +549,40 @@ func rewriteDockerfileFrom(dockerfileName string, translator func(string, regist
if tag == "" {
tag = tags.DEFAULTTAG
}

repoInfo, err := registry.ParseRepositoryInfo(repo)
if err != nil {
return nil, nil, fmt.Errorf("unable to parse repository info: %v", err)
}

ref := registry.ParseReference(tag)

if !ref.HasDigest() && isTrusted() {
trustedRef, err := translator(repo, ref)
if err != nil {
return nil, err
return nil, nil, err
}

line = dockerfileFromLinePattern.ReplaceAllLiteralString(line, fmt.Sprintf("FROM %s", trustedRef.ImageName(repo)))
resolvedTags = append(resolvedTags, &resolvedTag{
repoInfo: repoInfo,
digestRef: trustedRef,
tagRef: ref,
})
}
}

n, err := fmt.Fprintln(tempFile, line)
if err != nil {
return nil, err
return nil, nil, err
}

trustedFile.size += int64(n)
}

tempFile.Seek(0, os.SEEK_SET)

return trustedFile, scanner.Err()
return trustedFile, resolvedTags, scanner.Err()
}

// replaceDockerfileTarWrapper wraps the given input tar archive stream and
Expand Down
11 changes: 9 additions & 2 deletions integration-cli/docker_cli_build_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5370,8 +5370,15 @@ func (s *DockerTrustSuite) TestTrustedBuild(c *check.C) {
c.Fatalf("Unexpected output on trusted build:\n%s", out)
}

// Build command does not create untrusted tag
//dockerCmd(c, "rmi", repoName)
// We should also have a tag reference for the image.
if out, exitCode := dockerCmd(c, "inspect", repoName); exitCode != 0 {
c.Fatalf("unexpected exit code inspecting image %q: %d: %s", repoName, exitCode, out)
}

// We should now be able to remove the tag reference.
if out, exitCode := dockerCmd(c, "rmi", repoName); exitCode != 0 {
c.Fatalf("unexpected exit code inspecting image %q: %d: %s", repoName, exitCode, out)
}
}

func (s *DockerTrustSuite) TestTrustedBuildUntrustedTag(c *check.C) {
Expand Down

0 comments on commit d94aeb2

Please sign in to comment.