Skip to content

Commit 310146b

Browse files
committed
refactor(config): centralize silent credential clear for logout and MCP
- Rename ClearMCPProfileCredentials to ClearActiveProfileCredentials; document disk vs memory paths - Logout uses the same helper as MCP reauth; zeroProfileCredentialFields helper - RemoveAllProfiles clears in-memory credential fields after wiping the file (parity with logout -a) - Rename config test to match new API Made-with: Cursor
1 parent 209d297 commit 310146b

4 files changed

Lines changed: 34 additions & 19 deletions

File tree

pkg/config/clear_mcp_credentials_test.go renamed to pkg/config/clear_active_profile_credentials_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,13 @@ import (
77
"github.com/stretchr/testify/require"
88
)
99

10-
func TestClearMCPProfileCredentials_MemoryOnly(t *testing.T) {
10+
func TestClearActiveProfileCredentials_MemoryOnly(t *testing.T) {
1111
c := &Config{}
1212
c.Profile.APIKey = "sk_test_123456789012"
1313
c.Profile.ProjectId = "proj_1"
1414
c.Profile.ProjectMode = "inbound"
1515
c.Profile.ProjectType = ProjectTypeGateway
16-
require.NoError(t, c.ClearMCPProfileCredentials())
16+
require.NoError(t, c.ClearActiveProfileCredentials())
1717
assert.Empty(t, c.Profile.APIKey)
1818
assert.Empty(t, c.Profile.ProjectId)
1919
}

pkg/config/config.go

Lines changed: 30 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -293,7 +293,13 @@ func (c *Config) RemoveAllProfiles() error {
293293
runtimeViper.SetConfigType("toml")
294294
runtimeViper.SetConfigFile(c.viper.ConfigFileUsed())
295295
c.viper = runtimeViper
296-
return c.writeConfig()
296+
if err := c.writeConfig(); err != nil {
297+
return err
298+
}
299+
// Match single-profile logout: clear credential fields in memory so a long-lived
300+
// process does not keep using stale keys after the file was wiped.
301+
zeroProfileCredentialFields(&c.Profile)
302+
return nil
297303
}
298304

299305
func (c *Config) writeConfig() error {
@@ -359,32 +365,41 @@ func (c *Config) SetTelemetryDisabled(disabled bool) error {
359365
return c.writeConfig()
360366
}
361367

362-
// ClearMCPProfileCredentials clears the active profile API key and project fields for an MCP
363-
// reauth flow. When viper is initialized (normal CLI config), the profile block is removed
364-
// from disk; otherwise only in-memory fields are cleared (e.g. tests).
365-
func (c *Config) ClearMCPProfileCredentials() error {
368+
// ClearActiveProfileCredentials removes stored credentials for the active profile without
369+
// printing.
370+
//
371+
// Two paths:
372+
// - Persisted config (viper set): removes the active profile section from the config file
373+
// (same as RemoveProfile) and clears api_key / project_* / guest_url on the in-memory
374+
// Profile. This is what the real CLI and MCP server use after InitConfig.
375+
// - No viper (e.g. some tests): only clears those Profile fields in memory; nothing is
376+
// written to disk.
377+
//
378+
// MCP reauth uses the persisted path in production. The shared *hookdeck.Client is also
379+
// cleared separately in the MCP handler so API calls stop using the old key immediately.
380+
func (c *Config) ClearActiveProfileCredentials() error {
366381
if c == nil || c.Profile.APIKey == "" {
367382
return nil
368383
}
369384
if c.viper == nil {
370-
c.Profile.APIKey = ""
371-
c.Profile.ProjectId = ""
372-
c.Profile.ProjectMode = ""
373-
c.Profile.ProjectType = ""
374-
c.Profile.GuestURL = ""
385+
zeroProfileCredentialFields(&c.Profile)
375386
return nil
376387
}
377388
if err := c.Profile.RemoveProfile(); err != nil {
378389
return err
379390
}
380-
c.Profile.APIKey = ""
381-
c.Profile.ProjectId = ""
382-
c.Profile.ProjectMode = ""
383-
c.Profile.ProjectType = ""
384-
c.Profile.GuestURL = ""
391+
zeroProfileCredentialFields(&c.Profile)
385392
return nil
386393
}
387394

395+
func zeroProfileCredentialFields(p *Profile) {
396+
p.APIKey = ""
397+
p.ProjectId = ""
398+
p.ProjectMode = ""
399+
p.ProjectType = ""
400+
p.GuestURL = ""
401+
}
402+
388403
// getConfigPath returns the path for the config file.
389404
// Precedence:
390405
// - path (if path is provided, e.g. from --hookdeck-config flag)

pkg/gateway/mcp/tool_login.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ func handleLogin(client *hookdeck.Client, cfg *config.Config) mcpsdk.ToolHandler
5858
), nil
5959
}
6060
}
61-
if err := cfg.ClearMCPProfileCredentials(); err != nil {
61+
if err := cfg.ClearActiveProfileCredentials(); err != nil {
6262
return ErrorResult(fmt.Sprintf("reauth: could not clear stored credentials: %v", err)), nil
6363
}
6464
client.APIKey = ""

pkg/logout/logout.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ func Logout(config *config.Config) error {
1818
fmt.Println("Logging out...")
1919

2020
profileName := config.Profile.Name
21-
if err := config.Profile.RemoveProfile(); err != nil {
21+
if err := config.ClearActiveProfileCredentials(); err != nil {
2222
return err
2323
}
2424

0 commit comments

Comments
 (0)