diff --git a/cmd/buildah/bud.go b/cmd/buildah/bud.go index 9368f4580..93c9acfd1 100644 --- a/cmd/buildah/bud.go +++ b/cmd/buildah/bud.go @@ -16,7 +16,7 @@ import ( "github.com/spf13/cobra" ) -type budResults struct { +type budOptions struct { *buildahcli.LayerResults *buildahcli.BudResults *buildahcli.UserNSResults @@ -45,7 +45,7 @@ func init() { Long: budDescription, //Flags: sortFlags(append(append(buildahcli.BudFlags, buildahcli.LayerFlags...), buildahcli.FromAndBudFlags...)), RunE: func(cmd *cobra.Command, args []string) error { - br := budResults{ + br := budOptions{ &layerFlagsResults, &budFlagResults, &userNSResults, @@ -90,7 +90,7 @@ func getDockerfiles(files []string) []string { return dockerfiles } -func budCmd(c *cobra.Command, inputArgs []string, iopts budResults) error { +func budCmd(c *cobra.Command, inputArgs []string, iopts budOptions) error { output := "" tags := []string{} if c.Flag("tag").Changed { @@ -340,6 +340,7 @@ func budCmd(c *cobra.Command, inputArgs []string, iopts budResults) error { TransientMounts: transientMounts, Devices: devices, DefaultEnv: defaultContainerConfig.GetDefaultEnv(), + SignBy: iopts.SignBy, } if iopts.Quiet { diff --git a/cmd/buildah/commit.go b/cmd/buildah/commit.go index fb2a8510b..919234567 100644 --- a/cmd/buildah/commit.go +++ b/cmd/buildah/commit.go @@ -31,6 +31,7 @@ type commitInputOptions struct { referenceTime string rm bool signaturePolicy string + signBy string squash bool tlsVerify bool } @@ -70,6 +71,7 @@ func init() { flags.BoolVar(&opts.omitTimestamp, "omit-timestamp", false, "set created timestamp to epoch 0 to allow for deterministic builds") flags.BoolVarP(&opts.quiet, "quiet", "q", false, "don't output progress information when writing images") flags.StringVar(&opts.referenceTime, "reference-time", "", "set the timestamp on the image to match the named `file`") + flags.StringVar(&opts.signBy, "sign-by", "", "sign the image using a GPG key with the specified `FINGERPRINT`") if err := flags.MarkHidden("reference-time"); err != nil { panic(fmt.Sprintf("error marking reference-time as hidden: %v", err)) @@ -175,6 +177,7 @@ func commitCmd(c *cobra.Command, args []string, iopts commitInputOptions) error Squash: iopts.squash, BlobDirectory: iopts.blobCache, OmitTimestamp: iopts.omitTimestamp, + SignBy: iopts.signBy, } if !iopts.quiet { options.ReportWriter = os.Stderr diff --git a/cmd/buildah/manifest.go b/cmd/buildah/manifest.go index 6d2062660..5fe5c304b 100644 --- a/cmd/buildah/manifest.go +++ b/cmd/buildah/manifest.go @@ -38,8 +38,8 @@ type manifestAnnotateOpts = struct { } type manifestInspectOpts = struct{} type manifestPushOpts = struct { - purge, quiet, all, tlsVerify bool - authfile, certDir, creds, digestfile, signaturePolicy string + purge, quiet, all, tlsVerify, removeSignatures bool + authfile, certDir, creds, digestfile, signaturePolicy, signBy string } func init() { @@ -194,6 +194,8 @@ func init() { flags.StringVar(&manifestPushOpts.certDir, "cert-dir", "", "use certificates at the specified path to access the registry") flags.StringVar(&manifestPushOpts.creds, "creds", "", "use `[username[:password]]` for accessing the registry") flags.StringVar(&manifestPushOpts.digestfile, "digestfile", "", "after copying the image, write the digest of the resulting digest to the file") + flags.BoolVarP(&manifestPushOpts.removeSignatures, "remove-signatures", "", false, "don't copy signatures when pushing images") + flags.StringVar(&manifestPushOpts.signBy, "sign-by", "", "sign the image using a GPG key with the specified `FINGERPRINT`") flags.StringVar(&manifestPushOpts.signaturePolicy, "signature-policy", "", "`pathname` of signature policy file (not usually used)") if err := flags.MarkHidden("signature-policy"); err != nil { panic(fmt.Sprintf("error marking signature-policy as hidden: %v", err)) @@ -642,6 +644,8 @@ func manifestPushCmd(c *cobra.Command, args []string, opts manifestPushOpts) err SystemContext: systemContext, ImageListSelection: cp.CopySpecificImages, Instances: nil, + RemoveSignatures: opts.removeSignatures, + SignBy: opts.signBy, } if opts.all { options.ImageListSelection = cp.CopyAllImages diff --git a/cmd/buildah/pull.go b/cmd/buildah/pull.go index 72e93ae46..c99b6803a 100644 --- a/cmd/buildah/pull.go +++ b/cmd/buildah/pull.go @@ -12,22 +12,23 @@ import ( "github.com/spf13/cobra" ) -type pullResults struct { - allTags bool - authfile string - blobCache string - certDir string - creds string - overrideArch string - overrideOS string - signaturePolicy string - quiet bool - tlsVerify bool +type pullOptions struct { + allTags bool + authfile string + blobCache string + certDir string + creds string + overrideArch string + overrideOS string + signaturePolicy string + quiet bool + removeSignatures bool + tlsVerify bool } func init() { var ( - opts pullResults + opts pullOptions pullDescription = ` Pulls an image from a registry and stores it locally. An image can be pulled using its tag or digest. If a tag is not @@ -54,6 +55,7 @@ func init() { flags.StringVar(&opts.blobCache, "blob-cache", "", "store copies of pulled image blobs in the specified directory") flags.StringVar(&opts.certDir, "cert-dir", "", "use certificates at the specified path to access the registry") flags.StringVar(&opts.creds, "creds", "", "use `[username[:password]]` for accessing the registry") + flags.BoolVarP(&opts.removeSignatures, "remove-signatures", "", false, "don't copy signatures when pulling image") flags.StringVar(&opts.signaturePolicy, "signature-policy", "", "`pathname` of signature policy file (not usually used)") if err := flags.MarkHidden("signature-policy"); err != nil { panic(fmt.Sprintf("error marking signature-policy as hidden: %v", err)) @@ -75,7 +77,7 @@ func init() { rootCmd.AddCommand(pullCommand) } -func pullCmd(c *cobra.Command, args []string, iopts pullResults) error { +func pullCmd(c *cobra.Command, args []string, iopts pullOptions) error { if len(args) == 0 { return errors.Errorf("an image name must be specified") } @@ -106,6 +108,7 @@ func pullCmd(c *cobra.Command, args []string, iopts pullResults) error { BlobDirectory: iopts.blobCache, AllTags: iopts.allTags, ReportWriter: os.Stderr, + RemoveSignatures: iopts.removeSignatures, } if iopts.quiet { diff --git a/cmd/buildah/push.go b/cmd/buildah/push.go index 776612cee..93a60c8c8 100644 --- a/cmd/buildah/push.go +++ b/cmd/buildah/push.go @@ -20,7 +20,7 @@ import ( "github.com/spf13/cobra" ) -type pushResults struct { +type pushOptions struct { authfile string blobCache string certDir string @@ -29,13 +29,15 @@ type pushResults struct { disableCompression bool format string quiet bool + removeSignatures bool signaturePolicy string + signBy string tlsVerify bool } func init() { var ( - opts pushResults + opts pushOptions pushDescription = fmt.Sprintf(` Pushes an image to a specified location. @@ -71,6 +73,8 @@ func init() { flags.BoolVarP(&opts.disableCompression, "disable-compression", "D", false, "don't compress layers") flags.StringVarP(&opts.format, "format", "f", "", "manifest type (oci, v2s1, or v2s2) to use when saving image using the 'dir:' transport (default is manifest type of source)") flags.BoolVarP(&opts.quiet, "quiet", "q", false, "don't output progress information when pushing images") + flags.BoolVarP(&opts.removeSignatures, "remove-signatures", "", false, "don't copy signatures when pushing image") + flags.StringVar(&opts.signBy, "sign-by", "", "sign the image using a GPG key with the specified `FINGERPRINT`") flags.StringVar(&opts.signaturePolicy, "signature-policy", "", "`pathname` of signature policy file (not usually used)") if err := flags.MarkHidden("signature-policy"); err != nil { panic(fmt.Sprintf("error marking signature-policy as hidden: %v", err)) @@ -83,7 +87,7 @@ func init() { rootCmd.AddCommand(pushCommand) } -func pushCmd(c *cobra.Command, args []string, iopts pushResults) error { +func pushCmd(c *cobra.Command, args []string, iopts pushOptions) error { var src, destSpec string if err := buildahcli.VerifyFlagsArgsOrder(args); err != nil { @@ -167,6 +171,8 @@ func pushCmd(c *cobra.Command, args []string, iopts pushResults) error { Store: store, SystemContext: systemContext, BlobDirectory: iopts.blobCache, + RemoveSignatures: iopts.removeSignatures, + SignBy: iopts.signBy, } if !iopts.quiet { options.ReportWriter = os.Stderr diff --git a/commit.go b/commit.go index 24642f4dc..aa0ac2713 100644 --- a/commit.go +++ b/commit.go @@ -81,6 +81,8 @@ type CommitOptions struct { // OmitTimestamp forces epoch 0 as created timestamp to allow for // deterministic, content-addressable builds. OmitTimestamp bool + // SignBy is the fingerprint of a GPG key to use for signing the image. + SignBy string } // PushOptions can be used to alter how an image is copied somewhere. @@ -115,6 +117,11 @@ type PushOptions struct { // the user will be displayed, this is best used for logging. // The default is false. Quiet bool + // SignBy is the fingerprint of a GPG key to use for signing the image. + SignBy string + // RemoveSignatures causes any existing signatures for the image to be + // discarded for the pushed copy. + RemoveSignatures bool } var ( @@ -294,7 +301,7 @@ func (b *Builder) Commit(ctx context.Context, dest types.ImageReference, options systemContext.DirForceCompress = true } var manifestBytes []byte - if manifestBytes, err = cp.Image(ctx, policyContext, maybeCachedDest, maybeCachedSrc, getCopyOptions(b.store, options.ReportWriter, nil, systemContext, "")); err != nil { + if manifestBytes, err = cp.Image(ctx, policyContext, maybeCachedDest, maybeCachedSrc, getCopyOptions(b.store, options.ReportWriter, nil, systemContext, "", false, options.SignBy)); err != nil { return imgID, nil, "", errors.Wrapf(err, "error copying layers and metadata for container %q", b.ContainerID) } // If we've got more names to attach, and we know how to do that for @@ -426,7 +433,7 @@ func Push(ctx context.Context, image string, dest types.ImageReference, options systemContext.DirForceCompress = true } var manifestBytes []byte - if manifestBytes, err = cp.Image(ctx, policyContext, dest, maybeCachedSrc, getCopyOptions(options.Store, options.ReportWriter, nil, systemContext, options.ManifestType)); err != nil { + if manifestBytes, err = cp.Image(ctx, policyContext, dest, maybeCachedSrc, getCopyOptions(options.Store, options.ReportWriter, nil, systemContext, options.ManifestType, options.RemoveSignatures, options.SignBy)); err != nil { return nil, "", errors.Wrapf(err, "error copying layers and metadata from %q to %q", transports.ImageName(maybeCachedSrc), transports.ImageName(dest)) } if options.ReportWriter != nil { diff --git a/common.go b/common.go index 35a7c6538..a3ef70ec5 100644 --- a/common.go +++ b/common.go @@ -18,7 +18,7 @@ const ( DOCKER = "docker" ) -func getCopyOptions(store storage.Store, reportWriter io.Writer, sourceSystemContext *types.SystemContext, destinationSystemContext *types.SystemContext, manifestType string) *cp.Options { +func getCopyOptions(store storage.Store, reportWriter io.Writer, sourceSystemContext *types.SystemContext, destinationSystemContext *types.SystemContext, manifestType string, removeSignatures bool, addSigner string) *cp.Options { sourceCtx := getSystemContext(store, nil, "") if sourceSystemContext != nil { *sourceCtx = *sourceSystemContext @@ -33,6 +33,8 @@ func getCopyOptions(store storage.Store, reportWriter io.Writer, sourceSystemCon SourceCtx: sourceCtx, DestinationCtx: destinationCtx, ForceManifestMIMEType: manifestType, + RemoveSignatures: removeSignatures, + SignBy: addSigner, } } diff --git a/contrib/completions/bash/buildah b/contrib/completions/bash/buildah index ee4ef729c..e2e4eb1e4 100644 --- a/contrib/completions/bash/buildah +++ b/contrib/completions/bash/buildah @@ -326,6 +326,7 @@ return 1 --format -f --iidfile + --sign-by " local all_options="$options_with_args $boolean_options" @@ -415,6 +416,7 @@ return 1 --runtime-flag --security-opt --shm-size + --sign-by -t --tag --target @@ -577,6 +579,7 @@ return 1 --quiet -q --tls-verify + --remove-signatures " local options_with_args=" @@ -603,6 +606,7 @@ return 1 --quiet -q --tls-verify + --remove-signatures " local options_with_args=" @@ -611,6 +615,7 @@ return 1 --creds --format -f + --sign-by " local all_options="$options_with_args $boolean_options" @@ -810,6 +815,7 @@ return 1 --help -h --all + --remove-signatures " local options_with_args=" @@ -818,6 +824,7 @@ return 1 --creds --digestfile --purge + --sign-by --tls-verify " diff --git a/docs/buildah-bud.md b/docs/buildah-bud.md index 10829ed46..89b11c8f7 100644 --- a/docs/buildah-bud.md +++ b/docs/buildah-bud.md @@ -414,6 +414,10 @@ Size of `/dev/shm`. The format is ``. `number` must be greater tha Unit is optional and can be `b` (bytes), `k` (kilobytes), `m`(megabytes), or `g` (gigabytes). If you omit the unit, the system uses bytes. If you omit the size entirely, the system uses `64m`. +**--sign-by** *fingerprint* + +Sign the built image using the GPG key that matches the specified fingerprint. + **--squash** Squash all of the new image's layers (including those inherited from a base image) into a single new layer. diff --git a/docs/buildah-commit.md b/docs/buildah-commit.md index 9183c1b36..5e37cc15f 100644 --- a/docs/buildah-commit.md +++ b/docs/buildah-commit.md @@ -64,6 +64,10 @@ When writing the output image, suppress progress output. Remove the container and its content after committing it to an image. Default leaves the container and its content in place. +**--sign-by** *fingerprint* + +Sign the new image using the GPG key that matches the specified fingerprint. + **--squash** Squash all of the new image's layers (including those inherited from a base image) into a single new layer. diff --git a/docs/buildah-manifest-push.md b/docs/buildah-manifest-push.md index e1f2cf176..edff90de6 100644 --- a/docs/buildah-manifest-push.md +++ b/docs/buildah-manifest-push.md @@ -47,6 +47,14 @@ After copying the image, write the digest of the resulting image to the file. Delete the manifest list or image index from local storage if pushing succeeds. +**--remove-signatures** + +Don't copy signatures when pushing images. + +**--sign-by** *fingerprint* + +Sign the pushed images using the GPG key that matches the specified fingerprint. + **--tls-verify** *bool-value* Require HTTPS and verify certificates when talking to container registries (defaults to true) diff --git a/docs/buildah-pull.md b/docs/buildah-pull.md index 10595dad1..4d0d7d8bc 100644 --- a/docs/buildah-pull.md +++ b/docs/buildah-pull.md @@ -66,6 +66,10 @@ value can be entered. The password is entered without echo. If an image needs to be pulled from the registry, suppress progress output. +**--remove-signatures** + +Don't copy signatures when pulling images. + **--shm-size**="" Size of `/dev/shm`. The format is ``. `number` must be greater than `0`. diff --git a/docs/buildah-push.md b/docs/buildah-push.md index c7124b449..25de97cf5 100644 --- a/docs/buildah-push.md +++ b/docs/buildah-push.md @@ -1,4 +1,4 @@ -# buildah-push"1" "June 2017" "buildah" +# buildah-push "1" "June 2017" "buildah" ## NAME buildah\-push - Push an image from local storage to elsewhere. @@ -74,6 +74,14 @@ Manifest Type (oci, v2s1, or v2s2) to use when saving image to directory using t When writing the output image, suppress progress output. +**--remove-signatures** + +Don't copy signatures when pushing images. + +**--sign-by** *fingerprint* + +Sign the pushed image using the GPG key that matches the specified fingerprint. + **--tls-verify** *bool-value* Require HTTPS and verify certificates when talking to container registries (defaults to true) diff --git a/docs/buildah-rename.md b/docs/buildah-rename.md index f27c5352b..e1037152a 100644 --- a/docs/buildah-rename.md +++ b/docs/buildah-rename.md @@ -1,4 +1,4 @@ -# buildah-rename "9" "July 2018" "buildah" +# buildah-rename "1" "July 2018" "buildah" ## NAME buildah\-rename - Rename a local container. diff --git a/imagebuildah/build.go b/imagebuildah/build.go index bdd717ad4..5d315ac67 100644 --- a/imagebuildah/build.go +++ b/imagebuildah/build.go @@ -152,12 +152,14 @@ type BuildOptions struct { ForceRmIntermediateCtrs bool // BlobDirectory is a directory which we'll use for caching layer blobs. BlobDirectory string - // Target the targeted FROM in the Dockerfile to build + // Target the targeted FROM in the Dockerfile to build. Target string - // Devices are the additional devices to add to the containers + // Devices are the additional devices to add to the containers. Devices []configs.Device - //DefaultEnv for containers + // DefaultEnv for containers. DefaultEnv []string + // SignBy is the fingerprint of a GPG key to use for signing images. + SignBy string } // BuildDockerfiles parses a set of one or more Dockerfiles (which may be diff --git a/imagebuildah/executor.go b/imagebuildah/executor.go index f319f1562..839d91a71 100644 --- a/imagebuildah/executor.go +++ b/imagebuildah/executor.go @@ -93,6 +93,7 @@ type Executor struct { buildArgs map[string]string capabilities []string devices []configs.Device + signBy string } // NewExecutor creates a new instance of the imagebuilder.Executor interface. @@ -149,6 +150,7 @@ func NewExecutor(store storage.Store, options BuildOptions, mainNode *parser.Nod buildArgs: options.Args, capabilities: options.Capabilities, devices: options.Devices, + signBy: options.SignBy, } if exec.err == nil { exec.err = os.Stderr diff --git a/imagebuildah/stage_executor.go b/imagebuildah/stage_executor.go index cf5f4234f..4fd630a83 100644 --- a/imagebuildah/stage_executor.go +++ b/imagebuildah/stage_executor.go @@ -1203,6 +1203,7 @@ func (s *StageExecutor) commit(ctx context.Context, ib *imagebuilder.Builder, cr Squash: s.executor.squash, EmptyLayer: emptyLayer, BlobDirectory: s.executor.blobDirectory, + SignBy: s.executor.signBy, } imgID, _, manifestDigest, err := s.builder.Commit(ctx, imageRef, options) if err != nil { diff --git a/manifests/manifests.go b/manifests/manifests.go index cfd141830..c3efea100 100644 --- a/manifests/manifests.go +++ b/manifests/manifests.go @@ -53,6 +53,8 @@ type PushOptions struct { ImageListSelection cp.ImageListSelection // set to either CopySystemImage, CopyAllImages, or CopySpecificImages Instances []digest.Digest // instances to copy if ImageListSelection == CopySpecificImages ReportWriter io.Writer // will be used to log the writing of the list and any blobs + SignBy string // fingerprint of GPG key to use to sign images + RemoveSignatures bool // true to discard signatures in images } // Create creates a new list containing information about the specified image, @@ -211,6 +213,8 @@ func (l *list) Push(ctx context.Context, dest types.ImageReference, options Push SourceCtx: options.SystemContext, DestinationCtx: options.SystemContext, ReportWriter: options.ReportWriter, + RemoveSignatures: options.RemoveSignatures, + SignBy: options.SignBy, } // Copy whatever we were asked to copy. diff --git a/pkg/cli/common.go b/pkg/cli/common.go index a2baa65b6..1e74072d5 100644 --- a/pkg/cli/common.go +++ b/pkg/cli/common.go @@ -70,6 +70,7 @@ type BudResults struct { Runtime string RuntimeFlags []string SignaturePolicy string + SignBy string Squash bool Tag []string Target string @@ -168,8 +169,9 @@ func GetBudFlags(flags *BudResults) pflag.FlagSet { fs.BoolVar(&flags.Rm, "rm", true, "Remove intermediate containers after a successful build") // "runtime" definition moved to avoid name collision in podman build. Defined in cmd/buildah/bud.go. fs.StringSliceVar(&flags.RuntimeFlags, "runtime-flag", []string{}, "add global flags for the container runtime") + fs.StringVar(&flags.SignBy, "sign-by", "", "sign the image using a GPG key with the specified `FINGERPRINT`") fs.StringVar(&flags.SignaturePolicy, "signature-policy", "", "`pathname` of signature policy file (not usually used)") - fs.BoolVar(&flags.Squash, "squash", false, "Squash newly built layers into a single new layer.") + fs.BoolVar(&flags.Squash, "squash", false, "squash newly built layers into a single new layer") fs.StringArrayVarP(&flags.Tag, "tag", "t", []string{}, "tagged `name` to apply to the built image") fs.StringVar(&flags.Target, "target", "", "set the target build stage to build") fs.BoolVar(&flags.TLSVerify, "tls-verify", true, "require HTTPS and verify certificates when accessing the registry") diff --git a/pull.go b/pull.go index 300f3b396..b6204c9d1 100644 --- a/pull.go +++ b/pull.go @@ -49,6 +49,9 @@ type PullOptions struct { // AllTags is a boolean value that determines if all tagged images // will be downloaded from the repository. The default is false. AllTags bool + // RemoveSignatures causes any existing signatures for the image to be + // discarded when pulling it. + RemoveSignatures bool } func localImageNameForReference(ctx context.Context, store storage.Store, srcRef types.ImageReference) (string, error) { @@ -260,7 +263,7 @@ func pullImage(ctx context.Context, store storage.Store, srcRef types.ImageRefer }() logrus.Debugf("copying %q to %q", transports.ImageName(srcRef), destName) - if _, err := cp.Image(ctx, policyContext, maybeCachedDestRef, srcRef, getCopyOptions(store, options.ReportWriter, sc, nil, "")); err != nil { + if _, err := cp.Image(ctx, policyContext, maybeCachedDestRef, srcRef, getCopyOptions(store, options.ReportWriter, sc, nil, "", options.RemoveSignatures, "")); err != nil { logrus.Debugf("error copying src image [%q] to dest image [%q] err: %v", transports.ImageName(srcRef), destName, err) return nil, err } diff --git a/tests/sign.bats b/tests/sign.bats new file mode 100644 index 000000000..b0e337597 --- /dev/null +++ b/tests/sign.bats @@ -0,0 +1,94 @@ +#!/usr/bin/env bats + +load helpers + +@test "commit-pull-push-signatures" { + if ! which gpg > /dev/null 2> /dev/null ; then + skip 'gpg command not found in $PATH' + fi + + export GNUPGHOME=${TESTDIR}/.gnupg + cat > genkey-answers <<- EOF + %echo Generating a basic OpenPGP key + Key-Type: RSA + Key-Length: 512 + Name-Real: Amanda Lorian + Name-Comment: Mandy to her friends + Name-Email: amanda@localhost + %commit + %echo done + EOF + gpg --batch --gen-key < genkey-answers + + mkdir -p ${TESTDIR}/signed-image ${TESTDIR}/unsigned-image + + run_buildah from --quiet --pull=false --signature-policy ${TESTSDIR}/policy.json alpine + cid=$output + run_buildah commit --signature-policy ${TESTSDIR}/policy.json --sign-by amanda@localhost $cid signed-alpine-image + + # Pushing should preserve the signature. + run_buildah push --signature-policy ${TESTSDIR}/policy.json signed-alpine-image dir:${TESTDIR}/signed-image + ls -l ${TESTDIR}/signed-image/ + test -s ${TESTDIR}/signed-image/signature-1 + + # Pushing with --remove-signatures should remove the signature. + run_buildah push --signature-policy ${TESTSDIR}/policy.json --remove-signatures signed-alpine-image dir:${TESTDIR}/unsigned-image + ls -l ${TESTDIR}/unsigned-image/ + ! test -s ${TESTDIR}/unsigned-image/signature-1 + + run_buildah commit --signature-policy ${TESTSDIR}/policy.json $cid unsigned-alpine-image + # Pushing with --sign-by should fail add the signature to a dir: location, if it tries to add them. + run_buildah 1 push --signature-policy ${TESTSDIR}/policy.json --sign-by amanda@localhost unsigned-alpine-image dir:${TESTDIR}/signed-image + expect_output --substring "Cannot determine canonical Docker reference" + + # Clear out images, so that we don't have leftover signatures when we pull in an image that will end up + # causing us to merge its contents with the image with the same ID. + run_buildah rmi -a -f + + # Pulling with --remove-signatures should remove signatures, and pushing should have none to keep. + run_buildah pull --signature-policy ${TESTSDIR}/policy.json --quiet dir:${TESTDIR}/signed-image + imageID="$output" + run_buildah push --signature-policy ${TESTSDIR}/policy.json "$imageID" dir:${TESTDIR}/unsigned-image + ls -l ${TESTDIR}/unsigned-image/ + ! test -s ${TESTDIR}/unsigned-image/signature-1 + + # Build a manifest list and try to push the list with signatures. + run_buildah manifest create list + run_buildah manifest add list $imageID + run_buildah 1 manifest push --signature-policy ${TESTSDIR}/policy.json --sign-by amanda@localhost --all list dir:${TESTDIR}/signed-image + expect_output --substring "Cannot determine canonical Docker reference" + run_buildah manifest push --signature-policy ${TESTSDIR}/policy.json --all list dir:${TESTDIR}/unsigned-image +} + +@test "build-with-dockerfile-signatures" { + if ! which gpg > /dev/null 2> /dev/null ; then + skip 'gpg command not found in $PATH' + fi + + export GNUPGHOME=${TESTDIR}/.gnupg + cat > genkey-answers <<- EOF + %echo Generating a basic OpenPGP key + Key-Type: RSA + Key-Length: 512 + Name-Real: Amanda Lorian + Name-Comment: Mandy to her friends + Name-Email: amanda@localhost + %commit + %echo done + EOF + gpg --batch --gen-key < genkey-answers + + cat > Dockerfile <<- EOF + FROM scratch + ADD Dockerfile / + EOF + + # We should be able to sign at build-time. + run_buildah bud --signature-policy ${TESTSDIR}/policy.json --sign-by amanda@localhost -t signed-scratch-image . + + mkdir -p ${TESTDIR}/signed-image + # Pushing should preserve the signature. + run_buildah push --signature-policy ${TESTSDIR}/policy.json signed-scratch-image dir:${TESTDIR}/signed-image + ls -l ${TESTDIR}/signed-image/ + test -s ${TESTDIR}/signed-image/signature-1 +}