diff --git a/internal/cli/cli_test.go b/internal/cli/cli_test.go index 3bbd025..4670cf2 100644 --- a/internal/cli/cli_test.go +++ b/internal/cli/cli_test.go @@ -81,8 +81,10 @@ func TestRunExportHappyPath(t *testing.T) { dir := t.TempDir() err := RunExport(context.Background(), config.ExportConfig{ - AdminURL: srv.URL, - Token: "secret", + AuthConfig: config.AuthConfig{ + AdminURL: srv.URL, + Token: "secret", + }, OutDir: dir, ToolboxNativeBinary: toolboxBin, }) diff --git a/internal/config/config.go b/internal/config/config.go index 8b206e8..19d73ff 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -21,14 +21,12 @@ var ( ) type ExportConfig struct { - AdminURL string - Token string + AuthConfig OutDir string IncludeApplications bool RedactSecrets bool PerPage int MaxConcurrent int - InsecureTLS bool ToolboxImage string ToolboxRuntime string ToolboxNativeBinary string @@ -37,29 +35,18 @@ type ExportConfig struct { func LoadExportFromEnv() (ExportConfig, error) { cfg := ExportConfig{ - AdminURL: strings.TrimSpace(os.Getenv("THREESCALE_ADMIN_URL")), - Token: strings.TrimSpace(os.Getenv("THREESCALE_ACCESS_TOKEN")), - OutDir: strings.TrimSpace(os.Getenv("THREESCALE_OUTPUT_DIR")), - PerPage: DefaultPerPage, - MaxConcurrent: DefaultMaxConcurrent, - ToolboxImage: strings.TrimSpace(os.Getenv("THREESCALE_TOOLBOX_IMAGE")), - ToolboxRuntime: strings.TrimSpace(os.Getenv("THREESCALE_TOOLBOX_RUNTIME")), - ToolboxNativeBinary: strings.TrimSpace(os.Getenv("THREESCALE_TOOLBOX_BINARY")), - ToolboxCertFile: strings.TrimSpace(os.Getenv("THREESCALE_TOOLBOX_TLS_CERT")), + AuthConfig: LoadAuthFromEnv(), + OutDir: strings.TrimSpace(os.Getenv("THREESCALE_OUTPUT_DIR")), + PerPage: DefaultPerPage, + MaxConcurrent: DefaultMaxConcurrent, + ToolboxImage: strings.TrimSpace(os.Getenv("THREESCALE_TOOLBOX_IMAGE")), + ToolboxRuntime: strings.TrimSpace(os.Getenv("THREESCALE_TOOLBOX_RUNTIME")), + ToolboxNativeBinary: strings.TrimSpace(os.Getenv("THREESCALE_TOOLBOX_BINARY")), + ToolboxCertFile: strings.TrimSpace(os.Getenv("THREESCALE_TOOLBOX_TLS_CERT")), } return cfg, cfg.ValidateAuth() } -func (c ExportConfig) ValidateAuth() error { - if c.AdminURL == "" { - return ErrMissingAdminURL - } - if c.Token == "" { - return ErrMissingToken - } - return nil -} - func (c ExportConfig) ValidateOutput() error { if err := c.ValidateAuth(); err != nil { return err @@ -71,14 +58,12 @@ func (c ExportConfig) ValidateOutput() error { } func BindExportFlags(fs *pflag.FlagSet, cfg *ExportConfig) { - fs.StringVar(&cfg.AdminURL, "admin-url", cfg.AdminURL, "3scale Admin Portal base URL") - fs.StringVar(&cfg.Token, "token", cfg.Token, "3scale Personal Access Token") + BindAuthFlags(fs, &cfg.AuthConfig) fs.StringVar(&cfg.OutDir, "output", cfg.OutDir, "export output directory") fs.BoolVar(&cfg.IncludeApplications, "include-applications", cfg.IncludeApplications, "export applications and linked accounts") fs.BoolVar(&cfg.RedactSecrets, "redact-secrets", cfg.RedactSecrets, "mask API keys and OIDC secrets in output") fs.IntVar(&cfg.PerPage, "per-page", cfg.PerPage, "Admin API page size (max 500)") fs.IntVar(&cfg.MaxConcurrent, "concurrency", cfg.MaxConcurrent, "max concurrent Admin API requests") - fs.BoolVar(&cfg.InsecureTLS, "insecure", cfg.InsecureTLS, "skip TLS certificate verification") fs.StringVar(&cfg.ToolboxImage, "toolbox-image", cfg.ToolboxImage, "3scale toolbox container image (Red Hat official)") fs.StringVar(&cfg.ToolboxRuntime, "toolbox-runtime", cfg.ToolboxRuntime, "container runtime for toolbox (docker or podman; auto-detects if empty)") fs.StringVar(&cfg.ToolboxNativeBinary, "toolbox-binary", cfg.ToolboxNativeBinary, "optional local 3scale binary instead of container") diff --git a/internal/config/config_test.go b/internal/config/config_test.go index 6db3161..bf362d8 100644 --- a/internal/config/config_test.go +++ b/internal/config/config_test.go @@ -8,7 +8,7 @@ import ( ) func TestValidateAuthMissingURL(t *testing.T) { - cfg := ExportConfig{Token: "tok"} + cfg := ExportConfig{AuthConfig: AuthConfig{Token: "tok"}} err := cfg.ValidateAuth() if !errors.Is(err, ErrMissingAdminURL) { t.Fatalf("err = %v", err) @@ -16,7 +16,7 @@ func TestValidateAuthMissingURL(t *testing.T) { } func TestValidateAuthMissingToken(t *testing.T) { - cfg := ExportConfig{AdminURL: "https://tenant.example.com"} + cfg := ExportConfig{AuthConfig: AuthConfig{AdminURL: "https://tenant.example.com"}} err := cfg.ValidateAuth() if !errors.Is(err, ErrMissingToken) { t.Fatalf("err = %v", err) @@ -25,8 +25,10 @@ func TestValidateAuthMissingToken(t *testing.T) { func TestValidateOutputRequiresDir(t *testing.T) { cfg := ExportConfig{ - AdminURL: "https://tenant.example.com", - Token: "tok", + AuthConfig: AuthConfig{ + AdminURL: "https://tenant.example.com", + Token: "tok", + }, } err := cfg.ValidateOutput() if err == nil || err.Error() != "output directory is required: use --output" {