Skip to content

Commit 8ae051d

Browse files
Merge branch 'coder:main' into issue/12496
2 parents 26e358e + a546cb8 commit 8ae051d

40 files changed

+750
-201
lines changed

cli/login.go

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,16 +136,28 @@ func (r *RootCmd) login() *clibase.Cmd {
136136
useTokenForSession bool
137137
)
138138
cmd := &clibase.Cmd{
139-
Use: "login <url>",
139+
Use: "login [<url>]",
140140
Short: "Authenticate with Coder deployment",
141141
Middleware: clibase.RequireRangeArgs(0, 1),
142142
Handler: func(inv *clibase.Invocation) error {
143143
ctx := inv.Context()
144144
rawURL := ""
145+
var urlSource string
146+
145147
if len(inv.Args) == 0 {
146148
rawURL = r.clientURL.String()
149+
urlSource = "flag"
150+
if rawURL != "" && rawURL == inv.Environ.Get(envURL) {
151+
urlSource = "environment"
152+
}
147153
} else {
148154
rawURL = inv.Args[0]
155+
urlSource = "argument"
156+
}
157+
158+
if url, err := r.createConfig().URL().Read(); rawURL == "" && err == nil {
159+
urlSource = "config"
160+
rawURL = url
149161
}
150162

151163
if rawURL == "" {
@@ -187,6 +199,9 @@ func (r *RootCmd) login() *clibase.Cmd {
187199
if err != nil {
188200
return xerrors.Errorf("Failed to check server %q for first user, is the URL correct and is coder accessible from your browser? Error - has initial user: %w", serverURL.String(), err)
189201
}
202+
203+
_, _ = fmt.Fprintf(inv.Stdout, "Attempting to authenticate with %s URL: '%s'\n", urlSource, serverURL)
204+
190205
if !hasFirstUser {
191206
_, _ = fmt.Fprintf(inv.Stdout, Caret+"Your Coder deployment hasn't been set up!\n")
192207

cli/login_test.go

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ func TestLogin(t *testing.T) {
116116

117117
clitest.Start(t, inv)
118118

119+
pty.ExpectMatch(fmt.Sprintf("Attempting to authenticate with flag URL: '%s'", client.URL.String()))
119120
matches := []string{
120121
"first user?", "yes",
121122
"username", "testuser",
@@ -205,6 +206,7 @@ func TestLogin(t *testing.T) {
205206
assert.NoError(t, err)
206207
}()
207208

209+
pty.ExpectMatch(fmt.Sprintf("Attempting to authenticate with argument URL: '%s'", client.URL.String()))
208210
pty.ExpectMatch("Paste your token here:")
209211
pty.WriteLine(client.SessionToken())
210212
if runtime.GOOS != "windows" {
@@ -215,6 +217,52 @@ func TestLogin(t *testing.T) {
215217
<-doneChan
216218
})
217219

220+
t.Run("ExistingUserURLSavedInConfig", func(t *testing.T) {
221+
t.Parallel()
222+
client := coderdtest.New(t, nil)
223+
url := client.URL.String()
224+
coderdtest.CreateFirstUser(t, client)
225+
226+
inv, root := clitest.New(t, "login", "--no-open")
227+
clitest.SetupConfig(t, client, root)
228+
229+
doneChan := make(chan struct{})
230+
pty := ptytest.New(t).Attach(inv)
231+
go func() {
232+
defer close(doneChan)
233+
err := inv.Run()
234+
assert.NoError(t, err)
235+
}()
236+
237+
pty.ExpectMatch(fmt.Sprintf("Attempting to authenticate with config URL: '%s'", url))
238+
pty.ExpectMatch("Paste your token here:")
239+
pty.WriteLine(client.SessionToken())
240+
<-doneChan
241+
})
242+
243+
t.Run("ExistingUserURLSavedInEnv", func(t *testing.T) {
244+
t.Parallel()
245+
client := coderdtest.New(t, nil)
246+
url := client.URL.String()
247+
coderdtest.CreateFirstUser(t, client)
248+
249+
inv, _ := clitest.New(t, "login", "--no-open")
250+
inv.Environ.Set("CODER_URL", url)
251+
252+
doneChan := make(chan struct{})
253+
pty := ptytest.New(t).Attach(inv)
254+
go func() {
255+
defer close(doneChan)
256+
err := inv.Run()
257+
assert.NoError(t, err)
258+
}()
259+
260+
pty.ExpectMatch(fmt.Sprintf("Attempting to authenticate with environment URL: '%s'", url))
261+
pty.ExpectMatch("Paste your token here:")
262+
pty.WriteLine(client.SessionToken())
263+
<-doneChan
264+
})
265+
218266
t.Run("ExistingUserInvalidTokenTTY", func(t *testing.T) {
219267
t.Parallel()
220268
client := coderdtest.New(t, nil)

cli/logout_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ func TestLogout(t *testing.T) {
119119
go func() {
120120
defer close(logoutChan)
121121
err = logout.Run()
122-
assert.ErrorContains(t, err, "You are not logged in. Try logging in using 'coder login <url>'.")
122+
assert.ErrorContains(t, err, "You are not logged in. Try logging in using 'coder login'.")
123123
}()
124124

125125
<-logoutChan

cli/root.go

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,9 @@ const (
6565
varVerbose = "verbose"
6666
varOrganizationSelect = "organization"
6767
varDisableDirect = "disable-direct-connections"
68-
notLoggedInMessage = "You are not logged in. Try logging in using 'coder login <url>'."
68+
69+
notLoggedInMessage = "You are not logged in. Try logging in using 'coder login <url>'."
70+
notLoggedInURLSavedMessage = "You are not logged in. Try logging in using 'coder login'."
6971

7072
envNoVersionCheck = "CODER_NO_VERSION_WARNING"
7173
envNoFeatureWarning = "CODER_NO_FEATURE_WARNING"
@@ -77,7 +79,10 @@ const (
7779
envURL = "CODER_URL"
7880
)
7981

80-
var errUnauthenticated = xerrors.New(notLoggedInMessage)
82+
var (
83+
errUnauthenticated = xerrors.New(notLoggedInMessage)
84+
errUnauthenticatedURLSaved = xerrors.New(notLoggedInURLSavedMessage)
85+
)
8186

8287
func (r *RootCmd) Core() []*clibase.Cmd {
8388
// Please re-sort this list alphabetically if you change it!
@@ -574,7 +579,7 @@ func (r *RootCmd) initClientInternal(client *codersdk.Client, allowTokenMissing
574579
// If the configuration files are absent, the user is logged out
575580
if os.IsNotExist(err) {
576581
if !allowTokenMissing {
577-
return errUnauthenticated
582+
return errUnauthenticatedURLSaved
578583
}
579584
} else if err != nil {
580585
return err

cli/testdata/coder_login_--help.golden

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
coder v0.0.0-devel
22

33
USAGE:
4-
coder login [flags] <url>
4+
coder login [flags] [<url>]
55

66
Authenticate with Coder deployment
77

coderd/database/dbmem/dbmem.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8266,6 +8266,19 @@ func (q *FakeQuerier) GetAuthorizedWorkspaces(ctx context.Context, arg database.
82668266
}
82678267
}
82688268

8269+
if len(arg.WorkspaceIds) > 0 {
8270+
match := false
8271+
for _, id := range arg.WorkspaceIds {
8272+
if workspace.ID == id {
8273+
match = true
8274+
break
8275+
}
8276+
}
8277+
if !match {
8278+
continue
8279+
}
8280+
}
8281+
82698282
// If the filter exists, ensure the object is authorized.
82708283
if prepared != nil && prepared.Authorize(ctx, workspace.RBACObject()) != nil {
82718284
continue

coderd/database/dbpurge/dbpurge_test.go

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ func containsAgentLog(daemons []database.WorkspaceAgentLog, output string) bool
202202
func TestDeleteOldProvisionerDaemons(t *testing.T) {
203203
t.Parallel()
204204

205-
db, _ := dbtestutil.NewDB(t)
205+
db, _ := dbtestutil.NewDB(t, dbtestutil.WithDumpOnFailure())
206206
defaultOrg := dbgen.Organization(t, db, database.Organization{})
207207
logger := slogtest.Make(t, &slogtest.Options{IgnoreErrors: true})
208208

@@ -214,11 +214,12 @@ func TestDeleteOldProvisionerDaemons(t *testing.T) {
214214
// given
215215
_, err := db.UpsertProvisionerDaemon(ctx, database.UpsertProvisionerDaemonParams{
216216
// Provisioner daemon created 14 days ago, and checked in just before 7 days deadline.
217-
Name: "external-0",
218-
Provisioners: []database.ProvisionerType{"echo"},
219-
Tags: database.StringMap{provisionersdk.TagScope: provisionersdk.ScopeOrganization},
220-
CreatedAt: now.Add(-14 * 24 * time.Hour),
221-
LastSeenAt: sql.NullTime{Valid: true, Time: now.Add(-7 * 24 * time.Hour).Add(time.Minute)},
217+
Name: "external-0",
218+
Provisioners: []database.ProvisionerType{"echo"},
219+
Tags: database.StringMap{provisionersdk.TagScope: provisionersdk.ScopeOrganization},
220+
CreatedAt: now.AddDate(0, 0, -14),
221+
// Note: adding an hour and a minute to account for DST variations
222+
LastSeenAt: sql.NullTime{Valid: true, Time: now.AddDate(0, 0, -7).Add(61 * time.Minute)},
222223
Version: "1.0.0",
223224
APIVersion: proto.CurrentVersion.String(),
224225
OrganizationID: defaultOrg.ID,
@@ -229,8 +230,8 @@ func TestDeleteOldProvisionerDaemons(t *testing.T) {
229230
Name: "external-1",
230231
Provisioners: []database.ProvisionerType{"echo"},
231232
Tags: database.StringMap{provisionersdk.TagScope: provisionersdk.ScopeOrganization},
232-
CreatedAt: now.Add(-8 * 24 * time.Hour),
233-
LastSeenAt: sql.NullTime{Valid: true, Time: now.Add(-8 * 24 * time.Hour).Add(time.Hour)},
233+
CreatedAt: now.AddDate(0, 0, -8),
234+
LastSeenAt: sql.NullTime{Valid: true, Time: now.AddDate(0, 0, -8).Add(time.Hour)},
234235
Version: "1.0.0",
235236
APIVersion: proto.CurrentVersion.String(),
236237
OrganizationID: defaultOrg.ID,
@@ -244,7 +245,7 @@ func TestDeleteOldProvisionerDaemons(t *testing.T) {
244245
provisionersdk.TagScope: provisionersdk.ScopeUser,
245246
provisionersdk.TagOwner: uuid.NewString(),
246247
},
247-
CreatedAt: now.Add(-9 * 24 * time.Hour),
248+
CreatedAt: now.AddDate(0, 0, -9),
248249
Version: "1.0.0",
249250
APIVersion: proto.CurrentVersion.String(),
250251
OrganizationID: defaultOrg.ID,
@@ -258,8 +259,8 @@ func TestDeleteOldProvisionerDaemons(t *testing.T) {
258259
provisionersdk.TagScope: provisionersdk.ScopeUser,
259260
provisionersdk.TagOwner: uuid.NewString(),
260261
},
261-
CreatedAt: now.Add(-6 * 24 * time.Hour),
262-
LastSeenAt: sql.NullTime{Valid: true, Time: now.Add(-6 * 24 * time.Hour)},
262+
CreatedAt: now.AddDate(0, 0, -6),
263+
LastSeenAt: sql.NullTime{Valid: true, Time: now.AddDate(0, 0, -6)},
263264
Version: "1.0.0",
264265
APIVersion: proto.CurrentVersion.String(),
265266
OrganizationID: defaultOrg.ID,
@@ -276,11 +277,18 @@ func TestDeleteOldProvisionerDaemons(t *testing.T) {
276277
if err != nil {
277278
return false
278279
}
280+
281+
daemonNames := make([]string, 0, len(daemons))
282+
for _, d := range daemons {
283+
daemonNames = append(daemonNames, d.Name)
284+
}
285+
t.Logf("found %d daemons: %v", len(daemons), daemonNames)
286+
279287
return containsProvisionerDaemon(daemons, "external-0") &&
280288
!containsProvisionerDaemon(daemons, "external-1") &&
281289
!containsProvisionerDaemon(daemons, "alice-provisioner") &&
282290
containsProvisionerDaemon(daemons, "bob-provisioner")
283-
}, testutil.WaitShort, testutil.IntervalFast)
291+
}, testutil.WaitShort, testutil.IntervalSlow)
284292
}
285293

286294
func containsProvisionerDaemon(daemons []database.ProvisionerDaemon, name string) bool {

coderd/database/modelqueries.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,7 @@ func (q *sqlQuerier) GetAuthorizedWorkspaces(ctx context.Context, arg GetWorkspa
221221
arg.OwnerUsername,
222222
arg.TemplateName,
223223
pq.Array(arg.TemplateIDs),
224+
pq.Array(arg.WorkspaceIds),
224225
arg.Name,
225226
arg.HasAgent,
226227
arg.AgentInactiveDisconnectTimeoutSeconds,

coderd/database/queries.sql.go

Lines changed: 25 additions & 17 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)