Skip to content

Commit e223f72

Browse files
authored
fix: config describe prints secure properties with value redacted (#4195)
1 parent 25f551b commit e223f72

File tree

5 files changed

+117
-7
lines changed

5 files changed

+117
-7
lines changed

build/package/purls.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ pkg:golang/github.com/mholt/archives@v0.1.3
7575
pkg:golang/github.com/mikelolasagasti/xz@v1.0.1
7676
pkg:golang/github.com/minio/minlz@v1.0.0
7777
pkg:golang/github.com/mongodb-forks/digest@v1.1.0
78-
pkg:golang/github.com/mongodb/atlas-cli-core@v0.0.0-20250904105537-cdeae83f46e0
78+
pkg:golang/github.com/mongodb/atlas-cli-core@v0.0.0-20250909113945-ffb322e05f59
7979
pkg:golang/github.com/montanaflynn/stats@v0.7.1
8080
pkg:golang/github.com/nwaples/rardecode/v2@v2.1.0
8181
pkg:golang/github.com/pelletier/go-toml/v2@v2.2.3

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ require (
2929
github.com/mattn/go-isatty v0.0.20
3030
github.com/mholt/archives v0.1.3
3131
github.com/mongodb-labs/cobra2snooty v1.19.1
32-
github.com/mongodb/atlas-cli-core v0.0.0-20250904105537-cdeae83f46e0
32+
github.com/mongodb/atlas-cli-core v0.0.0-20250909113945-ffb322e05f59
3333
github.com/pelletier/go-toml v1.9.5
3434
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c
3535
github.com/shirou/gopsutil/v4 v4.25.8

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -320,8 +320,8 @@ github.com/mongodb-forks/digest v1.1.0 h1:7eUdsR1BtqLv0mdNm4OXs6ddWvR4X2/OsLwdKk
320320
github.com/mongodb-forks/digest v1.1.0/go.mod h1:rb+EX8zotClD5Dj4NdgxnJXG9nwrlx3NWKJ8xttz1Dg=
321321
github.com/mongodb-labs/cobra2snooty v1.19.1 h1:GDEQZWy8f/DeJlImNgVvStu6sgNi8nuSOR1Oskcw8BI=
322322
github.com/mongodb-labs/cobra2snooty v1.19.1/go.mod h1:Hyq4YadN8dwdOiz56MXwTuVN63p0WlkQwxdLxOSGdX8=
323-
github.com/mongodb/atlas-cli-core v0.0.0-20250904105537-cdeae83f46e0 h1:1g0tih3u0OGiMVmo4R5iBkduFtrNJMZUJD6MwEyWtr4=
324-
github.com/mongodb/atlas-cli-core v0.0.0-20250904105537-cdeae83f46e0/go.mod h1:QDfVGpdfxXM1httLNXCKsfWTKv6slzCqBZxkkPIktlQ=
323+
github.com/mongodb/atlas-cli-core v0.0.0-20250909113945-ffb322e05f59 h1:uIxkUglkDOtrvfzyNsV/FHwGC717mAI0S4/jzFOBvsM=
324+
github.com/mongodb/atlas-cli-core v0.0.0-20250909113945-ffb322e05f59/go.mod h1:QDfVGpdfxXM1httLNXCKsfWTKv6slzCqBZxkkPIktlQ=
325325
github.com/montanaflynn/stats v0.7.1 h1:etflOAAHORrCC44V+aR6Ftzort912ZU+YLiSTuV8eaE=
326326
github.com/montanaflynn/stats v0.7.1/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow=
327327
github.com/nwaples/rardecode/v2 v2.1.0 h1:JQl9ZoBPDy+nIZGb1mx8+anfHp/LV3NE2MjMiv0ct/U=

internal/cli/config/describe.go

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ package config
1616

1717
import (
1818
"fmt"
19+
"slices"
1920

2021
"github.com/mongodb/atlas-cli-core/config"
2122
"github.com/mongodb/mongodb-atlas-cli/atlascli/internal/cli"
@@ -32,16 +33,49 @@ var descTemplate = `SETTING VALUE{{ range $key, $value := . }}
3233
{{$key}} {{$value}}{{end}}
3334
`
3435

36+
const (
37+
redactedSecureText = "[redacted - source: secure storage]"
38+
redactedConfigText = "[redacted - source: config file]"
39+
servicePrefix = "atlascli_"
40+
)
41+
42+
func (*describeOpts) GetConfig(configStore config.Store, profileName string) (map[string]string, error) {
43+
// Get the profile map, this only contains properties coming from the insecure store
44+
profileMap := configStore.GetProfileStringMap(profileName)
45+
46+
redactedText := redactedConfigText
47+
if configStore.IsSecure() {
48+
redactedText = redactedSecureText
49+
}
50+
51+
// Redact values
52+
for _, key := range config.SecureProperties {
53+
if v := configStore.GetProfileValue(profileName, key); v != nil && v != "" {
54+
profileMap[key] = redactedText
55+
}
56+
}
57+
58+
return profileMap, nil
59+
}
60+
3561
func (opts *describeOpts) Run() error {
36-
if !config.Exists(opts.name) {
62+
// Create a new config proxy store
63+
configStore, err := config.NewStoreWithEnvOption(false)
64+
if err != nil {
65+
return fmt.Errorf("could not create config store: %w", err)
66+
}
67+
68+
profileNames := configStore.GetProfileNames()
69+
if !slices.Contains(profileNames, opts.name) {
3770
return fmt.Errorf("you don't have a profile named '%s'", opts.name)
3871
}
3972

40-
if err := config.SetName(opts.name); err != nil {
73+
mapConfig, err := opts.GetConfig(configStore, opts.name)
74+
if err != nil {
4175
return err
4276
}
4377

44-
return opts.Print(config.Map())
78+
return opts.Print(mapConfig)
4579
}
4680

4781
func DescribeBuilder() *cobra.Command {
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
// Copyright 2025 MongoDB Inc
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package config
16+
17+
import (
18+
"testing"
19+
20+
"github.com/mongodb/atlas-cli-core/mocks"
21+
"github.com/stretchr/testify/assert"
22+
"github.com/stretchr/testify/require"
23+
"go.uber.org/mock/gomock"
24+
)
25+
26+
func TestGetConfig(t *testing.T) {
27+
tests := []struct {
28+
name string
29+
isSecure bool
30+
}{
31+
{
32+
name: "secure store redaction",
33+
isSecure: true,
34+
},
35+
{
36+
name: "config file redaction",
37+
isSecure: false,
38+
},
39+
}
40+
41+
for _, tt := range tests {
42+
t.Run(tt.name, func(t *testing.T) {
43+
ctrl := gomock.NewController(t)
44+
defer ctrl.Finish()
45+
46+
profileName := "test"
47+
mockStore := mocks.NewMockStore(ctrl)
48+
49+
// Set up mock expectations
50+
mockStore.EXPECT().GetProfileStringMap(profileName).Return(map[string]string{
51+
"project_id": "proj123",
52+
"public_api_key": "public-key",
53+
}).Times(1)
54+
mockStore.EXPECT().GetProfileValue(profileName, "public_api_key").Return("pub-key").Times(1)
55+
mockStore.EXPECT().GetProfileValue(profileName, "private_api_key").Return("priv-key").Times(1)
56+
mockStore.EXPECT().GetProfileValue(profileName, "access_token").Return("").Times(1)
57+
mockStore.EXPECT().GetProfileValue(profileName, "refresh_token").Return("").Times(1)
58+
mockStore.EXPECT().GetProfileValue(profileName, "client_id").Return("").Times(1)
59+
mockStore.EXPECT().GetProfileValue(profileName, "client_secret").Return("").Times(1)
60+
61+
mockStore.EXPECT().IsSecure().Return(tt.isSecure).Times(1)
62+
63+
opts := &describeOpts{}
64+
result, err := opts.GetConfig(mockStore, profileName)
65+
require.NoError(t, err)
66+
assert.Equal(t, "proj123", result["project_id"])
67+
if tt.isSecure {
68+
assert.Contains(t, result["public_api_key"], redactedSecureText)
69+
assert.Contains(t, result["private_api_key"], redactedSecureText)
70+
} else {
71+
assert.Contains(t, result["public_api_key"], redactedConfigText)
72+
assert.Contains(t, result["private_api_key"], redactedConfigText)
73+
}
74+
})
75+
}
76+
}

0 commit comments

Comments
 (0)