Skip to content

Commit 0a77812

Browse files
author
Mélanie Marques
committed
feat: add warning message if multiple variable sources
1 parent 3a1f808 commit 0a77812

File tree

4 files changed

+142
-1
lines changed

4 files changed

+142
-1
lines changed

core/bootstrap.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,12 @@ func Bootstrap(config *BootstrapConfig) (exitCode int, result any, err error) {
236236
// Run checks after command has been executed
237237
defer func() { // if we plan to remove defer, do not forget logger is not set until cobra pre init func
238238
// Check CLI new version and api key expiration date
239-
runAfterCommandChecks(ctx, config.BuildInfo.checkVersion, checkAPIKey)
239+
runAfterCommandChecks(
240+
ctx,
241+
config.BuildInfo.checkVersion,
242+
checkAPIKey,
243+
checkIfMultipleVariableSources,
244+
)
240245
}()
241246

242247
if !config.DisableAliases {

core/checks.go

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,27 @@
11
package core
22

33
import (
4+
"bytes"
45
"context"
56
"fmt"
67
"os"
78
"path/filepath"
9+
"reflect"
810
"time"
911

1012
iam "github.com/scaleway/scaleway-sdk-go/api/iam/v1alpha1"
13+
"github.com/scaleway/scaleway-sdk-go/scw"
1114
)
1215

1316
var (
1417
apiKeyExpireTime = 24 * time.Hour
1518
lastChecksFileLocalName = "last-cli-checks"
1619
)
1720

21+
const (
22+
defaultCredentialSource = "environment variable"
23+
)
24+
1825
type AfterCommandCheckFunc func(ctx context.Context)
1926

2027
// wasFileModifiedLast24h checks whether the file has been updated during last 24 hours.
@@ -105,3 +112,43 @@ func checkAPIKey(ctx context.Context) {
105112
ExtractLogger(ctx).Warningf("Current api key expires in %s\n", expiresIn)
106113
}
107114
}
115+
116+
// checkIfMultipleVariableSources return an informative message during the CLI initialization
117+
// if there are multiple sources of configuration that could confuse the user
118+
func checkIfMultipleVariableSources(ctx context.Context) {
119+
config, err := scw.LoadConfigFromPath(ExtractConfigPath(ctx))
120+
if err != nil {
121+
return
122+
}
123+
124+
activeProfile, err := config.GetActiveProfile()
125+
if err != nil {
126+
return
127+
}
128+
129+
profileEnv := scw.LoadEnvProfile()
130+
131+
vFile := reflect.ValueOf(activeProfile).Elem()
132+
vEnv := reflect.ValueOf(profileEnv).Elem()
133+
t := vFile.Type()
134+
135+
var buffer bytes.Buffer
136+
buffer.WriteString("Checking multiple variable sources: \n")
137+
138+
for i := range t.NumField() {
139+
valFile := vFile.Field(i)
140+
valEnv := vEnv.Field(i)
141+
142+
if !valFile.IsNil() && !valEnv.IsNil() {
143+
if valFile.Elem().String() != valEnv.Elem().String() {
144+
buffer.WriteString(fmt.Sprintf(
145+
"- Variable '%s' is defined in both config.yaml and environment with different values. Using: %s.\n",
146+
t.Field(i).Name,
147+
defaultCredentialSource,
148+
))
149+
}
150+
}
151+
}
152+
153+
ExtractLogger(ctx).Warning(buffer.String())
154+
}

core/checks_test.go

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,3 +86,57 @@ func TestCheckAPIKey(t *testing.T) {
8686
},
8787
}))
8888
}
89+
90+
func TestCheckIfMultipleVariableSources(t *testing.T) {
91+
testCommands := core.NewCommands(
92+
&core.Command{
93+
Namespace: "test",
94+
ArgSpecs: core.ArgSpecs{},
95+
ArgsType: reflect.TypeOf(testType{}),
96+
Run: func(ctx context.Context, _ any) (any, error) { return "", nil },
97+
},
98+
)
99+
100+
t.Run("conflicting sources should trigger warning", core.Test(&core.TestConfig{
101+
Commands: testCommands,
102+
TmpHomeDir: true,
103+
BeforeFunc: func(ctx *core.BeforeFuncCtx) error {
104+
cfg := &scw.Config{
105+
Profile: scw.Profile{
106+
AccessKey: scw.StringPtr("SCW11111111111111111"),
107+
SecretKey: scw.StringPtr("config-secret"),
108+
DefaultProjectID: scw.StringPtr("config-project-id"),
109+
},
110+
}
111+
112+
configPath := filepath.Join(ctx.OverrideEnv["HOME"], ".config", "scw", "config.yaml")
113+
if err := cfg.SaveTo(configPath); err != nil {
114+
return err
115+
}
116+
117+
t.Setenv("SCW_ACCESS_KEY", "SCW99999999999999999")
118+
t.Setenv("SCW_SECRET_KEY", "env-secret")
119+
t.Setenv("SCW_DEFAULT_PROJECT_ID", "config-project-id")
120+
121+
return nil
122+
},
123+
Cmd: "scw test",
124+
Check: core.TestCheckCombine(
125+
core.TestCheckExitCode(0),
126+
func(t *testing.T, ctx *core.CheckFuncCtx) {
127+
t.Helper()
128+
assert.Contains(t, ctx.LogBuffer, "Checking multiple variable sources")
129+
assert.Contains(
130+
t,
131+
ctx.LogBuffer,
132+
"Variable 'AccessKey' is defined in both config.yaml and environment with different values. Using: environment variable.",
133+
)
134+
assert.Contains(
135+
t,
136+
ctx.LogBuffer,
137+
"Variable 'SecretKey' is defined in both config.yaml and environment with different values. Using: environment variable.",
138+
)
139+
},
140+
),
141+
}))
142+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
---
2+
version: 1
3+
interactions:
4+
- request:
5+
body: '{"message":"authentication is denied","method":"api_key","reason":"not_found","type":"denied_authentication"}'
6+
form: {}
7+
headers:
8+
User-Agent:
9+
- scaleway-sdk-go/v1.0.0-beta.7+dev (go1.24.4; darwin; arm64) cli-e2e-test
10+
url: https://api.scaleway.com/iam/v1alpha1/api-keys/SCWXXXXXXXXXXXXXXXXX
11+
method: GET
12+
response:
13+
body: '{"message":"authentication is denied","method":"api_key","reason":"not_found","type":"denied_authentication"}'
14+
headers:
15+
Content-Length:
16+
- "109"
17+
Content-Security-Policy:
18+
- default-src 'none'; frame-ancestors 'none'
19+
Content-Type:
20+
- application/json
21+
Date:
22+
- Tue, 22 Jul 2025 12:16:22 GMT
23+
Server:
24+
- Scaleway API Gateway (fr-par-1;edge01)
25+
Strict-Transport-Security:
26+
- max-age=63072000
27+
X-Content-Type-Options:
28+
- nosniff
29+
X-Frame-Options:
30+
- DENY
31+
X-Request-Id:
32+
- d55dda1c-064c-4670-95ff-50d7c32fe521
33+
status: 401 Unauthorized
34+
code: 401
35+
duration: ""

0 commit comments

Comments
 (0)