Skip to content

Commit f42b842

Browse files
committed
Add support on custom config file path
1 parent ce7ffa4 commit f42b842

7 files changed

Lines changed: 162 additions & 13 deletions

File tree

internal/params/binds.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,4 +74,5 @@ var EnvVarsBinds = []struct {
7474
{ASCAPortKey, ASCAPortEnv, ""},
7575
{ScsRepoTokenKey, ScsRepoTokenEnv, ""},
7676
{RiskManagementPathKey, RiskManagementPathEnv, "api/risk-management/projects/%s/results"},
77+
{ConfigFilePathKey, ConfigFilePathEnv, ""},
7778
}

internal/params/envs.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,4 +73,5 @@ const (
7373
ASCAPortEnv = "CX_ASCA_PORT"
7474
ScsRepoTokenEnv = "SCS_REPO_TOKEN"
7575
RiskManagementPathEnv = "CX_RISK_MANAGEMENT_PATH"
76+
ConfigFilePathEnv = "CX_CONFIG_FILE_PATH"
7677
)

internal/params/keys.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,4 +73,5 @@ var (
7373
ASCAPortKey = strings.ToLower(ASCAPortEnv)
7474
ScsRepoTokenKey = strings.ToLower(ScsRepoTokenEnv)
7575
RiskManagementPathKey = strings.ToLower(RiskManagementPathEnv)
76+
ConfigFilePathKey = strings.ToLower(ConfigFilePathEnv)
7677
)

internal/wrappers/configuration/configuration.go

Lines changed: 55 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -118,17 +118,54 @@ func SetConfigProperty(propName, propValue string) {
118118
}
119119

120120
func LoadConfiguration() {
121-
usr, err := user.Current()
121+
configFilePath := viper.GetString(params.ConfigFilePathKey)
122+
123+
if configFilePath != "" {
124+
err := validateConfigFile(configFilePath)
125+
if err != nil {
126+
fmt.Println("❌", err)
127+
os.Exit(1)
128+
}
129+
viper.SetConfigFile(configFilePath)
130+
if err = viper.ReadInConfig(); err != nil {
131+
fmt.Println("❌ An error occurred while accessing the file or environment variable. Please verify the CLI configuration file")
132+
os.Exit(1)
133+
}
134+
} else {
135+
usr, err := user.Current()
136+
if err != nil {
137+
log.Fatal("Cannot file home directory.", err)
138+
}
139+
fullPath := usr.HomeDir + configDirName
140+
verifyConfigDir(fullPath)
141+
viper.AddConfigPath(fullPath)
142+
configFile := "checkmarxcli"
143+
viper.SetConfigName(configFile)
144+
viper.SetConfigType("yaml")
145+
_ = viper.ReadInConfig()
146+
}
147+
}
148+
149+
func validateConfigFile(configFilePath string) error {
150+
info, err := os.Stat(configFilePath)
151+
if err != nil {
152+
if os.IsNotExist(err) {
153+
return fmt.Errorf("The specified file does not exist. Please check the path and ensure the CLI configuration file is available.")
154+
}
155+
return fmt.Errorf("An error occurred while accessing the file or environment variable. Please verify the CLI configuration file")
156+
}
157+
158+
if info.IsDir() {
159+
return fmt.Errorf("The specified file does not exist. Please check the path and ensure the CLI configuration file is available.")
160+
}
161+
162+
file, err := os.OpenFile(configFilePath, os.O_RDONLY, 0644)
122163
if err != nil {
123-
log.Fatal("Cannot file home directory.", err)
164+
return fmt.Errorf("Access to the specified file is restricted. Please ensure you have the necessary permissions to access the CLI configuration file")
124165
}
125-
fullPath := usr.HomeDir + configDirName
126-
verifyConfigDir(fullPath)
127-
viper.AddConfigPath(fullPath)
128-
configFile := "checkmarxcli"
129-
viper.SetConfigName(configFile)
130-
viper.SetConfigType("yaml")
131-
_ = viper.ReadInConfig()
166+
defer file.Close()
167+
168+
return nil
132169
}
133170

