Skip to content

Commit 949d353

Browse files
committed
Merge branch 'main' into taildefault
2 parents a922a88 + 57c7fcf commit 949d353

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+748
-113
lines changed

cli/cliflag/cliflag.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,18 @@ func StringVarP(flagset *pflag.FlagSet, p *string, name string, shorthand string
6161
flagset.StringVarP(p, name, shorthand, v, fmtUsage(usage, env))
6262
}
6363

64+
func StringArray(flagset *pflag.FlagSet, name, shorthand, env string, def []string, usage string) {
65+
v, ok := os.LookupEnv(env)
66+
if !ok || v == "" {
67+
if v == "" {
68+
def = []string{}
69+
} else {
70+
def = strings.Split(v, ",")
71+
}
72+
}
73+
flagset.StringArrayP(name, shorthand, def, fmtUsage(usage, env))
74+
}
75+
6476
func StringArrayVarP(flagset *pflag.FlagSet, ptr *[]string, name string, shorthand string, env string, def []string, usage string) {
6577
val, ok := os.LookupEnv(env)
6678
if ok {

cli/login.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,10 @@ func login() *cobra.Command {
6666
serverURL.Scheme = "https"
6767
}
6868

69-
client := codersdk.New(serverURL)
69+
client, err := createUnauthenticatedClient(cmd, serverURL)
70+
if err != nil {
71+
return err
72+
}
7073

7174
// Try to check the version of the server prior to logging in.
7275
// It may be useful to warn the user if they are trying to login

cli/root.go

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"context"
55
"flag"
66
"fmt"
7+
"net/http"
78
"net/url"
89
"os"
910
"strings"
@@ -41,6 +42,7 @@ const (
4142
varAgentToken = "agent-token"
4243
varAgentURL = "agent-url"
4344
varGlobalConfig = "global-config"
45+
varHeader = "header"
4446
varNoOpen = "no-open"
4547
varNoVersionCheck = "no-version-warning"
4648
varNoFeatureWarning = "no-feature-warning"
@@ -174,6 +176,7 @@ func Root(subcommands []*cobra.Command) *cobra.Command {
174176
cliflag.String(cmd.PersistentFlags(), varAgentURL, "", "CODER_AGENT_URL", "", "Specify the URL for an agent to access your deployment.")
175177
_ = cmd.PersistentFlags().MarkHidden(varAgentURL)
176178
cliflag.String(cmd.PersistentFlags(), varGlobalConfig, "", "CODER_CONFIG_DIR", configdir.LocalConfig("coderv2"), "Specify the path to the global `coder` config directory.")
179+
cliflag.StringArray(cmd.PersistentFlags(), varHeader, "", "CODER_HEADER", []string{}, "HTTP headers added to all requests. Provide as \"Key=Value\"")
177180
cmd.PersistentFlags().Bool(varForceTty, false, "Force the `coder` command to run as if connected to a TTY.")
178181
_ = cmd.PersistentFlags().MarkHidden(varForceTty)
179182
cmd.PersistentFlags().Bool(varNoOpen, false, "Block automatically opening URLs in the browser.")
@@ -237,8 +240,32 @@ func CreateClient(cmd *cobra.Command) (*codersdk.Client, error) {
237240
return nil, err
238241
}
239242
}
243+
client, err := createUnauthenticatedClient(cmd, serverURL)
244+
if err != nil {
245+
return nil, err
246+
}
247+
client.SessionToken = token
248+
return client, nil
249+
}
250+
251+
func createUnauthenticatedClient(cmd *cobra.Command, serverURL *url.URL) (*codersdk.Client, error) {
240252
client := codersdk.New(serverURL)
241-
client.SessionToken = strings.TrimSpace(token)
253+
headers, err := cmd.Flags().GetStringArray(varHeader)
254+
if err != nil {
255+
return nil, err
256+
}
257+
transport := &headerTransport{
258+
transport: http.DefaultTransport,
259+
headers: map[string]string{},
260+
}
261+
for _, header := range headers {
262+
parts := strings.SplitN(header, "=", 2)
263+
if len(parts) < 2 {
264+
return nil, xerrors.Errorf("split header %q had less than two parts", header)
265+
}
266+
transport.headers[parts[0]] = parts[1]
267+
}
268+
client.HTTPClient.Transport = transport
242269
return client, nil
243270
}
244271

@@ -530,3 +557,15 @@ func checkWarnings(cmd *cobra.Command, client *codersdk.Client) error {
530557

531558
return nil
532559
}
560+
561+
type headerTransport struct {
562+
transport http.RoundTripper
563+
headers map[string]string
564+
}
565+
566+
func (h *headerTransport) RoundTrip(req *http.Request) (*http.Response, error) {
567+
for k, v := range h.headers {
568+
req.Header.Add(k, v)
569+
}
570+
return h.transport.RoundTrip(req)
571+
}

cli/root_test.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,12 @@ package cli_test
22

33
import (
44
"bytes"
5+
"net/http"
6+
"net/http/httptest"
57
"testing"
68

79
"github.com/spf13/cobra"
10+
"github.com/stretchr/testify/assert"
811
"github.com/stretchr/testify/require"
912
"golang.org/x/xerrors"
1013

@@ -129,4 +132,25 @@ func TestRoot(t *testing.T) {
129132
require.Contains(t, output, buildinfo.Version(), "has version")
130133
require.Contains(t, output, buildinfo.ExternalURL(), "has url")
131134
})
135+
136+
t.Run("Header", func(t *testing.T) {
137+
t.Parallel()
138+
139+
done := make(chan struct{})
140+
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
141+
assert.Equal(t, "wow", r.Header.Get("X-Testing"))
142+
w.WriteHeader(http.StatusGone)
143+
select {
144+
case <-done:
145+
close(done)
146+
default:
147+
}
148+
}))
149+
defer srv.Close()
150+
buf := new(bytes.Buffer)
151+
cmd, _ := clitest.New(t, "--header", "X-Testing=wow", "login", srv.URL)
152+
cmd.SetOut(buf)
153+
// This won't succeed, because we're using the login cmd to assert requests.
154+
_ = cmd.Execute()
155+
})
132156
}

