Skip to content

feat(meta): warn the user if there are multiple variable sources used #3144

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jun 13, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 55 additions & 0 deletions internal/meta/meta.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
package meta

import (
"bytes"
"context"
"errors"
"fmt"
"net/http"
"os"
"strings"
"text/tabwriter"

"github.com/hashicorp/terraform-plugin-log/tflog"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
Expand All @@ -24,6 +27,7 @@ const (
)

type CredentialsSource struct {
Variables map[string][]string
AccessKey string
SecretKey string
ProjectID string
Expand Down Expand Up @@ -73,6 +77,47 @@ func (m Meta) ZoneSource() string {
return m.credentialsSource.DefaultZone
}

// HasMultipleVariableSources return an informative message during the Provider initialization
// if there are multiple sources of configuration that could confuse the user
//
// Variable AvailableSources Using
// SCW_ACCESS_KEY Active Profile in config.yaml, Environment variable Environment variable
// SCW_SECRET_KEY Active Profile in config.yaml, Environment variable Environment variable
func (m Meta) HasMultipleVariableSources() (bool, string, error) {
multiple := false

variables := []string{scw.ScwAccessKeyEnv, scw.ScwSecretKeyEnv, scw.ScwDefaultProjectIDEnv, scw.ScwDefaultRegionEnv, scw.ScwDefaultZoneEnv}

w := new(tabwriter.Writer)
buf := &bytes.Buffer{}
w.Init(buf, 0, 8, 0, '\t', 0)

_, err := fmt.Fprintln(w, "Variable\tAvailableSources\tUsing")
if err != nil {
return false, "", err
}

for _, variable := range variables {
values, ok := m.credentialsSource.Variables[variable]
if ok {
if len(values) > 1 {
_, err := fmt.Fprintf(w, "%s\t%s\t%s\n", variable, strings.Join(values, ", "), values[len(values)-1])
if err != nil {
return false, "", err
}

multiple = true
}
}
}

if err := w.Flush(); err != nil {
return false, "", err
}

return multiple, buf.String(), nil
}

type Config struct {
ProviderSchema *schema.ResourceData
HTTPClient *http.Client
Expand Down Expand Up @@ -270,29 +315,39 @@ func GetCredentialsSource(defaultZoneProfile, activeProfile, providerProfile, en
},
}
credentialsSource := &CredentialsSource{}
credentialsSource.Variables = map[string][]string{}

for _, pair := range profilesInOrder {
source := pair.Source
profile := pair.Profile

if profile.AccessKey != nil {
credentialsSource.AccessKey = source
credentialsSource.Variables[scw.ScwAccessKeyEnv] = append(credentialsSource.Variables[scw.ScwAccessKeyEnv], source)
}

if profile.SecretKey != nil {
credentialsSource.SecretKey = source
credentialsSource.Variables[scw.ScwSecretKeyEnv] = append(credentialsSource.Variables[scw.ScwSecretKeyEnv], source)
}

if profile.DefaultProjectID != nil {
credentialsSource.ProjectID = source
credentialsSource.Variables[scw.ScwDefaultProjectIDEnv] = append(credentialsSource.Variables[scw.ScwDefaultProjectIDEnv], source)
}

if profile.DefaultRegion != nil {
credentialsSource.DefaultRegion = source
if source != CredentialsSourceDefault {
credentialsSource.Variables[scw.ScwDefaultRegionEnv] = append(credentialsSource.Variables[scw.ScwDefaultRegionEnv], source)
}
}

if profile.DefaultZone != nil {
credentialsSource.DefaultZone = source
if source != CredentialsSourceDefault {
credentialsSource.Variables[scw.ScwDefaultZoneEnv] = append(credentialsSource.Variables[scw.ScwDefaultZoneEnv], source)
}
}
}

Expand Down
49 changes: 49 additions & 0 deletions internal/meta/meta_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package meta_test

import (
"os"
"path"
"testing"

"github.com/scaleway/terraform-provider-scaleway/v2/internal/meta"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestHasMultipleVariableSources(t *testing.T) {
ctx := t.Context()

cfg := &meta.Config{}

scwConfigigFile := `profiles:
test:
access_key: SCWXXXXXXXXXXXXXXXXX
secret_key: 866F4A9A-D058-4D3C-A39F-86930849CCC0
default_project_id: 866F4A9A-D058-4D3C-A39F-86930849CCC0
`

dir := t.TempDir()

err := os.WriteFile(path.Join(dir, "config.yaml"), []byte(scwConfigigFile), 0o644)
require.NoError(t, err)

t.Setenv("SCW_CONFIG_PATH", path.Join(dir, "config.yaml"))
t.Setenv("SCW_PROFILE", "test")
t.Setenv("SCW_ACCESS_KEY", "SCWXXXXXXXXXXXXXXXXX")
t.Setenv("SCW_SECRET_KEY", "866F4A9A-D058-4D3C-A39F-86930849CCC0")
t.Setenv("SCW_DEFAULT_PROJECT_ID", "866F4A9A-D058-4D3C-A39F-86930849CCC0")

m, err := meta.NewMeta(ctx, cfg)
require.NoError(t, err)

ok, message, err := m.HasMultipleVariableSources()
require.NoError(t, err)
assert.True(t, ok)

expectedMessage := `Variable AvailableSources Using
SCW_ACCESS_KEY Active Profile in config.yaml, Environment variable Environment variable
SCW_SECRET_KEY Active Profile in config.yaml, Environment variable Environment variable
SCW_DEFAULT_PROJECT_ID Active Profile in config.yaml, Environment variable Environment variable
`
assert.Equal(t, expectedMessage, message)
}
23 changes: 22 additions & 1 deletion internal/provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -357,7 +357,28 @@ func Provider(config *Config) plugin.ProviderFunc {
return nil, diag.FromErr(err)
}

return m, nil
var diags diag.Diagnostics

ok, message, err := m.HasMultipleVariableSources()
if err != nil {
diags = append(diags, diag.Diagnostic{
Severity: diag.Warning,
Summary: "Error checking multiple variable sources",
Detail: err.Error(),
})

return m, diags
}

if ok && err == nil {
diags = append(diags, diag.Diagnostic{
Severity: diag.Warning,
Summary: "Multiple variable sources detected, please make sure the right credentials are used",
Detail: message,
})
}

return m, diags
}

return p
Expand Down
Loading