134171
func SafeWriteSingleConfigKey(configFilePath, key string, value int) error {
@@ -231,11 +268,16 @@ func SaveConfig(path string, config map[string]interface{}) error {
231268
}
232269

233270
func GetConfigFilePath() (string, error) {
234-
usr, err := user.Current()
235-
if err != nil {
236-
return "", fmt.Errorf("error getting current user: %w", err)
271+
configFilePath := viper.GetString(params.ConfigFilePathKey)
272+
273+
if configFilePath == "" {
274+
usr, err := user.Current()
275+
if err != nil {
276+
return "", fmt.Errorf("error getting current user: %w", err)
277+
}
278+
configFilePath = usr.HomeDir + configDirName + "/checkmarxcli.yaml"
237279
}
238-
return usr.HomeDir + configDirName + "/checkmarxcli.yaml", nil
280+
return configFilePath, nil
239281
}
240282

241283
func verifyConfigDir(fullPath string) {
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
//go:build integration
2+
3+
package integration
4+
5+
import (
6+
"gotest.tools/assert"
7+
"os"
8+
"strings"
9+
"testing"
10+
)
11+
12+
var filePath = "data/config.yaml"
13+
14+
func TestIntegration_LoadConfiguration_EnvVarConfigFilePath(t *testing.T) {
15+
os.Setenv("CX_CONFIG_FILE_PATH", filePath)
16+
defer os.Unsetenv("CX_CONFIG_FILE_PATH")
17+
18+
cmd, buffer := createRedirectedTestCommand(t)
19+
20+
err := execute(cmd, "configure", "show")
21+
assert.NilError(t, err)
22+
23+
output := buffer.String()
24+
if !strings.Contains(output, "cx_base_uri: https://example.com") {
25+
t.Errorf("expected output to contain 'cx_base_uri: https://example.com', but it did not")
26+
}
27+
}
28+
29+
func TestIntegration_LoadConfiguration_FileNotFound(t *testing.T) {
30+
// Set an invalid file path
31+
os.Setenv("CX_CONFIG_FILE_PATH", "data/nonexistent_config.yaml")
32+
defer os.Unsetenv("CX_CONFIG_FILE_PATH")
33+
34+
cmd, buffer := createRedirectedTestCommand(t)
35+
36+
// Execute the command
37+
err := execute(cmd, "configure", "show")
38+
39+
// Verify that an error occurred
40+
assert.ErrorContains(t, err, "The specified file does not exist")
41+
42+
// Verify the output contains the expected error message
43+
output := buffer.String()
44+
if !strings.Contains(output, "The specified file does not exist") {
45+
t.Errorf("expected output to contain 'The specified file does not exist', but it did not")
46+
}
47+
}
48+
49+
func TestIntegration_LoadConfiguration_FileWithoutPermission_UsingConfigFile(t *testing.T) {
50+
51+
// Set the file to have no permissions
52+
if err := os.Chmod(filePath, 0000); err != nil {
53+
t.Fatalf("failed to set file permissions: %v", err)
54+
}
55+
defer os.Chmod(filePath, 0644) // Restore permissions for cleanup
56+
57+
// Set the environment variable to point to the restricted file
58+
os.Setenv("CX_CONFIG_FILE_PATH", filePath)
59+
defer os.Unsetenv("CX_CONFIG_FILE_PATH")
60+
61+
cmd, buffer := createRedirectedTestCommand(t)
62+
63+
// Execute the command
64+
err := execute(cmd, "configure", "show")
65+
66+
// Verify that an error occurred
67+
assert.ErrorContains(t, err, "Access to the specified file is restricted")
68+
69+
// Verify the output contains the expected error message
70+
output := buffer.String()
71+
if !strings.Contains(output, "Access to the specified file is restricted") {
72+
t.Errorf("expected output to contain 'Access to the specified file is restricted', but it did not")
73+
}
74+
}
75+
76+
//
77+
//func TestIntegration_SetConfigProperty_EnvVarConfigFilePath(t *testing.T) {
78+
// // Set environment variable
79+
// os.Setenv("CX_CONFIG_FILE_PATH", filePath)
80+
// defer os.Unsetenv("CX_CONFIG_FILE_PATH")
81+
//
82+
// // Create command
83+
// cmd, buffer := createRedirectedTestCommand(t)
84+
//
85+
// // Execute command
86+
// err := execute(cmd, "configure", "set", "--prop-name", "new_key", "--prop-value", "new_value")
87+
// assert.NilError(t, err)
88+
//
89+
// // Verify output
90+
// output := buffer.String()
91+
// asserts.Contains(t, output, "Setting property [new_key] to value [new_value]")
92+
//
93+
// // Verify configuration
94+
// asserts.Equal(t, viper.GetString("new_key"), "new_value")
95+
//}

test/integration/data/config.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
cx_base_uri: https://example.com
2+
cx_base_auth_uri: https://auth.example.com
3+
cx_tenant: example_tenant
4+
cx_api_key: example_api_key
5+
cx_client_id: example_client_id
6+
cx_client_secret: example_client_secret
7+
cx_proxy: http://proxy.example.com

test/integration/util_command.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"github.com/checkmarx/ast-cli/internal/commands"
1515
"github.com/checkmarx/ast-cli/internal/params"
1616
"github.com/checkmarx/ast-cli/internal/wrappers"
17+
"github.com/checkmarx/ast-cli/internal/wrappers/configuration"
1718
"github.com/spf13/cobra"
1819
"github.com/spf13/viper"
1920
"gotest.tools/assert"
@@ -56,6 +57,7 @@ func bindProxy(t *testing.T) {
5657
func createASTIntegrationTestCommand(t *testing.T) *cobra.Command {
5758
bindProxy(t)
5859
bindKeysToEnvAndDefault(t)
60+
configuration.LoadConfiguration()
5961
_ = viper.BindEnv(pat)
6062
viper.AutomaticEnv()
6163
viper.Set("CX_TOKEN_EXPIRY_SECONDS", 2)

0 commit comments

Comments
 (0)