coderd/coderd.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,7 @@ func New(options *Options) *API {
352352
})
353353
r.Route("/{user}", func(r chi.Router) {
354354
r.Use(httpmw.ExtractUserParam(options.Database))
355+
r.Delete("/", api.deleteUser)
355356
r.Get("/", api.userByName)
356357
r.Put("/profile", api.putUserProfile)
357358
r.Route("/status", func(r chi.Router) {

coderd/database/databasefake/databasefake.go

Lines changed: 42 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -284,7 +284,7 @@ func (q *fakeQuerier) GetUserByEmailOrUsername(_ context.Context, arg database.G
284284
defer q.mutex.RUnlock()
285285

286286
for _, user := range q.users {
287-
if user.Email == arg.Email || user.Username == arg.Username {
287+
if (user.Email == arg.Email || user.Username == arg.Username) && user.Deleted == arg.Deleted {
288288
return user, nil
289289
}
290290
}
@@ -307,7 +307,13 @@ func (q *fakeQuerier) GetUserCount(_ context.Context) (int64, error) {
307307
q.mutex.RLock()
308308
defer q.mutex.RUnlock()
309309

310-
return int64(len(q.users)), nil
310+
existing := int64(0)
311+
for _, u := range q.users {
312+
if !u.Deleted {
313+
existing++
314+
}
315+
}
316+
return existing, nil
311317
}
312318

313319
func (q *fakeQuerier) GetActiveUserCount(_ context.Context) (int64, error) {
@@ -316,13 +322,27 @@ func (q *fakeQuerier) GetActiveUserCount(_ context.Context) (int64, error) {
316322

317323
active := int64(0)
318324
for _, u := range q.users {
319-
if u.Status == database.UserStatusActive {
325+
if u.Status == database.UserStatusActive && !u.Deleted {
320326
active++
321327
}
322328
}
323329
return active, nil
324330
}
325331

332+
func (q *fakeQuerier) UpdateUserDeletedByID(_ context.Context, params database.UpdateUserDeletedByIDParams) error {
333+
q.mutex.Lock()
334+
defer q.mutex.Unlock()
335+
336+
for i, u := range q.users {
337+
if u.ID == params.ID {
338+
u.Deleted = params.Deleted
339+
q.users[i] = u
340+
return nil
341+
}
342+
}
343+
return sql.ErrNoRows
344+
}
345+
326346
func (q *fakeQuerier) GetUsers(_ context.Context, params database.GetUsersParams) ([]database.User, error) {
327347
q.mutex.RLock()
328348
defer q.mutex.RUnlock()
@@ -341,6 +361,16 @@ func (q *fakeQuerier) GetUsers(_ context.Context, params database.GetUsersParams
341361
return a.CreatedAt.Before(b.CreatedAt)
342362
})
343363

364+
if params.Deleted {
365+
tmp := make([]database.User, 0, len(users))
366+
for _, user := range users {
367+
if user.Deleted {
368+
tmp = append(tmp, user)
369+
}
370+
}
371+
users = tmp
372+
}
373+
344374
if params.AfterID != uuid.Nil {
345375
found := false
346376
for i, v := range users {
@@ -409,16 +439,19 @@ func (q *fakeQuerier) GetUsers(_ context.Context, params database.GetUsersParams
409439
return users, nil
410440
}
411441

412-
func (q *fakeQuerier) GetUsersByIDs(_ context.Context, ids []uuid.UUID) ([]database.User, error) {
442+
func (q *fakeQuerier) GetUsersByIDs(_ context.Context, params database.GetUsersByIDsParams) ([]database.User, error) {
413443
q.mutex.RLock()
414444
defer q.mutex.RUnlock()
415445

416446
users := make([]database.User, 0)
417447
for _, user := range q.users {
418-
for _, id := range ids {
448+
for _, id := range params.IDs {
419449
if user.ID.String() != id.String() {
420450
continue
421451
}
452+
if user.Deleted != params.Deleted {
453+
continue
454+
}
422455
users = append(users, user)
423456
}
424457
}
@@ -879,8 +912,8 @@ func (q *fakeQuerier) ParameterValues(_ context.Context, arg database.ParameterV
879912
}
880913
}
881914

882-
if len(arg.Ids) > 0 {
883-
if !slice.Contains(arg.Ids, parameterValue.ID) {
915+
if len(arg.IDs) > 0 {
916+
if !slice.Contains(arg.IDs, parameterValue.ID) {
884917
continue
885918
}
886919
}
@@ -961,9 +994,9 @@ func (q *fakeQuerier) GetTemplatesWithFilter(_ context.Context, arg database.Get
961994
continue
962995
}
963996

964-
if len(arg.Ids) > 0 {
997+
if len(arg.IDs) > 0 {
965998
match := false
966-
for _, id := range arg.Ids {
999+
for _, id := range arg.IDs {
9671000
if template.ID == id {
9681001
match = true
9691002
break

coderd/database/dump.sql

Lines changed: 5 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
ALTER TABLE users
2+
DROP COLUMN deleted;
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
ALTER TABLE users
2+
ADD COLUMN deleted boolean DEFAULT false NOT NULL;
3+
4+
DROP INDEX idx_users_email;
5+
DROP INDEX idx_users_username;
6+
DROP INDEX users_username_lower_idx;
7+
CREATE UNIQUE INDEX idx_users_email ON users USING btree (email) WHERE deleted = false;
8+
CREATE UNIQUE INDEX idx_users_username ON users USING btree (username) WHERE deleted = false;
9+
CREATE UNIQUE INDEX users_username_lower_idx ON users USING btree (lower(username)) WHERE deleted = false;

coderd/database/models.go

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/database/querier.go

Lines changed: 2 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)