Skip to content

Commit 3ded94f

Browse files
committed
fix(sdk/go): fall back to system active gateway
Match the CLI: use the system active_gateway when the user one is missing or invalid. Signed-off-by: Eric Curtin <[email protected]>
1 parent c4688aa commit 3ded94f

4 files changed

Lines changed: 86 additions & 8 deletions

File tree

‎sdk/go/openshell/v1/gateway/gateway.go‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import (
1313

1414
// NewClient creates a fully wired SDK client from an on-disk gateway
1515
// configuration. If name is empty, the active gateway (set via
16-
// `openshell gateway use`) is used.
16+
// `openshell gateway use`, or the system default) is used.
1717
//
1818
// The function resolves the gateway directory, parses metadata.json,
1919
// loads tokens lazily, maps the auth mode to an SDK auth provider, and
@@ -66,8 +66,8 @@ func NewClient(name string, opts ...ClientOption) (*v1.Client, error) {
6666
}
6767

6868
// LoadConfig reads and parses a gateway's on-disk configuration without
69-
// creating a client connection. If name is empty, the active gateway is
70-
// used.
69+
// creating a client connection. If name is empty, the active gateway (user
70+
// selection, then system default) is used.
7171
//
7272
// The returned [Config] is an immutable snapshot; changes to the on-disk
7373
// files after this call are not reflected.

‎sdk/go/openshell/v1/gateway/gateway_test.go‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -387,13 +387,29 @@ func TestNewClient_ActiveGateway(t *testing.T) {
387387
func TestNewClient_NoActiveGateway(t *testing.T) {
388388
tmp := t.TempDir()
389389
t.Setenv("XDG_CONFIG_HOME", tmp)
390+
t.Setenv(systemGatewayDirEnv, t.TempDir())
390391
require.NoError(t, os.MkdirAll(filepath.Join(tmp, "openshell"), 0o755))
391392

392393
_, err := NewClient("")
393394
require.Error(t, err)
394395
assert.ErrorIs(t, err, ErrNoActiveGateway)
395396
}
396397

398+
func TestLoadConfig_SystemActiveGateway(t *testing.T) {
399+
user, system := t.TempDir(), t.TempDir()
400+
t.Setenv("XDG_CONFIG_HOME", user)
401+
t.Setenv(systemGatewayDirEnv, system)
402+
writeFile(t, system, "active_gateway", "corp")
403+
gwDir := filepath.Join(system, "gateways", "corp")
404+
require.NoError(t, os.MkdirAll(gwDir, 0o755))
405+
writeFile(t, gwDir, "metadata.json", `{"gateway_endpoint":"host:443"}`)
406+
407+
cfg, err := LoadConfig("")
408+
require.NoError(t, err)
409+
assert.Equal(t, "corp", cfg.Name)
410+
assert.Equal(t, SourceSystem, cfg.Source)
411+
}
412+
397413
func TestLoadConfig_ActiveGateway(t *testing.T) {
398414
tmp := setupGateway(t, "my-active", `{"gateway_endpoint":"host:443","auth_mode":"oidc"}`)
399415
writeFile(t, filepath.Join(tmp, "openshell"), "active_gateway", "my-active")

‎sdk/go/openshell/v1/gateway/paths.go‎

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -137,16 +137,29 @@ func validateGatewayName(name string) error {
137137
return nil
138138
}
139139

140-
// resolveActiveGateway reads the active_gateway file from the user
141-
// config directory and returns the validated gateway name. Returns
142-
// ErrNoActiveGateway if the file is missing or empty.
140+
// resolveActiveGateway returns the validated active gateway name. It reads
141+
// the user active_gateway file and falls back to the system one when the user
142+
// file is missing, empty, or invalid, matching the CLI. Returns
143+
// ErrNoActiveGateway describing the user file when neither yields a name.
143144
func resolveActiveGateway() (string, error) {
144145
userBase, err := userConfigDir()
145146
if err != nil {
146-
return "", fmt.Errorf("%w: cannot determine config directory: %v", ErrNoActiveGateway, err)
147+
err = fmt.Errorf("%w: cannot determine config directory: %v", ErrNoActiveGateway, err)
148+
} else {
149+
var name string
150+
if name, err = readActiveGatewayFile(filepath.Join(userBase, activeGatewayFile)); err == nil {
151+
return name, nil
152+
}
153+
}
154+
155+
if name, sysErr := readActiveGatewayFile(filepath.Join(systemConfigDir(), activeGatewayFile)); sysErr == nil {
156+
return name, nil
147157
}
158+
return "", err
159+
}
148160

149-
path := filepath.Join(userBase, activeGatewayFile)
161+
// readActiveGatewayFile reads and validates the gateway name stored at path.
162+
func readActiveGatewayFile(path string) (string, error) {
150163
data, err := os.ReadFile(path)
151164
if err != nil {
152165
return "", fmt.Errorf("%w", ErrNoActiveGateway)

‎sdk/go/openshell/v1/gateway/paths_test.go‎

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,7 @@ func TestResolveActiveGateway_WhitespaceHandling(t *testing.T) {
198198
func TestResolveActiveGateway_FileMissing(t *testing.T) {
199199
tmp := t.TempDir()
200200
t.Setenv("XDG_CONFIG_HOME", tmp)
201+
t.Setenv(systemGatewayDirEnv, t.TempDir())
201202
require.NoError(t, os.MkdirAll(filepath.Join(tmp, "openshell"), 0o755))
202203

203204
_, err := resolveActiveGateway()
@@ -208,6 +209,7 @@ func TestResolveActiveGateway_FileMissing(t *testing.T) {
208209
func TestResolveActiveGateway_EmptyFile(t *testing.T) {
209210
tmp := t.TempDir()
210211
t.Setenv("XDG_CONFIG_HOME", tmp)
212+
t.Setenv(systemGatewayDirEnv, t.TempDir())
211213
require.NoError(t, os.MkdirAll(filepath.Join(tmp, "openshell"), 0o755))
212214
require.NoError(t, os.WriteFile(filepath.Join(tmp, "openshell", "active_gateway"), []byte(" \n"), 0o644))
213215

@@ -216,6 +218,53 @@ func TestResolveActiveGateway_EmptyFile(t *testing.T) {
216218
assert.ErrorIs(t, err, ErrNoActiveGateway)
217219
}
218220

221+
func TestResolveActiveGateway_FallsBackToSystem(t *testing.T) {
222+
user, system := t.TempDir(), t.TempDir()
223+
t.Setenv("XDG_CONFIG_HOME", user)
224+
t.Setenv(systemGatewayDirEnv, system)
225+
require.NoError(t, os.WriteFile(filepath.Join(system, "active_gateway"), []byte("corp\n"), 0o644))
226+
227+
name, err := resolveActiveGateway()
228+
require.NoError(t, err)
229+
assert.Equal(t, "corp", name)
230+
}
231+
232+
func TestResolveActiveGateway_PrefersUser(t *testing.T) {
233+
user, system := t.TempDir(), t.TempDir()
234+
t.Setenv("XDG_CONFIG_HOME", user)
235+
t.Setenv(systemGatewayDirEnv, system)
236+
require.NoError(t, os.MkdirAll(filepath.Join(user, "openshell"), 0o755))
237+
require.NoError(t, os.WriteFile(filepath.Join(user, "openshell", "active_gateway"), []byte("mine"), 0o644))
238+
require.NoError(t, os.WriteFile(filepath.Join(system, "active_gateway"), []byte("corp"), 0o644))
239+
240+
name, err := resolveActiveGateway()
241+
require.NoError(t, err)
242+
assert.Equal(t, "mine", name)
243+
}
244+
245+
func TestResolveActiveGateway_InvalidUserFallsBackToSystem(t *testing.T) {
246+
user, system := t.TempDir(), t.TempDir()
247+
t.Setenv("XDG_CONFIG_HOME", user)
248+
t.Setenv(systemGatewayDirEnv, system)
249+
require.NoError(t, os.MkdirAll(filepath.Join(user, "openshell"), 0o755))
250+
require.NoError(t, os.WriteFile(filepath.Join(user, "openshell", "active_gateway"), []byte("../escape"), 0o644))
251+
require.NoError(t, os.WriteFile(filepath.Join(system, "active_gateway"), []byte("corp"), 0o644))
252+
253+
name, err := resolveActiveGateway()
254+
require.NoError(t, err)
255+
assert.Equal(t, "corp", name)
256+
}
257+
258+
func TestResolveActiveGateway_InvalidSystemIsIgnored(t *testing.T) {
259+
user, system := t.TempDir(), t.TempDir()
260+
t.Setenv("XDG_CONFIG_HOME", user)
261+
t.Setenv(systemGatewayDirEnv, system)
262+
require.NoError(t, os.WriteFile(filepath.Join(system, "active_gateway"), []byte("../escape"), 0o644))
263+
264+
_, err := resolveActiveGateway()
265+
assert.ErrorIs(t, err, ErrNoActiveGateway)
266+
}
267+
219268
func TestValidateGatewayName_SpecialCharacters(t *testing.T) {
220269
cases := []struct {
221270
name string

0 commit comments

Comments
 (0)