Builds where the base images have been resolved to trusted digest
references will now be tagged with the original tag reference from
the Dockerfile on a successful build.
Docker-DCO-1.1-Signed-off-by: Josh Hawn <josh.hawn@docker.com> (github: jlhawn)
| ... | ... |
@@ -115,8 +115,9 @@ func (cli *DockerCli) CmdBuild(args ...string) error {
|
| 115 | 115 |
} |
| 116 | 116 |
|
| 117 | 117 |
// Resolve the FROM lines in the Dockerfile to trusted digest references |
| 118 |
- // using Notary. |
|
| 119 |
- newDockerfile, err := rewriteDockerfileFrom(filepath.Join(contextDir, relDockerfile), cli.trustedReference) |
|
| 118 |
+ // using Notary. On a successful build, we must tag the resolved digests |
|
| 119 |
+ // to the original name specified in the Dockerfile. |
|
| 120 |
+ newDockerfile, resolvedTags, err := rewriteDockerfileFrom(filepath.Join(contextDir, relDockerfile), cli.trustedReference) |
|
| 120 | 121 |
if err != nil {
|
| 121 | 122 |
return fmt.Errorf("unable to process Dockerfile: %v", err)
|
| 122 | 123 |
} |
| ... | ... |
@@ -291,7 +292,20 @@ func (cli *DockerCli) CmdBuild(args ...string) error {
|
| 291 | 291 |
} |
| 292 | 292 |
return Cli.StatusError{Status: jerr.Message, StatusCode: jerr.Code}
|
| 293 | 293 |
} |
| 294 |
- return err |
|
| 294 |
+ |
|
| 295 |
+ if err != nil {
|
|
| 296 |
+ return err |
|
| 297 |
+ } |
|
| 298 |
+ |
|
| 299 |
+ // Since the build was successful, now we must tag any of the resolved |
|
| 300 |
+ // images from the above Dockerfile rewrite. |
|
| 301 |
+ for _, resolved := range resolvedTags {
|
|
| 302 |
+ if err := cli.tagTrusted(resolved.repoInfo, resolved.digestRef, resolved.tagRef); err != nil {
|
|
| 303 |
+ return err |
|
| 304 |
+ } |
|
| 305 |
+ } |
|
| 306 |
+ |
|
| 307 |
+ return nil |
|
| 295 | 308 |
} |
| 296 | 309 |
|
| 297 | 310 |
// getDockerfileRelPath uses the given context directory for a `docker build` |
| ... | ... |
@@ -483,14 +497,21 @@ func (td *trustedDockerfile) Close() error {
|
| 483 | 483 |
return os.Remove(td.File.Name()) |
| 484 | 484 |
} |
| 485 | 485 |
|
| 486 |
+// resolvedTag records the repository, tag, and resolved digest reference |
|
| 487 |
+// from a Dockerfile rewrite. |
|
| 488 |
+type resolvedTag struct {
|
|
| 489 |
+ repoInfo *registry.RepositoryInfo |
|
| 490 |
+ digestRef, tagRef registry.Reference |
|
| 491 |
+} |
|
| 492 |
+ |
|
| 486 | 493 |
// rewriteDockerfileFrom rewrites the given Dockerfile by resolving images in |
| 487 | 494 |
// "FROM <image>" instructions to a digest reference. `translator` is a |
| 488 | 495 |
// function that takes a repository name and tag reference and returns a |
| 489 | 496 |
// trusted digest reference. |
| 490 |
-func rewriteDockerfileFrom(dockerfileName string, translator func(string, registry.Reference) (registry.Reference, error)) (newDockerfile *trustedDockerfile, err error) {
|
|
| 497 |
+func rewriteDockerfileFrom(dockerfileName string, translator func(string, registry.Reference) (registry.Reference, error)) (newDockerfile *trustedDockerfile, resolvedTags []*resolvedTag, err error) {
|
|
| 491 | 498 |
dockerfile, err := os.Open(dockerfileName) |
| 492 | 499 |
if err != nil {
|
| 493 |
- return nil, fmt.Errorf("unable to open Dockerfile: %v", err)
|
|
| 500 |
+ return nil, nil, fmt.Errorf("unable to open Dockerfile: %v", err)
|
|
| 494 | 501 |
} |
| 495 | 502 |
defer dockerfile.Close() |
| 496 | 503 |
|
| ... | ... |
@@ -499,7 +520,7 @@ func rewriteDockerfileFrom(dockerfileName string, translator func(string, regist |
| 499 | 499 |
// Make a tempfile to store the rewritten Dockerfile. |
| 500 | 500 |
tempFile, err := ioutil.TempFile("", "trusted-dockerfile-")
|
| 501 | 501 |
if err != nil {
|
| 502 |
- return nil, fmt.Errorf("unable to make temporary trusted Dockerfile: %v", err)
|
|
| 502 |
+ return nil, nil, fmt.Errorf("unable to make temporary trusted Dockerfile: %v", err)
|
|
| 503 | 503 |
} |
| 504 | 504 |
|
| 505 | 505 |
trustedFile := &trustedDockerfile{
|
| ... | ... |
@@ -525,21 +546,32 @@ func rewriteDockerfileFrom(dockerfileName string, translator func(string, regist |
| 525 | 525 |
if tag == "" {
|
| 526 | 526 |
tag = tags.DEFAULTTAG |
| 527 | 527 |
} |
| 528 |
+ |
|
| 529 |
+ repoInfo, err := registry.ParseRepositoryInfo(repo) |
|
| 530 |
+ if err != nil {
|
|
| 531 |
+ return nil, nil, fmt.Errorf("unable to parse repository info: %v", err)
|
|
| 532 |
+ } |
|
| 533 |
+ |
|
| 528 | 534 |
ref := registry.ParseReference(tag) |
| 529 | 535 |
|
| 530 | 536 |
if !ref.HasDigest() && isTrusted() {
|
| 531 | 537 |
trustedRef, err := translator(repo, ref) |
| 532 | 538 |
if err != nil {
|
| 533 |
- return nil, err |
|
| 539 |
+ return nil, nil, err |
|
| 534 | 540 |
} |
| 535 | 541 |
|
| 536 | 542 |
line = dockerfileFromLinePattern.ReplaceAllLiteralString(line, fmt.Sprintf("FROM %s", trustedRef.ImageName(repo)))
|
| 543 |
+ resolvedTags = append(resolvedTags, &resolvedTag{
|
|
| 544 |
+ repoInfo: repoInfo, |
|
| 545 |
+ digestRef: trustedRef, |
|
| 546 |
+ tagRef: ref, |
|
| 547 |
+ }) |
|
| 537 | 548 |
} |
| 538 | 549 |
} |
| 539 | 550 |
|
| 540 | 551 |
n, err := fmt.Fprintln(tempFile, line) |
| 541 | 552 |
if err != nil {
|
| 542 |
- return nil, err |
|
| 553 |
+ return nil, nil, err |
|
| 543 | 554 |
} |
| 544 | 555 |
|
| 545 | 556 |
trustedFile.size += int64(n) |
| ... | ... |
@@ -547,7 +579,7 @@ func rewriteDockerfileFrom(dockerfileName string, translator func(string, regist |
| 547 | 547 |
|
| 548 | 548 |
tempFile.Seek(0, os.SEEK_SET) |
| 549 | 549 |
|
| 550 |
- return trustedFile, scanner.Err() |
|
| 550 |
+ return trustedFile, resolvedTags, scanner.Err() |
|
| 551 | 551 |
} |
| 552 | 552 |
|
| 553 | 553 |
// replaceDockerfileTarWrapper wraps the given input tar archive stream and |
| ... | ... |
@@ -5370,8 +5370,15 @@ func (s *DockerTrustSuite) TestTrustedBuild(c *check.C) {
|
| 5370 | 5370 |
c.Fatalf("Unexpected output on trusted build:\n%s", out)
|
| 5371 | 5371 |
} |
| 5372 | 5372 |
|
| 5373 |
- // Build command does not create untrusted tag |
|
| 5374 |
- //dockerCmd(c, "rmi", repoName) |
|
| 5373 |
+ // We should also have a tag reference for the image. |
|
| 5374 |
+ if out, exitCode := dockerCmd(c, "inspect", repoName); exitCode != 0 {
|
|
| 5375 |
+ c.Fatalf("unexpected exit code inspecting image %q: %d: %s", repoName, exitCode, out)
|
|
| 5376 |
+ } |
|
| 5377 |
+ |
|
| 5378 |
+ // We should now be able to remove the tag reference. |
|
| 5379 |
+ if out, exitCode := dockerCmd(c, "rmi", repoName); exitCode != 0 {
|
|
| 5380 |
+ c.Fatalf("unexpected exit code inspecting image %q: %d: %s", repoName, exitCode, out)
|
|
| 5381 |
+ } |
|
| 5375 | 5382 |
} |
| 5376 | 5383 |
|
| 5377 | 5384 |
func (s *DockerTrustSuite) TestTrustedBuildUntrustedTag(c *check.C) {
|