Skip to content

Commit 5ff29c0

Browse files
committed
Merge branch 'main' of github.com:/coder/coder into dk/system-notifications-o11y
2 parents 114797d + 978364b commit 5ff29c0

File tree

13 files changed

+1097
-821
lines changed

13 files changed

+1097
-821
lines changed

.github/actions/setup-go/action.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ description: |
44
inputs:
55
version:
66
description: "The Go version to use."
7-
default: "1.22.4"
7+
default: "1.22.5"
88
runs:
99
using: "composite"
1010
steps:

.github/dependabot.yaml

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@ updates:
3939
prefix: "chore"
4040
labels: []
4141
open-pull-requests-limit: 15
42+
groups:
43+
x:
44+
patterns:
45+
- "golang.org/x/*"
4246
ignore:
4347
# Ignore patch updates for all dependencies
4448
- dependency-name: "*"
@@ -73,6 +77,32 @@ updates:
7377
commit-message:
7478
prefix: "chore"
7579
labels: []
80+
groups:
81+
xterm:
82+
patterns:
83+
- "@xterm*"
84+
mui:
85+
patterns:
86+
- "@mui*"
87+
react:
88+
patterns:
89+
- "react*"
90+
- "@types/react*"
91+
emotion:
92+
patterns:
93+
- "@emotion*"
94+
eslint:
95+
patterns:
96+
- "eslint*"
97+
- "@typescript-eslint*"
98+
jest:
99+
patterns:
100+
- "jest*"
101+
- "@types/jest"
102+
vite:
103+
patterns:
104+
- "vite*"
105+
- "@vitejs/plugin-react"
76106
ignore:
77107
# Ignore patch updates for all dependencies
78108
- dependency-name: "*"
@@ -83,4 +113,10 @@ updates:
83113
- dependency-name: "@types/node"
84114
update-types:
85115
- version-update:semver-major
116+
# Ignore @storybook updates, run `pnpm dlx storybook@latest upgrade` to upgrade manually
117+
- dependency-name: "*storybook*" # matches @storybook/* and storybook*
118+
update-types:
119+
- version-update:semver-major
120+
- version-update:semver-minor
121+
- version-update:semver-patch
86122
open-pull-requests-limit: 15

cli/configssh.go

Lines changed: 26 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ type sshConfigOptions struct {
5454
disableAutostart bool
5555
header []string
5656
headerCommand string
57+
removedKeys map[string]bool
5758
}
5859

