Skip to content

Commit de51eae

Browse files
appleboyclaude
andcommitted
fix(credentials): address PR review comments
- Guard migration with viper.InConfig() to avoid persisting env vars - Handle os.UserHomeDir() error with TempDir fallback - Create fallback credential directory before constructing file store - Use viper.InConfig() in config list to detect YAML-stored keys - Surface GetCredential errors in config list instead of silent failure - Use filepath.Join in tests for cross-platform path safety Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
1 parent 69a40de commit de51eae

4 files changed

Lines changed: 29 additions & 8 deletions

File tree

cmd/cmd.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,12 @@ var sensitiveConfigKeys = []string{"openai.api_key", "gemini.api_key"}
4141
// config into the secure credential store and clears them from the config file.
4242
func migrateCredentialsToStore() {
4343
for _, key := range sensitiveConfigKeys {
44+
// Only migrate values that actually exist in the config file.
45+
// This prevents env vars (e.g. OPENAI_API_KEY) from being silently
46+
// persisted into the credential store.
47+
if !viper.InConfig(key) {
48+
continue
49+
}
4450
val := viper.GetString(key)
4551
if val == "" {
4652
continue

cmd/config_list.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,15 +77,19 @@ var configListCmd = &cobra.Command{
7777
// Add the key and value to the table
7878
for _, v := range keys {
7979
if slices.Contains(sensitiveConfigKeys, v) {
80-
cred, _ := util.GetCredential(v)
80+
cred, err := util.GetCredential(v)
81+
if err != nil {
82+
tbl.AddRow(v, "(error reading secure store)")
83+
continue
84+
}
8185
switch {
8286
case cred != "":
8387
if util.CredStoreIsKeyring() {
8488
tbl.AddRow(v, "(stored in keyring)")
8589
} else {
8690
tbl.AddRow(v, "(stored in secure file)")
8791
}
88-
case viper.GetString(v) != "":
92+
case viper.InConfig(v):
8993
tbl.AddRow(v, "**************** (YAML — run config set to migrate)")
9094
default:
9195
tbl.AddRow(v, "(not set)")

util/credstore.go

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,18 @@ const credServiceName = "codegpt"
1414
var credStore *credstore.SecureStore[string]
1515

1616
func init() {
17-
home, _ := os.UserHomeDir()
18-
fallbackPath := filepath.Join(home, ".config", "codegpt", ".cache", "credentials.json")
17+
home, err := os.UserHomeDir()
18+
var fallbackPath string
19+
if err != nil || home == "" {
20+
fallbackPath = filepath.Join(os.TempDir(), "codegpt", "credentials.json")
21+
} else {
22+
fallbackPath = filepath.Join(home, ".config", "codegpt", ".cache", "credentials.json")
23+
}
24+
25+
// Ensure the directory for the fallback credential file exists.
26+
dir := filepath.Dir(fallbackPath)
27+
_ = os.MkdirAll(dir, 0o700)
28+
1929
keyring := credstore.NewStringKeyringStore(credServiceName)
2030
file := credstore.NewStringFileStore(fallbackPath)
2131
credStore = credstore.NewSecureStore(keyring, file)

util/credstore_test.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package util
22

33
import (
4+
"path/filepath"
45
"testing"
56

67
"github.com/go-authgate/sdk-go/credstore"
@@ -10,7 +11,7 @@ import (
1011
// This avoids touching the OS keyring in CI/CD environments.
1112
func newTestCredStore(t *testing.T) *credstore.SecureStore[string] {
1213
t.Helper()
13-
path := t.TempDir() + "/creds.json"
14+
path := filepath.Join(t.TempDir(), "creds.json")
1415
file := credstore.NewStringFileStore(path)
1516
// Pass file as both primary and fallback so NewSecureStore always picks file.
1617
return credstore.NewSecureStore[string](file, file)
@@ -63,7 +64,7 @@ func TestGetCredential_Missing(t *testing.T) {
6364
original := credStore
6465
defer func() { credStore = original }()
6566

66-
path := t.TempDir() + "/creds.json"
67+
path := filepath.Join(t.TempDir(), "creds.json")
6768
file := credstore.NewStringFileStore(path)
6869
credStore = credstore.NewSecureStore[string](file, file)
6970

@@ -81,7 +82,7 @@ func TestSetAndGetCredential(t *testing.T) {
8182
original := credStore
8283
defer func() { credStore = original }()
8384

84-
path := t.TempDir() + "/creds.json"
85+
path := filepath.Join(t.TempDir(), "creds.json")
8586
file := credstore.NewStringFileStore(path)
8687
credStore = credstore.NewSecureStore[string](file, file)
8788

@@ -103,7 +104,7 @@ func TestDeleteCredential(t *testing.T) {
103104
original := credStore
104105
defer func() { credStore = original }()
105106

106-
path := t.TempDir() + "/creds.json"
107+
path := filepath.Join(t.TempDir(), "creds.json")
107108
file := credstore.NewStringFileStore(path)
108109
credStore = credstore.NewSecureStore[string](file, file)
109110

0 commit comments

Comments
 (0)