Skip to content
Merged
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
37 changes: 21 additions & 16 deletions cmd/server/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"github.com/go-chi/chi/v5/middleware"
"github.com/prometheus/client_golang/prometheus/promhttp"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
"github.com/spf13/viper"

"github.com/openchami/boot-service/internal/storage"
Expand Down Expand Up @@ -72,7 +73,7 @@ func DefaultConfig() Config {
StorageType: "file",
EnableAuth: false,
EnableMetrics: false,
EnableLegacyAPI: true,
EnableLegacyAPI: false,
MetricsPort: 9090,
TokenSmithURL: "",
TokenSmithBootstrapToken: "",
Expand Down Expand Up @@ -100,6 +101,21 @@ var serveCmd = &cobra.Command{
RunE: runServe,
}

func bindFlagsWithUnderscoreKeys(v *viper.Viper, flags *pflag.FlagSet) error {
var bindErr error

flags.VisitAll(func(flag *pflag.Flag) {
if bindErr != nil {
return
}

key := strings.ReplaceAll(flag.Name, "-", "_")
bindErr = v.BindPFlag(key, flag)
})

return bindErr
}

func init() {
// Server configuration flags
serveCmd.Flags().Int("port", 8080, "Port to listen on")
Expand All @@ -119,7 +135,7 @@ func init() {
serveCmd.Flags().Int("metrics-port", 9090, "Port for metrics endpoint")

// Authentication configuration flags
serveCmd.Flags().String("tokensmith_url", "", "TokenSmith service URL for authentication")
serveCmd.Flags().String("tokensmith-url", "", "TokenSmith service URL for authentication")
serveCmd.Flags().String("tokensmith-bootstrap-token", "", "Bootstrap token used to exchange HSM service tokens")
serveCmd.Flags().String("tokensmith-target-service", "hsm", "Target service audience for HSM service token exchange")
serveCmd.Flags().String("tokensmith-bootstrap-policy-scopes-hint", "", "Comma-separated scope hint from bootstrap token policy used for diagnostics only")
Expand All @@ -133,7 +149,9 @@ func init() {
serveCmd.Flags().Int("hsm-sync-interval", 5, "HSM sync interval in minutes")

// Bind flags to viper
viper.BindPFlags(serveCmd.Flags()) //nolint:errcheck
if err := bindFlagsWithUnderscoreKeys(viper.GetViper(), serveCmd.Flags()); err != nil {
panic(fmt.Errorf("failed to bind serve flags: %w", err))
}

// Add commands
rootCmd.AddCommand(serveCmd)
Expand All @@ -152,19 +170,6 @@ func main() {
viper.SetEnvKeyReplacer(strings.NewReplacer("-", "_"))
viper.AutomaticEnv()

// Register aliases for flags with dashes to work with mapstructure tags that use underscores
viper.RegisterAlias("hsm_url", "hsm-url")
viper.RegisterAlias("hsm_sync_enabled", "hsm-sync-enabled")
viper.RegisterAlias("hsm_sync_interval", "hsm-sync-interval")
viper.RegisterAlias("tokensmith_bootstrap_token", "tokensmith-bootstrap-token")
viper.RegisterAlias("tokensmith_target_service", "tokensmith-target-service")
viper.RegisterAlias("tokensmith_bootstrap_policy_scopes_hint", "tokensmith-bootstrap-policy-scopes-hint")
viper.RegisterAlias("tokensmith_scopes", "tokensmith-scopes")
viper.RegisterAlias("tokensmith_refresh_skew_sec", "tokensmith-refresh-skew-sec")
viper.RegisterAlias("enable_auth", "enable-auth")
viper.RegisterAlias("enable_legacy_api", "enable-legacy-api")
viper.RegisterAlias("enable_metrics", "enable-metrics")

// Standardized TokenSmith env vars for cross-service UX consistency.
viper.BindEnv("tokensmith_url", "TOKENSMITH_URL") //nolint:errcheck
viper.BindEnv("tokensmith_bootstrap_token", "TOKENSMITH_BOOTSTRAP_TOKEN") //nolint:errcheck
Expand Down
84 changes: 84 additions & 0 deletions cmd/server/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,96 @@ import (

"github.com/go-chi/chi/v5"
"github.com/go-chi/chi/v5/middleware"
"github.com/spf13/pflag"
"github.com/spf13/viper"

"github.com/openchami/boot-service/internal/storage"
bootclient "github.com/openchami/boot-service/pkg/client"
"github.com/openchami/boot-service/pkg/handlers/boot"
)

func TestBindFlagsWithUnderscoreKeys_ConfigValuesBeatUnchangedFlagDefaults(t *testing.T) {
flags := pflag.NewFlagSet("test", pflag.ContinueOnError)
flags.Bool("enable-auth", false, "Enable authentication with TokenSmith")
flags.Bool("enable-metrics", false, "Enable Prometheus metrics")
flags.Bool("enable-legacy-api", true, "Enable legacy BSS API compatibility")
flags.String("tokensmith-url", "", "TokenSmith service URL for authentication")
flags.String("tokensmith-target-service", "hsm", "Target service audience for HSM service token exchange")
flags.String("hsm-url", "", "Hardware State Manager service URL")
flags.Bool("hsm-sync-enabled", true, "Enable background sync with HSM")

v := viper.New()
if err := bindFlagsWithUnderscoreKeys(v, flags); err != nil {
t.Fatalf("bindFlagsWithUnderscoreKeys failed: %v", err)
}

v.SetConfigType("yaml")
configYAML := `
enable_auth: true
tokensmith_url: http://tokensmith:8080
tokensmith_target_service: smd
hsm_url: http://smd:27779
hsm_sync_enabled: true
enable_legacy_api: true
enable_metrics: false
`
if err := v.ReadConfig(strings.NewReader(configYAML)); err != nil {
t.Fatalf("ReadConfig failed: %v", err)
}

config := DefaultConfig()
if err := v.Unmarshal(&config); err != nil {
t.Fatalf("Unmarshal failed: %v", err)
}

if !config.EnableAuth {
t.Fatal("expected enable_auth config value to override unchanged --enable-auth default")
}
if config.TokenSmithURL != "http://tokensmith:8080" {
t.Fatalf("expected tokensmith_url from config, got %q", config.TokenSmithURL)
}
if config.TokenSmithTargetService != "smd" {
t.Fatalf("expected tokensmith_target_service from config, got %q", config.TokenSmithTargetService)
}
if config.HSMURL != "http://smd:27779" {
t.Fatalf("expected hsm_url config value to override unchanged --hsm-url default, got %q", config.HSMURL)
}
if !config.HSMSyncEnabled {
t.Fatal("expected hsm_sync_enabled from config")
}
if !config.EnableLegacyAPI {
t.Fatal("expected enable_legacy_api from config")
}
if config.EnableMetrics {
t.Fatal("expected enable_metrics to remain false")
}
}

func TestBindFlagsWithUnderscoreKeys_ChangedHyphenatedFlagsUseUnderscoreKeys(t *testing.T) {
flags := pflag.NewFlagSet("test", pflag.ContinueOnError)
flags.Bool("enable-auth", false, "Enable authentication with TokenSmith")
flags.String("hsm-url", "", "Hardware State Manager service URL")

if err := flags.Set("enable-auth", "true"); err != nil {
t.Fatalf("Set enable-auth failed: %v", err)
}
if err := flags.Set("hsm-url", "http://smd:27779"); err != nil {
t.Fatalf("Set hsm-url failed: %v", err)
}

v := viper.New()
if err := bindFlagsWithUnderscoreKeys(v, flags); err != nil {
t.Fatalf("bindFlagsWithUnderscoreKeys failed: %v", err)
}

if !v.GetBool("enable_auth") {
t.Fatal("expected --enable-auth to bind to enable_auth")
}
if got := v.GetString("hsm_url"); got != "http://smd:27779" {
t.Fatalf("expected --hsm-url to bind to hsm_url, got %q", got)
}
}

func newGeneratedRouterForTest(t *testing.T) http.Handler {
t.Helper()

Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ require (
github.com/prometheus/client_golang v1.23.2
github.com/rs/zerolog v1.34.0
github.com/spf13/cobra v1.10.2
github.com/spf13/pflag v1.0.10
github.com/spf13/viper v1.21.0
github.com/stretchr/testify v1.11.1
gopkg.in/yaml.v3 v3.0.1
Expand Down Expand Up @@ -65,7 +66,6 @@ require (
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect
github.com/spf13/afero v1.15.0 // indirect
github.com/spf13/cast v1.10.0 // indirect
github.com/spf13/pflag v1.0.10 // indirect
github.com/subosito/gotenv v1.6.0 // indirect
github.com/woodsbury/decimal128 v1.3.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
Expand Down
Loading