diff --git a/pkg/ccl/cliccl/BUILD.bazel b/pkg/ccl/cliccl/BUILD.bazel index ec1d26b52e0f..71116c967f9d 100644 --- a/pkg/ccl/cliccl/BUILD.bazel +++ b/pkg/ccl/cliccl/BUILD.bazel @@ -27,10 +27,12 @@ go_library( "//pkg/ccl/utilccl", "//pkg/ccl/workloadccl/cliccl", "//pkg/cli", + "//pkg/cli/clierror", "//pkg/cli/clierrorplus", "//pkg/cli/cliflagcfg", "//pkg/cli/cliflags", "//pkg/cli/democluster", + "//pkg/cli/exit", "//pkg/storage", "//pkg/storage/enginepb", "//pkg/util/log", @@ -44,6 +46,7 @@ go_library( "@com_github_cockroachdb_redact//:redact", "@com_github_olekukonko_tablewriter//:tablewriter", "@com_github_spf13_cobra//:cobra", + "@com_github_spf13_pflag//:pflag", ], ) diff --git a/pkg/ccl/cliccl/flags.go b/pkg/ccl/cliccl/flags.go index 58bd3e8d99ba..0c19bd81e0b5 100644 --- a/pkg/ccl/cliccl/flags.go +++ b/pkg/ccl/cliccl/flags.go @@ -9,11 +9,59 @@ package cliccl import ( + "os" + "strconv" + + "github.com/cockroachdb/cockroach/pkg/ccl/securityccl/fipsccl" "github.com/cockroachdb/cockroach/pkg/cli" + "github.com/cockroachdb/cockroach/pkg/cli/clierror" "github.com/cockroachdb/cockroach/pkg/cli/cliflagcfg" "github.com/cockroachdb/cockroach/pkg/cli/cliflags" + "github.com/cockroachdb/cockroach/pkg/cli/exit" + "github.com/cockroachdb/errors" + "github.com/spf13/pflag" ) +type requireFipsFlag bool + +// Type implements the pflag.Value interface. +func (f *requireFipsFlag) Type() string { + return "bool" +} + +// String implements the pflag.Value interface. +func (f *requireFipsFlag) String() string { + return strconv.FormatBool(bool(*f)) +} + +// Set implements the pflag.Value interface. +func (f *requireFipsFlag) Set(s string) error { + v, err := strconv.ParseBool(s) + if err != nil { + return err + } + // We implement the logic of this check in the flag setter itself because it + // applies to all commands and we do not have another good way to inject + // this behavior globally (PersistentPreRun functions don't help because + // they are inherited across different levels of the command hierarchy only + // if that level does not have its own hook). + if v && !fipsccl.IsFIPSReady() { + err := errors.WithHint(errors.New("FIPS readiness checks failed"), "Run `cockroach debug enterprise-check-fips` for details") + clierror.OutputError(os.Stderr, err, true, false) + exit.WithCode(exit.UnspecifiedError()) + } + *f = requireFipsFlag(v) + return nil +} + +var _ pflag.Value = (*requireFipsFlag)(nil) + +// IsBoolFlag implements a non-public pflag interface to indicate that this +// flag is used without an explicit value. +func (*requireFipsFlag) IsBoolFlag() bool { + return true +} + func init() { // Multi-tenancy proxy command flags. { @@ -44,4 +92,12 @@ func init() { // Use StringFlagDepth to avoid conflicting with the already registered KVAddrs env var. cliflagcfg.StringFlagDepth(1, f, &testDirectorySvrContext.kvAddrs, cliflags.KVAddrs) }) + + // FIPS verification flags. + cli.RegisterFlags(func() { + cmd := cli.CockroachCmd() + var requireFips = requireFipsFlag(false) + flag := cmd.PersistentFlags().VarPF(&requireFips, "enterprise-require-fips-ready", "", "abort if FIPS readiness checks fail") + flag.NoOptDefVal = "true" + }) } diff --git a/pkg/cli/cli.go b/pkg/cli/cli.go index 7beb18e35f4a..ec1ff3f14f79 100644 --- a/pkg/cli/cli.go +++ b/pkg/cli/cli.go @@ -228,6 +228,11 @@ var cockroachCmd = &cobra.Command{ }, } +// CockroachCmd returns the root cockroach Command object. +func CockroachCmd() *cobra.Command { + return cockroachCmd +} + var workloadCmd = workloadcli.WorkloadCmd(true /* userFacing */) func init() {