Skip to content

Commit c8f79d5

Browse files
Merge pull request #130 from langchain-ai/ramonn/warn-profile-env-api-key
fix: warn when env API key overrides profile
2 parents 4bcef40 + 0aee5c7 commit c8f79d5

3 files changed

Lines changed: 46 additions & 0 deletions

File tree

internal/cmd/root.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,9 @@ func resolveClientOptions(refreshOAuth bool) (client.Options, error) {
169169
case flagAPIKey != "":
170170
opts.APIKey = flagAPIKey
171171
case os.Getenv("LANGSMITH_API_KEY") != "":
172+
if flagProfile != "" {
173+
fmt.Fprintln(os.Stderr, "warning: --profile was specified, but LANGSMITH_API_KEY is set and takes precedence over saved profile auth")
174+
}
172175
opts.APIKey = os.Getenv("LANGSMITH_API_KEY")
173176
case hasProfile && (profile.AccessToken() != "" || (refreshOAuth && profile.OAuth.RefreshToken != "")):
174177
if refreshOAuth && profile.OAuth.RefreshToken != "" &&

internal/cmdutil/resolve.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,16 @@ func getFlagString(cmd *cobra.Command, name string) string {
5050
return ""
5151
}
5252

53+
func isFlagChanged(cmd *cobra.Command, name string) bool {
54+
if f := cmd.Flags().Lookup(name); f != nil {
55+
return f.Changed
56+
}
57+
if f := cmd.PersistentFlags().Lookup(name); f != nil {
58+
return f.Changed
59+
}
60+
return false
61+
}
62+
5363
// ResolveAPIKey reads the API key from cobra's flag tree → env.
5464
func ResolveAPIKey(cmd *cobra.Command) string {
5565
if v := getFlagString(cmd, "api-key"); v != "" {
@@ -147,6 +157,9 @@ func ResolveClientOptions(cmd *cobra.Command, refreshOAuth bool) (client.Options
147157
case getFlagString(cmd, "api-key") != "":
148158
opts.APIKey = getFlagString(cmd, "api-key")
149159
case os.Getenv("LANGSMITH_API_KEY") != "":
160+
if isFlagChanged(cmd, "profile") {
161+
fmt.Fprintln(cmd.ErrOrStderr(), "warning: --profile was specified, but LANGSMITH_API_KEY is set and takes precedence over saved profile auth")
162+
}
150163
opts.APIKey = os.Getenv("LANGSMITH_API_KEY")
151164
case hasProfile && (profile.AccessToken() != "" || (refreshOAuth && profile.OAuth.RefreshToken != "")):
152165
if refreshOAuth && profile.OAuth.RefreshToken != "" &&

internal/cmdutil/resolve_test.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package cmdutil
22

33
import (
4+
"bytes"
45
"encoding/json"
56
"net/http"
67
"net/http/httptest"
@@ -235,6 +236,35 @@ func TestResolveClientOptions_EnvAPIKeyOverridesProfileBearer(t *testing.T) {
235236
}
236237
}
237238

239+
func TestResolveClientOptions_ProfileFlagWarnsWhenEnvAPIKeyOverrides(t *testing.T) {
240+
path := filepath.Join(t.TempDir(), "config.json")
241+
t.Setenv("LANGSMITH_CONFIG_FILE", path)
242+
t.Setenv("LANGSMITH_API_KEY", "from-env")
243+
err := os.WriteFile(path, []byte(`{
244+
"profiles": {
245+
"prod": {
246+
"oauth": {
247+
"access_token": "test-access-token"
248+
}
249+
}
250+
}
251+
}
252+
`), 0600)
253+
require.NoError(t, err)
254+
255+
cmd := newTestCmd()
256+
var stderr bytes.Buffer
257+
cmd.SetErr(&stderr)
258+
err = cmd.PersistentFlags().Set("profile", "prod")
259+
require.NoError(t, err)
260+
261+
opts, err := ResolveClientOptions(cmd, false)
262+
require.NoError(t, err)
263+
require.Equal(t, "from-env", opts.APIKey)
264+
require.Empty(t, opts.OAuthAccessToken)
265+
require.Contains(t, stderr.String(), "warning: --profile was specified, but LANGSMITH_API_KEY is set")
266+
}
267+
238268
func TestResolveClientOptionsRefreshesProfileWithoutAccessToken(t *testing.T) {
239269
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
240270
if r.URL.Path != "/oauth/token" {

0 commit comments

Comments
 (0)