Fix --tls-verify

Differentiate, again, between (skopeo --tls-verify subcommand)
and (skope subcommand --tls-verify), by
- using a "local" Corba flag for the (skopeo --tls-verify ...) variant
- adding separate --tls-verify flags to subcommands that only accept
  them as legacy, available through deprecatedTLSVerifyFlags
  (unlike the non-legacy path of dockerImageFlags());
- using TraverseChildren: true; this causes the global and
  per-subcommand flags to be treated separately by Corba,
  i.e. they no longer happen to share the "Hidden" flag
  and Corba actually sets the right flag variable now.

So, we can now warn on (skopeo --tls-verify command) again,
and --help lists the flag correctly (it is hidden at the
global level, and in subcommands like copy that deprecated it,
but visible in subcommands like inspect where it's not deprecated).

NOTE: This removes --tls-verify from (skopeo manifest-digest) and
the three signing commands; it never made sense there. This change
could, in principle, break some users.

Also update man pages to match.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
This commit is contained in:
Miloslav Trmač 2021-07-23 15:46:15 +02:00
parent bb447f2f1e
commit 726d982ceb
14 changed files with 213 additions and 88 deletions

View File

@ -20,6 +20,7 @@ import (
type copyOptions struct { type copyOptions struct {
global *globalOptions global *globalOptions
deprecatedTLSVerify *deprecatedTLSVerifyOption
srcImage *imageOptions srcImage *imageOptions
destImage *imageDestOptions destImage *imageDestOptions
retryOpts *retry.RetryOptions retryOpts *retry.RetryOptions
@ -37,10 +38,12 @@ type copyOptions struct {
func copyCmd(global *globalOptions) *cobra.Command { func copyCmd(global *globalOptions) *cobra.Command {
sharedFlags, sharedOpts := sharedImageFlags() sharedFlags, sharedOpts := sharedImageFlags()
srcFlags, srcOpts := imageFlags(global, sharedOpts, "src-", "screds") deprecatedTLSVerifyFlags, deprecatedTLSVerifyOpt := deprecatedTLSVerifyFlags()
destFlags, destOpts := imageDestFlags(global, sharedOpts, "dest-", "dcreds") srcFlags, srcOpts := imageFlags(global, sharedOpts, deprecatedTLSVerifyOpt, "src-", "screds")
destFlags, destOpts := imageDestFlags(global, sharedOpts, deprecatedTLSVerifyOpt, "dest-", "dcreds")
retryFlags, retryOpts := retryFlags() retryFlags, retryOpts := retryFlags()
opts := copyOptions{global: global, opts := copyOptions{global: global,
deprecatedTLSVerify: deprecatedTLSVerifyOpt,
srcImage: srcOpts, srcImage: srcOpts,
destImage: destOpts, destImage: destOpts,
retryOpts: retryOpts, retryOpts: retryOpts,
@ -61,6 +64,7 @@ See skopeo(1) section "IMAGE NAMES" for the expected format
adjustUsage(cmd) adjustUsage(cmd)
flags := cmd.Flags() flags := cmd.Flags()
flags.AddFlagSet(&sharedFlags) flags.AddFlagSet(&sharedFlags)
flags.AddFlagSet(&deprecatedTLSVerifyFlags)
flags.AddFlagSet(&srcFlags) flags.AddFlagSet(&srcFlags)
flags.AddFlagSet(&destFlags) flags.AddFlagSet(&destFlags)
flags.AddFlagSet(&retryFlags) flags.AddFlagSet(&retryFlags)
@ -81,6 +85,7 @@ func (opts *copyOptions) run(args []string, stdout io.Writer) error {
if len(args) != 2 { if len(args) != 2 {
return errorShouldDisplayUsage{errors.New("Exactly two arguments expected")} return errorShouldDisplayUsage{errors.New("Exactly two arguments expected")}
} }
opts.deprecatedTLSVerify.warnIfUsed([]string{"--src-tls-verify", "--dest-tls-verify"})
imageNames := args imageNames := args
if err := reexecIfNecessaryForImages(imageNames...); err != nil { if err := reexecIfNecessaryForImages(imageNames...); err != nil {

View File

@ -20,7 +20,7 @@ type deleteOptions struct {
func deleteCmd(global *globalOptions) *cobra.Command { func deleteCmd(global *globalOptions) *cobra.Command {
sharedFlags, sharedOpts := sharedImageFlags() sharedFlags, sharedOpts := sharedImageFlags()
imageFlags, imageOpts := imageFlags(global, sharedOpts, "", "") imageFlags, imageOpts := imageFlags(global, sharedOpts, nil, "", "")
retryFlags, retryOpts := retryFlags() retryFlags, retryOpts := retryFlags()
opts := deleteOptions{ opts := deleteOptions{
global: global, global: global,

View File

@ -34,7 +34,7 @@ type inspectOptions struct {
func inspectCmd(global *globalOptions) *cobra.Command { func inspectCmd(global *globalOptions) *cobra.Command {
sharedFlags, sharedOpts := sharedImageFlags() sharedFlags, sharedOpts := sharedImageFlags()
imageFlags, imageOpts := imageFlags(global, sharedOpts, "", "") imageFlags, imageOpts := imageFlags(global, sharedOpts, nil, "", "")
retryFlags, retryOpts := retryFlags() retryFlags, retryOpts := retryFlags()
opts := inspectOptions{ opts := inspectOptions{
global: global, global: global,

View File

@ -25,7 +25,7 @@ type layersOptions struct {
func layersCmd(global *globalOptions) *cobra.Command { func layersCmd(global *globalOptions) *cobra.Command {
sharedFlags, sharedOpts := sharedImageFlags() sharedFlags, sharedOpts := sharedImageFlags()
imageFlags, imageOpts := imageFlags(global, sharedOpts, "", "") imageFlags, imageOpts := imageFlags(global, sharedOpts, nil, "", "")
retryFlags, retryOpts := retryFlags() retryFlags, retryOpts := retryFlags()
opts := layersOptions{ opts := layersOptions{
global: global, global: global,

View File

@ -30,7 +30,7 @@ type tagsOptions struct {
func tagsCmd(global *globalOptions) *cobra.Command { func tagsCmd(global *globalOptions) *cobra.Command {
sharedFlags, sharedOpts := sharedImageFlags() sharedFlags, sharedOpts := sharedImageFlags()
imageFlags, imageOpts := dockerImageFlags(global, sharedOpts, "", "") imageFlags, imageOpts := dockerImageFlags(global, sharedOpts, nil, "", "")
retryFlags, retryOpts := retryFlags() retryFlags, retryOpts := retryFlags()
opts := tagsOptions{ opts := tagsOptions{

View File

@ -50,6 +50,12 @@ func createApp() (*cobra.Command, *globalOptions) {
// already making us of that. If Skopeo decides to follow, please // already making us of that. If Skopeo decides to follow, please
// remove the line below (and hide the `completion` command). // remove the line below (and hide the `completion` command).
CompletionOptions: cobra.CompletionOptions{DisableDefaultCmd: true}, CompletionOptions: cobra.CompletionOptions{DisableDefaultCmd: true},
// This is documented to parse "local" (non-PersistentFlags) flags of parent commands before
// running subcommands and handling their options. We don't really run into such cases,
// because all of our flags on rootCommand are in PersistentFlags, except for the deprecated --tls-verify;
// in that case we need TraverseChildren so that we can distinguish between
// (skopeo --tls-verify inspect) (causes a warning) and (skopeo inspect --tls-verify) (no warning).
TraverseChildren: true,
} }
if gitCommit != "" { if gitCommit != "" {
rootCommand.Version = fmt.Sprintf("%s commit: %s", version.Version, gitCommit) rootCommand.Version = fmt.Sprintf("%s commit: %s", version.Version, gitCommit)
@ -60,8 +66,6 @@ func createApp() (*cobra.Command, *globalOptions) {
var dummyVersion bool var dummyVersion bool
rootCommand.Flags().BoolVarP(&dummyVersion, "version", "v", false, "Version for Skopeo") rootCommand.Flags().BoolVarP(&dummyVersion, "version", "v", false, "Version for Skopeo")
rootCommand.PersistentFlags().BoolVar(&opts.debug, "debug", false, "enable debug output") rootCommand.PersistentFlags().BoolVar(&opts.debug, "debug", false, "enable debug output")
flag := optionalBoolFlag(rootCommand.PersistentFlags(), &opts.tlsVerify, "tls-verify", "Require HTTPS and verify certificates when accessing the registry")
flag.Hidden = true
rootCommand.PersistentFlags().StringVar(&opts.policyPath, "policy", "", "Path to a trust policy file") rootCommand.PersistentFlags().StringVar(&opts.policyPath, "policy", "", "Path to a trust policy file")
rootCommand.PersistentFlags().BoolVar(&opts.insecurePolicy, "insecure-policy", false, "run the tool without any policy check") rootCommand.PersistentFlags().BoolVar(&opts.insecurePolicy, "insecure-policy", false, "run the tool without any policy check")
rootCommand.PersistentFlags().StringVar(&opts.registriesDirPath, "registries.d", "", "use registry configuration files in `DIR` (e.g. for container signature storage)") rootCommand.PersistentFlags().StringVar(&opts.registriesDirPath, "registries.d", "", "use registry configuration files in `DIR` (e.g. for container signature storage)")
@ -74,6 +78,8 @@ func createApp() (*cobra.Command, *globalOptions) {
logrus.Fatal("unable to mark registries-conf flag as hidden") logrus.Fatal("unable to mark registries-conf flag as hidden")
} }
rootCommand.PersistentFlags().StringVar(&opts.tmpDir, "tmpdir", "", "directory used to store temporary files") rootCommand.PersistentFlags().StringVar(&opts.tmpDir, "tmpdir", "", "directory used to store temporary files")
flag := optionalBoolFlag(rootCommand.Flags(), &opts.tlsVerify, "tls-verify", "Require HTTPS and verify certificates when accessing the registry")
flag.Hidden = true
rootCommand.AddCommand( rootCommand.AddCommand(
copyCmd(&opts), copyCmd(&opts),
deleteCmd(&opts), deleteCmd(&opts),

View File

@ -28,6 +28,7 @@ import (
// syncOptions contains information retrieved from the skopeo sync command line. // syncOptions contains information retrieved from the skopeo sync command line.
type syncOptions struct { type syncOptions struct {
global *globalOptions // Global (not command dependent) skopeo options global *globalOptions // Global (not command dependent) skopeo options
deprecatedTLSVerify *deprecatedTLSVerifyOption
srcImage *imageOptions // Source image options srcImage *imageOptions // Source image options
destImage *imageDestOptions // Destination image options destImage *imageDestOptions // Destination image options
retryOpts *retry.RetryOptions retryOpts *retry.RetryOptions
@ -68,12 +69,14 @@ type sourceConfig map[string]registrySyncConfig
func syncCmd(global *globalOptions) *cobra.Command { func syncCmd(global *globalOptions) *cobra.Command {
sharedFlags, sharedOpts := sharedImageFlags() sharedFlags, sharedOpts := sharedImageFlags()
srcFlags, srcOpts := dockerImageFlags(global, sharedOpts, "src-", "screds") deprecatedTLSVerifyFlags, deprecatedTLSVerifyOpt := deprecatedTLSVerifyFlags()
destFlags, destOpts := dockerImageFlags(global, sharedOpts, "dest-", "dcreds") srcFlags, srcOpts := dockerImageFlags(global, sharedOpts, deprecatedTLSVerifyOpt, "src-", "screds")
destFlags, destOpts := dockerImageFlags(global, sharedOpts, deprecatedTLSVerifyOpt, "dest-", "dcreds")
retryFlags, retryOpts := retryFlags() retryFlags, retryOpts := retryFlags()
opts := syncOptions{ opts := syncOptions{
global: global, global: global,
deprecatedTLSVerify: deprecatedTLSVerifyOpt,
srcImage: srcOpts, srcImage: srcOpts,
destImage: &imageDestOptions{imageOptions: destOpts}, destImage: &imageDestOptions{imageOptions: destOpts},
retryOpts: retryOpts, retryOpts: retryOpts,
@ -102,6 +105,7 @@ See skopeo-sync(1) for details.
flags.BoolVar(&opts.scoped, "scoped", false, "Images at DESTINATION are prefix using the full source image path as scope") flags.BoolVar(&opts.scoped, "scoped", false, "Images at DESTINATION are prefix using the full source image path as scope")
flags.BoolVarP(&opts.all, "all", "a", false, "Copy all images if SOURCE-IMAGE is a list") flags.BoolVarP(&opts.all, "all", "a", false, "Copy all images if SOURCE-IMAGE is a list")
flags.AddFlagSet(&sharedFlags) flags.AddFlagSet(&sharedFlags)
flags.AddFlagSet(&deprecatedTLSVerifyFlags)
flags.AddFlagSet(&srcFlags) flags.AddFlagSet(&srcFlags)
flags.AddFlagSet(&destFlags) flags.AddFlagSet(&destFlags)
flags.AddFlagSet(&retryFlags) flags.AddFlagSet(&retryFlags)
@ -492,6 +496,7 @@ func (opts *syncOptions) run(args []string, stdout io.Writer) error {
if len(args) != 2 { if len(args) != 2 {
return errorShouldDisplayUsage{errors.New("Exactly two arguments expected")} return errorShouldDisplayUsage{errors.New("Exactly two arguments expected")}
} }
opts.deprecatedTLSVerify.warnIfUsed([]string{"--src-tls-verify", "--dest-tls-verify"})
policyContext, err := opts.global.getPolicyContext() policyContext, err := opts.global.getPolicyContext()
if err != nil { if err != nil {

View File

@ -14,6 +14,7 @@ import (
"github.com/containers/image/v5/types" "github.com/containers/image/v5/types"
imgspecv1 "github.com/opencontainers/image-spec/specs-go/v1" imgspecv1 "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/spf13/pflag" "github.com/spf13/pflag"
) )
@ -38,6 +39,35 @@ func commandAction(handler func(args []string, stdout io.Writer) error) func(cmd
} }
} }
// deprecatedTLSVerifyOption represents a deprecated --tls-verify option,
// which was accepted for all subcommands, for a time.
// Every user should call deprecatedTLSVerifyOption.warnIfUsed() as part of handling the CLI,
// whether or not the value actually ends up being used.
// DO NOT ADD ANY NEW USES OF THIS; just call dockerImageFlags with an appropriate, possibly empty, flagPrefix.
type deprecatedTLSVerifyOption struct {
tlsVerify optionalBool // FIXME FIXME: Warn if this is used, or even if it is ignored.
}
// warnIfUsed warns if tlsVerify was set by the user, and suggests alternatives (which should
// start with "--").
// Every user should call this as part of handling the CLI, whether or not the value actually
// ends up being used.
func (opts *deprecatedTLSVerifyOption) warnIfUsed(alternatives []string) {
if opts.tlsVerify.present {
logrus.Warnf("'--tls-verify' is deprecated, instead use: %s", strings.Join(alternatives, ", "))
}
}
// deprecatedTLSVerifyFlags prepares the CLI flag writing into deprecatedTLSVerifyOption, and the managed deprecatedTLSVerifyOption structure.
// DO NOT ADD ANY NEW USES OF THIS; just call dockerImageFlags with an appropriate, possibly empty, flagPrefix.
func deprecatedTLSVerifyFlags() (pflag.FlagSet, *deprecatedTLSVerifyOption) {
opts := deprecatedTLSVerifyOption{}
fs := pflag.FlagSet{}
flag := optionalBoolFlag(&fs, &opts.tlsVerify, "tls-verify", "require HTTPS and verify certificates when accessing the container registry (defaults to true)")
flag.Hidden = true
return fs, &opts
}
// sharedImageOptions collects CLI flags which are image-related, but do not change across images. // sharedImageOptions collects CLI flags which are image-related, but do not change across images.
// This really should be a part of globalOptions, but that would break existing users of (skopeo copy --authfile=). // This really should be a part of globalOptions, but that would break existing users of (skopeo copy --authfile=).
type sharedImageOptions struct { type sharedImageOptions struct {
@ -58,6 +88,7 @@ func sharedImageFlags() (pflag.FlagSet, *sharedImageOptions) {
type dockerImageOptions struct { type dockerImageOptions struct {
global *globalOptions // May be shared across several imageOptions instances. global *globalOptions // May be shared across several imageOptions instances.
shared *sharedImageOptions // May be shared across several imageOptions instances. shared *sharedImageOptions // May be shared across several imageOptions instances.
deprecatedTLSVerify *deprecatedTLSVerifyOption // May be shared across several imageOptions instances, or nil.
authFilePath optionalString // Path to a */containers/auth.json (prefixed version to override shared image option). authFilePath optionalString // Path to a */containers/auth.json (prefixed version to override shared image option).
credsOption optionalString // username[:password] for accessing a registry credsOption optionalString // username[:password] for accessing a registry
registryToken optionalString // token to be used directly as a Bearer token when accessing the registry registryToken optionalString // token to be used directly as a Bearer token when accessing the registry
@ -76,11 +107,12 @@ type imageOptions struct {
// dockerImageFlags prepares a collection of docker-transport specific CLI flags // dockerImageFlags prepares a collection of docker-transport specific CLI flags
// writing into imageOptions, and the managed imageOptions structure. // writing into imageOptions, and the managed imageOptions structure.
func dockerImageFlags(global *globalOptions, shared *sharedImageOptions, flagPrefix, credsOptionAlias string) (pflag.FlagSet, *imageOptions) { func dockerImageFlags(global *globalOptions, shared *sharedImageOptions, deprecatedTLSVerify *deprecatedTLSVerifyOption, flagPrefix, credsOptionAlias string) (pflag.FlagSet, *imageOptions) {
flags := imageOptions{ flags := imageOptions{
dockerImageOptions: dockerImageOptions{ dockerImageOptions: dockerImageOptions{
global: global, global: global,
shared: shared, shared: shared,
deprecatedTLSVerify: deprecatedTLSVerify,
}, },
} }
@ -104,8 +136,8 @@ func dockerImageFlags(global *globalOptions, shared *sharedImageOptions, flagPre
} }
// imageFlags prepares a collection of CLI flags writing into imageOptions, and the managed imageOptions structure. // imageFlags prepares a collection of CLI flags writing into imageOptions, and the managed imageOptions structure.
func imageFlags(global *globalOptions, shared *sharedImageOptions, flagPrefix, credsOptionAlias string) (pflag.FlagSet, *imageOptions) { func imageFlags(global *globalOptions, shared *sharedImageOptions, deprecatedTLSVerify *deprecatedTLSVerifyOption, flagPrefix, credsOptionAlias string) (pflag.FlagSet, *imageOptions) {
dockerFlags, opts := dockerImageFlags(global, shared, flagPrefix, credsOptionAlias) dockerFlags, opts := dockerImageFlags(global, shared, deprecatedTLSVerify, flagPrefix, credsOptionAlias)
fs := pflag.FlagSet{} fs := pflag.FlagSet{}
fs.StringVar(&opts.sharedBlobDir, flagPrefix+"shared-blob-dir", "", "`DIRECTORY` to use to share blobs across OCI repositories") fs.StringVar(&opts.sharedBlobDir, flagPrefix+"shared-blob-dir", "", "`DIRECTORY` to use to share blobs across OCI repositories")
@ -135,6 +167,10 @@ func (opts *imageOptions) newSystemContext() (*types.SystemContext, error) {
if opts.dockerImageOptions.authFilePath.present { if opts.dockerImageOptions.authFilePath.present {
ctx.AuthFilePath = opts.dockerImageOptions.authFilePath.value ctx.AuthFilePath = opts.dockerImageOptions.authFilePath.value
} }
if opts.deprecatedTLSVerify != nil && opts.deprecatedTLSVerify.tlsVerify.present {
// If both this deprecated option and a non-deprecated option is present, we use the latter value.
ctx.DockerInsecureSkipTLSVerify = types.NewOptionalBool(!opts.deprecatedTLSVerify.tlsVerify.value)
}
if opts.tlsVerify.present { if opts.tlsVerify.present {
ctx.DockerDaemonInsecureSkipTLSVerify = !opts.tlsVerify.value ctx.DockerDaemonInsecureSkipTLSVerify = !opts.tlsVerify.value
} }
@ -171,8 +207,8 @@ type imageDestOptions struct {
} }
// imageDestFlags prepares a collection of CLI flags writing into imageDestOptions, and the managed imageDestOptions structure. // imageDestFlags prepares a collection of CLI flags writing into imageDestOptions, and the managed imageDestOptions structure.
func imageDestFlags(global *globalOptions, shared *sharedImageOptions, flagPrefix, credsOptionAlias string) (pflag.FlagSet, *imageDestOptions) { func imageDestFlags(global *globalOptions, shared *sharedImageOptions, deprecatedTLSVerify *deprecatedTLSVerifyOption, flagPrefix, credsOptionAlias string) (pflag.FlagSet, *imageDestOptions) {
genericFlags, genericOptions := imageFlags(global, shared, flagPrefix, credsOptionAlias) genericFlags, genericOptions := imageFlags(global, shared, deprecatedTLSVerify, flagPrefix, credsOptionAlias)
opts := imageDestOptions{imageOptions: genericOptions} opts := imageDestOptions{imageOptions: genericOptions}
fs := pflag.FlagSet{} fs := pflag.FlagSet{}
fs.AddFlagSet(&genericFlags) fs.AddFlagSet(&genericFlags)

View File

@ -8,6 +8,7 @@ import (
"github.com/containers/image/v5/types" "github.com/containers/image/v5/types"
imgspecv1 "github.com/opencontainers/image-spec/specs-go/v1" imgspecv1 "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/spf13/pflag"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
@ -17,17 +18,26 @@ func fakeGlobalOptions(t *testing.T, flags []string) (*globalOptions, *cobra.Com
app, opts := createApp() app, opts := createApp()
cmd := &cobra.Command{} cmd := &cobra.Command{}
app.AddCommand(cmd) app.AddCommand(cmd)
err := cmd.ParseFlags(flags) err := app.ParseFlags(flags)
require.NoError(t, err) require.NoError(t, err)
return opts, cmd return opts, cmd
} }
// fakeImageOptions creates imageOptions and sets it according to globalFlags/cmdFlags. // fakeImageOptions creates imageOptions and sets it according to globalFlags/cmdFlags.
func fakeImageOptions(t *testing.T, flagPrefix string, globalFlags []string, cmdFlags []string) *imageOptions { func fakeImageOptions(t *testing.T, flagPrefix string, useDeprecatedTLSVerify bool,
globalFlags []string, cmdFlags []string) *imageOptions {
globalOpts, cmd := fakeGlobalOptions(t, globalFlags) globalOpts, cmd := fakeGlobalOptions(t, globalFlags)
sharedFlags, sharedOpts := sharedImageFlags() sharedFlags, sharedOpts := sharedImageFlags()
imageFlags, imageOpts := imageFlags(globalOpts, sharedOpts, flagPrefix, "") var deprecatedTLSVerifyFlag pflag.FlagSet
var deprecatedTLSVerifyOpt *deprecatedTLSVerifyOption
if useDeprecatedTLSVerify {
deprecatedTLSVerifyFlag, deprecatedTLSVerifyOpt = deprecatedTLSVerifyFlags()
}
imageFlags, imageOpts := imageFlags(globalOpts, sharedOpts, deprecatedTLSVerifyOpt, flagPrefix, "")
cmd.Flags().AddFlagSet(&sharedFlags) cmd.Flags().AddFlagSet(&sharedFlags)
if useDeprecatedTLSVerify {
cmd.Flags().AddFlagSet(&deprecatedTLSVerifyFlag)
}
cmd.Flags().AddFlagSet(&imageFlags) cmd.Flags().AddFlagSet(&imageFlags)
err := cmd.ParseFlags(cmdFlags) err := cmd.ParseFlags(cmdFlags)
require.NoError(t, err) require.NoError(t, err)
@ -36,7 +46,7 @@ func fakeImageOptions(t *testing.T, flagPrefix string, globalFlags []string, cmd
func TestImageOptionsNewSystemContext(t *testing.T) { func TestImageOptionsNewSystemContext(t *testing.T) {
// Default state // Default state
opts := fakeImageOptions(t, "dest-", []string{}, []string{}) opts := fakeImageOptions(t, "dest-", true, []string{}, []string{})
res, err := opts.newSystemContext() res, err := opts.newSystemContext()
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, &types.SystemContext{ assert.Equal(t, &types.SystemContext{
@ -44,7 +54,7 @@ func TestImageOptionsNewSystemContext(t *testing.T) {
}, res) }, res)
// Set everything to non-default values. // Set everything to non-default values.
opts = fakeImageOptions(t, "dest-", []string{ opts = fakeImageOptions(t, "dest-", true, []string{
"--registries.d", "/srv/registries.d", "--registries.d", "/srv/registries.d",
"--override-arch", "overridden-arch", "--override-arch", "overridden-arch",
"--override-os", "overridden-os", "--override-os", "overridden-os",
@ -83,17 +93,26 @@ func TestImageOptionsNewSystemContext(t *testing.T) {
// Global/per-command tlsVerify behavior is tested in TestTLSVerifyFlags. // Global/per-command tlsVerify behavior is tested in TestTLSVerifyFlags.
// Invalid option values // Invalid option values
opts = fakeImageOptions(t, "dest-", []string{}, []string{"--dest-creds", ""}) opts = fakeImageOptions(t, "dest-", true, []string{}, []string{"--dest-creds", ""})
_, err = opts.newSystemContext() _, err = opts.newSystemContext()
assert.Error(t, err) assert.Error(t, err)
} }
// fakeImageDestOptions creates imageDestOptions and sets it according to globalFlags/cmdFlags. // fakeImageDestOptions creates imageDestOptions and sets it according to globalFlags/cmdFlags.
func fakeImageDestOptions(t *testing.T, flagPrefix string, globalFlags []string, cmdFlags []string) *imageDestOptions { func fakeImageDestOptions(t *testing.T, flagPrefix string, useDeprecatedTLSVerify bool,
globalFlags []string, cmdFlags []string) *imageDestOptions {
globalOpts, cmd := fakeGlobalOptions(t, globalFlags) globalOpts, cmd := fakeGlobalOptions(t, globalFlags)
sharedFlags, sharedOpts := sharedImageFlags() sharedFlags, sharedOpts := sharedImageFlags()
imageFlags, imageOpts := imageDestFlags(globalOpts, sharedOpts, flagPrefix, "") var deprecatedTLSVerifyFlag pflag.FlagSet
var deprecatedTLSVerifyOpt *deprecatedTLSVerifyOption
if useDeprecatedTLSVerify {
deprecatedTLSVerifyFlag, deprecatedTLSVerifyOpt = deprecatedTLSVerifyFlags()
}
imageFlags, imageOpts := imageDestFlags(globalOpts, sharedOpts, deprecatedTLSVerifyOpt, flagPrefix, "")
cmd.Flags().AddFlagSet(&sharedFlags) cmd.Flags().AddFlagSet(&sharedFlags)
if useDeprecatedTLSVerify {
cmd.Flags().AddFlagSet(&deprecatedTLSVerifyFlag)
}
cmd.Flags().AddFlagSet(&imageFlags) cmd.Flags().AddFlagSet(&imageFlags)
err := cmd.ParseFlags(cmdFlags) err := cmd.ParseFlags(cmdFlags)
require.NoError(t, err) require.NoError(t, err)
@ -102,7 +121,7 @@ func fakeImageDestOptions(t *testing.T, flagPrefix string, globalFlags []string,
func TestImageDestOptionsNewSystemContext(t *testing.T) { func TestImageDestOptionsNewSystemContext(t *testing.T) {
// Default state // Default state
opts := fakeImageDestOptions(t, "dest-", []string{}, []string{}) opts := fakeImageDestOptions(t, "dest-", true, []string{}, []string{})
res, err := opts.newSystemContext() res, err := opts.newSystemContext()
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, &types.SystemContext{ assert.Equal(t, &types.SystemContext{
@ -122,7 +141,7 @@ func TestImageDestOptionsNewSystemContext(t *testing.T) {
os.Setenv("REGISTRY_AUTH_FILE", authFile) os.Setenv("REGISTRY_AUTH_FILE", authFile)
// Explicitly set everything to default, except for when the default is “not present” // Explicitly set everything to default, except for when the default is “not present”
opts = fakeImageDestOptions(t, "dest-", []string{}, []string{ opts = fakeImageDestOptions(t, "dest-", true, []string{}, []string{
"--dest-compress=false", "--dest-compress=false",
}) })
res, err = opts.newSystemContext() res, err = opts.newSystemContext()
@ -133,7 +152,7 @@ func TestImageDestOptionsNewSystemContext(t *testing.T) {
}, res) }, res)
// Set everything to non-default values. // Set everything to non-default values.
opts = fakeImageDestOptions(t, "dest-", []string{ opts = fakeImageDestOptions(t, "dest-", true, []string{
"--registries.d", "/srv/registries.d", "--registries.d", "/srv/registries.d",
"--override-arch", "overridden-arch", "--override-arch", "overridden-arch",
"--override-os", "overridden-os", "--override-os", "overridden-os",
@ -173,7 +192,7 @@ func TestImageDestOptionsNewSystemContext(t *testing.T) {
// Global/per-command tlsVerify behavior is tested in TestTLSVerifyFlags. // Global/per-command tlsVerify behavior is tested in TestTLSVerifyFlags.
// Invalid option values in imageOptions // Invalid option values in imageOptions
opts = fakeImageDestOptions(t, "dest-", []string{}, []string{"--dest-creds", ""}) opts = fakeImageDestOptions(t, "dest-", true, []string{}, []string{"--dest-creds", ""})
_, err = opts.newSystemContext() _, err = opts.newSystemContext()
assert.Error(t, err) assert.Error(t, err)
} }
@ -185,50 +204,84 @@ func TestTLSVerifyFlags(t *testing.T) {
for _, creator := range []struct { for _, creator := range []struct {
name string name string
newOpts func(globalFlags, cmdFlags []string) systemContextOpts newOpts func(useDeprecatedTLSVerify bool, globalFlags, cmdFlags []string) systemContextOpts
}{ }{
{ {
"imageFlags", "imageFlags",
func(globalFlags, cmdFlags []string) systemContextOpts { func(useDeprecatedTLSVerify bool, globalFlags, cmdFlags []string) systemContextOpts {
return fakeImageOptions(t, "dest-", globalFlags, cmdFlags) return fakeImageOptions(t, "dest-", useDeprecatedTLSVerify, globalFlags, cmdFlags)
}, },
}, },
{ {
"imageDestFlags", "imageDestFlags",
func(globalFlags, cmdFlags []string) systemContextOpts { func(useDeprecatedTLSVerify bool, globalFlags, cmdFlags []string) systemContextOpts {
return fakeImageDestOptions(t, "dest-", globalFlags, cmdFlags) return fakeImageDestOptions(t, "dest-", useDeprecatedTLSVerify, globalFlags, cmdFlags)
}, },
}, },
} { } {
t.Run(creator.name, func(t *testing.T) { t.Run(creator.name, func(t *testing.T) {
for _, c := range []struct { for _, c := range []struct {
global, cmd string global, deprecatedCmd, cmd string
expectedDocker types.OptionalBool expectedDocker types.OptionalBool
expectedDockerDaemon bool expectedDockerDaemon bool
}{ }{
{"", "", types.OptionalBoolUndefined, false}, {"", "", "", types.OptionalBoolUndefined, false},
{"", "false", types.OptionalBoolTrue, true}, {"", "", "false", types.OptionalBoolTrue, true},
{"", "true", types.OptionalBoolFalse, false}, {"", "", "true", types.OptionalBoolFalse, false},
{"false", "", types.OptionalBoolTrue, false}, {"", "false", "", types.OptionalBoolTrue, false},
{"false", "false", types.OptionalBoolTrue, true}, {"", "false", "false", types.OptionalBoolTrue, true},
{"false", "true", types.OptionalBoolFalse, false}, {"", "false", "true", types.OptionalBoolFalse, false},
{"true", "", types.OptionalBoolFalse, false}, {"", "true", "", types.OptionalBoolFalse, false},
{"true", "false", types.OptionalBoolTrue, true}, {"", "true", "false", types.OptionalBoolTrue, true},
{"true", "true", types.OptionalBoolFalse, false}, {"", "true", "true", types.OptionalBoolFalse, false},
{"false", "", "", types.OptionalBoolTrue, false},
{"false", "", "false", types.OptionalBoolTrue, true},
{"false", "", "true", types.OptionalBoolFalse, false},
{"false", "false", "", types.OptionalBoolTrue, false},
{"false", "false", "false", types.OptionalBoolTrue, true},
{"false", "false", "true", types.OptionalBoolFalse, false},
{"false", "true", "", types.OptionalBoolFalse, false},
{"false", "true", "false", types.OptionalBoolTrue, true},
{"false", "true", "true", types.OptionalBoolFalse, false},
{"true", "", "", types.OptionalBoolFalse, false},
{"true", "", "false", types.OptionalBoolTrue, true},
{"true", "", "true", types.OptionalBoolFalse, false},
{"true", "false", "", types.OptionalBoolTrue, false},
{"true", "false", "false", types.OptionalBoolTrue, true},
{"true", "false", "true", types.OptionalBoolFalse, false},
{"true", "true", "", types.OptionalBoolFalse, false},
{"true", "true", "false", types.OptionalBoolTrue, true},
{"true", "true", "true", types.OptionalBoolFalse, false},
} { } {
globalFlags := []string{} globalFlags := []string{}
if c.global != "" { if c.global != "" {
globalFlags = append(globalFlags, "--tls-verify="+c.global) globalFlags = append(globalFlags, "--tls-verify="+c.global)
} }
cmdFlags := []string{} cmdFlags := []string{}
if c.deprecatedCmd != "" {
cmdFlags = append(cmdFlags, "--tls-verify="+c.deprecatedCmd)
}
if c.cmd != "" { if c.cmd != "" {
cmdFlags = append(cmdFlags, "--dest-tls-verify="+c.cmd) cmdFlags = append(cmdFlags, "--dest-tls-verify="+c.cmd)
} }
opts := creator.newOpts(globalFlags, cmdFlags) opts := creator.newOpts(true, globalFlags, cmdFlags)
res, err := opts.newSystemContext() res, err := opts.newSystemContext()
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, c.expectedDocker, res.DockerInsecureSkipTLSVerify, "%#v", c) assert.Equal(t, c.expectedDocker, res.DockerInsecureSkipTLSVerify, "%#v", c)
assert.Equal(t, c.expectedDockerDaemon, res.DockerDaemonInsecureSkipTLSVerify, "%#v", c) assert.Equal(t, c.expectedDockerDaemon, res.DockerDaemonInsecureSkipTLSVerify, "%#v", c)
if c.deprecatedCmd == "" { // Test also the behavior when deprecatedTLSFlag is not recognized
// Use globalFlags from the previous test
cmdFlags := []string{}
if c.cmd != "" {
cmdFlags = append(cmdFlags, "--dest-tls-verify="+c.cmd)
}
opts := creator.newOpts(false, globalFlags, cmdFlags)
res, err = opts.newSystemContext()
require.NoError(t, err)
assert.Equal(t, c.expectedDocker, res.DockerInsecureSkipTLSVerify, "%#v", c)
assert.Equal(t, c.expectedDockerDaemon, res.DockerDaemonInsecureSkipTLSVerify, "%#v", c)
}
} }
}) })
} }
@ -300,7 +353,7 @@ func TestImageOptionsAuthfileOverride(t *testing.T) {
}, "/srv/dest-authfile", }, "/srv/dest-authfile",
}, },
} { } {
opts := fakeImageOptions(t, testCase.flagPrefix, []string{}, testCase.cmdFlags) opts := fakeImageOptions(t, testCase.flagPrefix, false, []string{}, testCase.cmdFlags)
res, err := opts.newSystemContext() res, err := opts.newSystemContext()
require.NoError(t, err) require.NoError(t, err)

View File

@ -60,6 +60,10 @@ The number of times to retry. Retry wait time will be exponentially increased ba
Directory to use to share blobs across OCI repositories. Directory to use to share blobs across OCI repositories.
**--tls-verify**=_bool_
Require HTTPS and verify certificates when talking to the container registry or daemon (defaults to true)
## EXAMPLES ## EXAMPLES
Mark image example/pause for deletion from the registry.example.com registry: Mark image example/pause for deletion from the registry.example.com registry:

View File

@ -65,6 +65,10 @@ The number of times to retry; retry wait time will be exponentially increased ba
Directory to use to share blobs across OCI repositories. Directory to use to share blobs across OCI repositories.
**--tls-verify**=_bool_
Require HTTPS and verify certificates when talking to the container registry or daemon (defaults to true)
## EXAMPLES ## EXAMPLES
To review information for the image fedora from the docker.io registry: To review information for the image fedora from the docker.io registry:

View File

@ -39,6 +39,10 @@ Bearer token for accessing the registry.
The number of times to retry. Retry wait time will be exponentially increased based on the number of failed attempts. The number of times to retry. Retry wait time will be exponentially increased based on the number of failed attempts.
**--tls-verify**=_bool_
Require HTTPS and verify certificates when talking to the container registry or daemon (defaults to true)
## REPOSITORY NAMES ## REPOSITORY NAMES
Repository names are transport-specific references as each transport may have its own concept of a "repository" and "tags". Currently, only the Docker transport is supported. Repository names are transport-specific references as each transport may have its own concept of a "repository" and "tags". Currently, only the Docker transport is supported.

View File

@ -47,6 +47,10 @@ Default certificates directory is _/etc/containers/certs.d_.
Print usage statement Print usage statement
**--tls-verify**=_bool_
Require HTTPS and verify certificates when talking to the container registry or daemon (defaults to true)
**--verbose**, **-v** **--verbose**, **-v**
Write more detailed information to stdout Write more detailed information to stdout

View File

@ -29,6 +29,10 @@ Remove the cached credentials for all registries in the auth file
Print usage statement Print usage statement
**--tls-verify**=_bool_
Require HTTPS and verify certificates when talking to the container registry or daemon (defaults to true)
## EXAMPLES ## EXAMPLES
``` ```