diff --git a/packages/cmd/root.go b/packages/cmd/root.go index 1a8bfa62..81728198 100644 --- a/packages/cmd/root.go +++ b/packages/cmd/root.go @@ -21,6 +21,14 @@ import ( var Telemetry *telemetry.Telemetry +// domainFromWorkspaceConfig holds the apiUrl value read from .infisical.json during init(), +// so that PersistentPreRun can print an informational message about it. +var domainFromWorkspaceConfig string + +// workspaceConfigApiUrlMalformed is set during init() when .infisical.json contains a +// non-empty apiUrl that does not begin with http:// or https://. +var workspaceConfigApiUrlMalformed bool + var RootCmd = &cobra.Command{ Use: "infisical", Short: "Infisical CLI is used to inject environment variables into any process", @@ -94,7 +102,7 @@ func init() { cobra.OnInitialize(initLog) RootCmd.PersistentFlags().StringP("log-level", "l", "", "log level (trace, debug, info, warn, error, fatal)") RootCmd.PersistentFlags().Bool("telemetry", true, "Infisical collects non-sensitive telemetry data to enhance features and improve user experience. Participation is voluntary") - RootCmd.PersistentFlags().StringVar(&config.INFISICAL_URL, "domain", fmt.Sprintf("%s/api", util.INFISICAL_DEFAULT_US_URL), "Point the CLI to your Infisical instance (e.g., https://eu.infisical.com for EU Cloud, or https://your-instance.com for self-hosted). Can also set via INFISICAL_API_URL environment variable. Required for non-US Cloud users.") + RootCmd.PersistentFlags().StringVar(&config.INFISICAL_URL, "domain", fmt.Sprintf("%s/api", util.INFISICAL_DEFAULT_US_URL), "Point the CLI to your Infisical instance (e.g., https://eu.infisical.com for EU Cloud, or https://your-instance.com for self-hosted). Can also set via INFISICAL_API_URL environment variable or the 'apiUrl' field in .infisical.json. Required for non-US Cloud users.") RootCmd.PersistentFlags().Bool("silent", false, "Disable output of tip/info messages. Useful when running in scripts or CI/CD pipelines.") RootCmd.PersistentPreRun = func(cmd *cobra.Command, args []string) { silent, err := cmd.Flags().GetBool("silent") @@ -104,6 +112,12 @@ func init() { config.INFISICAL_URL = util.AppendAPIEndpoint(config.INFISICAL_URL) + if workspaceConfigApiUrlMalformed { + util.PrintWarningWithWriter("The 'apiUrl' field in .infisical.json is not a valid URL (must start with http:// or https://). It will be ignored.", cmd.ErrOrStderr()) + } else if domainFromWorkspaceConfig != "" && !silent { + fmt.Fprintf(cmd.ErrOrStderr(), "[INFO] Using domain '%s' from .infisical.json\n", domainFromWorkspaceConfig) + } + // util.DisplayAptInstallationChangeBannerWithWriter(silent, cmd.ErrOrStderr()) if !util.IsRunningInDocker() && !silent && !isStructuredOutputRequested(cmd) { util.CheckForUpdateWithWriter(cmd.ErrOrStderr()) @@ -121,11 +135,18 @@ func init() { } - // if config.INFISICAL_URL is set to the default value, check if INFISICAL_URL is set in the environment - // this is used to allow overrides of the default value + // Override the default domain if the --domain flag was not explicitly set. + // Priority order (highest to lowest): --domain flag > INFISICAL_API_URL env var > .infisical.json apiUrl field > default if !RootCmd.Flag("domain").Changed { if envInfisicalBackendUrl, ok := os.LookupEnv("INFISICAL_API_URL"); ok { config.INFISICAL_URL = util.AppendAPIEndpoint(envInfisicalBackendUrl) + } else if workspaceConfig, err := util.GetWorkSpaceFromFile(); err == nil && workspaceConfig.ApiUrl != "" { + if strings.HasPrefix(workspaceConfig.ApiUrl, "http://") || strings.HasPrefix(workspaceConfig.ApiUrl, "https://") { + config.INFISICAL_URL = util.AppendAPIEndpoint(workspaceConfig.ApiUrl) + domainFromWorkspaceConfig = workspaceConfig.ApiUrl + } else { + workspaceConfigApiUrlMalformed = true + } } } diff --git a/packages/models/cli.go b/packages/models/cli.go index 0a427f73..4a0d9320 100644 --- a/packages/models/cli.go +++ b/packages/models/cli.go @@ -112,6 +112,7 @@ type WorkspaceConfigFile struct { WorkspaceId string `json:"workspaceId"` DefaultEnvironment string `json:"defaultEnvironment"` GitBranchToEnvironmentMapping map[string]string `json:"gitBranchToEnvironmentMapping"` + ApiUrl string `json:"apiUrl,omitempty"` } type SymmetricEncryptionResult struct { diff --git a/packages/util/config_test.go b/packages/util/config_test.go new file mode 100644 index 00000000..ecc958c0 --- /dev/null +++ b/packages/util/config_test.go @@ -0,0 +1,38 @@ +package util + +import ( + "testing" +) + +func TestGetWorkspaceConfigByPath_WithApiUrl(t *testing.T) { + cfg, err := GetWorkspaceConfigByPath("testdata/infisical-with-api-url.json") + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if cfg.WorkspaceId != "test-workspace-id" { + t.Errorf("expected workspaceId 'test-workspace-id', got '%s'", cfg.WorkspaceId) + } + if cfg.ApiUrl != "https://custom.infisical.com/api" { + t.Errorf("expected apiUrl 'https://custom.infisical.com/api', got '%s'", cfg.ApiUrl) + } +} + +func TestGetWorkspaceConfigByPath_WithoutApiUrl(t *testing.T) { + cfg, err := GetWorkspaceConfigByPath("testdata/infisical-default-env.json") + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if cfg.ApiUrl != "" { + t.Errorf("expected empty apiUrl, got '%s'", cfg.ApiUrl) + } +} + +func TestGetWorkspaceConfigByPath_WithMalformedApiUrl(t *testing.T) { + cfg, err := GetWorkspaceConfigByPath("testdata/infisical-with-malformed-api-url.json") + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if cfg.ApiUrl != "not-a-valid-url" { + t.Errorf("expected apiUrl 'not-a-valid-url', got '%s'", cfg.ApiUrl) + } +} diff --git a/packages/util/testdata/infisical-with-api-url.json b/packages/util/testdata/infisical-with-api-url.json new file mode 100644 index 00000000..3ec1602e --- /dev/null +++ b/packages/util/testdata/infisical-with-api-url.json @@ -0,0 +1,6 @@ +{ + "workspaceId": "test-workspace-id", + "defaultEnvironment": "dev", + "gitBranchToEnvironmentMapping": null, + "apiUrl": "https://custom.infisical.com/api" +} diff --git a/packages/util/testdata/infisical-with-malformed-api-url.json b/packages/util/testdata/infisical-with-malformed-api-url.json new file mode 100644 index 00000000..0ee9fd0e --- /dev/null +++ b/packages/util/testdata/infisical-with-malformed-api-url.json @@ -0,0 +1,6 @@ +{ + "workspaceId": "test-workspace-id", + "defaultEnvironment": "dev", + "gitBranchToEnvironmentMapping": null, + "apiUrl": "not-a-valid-url" +}