Add --unsetenv option to buildah commit and build
This option will allow users to remove environment variables from the final image. Fixes: https://github.com/containers/buildah/issues/3512 Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
This commit is contained in:
parent
50ebc901d6
commit
a5d9f1cb28
|
@ -381,6 +381,7 @@ func buildCmd(c *cobra.Command, inputArgs []string, iopts buildOptions) error {
|
|||
Excludes: excludes,
|
||||
Timestamp: timestamp,
|
||||
Platforms: platforms,
|
||||
UnsetEnvs: iopts.UnsetEnvs,
|
||||
}
|
||||
if iopts.Quiet {
|
||||
options.ReportWriter = ioutil.Discard
|
||||
|
|
|
@ -11,6 +11,7 @@ import (
|
|||
"github.com/containers/buildah/pkg/parse"
|
||||
"github.com/containers/buildah/util"
|
||||
"github.com/containers/common/pkg/auth"
|
||||
"github.com/containers/common/pkg/completion"
|
||||
"github.com/containers/image/v5/pkg/shortnames"
|
||||
storageTransport "github.com/containers/image/v5/storage"
|
||||
"github.com/containers/image/v5/transports/alltransports"
|
||||
|
@ -40,6 +41,7 @@ type commitInputOptions struct {
|
|||
tlsVerify bool
|
||||
encryptionKeys []string
|
||||
encryptLayers []int
|
||||
unsetenvs []string
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
@ -59,30 +61,45 @@ func init() {
|
|||
buildah commit containerID docker://localhost:5000/imageId`,
|
||||
}
|
||||
commitCommand.SetUsageTemplate(UsageTemplate())
|
||||
flags := commitCommand.Flags()
|
||||
commitListFlagSet(commitCommand, &opts)
|
||||
rootCmd.AddCommand(commitCommand)
|
||||
|
||||
}
|
||||
|
||||
func commitListFlagSet(cmd *cobra.Command, opts *commitInputOptions) {
|
||||
flags := cmd.Flags()
|
||||
flags.SetInterspersed(false)
|
||||
|
||||
flags.StringVar(&opts.authfile, "authfile", auth.GetDefaultAuthFile(), "path of the authentication file. Use REGISTRY_AUTH_FILE environment variable to override")
|
||||
_ = cmd.RegisterFlagCompletionFunc("authfile", completion.AutocompleteDefault)
|
||||
flags.StringVar(&opts.blobCache, "blob-cache", "", "assume image blobs in the specified directory will be available for pushing")
|
||||
flags.StringSliceVar(&opts.encryptionKeys, "encryption-key", nil, "key with the encryption protocol to use needed to encrypt the image (e.g. jwe:/path/to/key.pem)")
|
||||
flags.IntSliceVar(&opts.encryptLayers, "encrypt-layer", nil, "layers to encrypt, 0-indexed layer indices with support for negative indexing (e.g. 0 is the first layer, -1 is the last layer). If not defined, will encrypt all layers if encryption-key flag is specified")
|
||||
|
||||
if err := flags.MarkHidden("blob-cache"); err != nil {
|
||||
panic(fmt.Sprintf("error marking blob-cache as hidden: %v", err))
|
||||
}
|
||||
flags.StringSliceVar(&opts.encryptionKeys, "encryption-key", nil, "key with the encryption protocol to use needed to encrypt the image (e.g. jwe:/path/to/key.pem)")
|
||||
_ = cmd.RegisterFlagCompletionFunc("encryption-key", completion.AutocompleteDefault)
|
||||
flags.IntSliceVar(&opts.encryptLayers, "encrypt-layer", nil, "layers to encrypt, 0-indexed layer indices with support for negative indexing (e.g. 0 is the first layer, -1 is the last layer). If not defined, will encrypt all layers if encryption-key flag is specified")
|
||||
_ = cmd.RegisterFlagCompletionFunc("encryption-key", completion.AutocompleteNone)
|
||||
|
||||
flags.StringVar(&opts.certDir, "cert-dir", "", "use certificates at the specified path to access the registry")
|
||||
_ = cmd.RegisterFlagCompletionFunc("cirt-dir", completion.AutocompleteDefault)
|
||||
flags.StringVar(&opts.creds, "creds", "", "use `[username[:password]]` for accessing the registry")
|
||||
_ = cmd.RegisterFlagCompletionFunc("creds", completion.AutocompleteNone)
|
||||
flags.BoolVarP(&opts.disableCompression, "disable-compression", "D", true, "don't compress layers")
|
||||
flags.StringVarP(&opts.format, "format", "f", defaultFormat(), "`format` of the image manifest and metadata")
|
||||
_ = cmd.RegisterFlagCompletionFunc("format", completion.AutocompleteNone)
|
||||
flags.StringVar(&opts.manifest, "manifest", "", "adds created image to the specified manifest list. Creates manifest list if it does not exist")
|
||||
_ = cmd.RegisterFlagCompletionFunc("manifest", completion.AutocompleteNone)
|
||||
flags.StringVar(&opts.iidfile, "iidfile", "", "write the image ID to the file")
|
||||
_ = cmd.RegisterFlagCompletionFunc("iidfile", completion.AutocompleteDefault)
|
||||
flags.BoolVar(&opts.omitTimestamp, "omit-timestamp", false, "set created timestamp to epoch 0 to allow for deterministic builds")
|
||||
flags.Int64Var(&opts.timestamp, "timestamp", 0, "set created timestamp to epoch seconds to allow for deterministic builds, defaults to current time")
|
||||
_ = cmd.RegisterFlagCompletionFunc("timestamp", completion.AutocompleteNone)
|
||||
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`")
|
||||
_ = cmd.RegisterFlagCompletionFunc("reference-time", completion.AutocompleteNone)
|
||||
flags.StringVar(&opts.signBy, "sign-by", "", "sign the image using a GPG key with the specified `FINGERPRINT`")
|
||||
|
||||
_ = cmd.RegisterFlagCompletionFunc("sign-by", completion.AutocompleteNone)
|
||||
if err := flags.MarkHidden("omit-timestamp"); err != nil {
|
||||
panic(fmt.Sprintf("error marking omit-timestamp as hidden: %v", err))
|
||||
}
|
||||
|
@ -92,6 +109,7 @@ func init() {
|
|||
|
||||
flags.BoolVar(&opts.rm, "rm", false, "remove the container and its content after committing it to an image. Default leaves the container and its content in place.")
|
||||
flags.StringVar(&opts.signaturePolicy, "signature-policy", "", "`pathname` of signature policy file (not usually used)")
|
||||
_ = cmd.RegisterFlagCompletionFunc("signature-policy", completion.AutocompleteDefault)
|
||||
|
||||
if err := flags.MarkHidden("signature-policy"); err != nil {
|
||||
panic(fmt.Sprintf("error marking signature-policy as hidden: %v", err))
|
||||
|
@ -100,8 +118,8 @@ func init() {
|
|||
flags.BoolVar(&opts.squash, "squash", false, "produce an image with only one layer")
|
||||
flags.BoolVar(&opts.tlsVerify, "tls-verify", true, "Require HTTPS and verify certificates when accessing the registry. TLS verification cannot be used when talking to an insecure registry.")
|
||||
|
||||
rootCmd.AddCommand(commitCommand)
|
||||
|
||||
flags.StringSliceVar(&opts.unsetenvs, "unsetenv", nil, "unset env from final image")
|
||||
_ = cmd.RegisterFlagCompletionFunc("unsetenv", completion.AutocompleteNone)
|
||||
}
|
||||
|
||||
func commitCmd(c *cobra.Command, args []string, iopts commitInputOptions) error {
|
||||
|
@ -190,6 +208,7 @@ func commitCmd(c *cobra.Command, args []string, iopts commitInputOptions) error
|
|||
SignBy: iopts.signBy,
|
||||
OciEncryptConfig: encConfig,
|
||||
OciEncryptLayers: encLayers,
|
||||
UnsetEnvs: iopts.unsetenvs,
|
||||
}
|
||||
exclusiveFlags := 0
|
||||
if c.Flag("reference-time").Changed {
|
||||
|
|
|
@ -101,6 +101,8 @@ type CommitOptions struct {
|
|||
// integers in the slice represent 0-indexed layer indices, with support for negative
|
||||
// indexing. i.e. 0 is the first layer, -1 is the last (top-most) layer.
|
||||
OciEncryptLayers *[]int
|
||||
// UnsetEnvs is a list of environments to not add to final image.
|
||||
UnsetEnvs []string
|
||||
}
|
||||
|
||||
var (
|
||||
|
|
|
@ -240,4 +240,6 @@ type BuildOptions struct {
|
|||
// to match the set of platforms for which all of the build's base
|
||||
// images are available. If this field is set, Platforms is ignored.
|
||||
AllPlatforms bool
|
||||
// UnsetEnvs is a list of environments to not add to final image.
|
||||
UnsetEnvs []string
|
||||
}
|
||||
|
|
|
@ -586,6 +586,10 @@ include:
|
|||
"sigpending": maximum number of pending signals (ulimit -i)
|
||||
"stack": maximum stack size (ulimit -s)
|
||||
|
||||
**--unsetenv** *env*
|
||||
|
||||
Unset environment variables from the final image.
|
||||
|
||||
**--userns** *how*
|
||||
|
||||
Sets the configuration for user namespaces when handling `RUN` instructions.
|
||||
|
|
|
@ -101,6 +101,10 @@ When --timestamp is set, the created timestamp is always set to the time specifi
|
|||
|
||||
Require HTTPS and verification of certificates when talking to container registries (defaults to true). TLS verification cannot be used when talking to an insecure registry.
|
||||
|
||||
**--unsetenv** *env*
|
||||
|
||||
Unset environment variables from the final image.
|
||||
|
||||
## EXAMPLE
|
||||
|
||||
This example saves an image based on the container.
|
||||
|
|
24
image.go
24
image.go
|
@ -752,11 +752,31 @@ func (b *Builder) makeImageRef(options CommitOptions) (types.ImageReference, err
|
|||
if manifestType == "" {
|
||||
manifestType = define.OCIv1ImageManifest
|
||||
}
|
||||
oconfig, err := json.Marshal(&b.OCIv1)
|
||||
oci1 := b.OCIv1
|
||||
docker := b.Docker
|
||||
for _, u := range options.UnsetEnvs {
|
||||
var env []string
|
||||
for _, e := range oci1.Config.Env {
|
||||
if strings.HasPrefix(e, u+"=") {
|
||||
continue
|
||||
}
|
||||
env = append(env, e)
|
||||
}
|
||||
oci1.Config.Env = env
|
||||
env = []string{}
|
||||
for _, e := range docker.Config.Env {
|
||||
if strings.HasPrefix(e, u+"=") {
|
||||
continue
|
||||
}
|
||||
env = append(env, e)
|
||||
}
|
||||
docker.Config.Env = env
|
||||
}
|
||||
oconfig, err := json.Marshal(&oci1)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "error encoding OCI-format image configuration %#v", b.OCIv1)
|
||||
}
|
||||
dconfig, err := json.Marshal(&b.Docker)
|
||||
dconfig, err := json.Marshal(&docker)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "error encoding docker-format image configuration %#v", b.Docker)
|
||||
}
|
||||
|
|
|
@ -126,6 +126,7 @@ type Executor struct {
|
|||
secrets map[string]define.Secret
|
||||
sshsources map[string]*sshagent.Source
|
||||
logPrefix string
|
||||
unsetEnvs []string
|
||||
}
|
||||
|
||||
type imageTypeAndHistoryAndDiffIDs struct {
|
||||
|
@ -270,6 +271,7 @@ func newExecutor(logger *logrus.Logger, logPrefix string, store storage.Store, o
|
|||
secrets: secrets,
|
||||
sshsources: sshsources,
|
||||
logPrefix: logPrefix,
|
||||
unsetEnvs: options.UnsetEnvs,
|
||||
}
|
||||
if exec.err == nil {
|
||||
exec.err = os.Stderr
|
||||
|
|
|
@ -1403,6 +1403,7 @@ func (s *StageExecutor) commit(ctx context.Context, createdBy string, emptyLayer
|
|||
RetryDelay: s.executor.retryPullPushDelay,
|
||||
HistoryTimestamp: s.executor.timestamp,
|
||||
Manifest: s.executor.manifest,
|
||||
UnsetEnvs: s.executor.unsetEnvs,
|
||||
}
|
||||
imgID, _, manifestDigest, err := s.builder.Commit(ctx, imageRef, options)
|
||||
if err != nil {
|
||||
|
|
|
@ -87,6 +87,7 @@ type BudResults struct {
|
|||
Jobs int
|
||||
LogRusage bool
|
||||
RusageLogFile string
|
||||
UnsetEnvs []string
|
||||
}
|
||||
|
||||
// FromAndBugResults represents the results for common flags
|
||||
|
@ -231,6 +232,7 @@ func GetBudFlags(flags *BudResults) pflag.FlagSet {
|
|||
fs.Int64Var(&flags.Timestamp, "timestamp", 0, "set created timestamp to the specified epoch seconds to allow for deterministic builds, defaults to current time")
|
||||
fs.BoolVar(&flags.TLSVerify, "tls-verify", true, "require HTTPS and verify certificates when accessing the registry")
|
||||
fs.String("variant", "", "override the `variant` of the specified image")
|
||||
fs.StringSliceVar(&flags.UnsetEnvs, "unsetenv", nil, "Unset environment variable from final image")
|
||||
return fs
|
||||
}
|
||||
|
||||
|
@ -263,6 +265,7 @@ func GetBudFlagsCompletions() commonComp.FlagCompletions {
|
|||
flagCompletion["target"] = commonComp.AutocompleteNone
|
||||
flagCompletion["timestamp"] = commonComp.AutocompleteNone
|
||||
flagCompletion["variant"] = commonComp.AutocompleteNone
|
||||
flagCompletion["unsetenv"] = commonComp.AutocompleteNone
|
||||
return flagCompletion
|
||||
}
|
||||
|
||||
|
|
|
@ -454,6 +454,17 @@ symlink(subdir)"
|
|||
expect_output "${target}-working-container"
|
||||
}
|
||||
|
||||
@test "build --unsetenv PATH" {
|
||||
_prefetch alpine
|
||||
target=scratch-image
|
||||
run_buildah build --unsetenv PATH --signature-policy ${TESTSDIR}/policy.json -t oci-${target} ${TESTSDIR}/bud/from-scratch
|
||||
run_buildah inspect --type=image --format '{{.OCIv1.Config.Env}}' oci-${target}
|
||||
expect_output "[]" "No Path should be defined"
|
||||
run_buildah build --unsetenv PATH --signature-policy ${TESTSDIR}/policy.json --format docker -t docker-${target} ${TESTSDIR}/bud/from-scratch
|
||||
run_buildah inspect --type=image --format '{{.OCIv1.Config.Env}}' docker-${target}
|
||||
expect_output "[]" "No Path should be defined"
|
||||
}
|
||||
|
||||
@test "bud-from-scratch-untagged" {
|
||||
run_buildah build --iidfile ${TESTDIR}/output.iid --signature-policy ${TESTSDIR}/policy.json ${TESTSDIR}/bud/from-scratch
|
||||
iid=$(cat ${TESTDIR}/output.iid)
|
||||
|
|
|
@ -39,6 +39,19 @@ load helpers
|
|||
expect_output --from="$mediatype" "application/vnd.docker.image.rootfs.diff.tar.gzip"
|
||||
}
|
||||
|
||||
@test "commit --unsetenv PATH" {
|
||||
_prefetch alpine
|
||||
run_buildah from --quiet --pull=false --signature-policy ${TESTSDIR}/policy.json alpine
|
||||
cid=$output
|
||||
run_buildah commit --unsetenv PATH --signature-policy ${TESTSDIR}/policy.json $cid alpine-image-oci
|
||||
run_buildah commit --unsetenv PATH --format docker --disable-compression=false --signature-policy ${TESTSDIR}/policy.json $cid alpine-image-docker
|
||||
|
||||
run_buildah inspect --type=image --format '{{.OCIv1.Config.Env}}' alpine-image-oci
|
||||
expect_output "[]" "No Path should be defined"
|
||||
run_buildah inspect --type=image --format '{{.Docker.Config.Env}}' alpine-image-docker
|
||||
expect_output "[]" "No Path should be defined"
|
||||
}
|
||||
|
||||
@test "commit quiet test" {
|
||||
_prefetch alpine
|
||||
run_buildah from --quiet --pull=false --signature-policy ${TESTSDIR}/policy.json alpine
|
||||
|
|
Loading…
Reference in New Issue