From 1838f044289e96962bda25c1e73f996e126fdc8a Mon Sep 17 00:00:00 2001 From: saiflayouni Date: Tue, 30 Jun 2026 19:38:45 +0100 Subject: [PATCH] feat: add --skip-ssl-verify and --override-base-url global flags (#675) Some users run apigeecli behind a corporate MITM proxy or against a local Apigee emulator. Two new persistent flags (and matching env vars) make this possible without patching the binary: - `--skip-ssl-verify` / `APIGEECLI_SKIP_SSL_VERIFY=true` Disables TLS certificate verification. Not recommended for production. - `--override-base-url ` / `APIGEECLI_OVERRIDE_BASE_URL=` Replaces the computed Apigee base URL entirely. Implementation: - `ApigeeClientOptions` gains `SkipSSLVerify bool` and `OverrideBaseURL string` - `GetApigeeBaseURL()` checks the override first - `GetHttpClient()` creates an `http.Transport` with `tls.Config.InsecureSkipVerify` so both the proxy and non-proxy code paths respect the flag --- internal/apiclient/httpclient.go | 12 +++++++++-- internal/apiclient/options.go | 35 ++++++++++++++++++++++++++++---- internal/cmd/root.go | 30 ++++++++++++++++++++------- 3 files changed, 64 insertions(+), 13 deletions(-) diff --git a/internal/apiclient/httpclient.go b/internal/apiclient/httpclient.go index 97d6b68c..aafb9bc7 100644 --- a/internal/apiclient/httpclient.go +++ b/internal/apiclient/httpclient.go @@ -17,6 +17,7 @@ package apiclient import ( "bytes" "context" + "crypto/tls" "encoding/json" "errors" "fmt" @@ -394,12 +395,15 @@ func GetHttpClient() (err error) { apiRateLimit = noAPIRateLimit } + tlsCfg := &tls.Config{InsecureSkipVerify: GetSkipSSLVerify()} //nolint:gosec + if GetProxyURL() != "" { if proxyUrl, err := url.Parse(GetProxyURL()); err == nil { ApigeeAPIClient = &RateLimitedHTTPClient{ client: &http.Client{ Transport: &http.Transport{ - Proxy: http.ProxyURL(proxyUrl), + Proxy: http.ProxyURL(proxyUrl), + TLSClientConfig: tlsCfg, }, }, Ratelimiter: apiRateLimit, @@ -409,7 +413,11 @@ func GetHttpClient() (err error) { } } else { ApigeeAPIClient = &RateLimitedHTTPClient{ - client: http.DefaultClient, + client: &http.Client{ + Transport: &http.Transport{ + TLSClientConfig: tlsCfg, + }, + }, Ratelimiter: apiRateLimit, } } diff --git a/internal/apiclient/options.go b/internal/apiclient/options.go index f213e00b..6de1a0d3 100644 --- a/internal/apiclient/options.go +++ b/internal/apiclient/options.go @@ -51,10 +51,12 @@ type ApigeeClientOptions struct { PrintOutput bool // prints output from http calls NoOutput bool // Disable all statements to stdout NoWarnings bool // Disable printing warnings to stderr - ProxyUrl string // use a proxy url - MetadataToken bool // use metadata outh2 token - APIRate Rate // throttle api calls to Apigee - Region string // control plane region + ProxyUrl string // use a proxy url + MetadataToken bool // use metadata outh2 token + APIRate Rate // throttle api calls to Apigee + Region string // control plane region + SkipSSLVerify bool // skip TLS certificate verification + OverrideBaseURL string // override the Apigee base URL // Space string // Apigee space } @@ -125,6 +127,8 @@ func NewApigeeClient(o ApigeeClientOptions) { options.PrintOutput = o.PrintOutput options.NoOutput = o.NoOutput options.NoWarnings = o.NoWarnings + options.SkipSSLVerify = o.SkipSSLVerify + options.OverrideBaseURL = o.OverrideBaseURL // initialize logs clilog.Init(options.DebugLog, options.PrintOutput, options.NoOutput, options.NoWarnings) @@ -348,8 +352,31 @@ func GetAPIObserveURL() (apiObserveURL string) { return fmt.Sprintf(apiObserveBaseURL, options.ProjectID, options.Region) } +// SetSkipSSLVerify +func SetSkipSSLVerify(skip bool) { + options.SkipSSLVerify = skip +} + +// GetSkipSSLVerify +func GetSkipSSLVerify() bool { + return options.SkipSSLVerify +} + +// SetOverrideBaseURL +func SetOverrideBaseURL(u string) { + options.OverrideBaseURL = u +} + +// GetOverrideBaseURL +func GetOverrideBaseURL() string { + return options.OverrideBaseURL +} + // GetApigeeBaseURL func GetApigeeBaseURL() string { + if options.OverrideBaseURL != "" { + return options.OverrideBaseURL + } if options.Region != "" { return fmt.Sprintf(baseDRZURL, options.Region) } diff --git a/internal/cmd/root.go b/internal/cmd/root.go index 94dfe86d..7a9c09bf 100644 --- a/internal/cmd/root.go +++ b/internal/cmd/root.go @@ -130,8 +130,9 @@ func Execute() { } var ( - accessToken, serviceAccount string + accessToken, serviceAccount, overrideBaseURL string disableCheck, printOutput, noOutput, metadataToken, defaultToken, noWarnings bool + skipSSLVerify bool api apiclient.API ) @@ -167,6 +168,12 @@ func init() { RootCmd.PersistentFlags().Var(&api, "api", "Sets the control plane API. Must be one of prod, autopush "+ "or staging; default is prod") + RootCmd.PersistentFlags().BoolVarP(&skipSSLVerify, "skip-ssl-verify", "", + false, "Skip TLS certificate verification (not recommended for production)") + + RootCmd.PersistentFlags().StringVarP(&overrideBaseURL, "override-base-url", "", + "", "Override the Apigee base URL (e.g. for local proxies or testing)") + RootCmd.AddCommand(apis.Cmd) RootCmd.AddCommand(org.Cmd) RootCmd.AddCommand(sync.Cmd) @@ -215,17 +222,26 @@ func initConfig() { skipCache, _ = strconv.ParseBool(os.Getenv("APIGEECLI_SKIPCACHE")) + if os.Getenv("APIGEECLI_SKIP_SSL_VERIFY") == ENABLED { + skipSSLVerify = true + } + if envOverride := os.Getenv("APIGEECLI_OVERRIDE_BASE_URL"); envOverride != "" { + overrideBaseURL = envOverride + } + if noOutput { printOutput = noOutput } apiclient.NewApigeeClient(apiclient.ApigeeClientOptions{ - TokenCheck: true, - PrintOutput: printOutput, - NoOutput: noOutput, - DebugLog: debug, - SkipCache: skipCache, - NoWarnings: noWarnings, + TokenCheck: true, + PrintOutput: printOutput, + NoOutput: noOutput, + DebugLog: debug, + SkipCache: skipCache, + NoWarnings: noWarnings, + SkipSSLVerify: skipSSLVerify, + OverrideBaseURL: overrideBaseURL, }) if os.Getenv("APIGEECLI_ENABLE_RATELIMIT") == ENABLED {