Skip to content

Commit 126917f

Browse files
alnrclaude
andcommitted
fix: do not persist the workspace when ory use workspace only prints it
`ory use workspace` without an argument is documented as printing the current default, but it called SelectWorkspace unconditionally. With ORY_WORKSPACE (or a workspace API key) set, the resolved value was written to the config file, silently replacing the stored default. Persist only when an id argument is actually given. Also accept the `workspaces` alias, matching `get`/`list`/`create workspace`, and drop the unused selectedWorkspace.String method (cmdx.PrintRow only uses Header/Columns/Interface). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JYzGVwAKQ4ormxRHZg1eDu
1 parent cec92b6 commit 126917f

3 files changed

Lines changed: 43 additions & 12 deletions

File tree

‎cmd/cloudx/workspace/output.go‎

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -63,10 +63,6 @@ type selectedWorkspace struct {
6363

6464
var _ cmdx.TableRow = (*selectedWorkspace)(nil)
6565

66-
func (i selectedWorkspace) String() string {
67-
return i.ID
68-
}
69-
7066
func (*selectedWorkspace) Header() []string {
7167
return []string{"ID"}
7268
}

‎cmd/cloudx/workspace/use.go‎

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import (
1313
func NewUseWorkspaceCmd() *cobra.Command {
1414
cmd := &cobra.Command{
1515
Use: "workspace [id]",
16-
Aliases: []string{"ws"},
16+
Aliases: []string{"workspaces", "ws"},
1717
Args: cobra.MaximumNArgs(1),
1818
Short: "Set the workspace as the default. When no id is provided, prints the currently used default workspace.",
1919
Example: `$ ory use workspace ecaaa3cb-0730-4ee8-a6df-9553cdfeef89
@@ -36,15 +36,20 @@ $ ory use workspace ecaaa3cb-0730-4ee8-a6df-9553cdfeef89 --format json
3636
}
3737

3838
// The helper resolves a (partial) name or ID to the workspace ID,
39-
// and falls back to the one already stored in the config when no
40-
// argument is given.
39+
// and falls back to the environment or the one already stored in
40+
// the config when no argument is given.
4141
id := h.WorkspaceID()
4242
if id == nil {
4343
return client.ErrWorkspaceNotSet
4444
}
4545

46-
if err := h.SelectWorkspace(*id); err != nil {
47-
return cmdx.PrintOpenAPIError(cmd, err)
46+
// Only persist when the user asked to change the default. Without
47+
// an argument this command just reports the current one, which must
48+
// not overwrite the stored default with e.g. an ORY_WORKSPACE value.
49+
if len(args) == 1 {
50+
if err := h.SelectWorkspace(*id); err != nil {
51+
return cmdx.PrintOpenAPIError(cmd, err)
52+
}
4853
}
4954

5055
cmdx.PrintRow(cmd, &selectedWorkspace{ID: *id})

‎cmd/cloudx/workspace/use_test.go‎

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,10 @@ func TestUseWorkspace(t *testing.T) {
2424
t.Parallel()
2525

2626
const (
27-
initial = "11111111-1111-1111-1111-111111111111"
28-
other = "33333333-3333-3333-3333-333333333333"
29-
project = "22222222-2222-2222-2222-222222222222"
27+
initial = "11111111-1111-1111-1111-111111111111"
28+
other = "33333333-3333-3333-3333-333333333333"
29+
project = "22222222-2222-2222-2222-222222222222"
30+
accessToken = "the-access-token"
3031
)
3132

3233
newContext := func(t *testing.T, workspace string) (context.Context, string) {
@@ -35,6 +36,7 @@ func TestUseWorkspace(t *testing.T) {
3536
conf := map[string]any{
3637
"version": client.ConfigVersion,
3738
"selected_project": project,
39+
"access_token": map[string]any{"access_token": accessToken, "token_type": "bearer"},
3840
}
3941
if workspace != "" {
4042
conf["selected_workspace"] = workspace
@@ -58,6 +60,32 @@ func TestUseWorkspace(t *testing.T) {
5860
assert.Equal(t, initial, strings.TrimSpace(stdout))
5961
})
6062

63+
t.Run("case=prints the default workspace as JSON", func(t *testing.T) {
64+
t.Parallel()
65+
66+
ctx, _ := newContext(t, initial)
67+
68+
stdout, _, err := testhelpers.Cmd(ctx).Exec(nil, "use", "workspace", "--format", "json")
69+
require.NoError(t, err)
70+
assert.JSONEq(t, `{"id":"`+initial+`"}`, stdout)
71+
})
72+
73+
t.Run("case=does not persist an overridden workspace when no id is given", func(t *testing.T) {
74+
t.Parallel()
75+
76+
ctx, location := newContext(t, initial)
77+
// Simulates ORY_WORKSPACE (or a workspace API key) pointing somewhere
78+
// else: printing the default must not rewrite it.
79+
ctx = client.ContextWithOptions(ctx, client.WithWorkspaceOverride(other))
80+
81+
stdout, _, err := testhelpers.Cmd(ctx).Exec(nil, "use", "workspace", "--quiet")
82+
require.NoError(t, err)
83+
assert.Equal(t, other, strings.TrimSpace(stdout))
84+
85+
conf := testhelpers.ReadConfig(t, location)
86+
assert.Equal(t, initial, conf.SelectedWorkspace.String())
87+
})
88+
6189
t.Run("case=sets the default workspace and persists it", func(t *testing.T) {
6290
t.Parallel()
6391

@@ -70,6 +98,8 @@ func TestUseWorkspace(t *testing.T) {
7098
conf := testhelpers.ReadConfig(t, location)
7199
assert.Equal(t, other, conf.SelectedWorkspace.String())
72100
assert.Equal(t, project, conf.SelectedProject.String(), "selecting a workspace must not clear the project")
101+
require.NotNil(t, conf.AccessToken, "selecting a workspace must not log the user out")
102+
assert.Equal(t, accessToken, conf.AccessToken.AccessToken)
73103
})
74104

75105
t.Run("case=errors when no workspace is set", func(t *testing.T) {

0 commit comments

Comments
 (0)