Skip to content

Commit 1eb389a

Browse files
committed
Merge branch 'main' into e2e-setup/presleyp
2 parents 3040187 + bb03df8 commit 1eb389a

File tree

137 files changed

+14322
-5957
lines changed

Some content is hidden

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

137 files changed

+14322
-5957
lines changed

.github/workflows/packages.yaml

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,11 @@ jobs:
1515
run: |
1616
Invoke-WebRequest https://aka.ms/wingetcreate/latest -OutFile wingetcreate.exe
1717
18-
# the package version is the same as the release tag without the leading
19-
# "v", and with a trailing ".0" (e.g. "v1.2.3" -> "1.2.3.0")
18+
# The package version is the same as the tag minus the leading "v".
2019
- name: Calculate package version
2120
id: version
2221
run: |
2322
$version = $env:CODER_VERSION -replace "^v", ""
24-
$version += ".0"
2523
echo "::set-output name=version::$version"
2624
2725
- name: Submit updated manifest to winget-pkgs
@@ -35,17 +33,30 @@ jobs:
3533
3634
echo "Installer URL: $installer_url"
3735
36+
# The URL "|X64" suffix forces the architecture as it cannot be
37+
# sniffed properly from the URL. wingetcreate checks both the URL and
38+
# binary magic bytes for the architecture and they need to both match,
39+
# but they only check for `x64`, `win64` and `_64` in the URL. Our URL
40+
# contains `amd64` which doesn't match sadly.
41+
#
42+
# wingetcreate will still do the binary magic bytes check, so if we
43+
# accidentally change the architecture of the installer, it will fail
44+
# submission.
3845
.\wingetcreate.exe update Coder.Coder `
3946
--submit `
4047
--version "${{ steps.version.outputs.version }}" `
41-
--urls "$installer_url" `
48+
--urls "${installer_url}|X64" `
4249
--token "${{ secrets.CDRCI_GITHUB_TOKEN }}"
4350
51+
env:
52+
# For gh CLI:
53+
GH_TOKEN: ${{ github.token }}
54+
4455
- name: Comment on PR
4556
run: |
4657
# find the PR that wingetcreate just made
4758
$pr_list = gh pr list --repo microsoft/winget-pkgs --search "author:cdrci Coder.Coder version ${{ steps.version.outputs.version }}" --limit 1 --json number | `
4859
ConvertFrom-Json`
4960
$pr_number = $pr_list[0].number
5061
51-
gh pr comment --repo microsoft/winget-pkgs "$pr_number" --body "🤖 cc: @deansheather"
62+
gh pr comment --repo microsoft/winget-pkgs "$pr_number" --body "🤖 cc: @deansheather @matifali"

.github/workflows/stale.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ jobs:
1313
steps:
1414
# v5.1.0 has a weird bug that makes stalebot add then remove its own label
1515
# https://github.com/actions/stale/pull/775
16-
- uses: actions/stale@v6.0.0
16+
- uses: actions/stale@v7.0.0
1717
with:
1818
stale-issue-label: "stale"
1919
stale-pr-label: "stale"

.swaggo

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
// Replace all NullTime with string
2+
replace github.com/coder/coder/codersdk.NullTime string

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -483,7 +483,7 @@ docs/admin/prometheus.md: scripts/metricsdocgen/main.go scripts/metricsdocgen/me
483483
cd site
484484
yarn run format:write:only ../docs/admin/prometheus.md
485485

486-
coderd/apidoc/swagger.json: $(shell find ./scripts/apidocgen -not \( -path './scripts/apidocgen/node_modules' -prune \) -type f) $(wildcard coderd/*.go) $(wildcard codersdk/*.go)
486+
coderd/apidoc/swagger.json: $(shell find ./scripts/apidocgen -not \( -path './scripts/apidocgen/node_modules' -prune \) -type f) $(wildcard coderd/*.go) $(wildcard codersdk/*.go) .swaggo
487487
./scripts/apidocgen/generate.sh
488488
cd site
489489
yarn run format:write:only ../docs/api ../docs/manifest.json ../coderd/apidoc/swagger.json

cli/deployment/config.go

Lines changed: 52 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,12 @@ func newConfig() *codersdk.DeploymentConfig {
248248
Flag: "oidc-ignore-email-verified",
249249
Default: false,
250250
},
251+
UsernameField: &codersdk.DeploymentConfigField[string]{
252+
Name: "OIDC Username Field",
253+
Usage: "OIDC claim field to use as the username.",
254+
Flag: "oidc-username-field",
255+
Default: "preferred_username",
256+
},
251257
},
252258

253259
Telemetry: &codersdk.TelemetryConfig{
@@ -356,12 +362,6 @@ func newConfig() *codersdk.DeploymentConfig {
356362
Flag: "ssh-keygen-algorithm",
357363
Default: "ed25519",
358364
},
359-
AutoImportTemplates: &codersdk.DeploymentConfigField[[]string]{
360-
Name: "Auto Import Templates",
361-
Usage: "Templates to auto-import. Available auto-importable templates are: kubernetes",
362-
Flag: "auto-import-template",
363-
Hidden: true,
364-
},
365365
MetricsCacheRefreshInterval: &codersdk.DeploymentConfigField[time.Duration]{
366366
Name: "Metrics Cache Refresh Interval",
367367
Usage: "How frequently metrics are refreshed",
@@ -429,11 +429,22 @@ func newConfig() *codersdk.DeploymentConfig {
429429
Default: 10 * time.Minute,
430430
},
431431
},
432-
APIRateLimit: &codersdk.DeploymentConfigField[int]{
433-
Name: "API Rate Limit",
434-
Usage: "Maximum number of requests per minute allowed to the API per user, or per IP address for unauthenticated users. Negative values mean no rate limit. Some API endpoints are always rate limited regardless of this value to prevent denial-of-service attacks.",
435-
Flag: "api-rate-limit",
436-
Default: 512,
432+
RateLimit: &codersdk.RateLimitConfig{
433+
DisableAll: &codersdk.DeploymentConfigField[bool]{
434+
Name: "Disable All Rate Limits",
435+
Usage: "Disables all rate limits. This is not recommended in production.",
436+
Flag: "dangerous-disable-rate-limits",
437+
Default: false,
438+
},
439+
API: &codersdk.DeploymentConfigField[int]{
440+
Name: "API Rate Limit",
441+
Usage: "Maximum number of requests per minute allowed to the API per user, or per IP address for unauthenticated users. Negative values mean no rate limit. Some API endpoints have separate strict rate limits regardless of this value to prevent denial-of-service or brute force attacks.",
442+
// Change the env from the auto-generated CODER_RATE_LIMIT_API to the
443+
// old value to avoid breaking existing deployments.
444+
EnvOverride: "CODER_API_RATE_LIMIT",
445+
Flag: "api-rate-limit",
446+
Default: 512,
447+
},
437448
},
438449
Experimental: &codersdk.DeploymentConfigField[bool]{
439450
Name: "Experimental",
@@ -498,21 +509,30 @@ func setConfig(prefix string, vip *viper.Viper, target interface{}) {
498509
// assigned a value.
499510
if strings.HasPrefix(typ.Name(), "DeploymentConfigField[") {
500511
value := val.FieldByName("Value").Interface()
512+
513+
env, ok := val.FieldByName("EnvOverride").Interface().(string)
514+
if !ok {
515+
panic("DeploymentConfigField[].EnvOverride must be a string")
516+
}
517+
if env == "" {
518+
env = formatEnv(prefix)
519+
}
520+
501521
switch value.(type) {
502522
case string:
503-
vip.MustBindEnv(prefix, formatEnv(prefix))
523+
vip.MustBindEnv(prefix, env)
504524
val.FieldByName("Value").SetString(vip.GetString(prefix))
505525
case bool:
506-
vip.MustBindEnv(prefix, formatEnv(prefix))
526+
vip.MustBindEnv(prefix, env)
507527
val.FieldByName("Value").SetBool(vip.GetBool(prefix))
508528
case int:
509-
vip.MustBindEnv(prefix, formatEnv(prefix))
529+
vip.MustBindEnv(prefix, env)
510530
val.FieldByName("Value").SetInt(int64(vip.GetInt(prefix)))
511531
case time.Duration:
512-
vip.MustBindEnv(prefix, formatEnv(prefix))
532+
vip.MustBindEnv(prefix, env)
513533
val.FieldByName("Value").SetInt(int64(vip.GetDuration(prefix)))
514534
case []string:
515-
vip.MustBindEnv(prefix, formatEnv(prefix))
535+
vip.MustBindEnv(prefix, env)
516536
// As of October 21st, 2022 we supported delimiting a string
517537
// with a comma, but Viper only supports with a space. This
518538
// is a small hack around it!
@@ -580,6 +600,9 @@ func readSliceFromViper[T any](vip *viper.Viper, key string, value any) []T {
580600

581601
// Ensure the env entry for this key is registered
582602
// before checking value.
603+
//
604+
// We don't support DeploymentConfigField[].EnvOverride for array flags so
605+
// this is fine to just use `formatEnv` here.
583606
vip.MustBindEnv(configKey, formatEnv(configKey))
584607

585608
value := vip.Get(configKey)
@@ -626,7 +649,7 @@ func setViperDefaults(prefix string, vip *viper.Viper, target interface{}) {
626649
val := reflect.ValueOf(target).Elem()
627650
val = reflect.Indirect(val)
628651
typ := val.Type()
629-
if strings.HasPrefix(typ.Name(), "DeploymentConfigField") {
652+
if strings.HasPrefix(typ.Name(), "DeploymentConfigField[") {
630653
value := val.FieldByName("Default").Interface()
631654
vip.SetDefault(prefix, value)
632655
return
@@ -663,7 +686,7 @@ func AttachFlags(flagset *pflag.FlagSet, vip *viper.Viper, enterprise bool) {
663686
func setFlags(prefix string, flagset *pflag.FlagSet, vip *viper.Viper, target interface{}, enterprise bool) {
664687
val := reflect.Indirect(reflect.ValueOf(target))
665688
typ := val.Type()
666-
if strings.HasPrefix(typ.Name(), "DeploymentConfigField") {
689+
if strings.HasPrefix(typ.Name(), "DeploymentConfigField[") {
667690
isEnt := val.FieldByName("Enterprise").Bool()
668691
if enterprise != isEnt {
669692
return
@@ -672,15 +695,24 @@ func setFlags(prefix string, flagset *pflag.FlagSet, vip *viper.Viper, target in
672695
if flg == "" {
673696
return
674697
}
698+
699+
env, ok := val.FieldByName("EnvOverride").Interface().(string)
700+
if !ok {
701+
panic("DeploymentConfigField[].EnvOverride must be a string")
702+
}
703+
if env == "" {
704+
env = formatEnv(prefix)
705+
}
706+
675707
usage := val.FieldByName("Usage").String()
676-
usage = fmt.Sprintf("%s\n%s", usage, cliui.Styles.Placeholder.Render("Consumes $"+formatEnv(prefix)))
708+
usage = fmt.Sprintf("%s\n%s", usage, cliui.Styles.Placeholder.Render("Consumes $"+env))
677709
shorthand := val.FieldByName("Shorthand").String()
678710
hidden := val.FieldByName("Hidden").Bool()
679711
value := val.FieldByName("Default").Interface()
680712

681713
// Allow currently set environment variables
682714
// to override default values in help output.
683-
vip.MustBindEnv(prefix, formatEnv(prefix))
715+
vip.MustBindEnv(prefix, env)
684716

685717
switch value.(type) {
686718
case string:

cli/scaletest.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,7 @@ func requireAdmin(ctx context.Context, client *codersdk.Client) (codersdk.User,
265265
// Only owners can do scaletests. This isn't a very strong check but there's
266266
// not much else we can do. Ratelimits are enforced for non-owners so
267267
// hopefully that limits the damage if someone disables this check and runs
268-
// it against a non-owner account.
268+
// it against a non-owner account on a production deployment.
269269
ok := false
270270
for _, role := range me.Roles {
271271
if role.Name == "owner" {
@@ -488,7 +488,9 @@ func scaletestCreateWorkspaces() *cobra.Command {
488488
cmd := &cobra.Command{
489489
Use: "create-workspaces",
490490
Short: "Creates many workspaces and waits for them to be ready",
491-
Long: "Creates many users, then creates a workspace for each user and waits for them finish building and fully come online. Optionally runs a command inside each workspace, and connects to the workspace over WireGuard.",
491+
Long: `Creates many users, then creates a workspace for each user and waits for them finish building and fully come online. Optionally runs a command inside each workspace, and connects to the workspace over WireGuard.
492+
493+
It is recommended that all rate limits are disabled on the server before running this scaletest. This test generates many login events which will be rate limited against the (most likely single) IP.`,
492494
RunE: func(cmd *cobra.Command, args []string) error {
493495
ctx := cmd.Context()
494496
client, err := CreateClient(cmd)

cli/server.go

Lines changed: 16 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,16 @@ func Server(vip *viper.Viper, newAPI func(context.Context, *coderd.Options) (*co
104104
return xerrors.Errorf("either HTTP or TLS must be enabled")
105105
}
106106

107+
// Disable rate limits if the `--dangerous-disable-rate-limits` flag
108+
// was specified.
109+
loginRateLimit := 60
110+
filesRateLimit := 12
111+
if cfg.RateLimit.DisableAll.Value {
112+
cfg.RateLimit.API.Value = -1
113+
loginRateLimit = -1
114+
filesRateLimit = -1
115+
}
116+
107117
printLogo(cmd)
108118
logger := slog.Make(sloghuman.Sink(cmd.ErrOrStderr()))
109119
if ok, _ := cmd.Flags().GetBool(varVerbose); ok {
@@ -371,27 +381,6 @@ func Server(vip *viper.Viper, newAPI func(context.Context, *coderd.Options) (*co
371381
return xerrors.Errorf("parse ssh keygen algorithm %s: %w", cfg.SSHKeygenAlgorithm.Value, err)
372382
}
373383

374-
// Validate provided auto-import templates.
375-
var (
376-
validatedAutoImportTemplates = make([]coderd.AutoImportTemplate, len(cfg.AutoImportTemplates.Value))
377-
seenValidatedAutoImportTemplates = make(map[coderd.AutoImportTemplate]struct{}, len(cfg.AutoImportTemplates.Value))
378-
)
379-
for i, autoImportTemplate := range cfg.AutoImportTemplates.Value {
380-
var v coderd.AutoImportTemplate
381-
switch autoImportTemplate {
382-
case "kubernetes":
383-
v = coderd.AutoImportTemplateKubernetes
384-
default:
385-
return xerrors.Errorf("auto import template %q is not supported", autoImportTemplate)
386-
}
387-
388-
if _, ok := seenValidatedAutoImportTemplates[v]; ok {
389-
return xerrors.Errorf("auto import template %q is specified more than once", v)
390-
}
391-
seenValidatedAutoImportTemplates[v] = struct{}{}
392-
validatedAutoImportTemplates[i] = v
393-
}
394-
395384
defaultRegion := &tailcfg.DERPRegion{
396385
EmbeddedRelay: true,
397386
RegionID: cfg.DERP.Server.RegionID.Value,
@@ -449,12 +438,13 @@ func Server(vip *viper.Viper, newAPI func(context.Context, *coderd.Options) (*co
449438
SSHKeygenAlgorithm: sshKeygenAlgorithm,
450439
TracerProvider: tracerProvider,
451440
Telemetry: telemetry.NewNoop(),
452-
AutoImportTemplates: validatedAutoImportTemplates,
453441
MetricsCacheRefreshInterval: cfg.MetricsCacheRefreshInterval.Value,
454442
AgentStatsRefreshInterval: cfg.AgentStatRefreshInterval.Value,
455443
DeploymentConfig: cfg,
456444
PrometheusRegistry: prometheus.NewRegistry(),
457-
APIRateLimit: cfg.APIRateLimit.Value,
445+
APIRateLimit: cfg.RateLimit.API.Value,
446+
LoginRateLimit: loginRateLimit,
447+
FilesRateLimit: filesRateLimit,
458448
HTTPClient: httpClient,
459449
}
460450
if tlsConfig != nil {
@@ -526,8 +516,9 @@ func Server(vip *viper.Viper, newAPI func(context.Context, *coderd.Options) (*co
526516
Verifier: oidcProvider.Verifier(&oidc.Config{
527517
ClientID: cfg.OIDC.ClientID.Value,
528518
}),
529-
EmailDomain: cfg.OIDC.EmailDomain.Value,
530-
AllowSignups: cfg.OIDC.AllowSignups.Value,
519+
EmailDomain: cfg.OIDC.EmailDomain.Value,
520+
AllowSignups: cfg.OIDC.AllowSignups.Value,
521+
UsernameField: cfg.OIDC.UsernameField.Value,
531522
}
532523
}
533524

cli/testdata/coder_scaletest_create-workspaces_--help.golden

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
Creates many users, then creates a workspace for each user and waits for them finish building and fully come online. Optionally runs a command inside each workspace, and connects to the workspace over WireGuard.
22

3+
It is recommended that all rate limits are disabled on the server before running this scaletest. This test generates many login events which will be rate limited against the (most likely single) IP.
4+
35
Usage:
46
coder scaletest create-workspaces [flags]
57

cli/testdata/coder_server_--help.golden

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,16 +18,20 @@ Flags:
1818
allowed to the API per user, or per IP
1919
address for unauthenticated users.
2020
Negative values mean no rate limit. Some
21-
API endpoints are always rate limited
22-
regardless of this value to prevent
23-
denial-of-service attacks.
21+
API endpoints have separate strict rate
22+
limits regardless of this value to
23+
prevent denial-of-service or brute force
24+
attacks.
2425
Consumes $CODER_API_RATE_LIMIT (default 512)
2526
--cache-dir string The directory to cache temporary files.
2627
If unspecified and $CACHE_DIRECTORY is
2728
set, it will be used for compatibility
2829
with systemd.
2930
Consumes $CODER_CACHE_DIRECTORY (default
3031
"/tmp/coder-cli-test-cache")
32+
--dangerous-disable-rate-limits Disables all rate limits. This is not
33+
recommended in production.
34+
Consumes $CODER_RATE_LIMIT_DISABLE_ALL
3135
--derp-config-path string Path to read a DERP mapping from. See:
3236
https://tailscale.com/kb/1118/custom-derp-servers/
3337
Consumes $CODER_DERP_CONFIG_PATH
@@ -112,6 +116,9 @@ Flags:
112116
OIDC.
113117
Consumes $CODER_OIDC_SCOPES (default
114118
[openid,profile,email])
119+
--oidc-username-field string OIDC claim field to use as the username.
120+
Consumes $CODER_OIDC_USERNAME_FIELD
121+
(default "preferred_username")
115122
--postgres-url string URL of a PostgreSQL database. If empty,
116123
PostgreSQL binaries will be downloaded
117124
from Maven

0 commit comments

Comments
 (0)