5960
// addOptions expects options in the form of "option=value" or "option value".
@@ -74,30 +75,20 @@ func (o *sshConfigOptions) addOption(option string) error {
7475
if err != nil {
7576
return err
7677
}
77-
for i, existing := range o.sshOptions {
78-
// Override existing option if they share the same key.
79-
// This is case-insensitive. Parsing each time might be a little slow,
80-
// but it is ok.
81-
existingKey, _, err := codersdk.ParseSSHConfigOption(existing)
82-
if err != nil {
83-
// Don't mess with original values if there is an error.
84-
// This could have come from the user's manual edits.
85-
continue
86-
}
87-
if strings.EqualFold(existingKey, key) {
88-
if value == "" {
89-
// Delete existing option.
90-
o.sshOptions = append(o.sshOptions[:i], o.sshOptions[i+1:]...)
91-
} else {
92-
// Override existing option.
93-
o.sshOptions[i] = option
94-
}
95-
return nil
96-
}
78+
lowerKey := strings.ToLower(key)
79+
if o.removedKeys != nil && o.removedKeys[lowerKey] {
80+
// Key marked as removed, skip.
81+
return nil
9782
}
98-
// Only append the option if it is not empty.
83+
// Only append the option if it is not empty
84+
// (we interpret empty as removal).
9985
if value != "" {
10086
o.sshOptions = append(o.sshOptions, option)
87+
} else {
88+
if o.removedKeys == nil {
89+
o.removedKeys = make(map[string]bool)
90+
}
91+
o.removedKeys[lowerKey] = true
10192
}
10293
return nil
10394
}
@@ -440,26 +431,29 @@ func (r *RootCmd) configSSH() *serpent.Command {
440431
configOptions := sshConfigOpts
441432
configOptions.sshOptions = nil
442433

443-
// Add standard options.
444-
err := configOptions.addOptions(defaultOptions...)
445-
if err != nil {
446-
return err
434+
// User options first (SSH only uses the first
435+
// option unless it can be given multiple times)
436+
for _, opt := range sshConfigOpts.sshOptions {
437+
err := configOptions.addOptions(opt)
438+
if err != nil {
439+
return xerrors.Errorf("add flag config option %q: %w", opt, err)
440+
}
447441
}
448442

449-
// Override with deployment options
443+
// Deployment options second, allow them to
444+
// override standard options.
450445
for k, v := range coderdConfig.SSHConfigOptions {
451446
opt := fmt.Sprintf("%s %s", k, v)
452447
err := configOptions.addOptions(opt)
453448
if err != nil {
454449
return xerrors.Errorf("add coderd config option %q: %w", opt, err)
455450
}
456451
}
457-
// Override with flag options
458-
for _, opt := range sshConfigOpts.sshOptions {
459-
err := configOptions.addOptions(opt)
460-
if err != nil {
461-
return xerrors.Errorf("add flag config option %q: %w", opt, err)
462-
}
452+
453+
// Finally, add the standard options.
454+
err := configOptions.addOptions(defaultOptions...)
455+
if err != nil {
456+
return err
463457
}
464458

465459
hostBlock := []string{

cli/configssh_internal_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -272,32 +272,32 @@ func Test_sshConfigOptions_addOption(t *testing.T) {
272272
},
273273
},
274274
{
275-
Name: "Replace",
275+
Name: "AddTwo",
276276
Start: []string{
277277
"foo bar",
278278
},
279279
Add: []string{"Foo baz"},
280280
Expect: []string{
281+
"foo bar",
281282
"Foo baz",
282283
},
283284
},
284285
{
285-
Name: "AddAndReplace",
286+
Name: "AddAndRemove",
286287
Start: []string{
287-
"a b",
288288
"foo bar",
289289
"buzz bazz",
290290
},
291291
Add: []string{
292292
"b c",
293+
"a ", // Empty value, means remove all following entries that start with "a", i.e. next line.
293294
"A hello",
294295
"hello world",
295296
},
296297
Expect: []string{
297298
"foo bar",
298299
"buzz bazz",
299300
"b c",
300-
"A hello",
301301
"hello world",
302302
},
303303
},

cli/configssh_test.go

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ func TestConfigSSH(t *testing.T) {
6565

6666
const hostname = "test-coder."
6767
const expectedKey = "ConnectionAttempts"
68-
const removeKey = "ConnectionTimeout"
68+
const removeKey = "ConnectTimeout"
6969
client, db := coderdtest.NewWithDatabase(t, &coderdtest.Options{
7070
ConfigSSH: codersdk.SSHConfigResponse{
7171
HostnamePrefix: hostname,
@@ -620,6 +620,19 @@ func TestConfigSSH_FileWriteAndOptionsFlow(t *testing.T) {
620620
regexMatch: `ProxyCommand .* --header-command "printf h1=v1 h2='v2'" ssh`,
621621
},
622622
},
623+
{
624+
name: "Multiple remote forwards",
625+
args: []string{
626+
"--yes",
627+
"--ssh-option", "RemoteForward 2222 192.168.11.1:2222",
628+
"--ssh-option", "RemoteForward 2223 192.168.11.1:2223",
629+
},
630+
wantErr: false,
631+
hasAgent: true,
632+
wantConfig: wantConfig{
633+
regexMatch: "RemoteForward 2222 192.168.11.1:2222.*\n.*RemoteForward 2223 192.168.11.1:2223",
634+
},
635+
},
623636
}
624637
for _, tt := range tests {
625638
tt := tt

coderd/coderdtest/oidctest/idp.go

Lines changed: 38 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,13 @@ func NewFakeIDP(t testing.TB, opts ...FakeIDPOpt) *FakeIDP {
343343
idp.realServer(t)
344344
}
345345

346+
// Log the url to indicate which port the IDP is running on if it is
347+
// being served on a real port.
348+
idp.logger.Info(context.Background(),
349+
"fake IDP created",
350+
slog.F("issuer", idp.IssuerURL().String()),
351+
)
352+
346353
return idp
347354
}
348355

@@ -744,7 +751,7 @@ func (f *FakeIDP) httpHandler(t testing.TB) http.Handler {
744751
// This endpoint is required to initialize the OIDC provider.
745752
// It is used to get the OIDC configuration.
746753
mux.Get("/.well-known/openid-configuration", func(rw http.ResponseWriter, r *http.Request) {
747-
f.logger.Info(r.Context(), "http OIDC config", slog.F("url", r.URL.String()))
754+
f.logger.Info(r.Context(), "http OIDC config", slogRequestFields(r)...)
748755

749756
_ = json.NewEncoder(rw).Encode(f.provider)
750757
})
@@ -754,7 +761,7 @@ func (f *FakeIDP) httpHandler(t testing.TB) http.Handler {
754761
// w/e and clicking "Allow". They will be redirected back to the redirect
755762
// when this is done.
756763
mux.Handle(authorizePath, http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
757-
f.logger.Info(r.Context(), "http call authorize", slog.F("url", r.URL.String()))
764+
f.logger.Info(r.Context(), "http call authorize", slogRequestFields(r)...)
758765

759766
clientID := r.URL.Query().Get("client_id")
760767
if !assert.Equal(t, f.clientID, clientID, "unexpected client_id") {
@@ -812,11 +819,12 @@ func (f *FakeIDP) httpHandler(t testing.TB) http.Handler {
812819
values, err = f.authenticateOIDCClientRequest(t, r)
813820
}
814821
f.logger.Info(r.Context(), "http idp call token",
815-
slog.F("url", r.URL.String()),
816-
slog.F("valid", err == nil),
817-
slog.F("grant_type", values.Get("grant_type")),
818-
slog.F("values", values.Encode()),
819-
)
822+
append(slogRequestFields(r),
823+
slog.F("valid", err == nil),
824+
slog.F("grant_type", values.Get("grant_type")),
825+
slog.F("values", values.Encode()),
826+
)...)
827+
820828
if err != nil {
821829
http.Error(rw, fmt.Sprintf("invalid token request: %s", err.Error()), httpErrorCode(http.StatusBadRequest, err))
822830
return
@@ -990,8 +998,10 @@ func (f *FakeIDP) httpHandler(t testing.TB) http.Handler {
990998
mux.Handle(userInfoPath, http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
991999
email, ok := validateMW(rw, r)
9921000
f.logger.Info(r.Context(), "http userinfo endpoint",
993-
slog.F("valid", ok),
994-
slog.F("email", email),
1001+
append(slogRequestFields(r),
1002+
slog.F("valid", ok),
1003+
slog.F("email", email),
1004+
)...,
9951005
)
9961006
if !ok {
9971007
return
@@ -1011,8 +1021,10 @@ func (f *FakeIDP) httpHandler(t testing.TB) http.Handler {
10111021
mux.Mount("/external-auth-validate/", http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
10121022
email, ok := validateMW(rw, r)
10131023
f.logger.Info(r.Context(), "http external auth validate",
1014-
slog.F("valid", ok),
1015-
slog.F("email", email),
1024+
append(slogRequestFields(r),
1025+
slog.F("valid", ok),
1026+
slog.F("email", email),
1027+
)...,
10161028
)
10171029
if !ok {
10181030
return
@@ -1028,7 +1040,7 @@ func (f *FakeIDP) httpHandler(t testing.TB) http.Handler {
10281040
}))
10291041

10301042
mux.Handle(keysPath, http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
1031-
f.logger.Info(r.Context(), "http call idp /keys")
1043+
f.logger.Info(r.Context(), "http call idp /keys", slogRequestFields(r)...)
10321044
set := jose.JSONWebKeySet{
10331045
Keys: []jose.JSONWebKey{
10341046
{
@@ -1042,7 +1054,7 @@ func (f *FakeIDP) httpHandler(t testing.TB) http.Handler {
10421054
}))
10431055

10441056
mux.Handle(deviceVerify, http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
1045-
f.logger.Info(r.Context(), "http call device verify")
1057+
f.logger.Info(r.Context(), "http call device verify", slogRequestFields(r)...)
10461058

10471059
inputParam := "user_input"
10481060
userInput := r.URL.Query().Get(inputParam)
@@ -1099,7 +1111,7 @@ func (f *FakeIDP) httpHandler(t testing.TB) http.Handler {
10991111
}))
11001112

11011113
mux.Handle(deviceAuth, http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
1102-
f.logger.Info(r.Context(), "http call device auth")
1114+
f.logger.Info(r.Context(), "http call device auth", slogRequestFields(r)...)
11031115

11041116
p := httpapi.NewQueryParamParser()
11051117
p.RequiredNotEmpty("client_id")
@@ -1161,7 +1173,7 @@ func (f *FakeIDP) httpHandler(t testing.TB) http.Handler {
11611173
}))
11621174

11631175
mux.NotFound(func(rw http.ResponseWriter, r *http.Request) {
1164-
f.logger.Error(r.Context(), "http call not found", slog.F("path", r.URL.Path))
1176+
f.logger.Error(r.Context(), "http call not found", slogRequestFields(r)...)
11651177
t.Errorf("unexpected request to IDP at path %q. Not supported", r.URL.Path)
11661178
})
11671179

@@ -1422,11 +1434,19 @@ func (f *FakeIDP) getClaims(m *syncmap.Map[string, jwt.MapClaims], key string) (
14221434
return v, true
14231435
}
14241436

1437+
func slogRequestFields(r *http.Request) []any {
1438+
return []any{
1439+
slog.F("url", r.URL.String()),
1440+
slog.F("host", r.Host),
1441+
slog.F("method", r.Method),
1442+
}
1443+
}
1444+
14251445
func httpErrorCode(defaultCode int, err error) int {
1426-
var stautsErr statusHookError
1446+
var statusErr statusHookError
14271447
status := defaultCode
1428-
if errors.As(err, &stautsErr) {
1429-
status = stautsErr.HTTPStatusCode
1448+
if errors.As(err, &statusErr) {
1449+
status = statusErr.HTTPStatusCode
14301450
}
14311451
return status
14321452
}

docs/install/releases.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,4 +56,4 @@ pages.
5656
| 2.11.x | May 07, 2024 | Security Support |
5757
| 2.12.x | June 04, 2024 | Stable |
5858
| 2.13.x | July 02, 2024 | Mainline |
59-
| 2.14.x | Aigust 06, 2024 | Not Released |
59+
| 2.14.x | August 06, 2024 | Not Released |

dogfood/Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ FROM ubuntu:jammy AS go
88

99
RUN apt-get update && apt-get install --yes curl gcc
1010
# Install Go manually, so that we can control the version
11-
ARG GO_VERSION=1.22.4
11+
ARG GO_VERSION=1.22.5
1212
RUN mkdir --parents /usr/local/go
1313

1414
# Boring Go is needed to build FIPS-compliant binaries.

0 commit comments

Comments
 (0)