Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: adds very basic feature flag capabilities #1058

Open
wants to merge 3 commits into
base: uds-tofu
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/cmd/internal.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ var genCLIDocs = &cobra.Command{
rootCmd.RemoveCommand(scanCmd)
rootCmd.RemoveCommand(planCmd)
rootCmd.RemoveCommand(applyCmd)
rootCmd.RemoveCommand(initCmd)

// Set the default value for the uds-cache flag (otherwise this defaults to the user's home directory)
rootCmd.Flag("uds-cache").DefValue = "~/.uds-cache"
Expand Down
16 changes: 16 additions & 0 deletions src/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"github.com/defenseunicorns/uds-cli/src/cmd/monitor"
"github.com/defenseunicorns/uds-cli/src/config"
"github.com/defenseunicorns/uds-cli/src/config/lang"
"github.com/defenseunicorns/uds-cli/src/pkg/featureflags"
"github.com/defenseunicorns/uds-cli/src/types"
goyaml "github.com/goccy/go-yaml"
"github.com/pterm/pterm"
Expand All @@ -25,6 +26,8 @@ var (

// Default global config for the bundler
bundleCfg = types.BundleConfig{}

cliFeatures string
)

var rootCmd = &cobra.Command{
Expand All @@ -47,6 +50,12 @@ var rootCmd = &cobra.Command{
return err
}
}
// Enable features from the --feature flag
if cliFeatures != "" {
for _, feature := range strings.Split(cliFeatures, ",") {
featureflags.EnableFeature(feature)
}
}
return nil
},
Short: lang.RootCmdShort,
Expand All @@ -64,6 +73,8 @@ var rootCmd = &cobra.Command{

// Execute is the entrypoint for the CLI.
func Execute() {
// initialize feature flags
featureflags.Initialize()
err := rootCmd.Execute()
if err == nil {
return
Expand Down Expand Up @@ -113,6 +124,11 @@ func init() {
rootCmd.PersistentFlags().IntVar(&config.CommonOptions.OCIConcurrency, "oci-concurrency", v.GetInt(V_BNDL_OCI_CONCURRENCY), lang.CmdBundleFlagConcurrency)
rootCmd.PersistentFlags().BoolVar(&config.NoColor, "no-color", v.GetBool(V_NO_COLOR), lang.RootCmdFlagNoColor)

// Add a persistent flag for setting features
rootCmd.PersistentFlags().StringVar(&cliFeatures, "feature", "", "Comma-separated list of features to enable via a flag")
// hide the 'feature' flag for now
_ = rootCmd.PersistentFlags().MarkHidden("feature")

rootCmd.AddCommand(monitor.Cmd)
}

Expand Down
2 changes: 2 additions & 0 deletions src/cmd/uds.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ var createCmd = &cobra.Command{
if err != nil {
return fmt.Errorf("error reading the current working directory")
}

if len(args) > 0 {
srcDir = args[0]
}
Expand Down Expand Up @@ -267,6 +268,7 @@ func init() {

// logs cmd
rootCmd.AddCommand(logsCmd)

}

// chooseBundle provides a file picker when users don't specify a file
Expand Down
28 changes: 28 additions & 0 deletions src/cmd/vendored.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (

"github.com/defenseunicorns/uds-cli/src/config"
"github.com/defenseunicorns/uds-cli/src/config/lang"
"github.com/defenseunicorns/uds-cli/src/pkg/featureflags"
"github.com/spf13/cobra"
zarfCLI "github.com/zarf-dev/zarf/src/cmd"
zarfConfig "github.com/zarf-dev/zarf/src/config"
Expand Down Expand Up @@ -121,6 +122,10 @@ var planCmd = &cobra.Command{
Short: lang.CmdBundlePlanShort,
// Args: cobra.MaximumNArgs(0),
RunE: func(_ *cobra.Command, _ []string) error {
if !featureflags.IsEnabled("tofu") {
message.Warn("The 'plan' command is not enabled. Use the '--feature=tofu' flag or set the FEATURE_FLAG environment variable.")
return nil
}
return useEmbeddedTofu()
},
DisableFlagParsing: true,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As you pointed out last week, flagParsing is currently disabled and will need to be handled in some way.

Context: I originally disabled flagParsing so that we can pass all the tofu flags directly as args. If flagParsing is not disabled we will have to manually capture all the flags the user is trying to provide to tofu and forward them along.

Expand All @@ -131,6 +136,11 @@ var applyCmd = &cobra.Command{
Short: lang.CmdBundleApplyShort,
Args: cobra.MaximumNArgs(0),
RunE: func(_ *cobra.Command, _ []string) error {
if !featureflags.IsEnabled("tofu") {
message.Warn("The 'apply' command is not enabled. Use the '--feature=tofu' flag or set the FEATURE_FLAG environment variable.")
return nil
}

return useEmbeddedTofu()
},
DisableFlagParsing: true,
Expand All @@ -148,6 +158,23 @@ var scanCmd = &cobra.Command{
DisableFlagParsing: true,
}

// uds init [bundle-name] will initialize tofu in the current directory. If a
// bundle name is provided, it will use the bundle as the source for the Tofu
// providers and uds-bundle.tf file.
var initCmd = &cobra.Command{
Use: "init [BUNDLE_TARBALL]",
Short: lang.CmdBundleApplyShort,
Args: cobra.MaximumNArgs(0),
RunE: func(_ *cobra.Command, _ []string) error {
if !featureflags.IsEnabled("tofu") {
fmt.Println("The 'init' command is not enabled. Use the '--feature=tofu' flag or set the FEATURE_FLAG environment variable.")
return nil
}
return useEmbeddedTofu()
},
DisableFlagParsing: true,
}

func init() {
// grab Zarf version to make Zarf library checks happy
if buildInfo, ok := debug.ReadBuildInfo(); ok {
Expand All @@ -170,4 +197,5 @@ func init() {
rootCmd.AddCommand(scanCmd) // uds-security-hub CLI command
rootCmd.AddCommand(planCmd) // tofu plan
rootCmd.AddCommand(applyCmd) // tofu apply
rootCmd.AddCommand(initCmd) // tofu init
}
3 changes: 2 additions & 1 deletion src/config/lang/lang.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ const (

// bundle apply
CmdBundleApplyShort = "Create or update infrastructure with Tofu"
CmdBundleInitShort = "Initialize OpenTofu"

// bundle inspect
CmdBundleInspectShort = "Display the metadata of a bundle"
Expand Down Expand Up @@ -125,4 +126,4 @@ const (
CmdPeprMonitorTimestampFlag = "Show timestamps in Pepr logs"
CmdPeprMonitorSinceFlag = "Only return logs newer than a relative duration like 5s, 2m, or 3h. Defaults to all logs."
CmdPeprMonitorJSONFlag = "Return the raw JSON output of the logs"
)
)
34 changes: 34 additions & 0 deletions src/pkg/featureflags/featureflags.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// Copyright 2025 Defense Unicorns
// SPDX-License-Identifier: AGPL-3.0-or-later OR LicenseRef-Defense-Unicorns-Commercial

package featureflags

import (
"os"
"strings"
)

// FeatureFlagMap stores the state of feature flags.
var FeatureFlagMap = map[string]bool{}

// Initialize initializes the feature flags from an environment variable.
func Initialize() {
// Check the FEATURE_FLAG environment variable.
// example: FEATURE_FLAG=tofu,encrypt-oci
envFeatures := os.Getenv("FEATURE_FLAG")
if envFeatures != "" {
for _, feature := range strings.Split(envFeatures, ",") {
FeatureFlagMap[feature] = true
}
}
}

// EnableFeature enables a feature flag programmatically.
func EnableFeature(feature string) {
FeatureFlagMap[feature] = true
}

// IsEnabled checks if a feature flag is enabled.
func IsEnabled(feature string) bool {
return FeatureFlagMap[feature]
}
2 changes: 1 addition & 1 deletion tasks.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -129,4 +129,4 @@ tasks:
- task: get-versions
- task: build-args
- task: download-tofu-mac-apple
- cmd: GOOS=darwin GOARCH=arm64 go build -ldflags="${BUILD_ARGS}" -o build/uds-mac-apple main.go
- cmd: GOOS=darwin GOARCH=arm64 go build -ldflags="${BUILD_ARGS}" -o build/uds-mac-apple main.go
Loading