Skip to content

Commit e25b59c

Browse files
committed
Merge branch 'main' into bq/prompt-template-variables
2 parents 8d83af3 + c39c0dc commit e25b59c

19 files changed

+177
-52
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ coder server --postgres-url <url> --access-url <url>
8484

8585
> <sup>1</sup> For production deployments, set up an external PostgreSQL instance for reliability.
8686
87-
Use `coder --help` to get a list of flags and environment variables. Use our [install guides](https://coder.com/docs/v2/latest/guides) for a full walkthrough.
87+
Use `coder --help` to get a list of flags and environment variables. Use our [install guides](https://coder.com/docs/v2/latest/install) for a full walkthrough.
8888

8989
## Documentation
9090

cli/cliui/select.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,17 +70,22 @@ type RichSelectOptions struct {
7070
// RichSelect displays a list of user options including name and description.
7171
func RichSelect(inv *clibase.Invocation, richOptions RichSelectOptions) (*codersdk.TemplateVersionParameterOption, error) {
7272
opts := make([]string, len(richOptions.Options))
73+
var defaultOpt string
7374
for i, option := range richOptions.Options {
7475
line := option.Name
7576
if len(option.Description) > 0 {
7677
line += ": " + option.Description
7778
}
7879
opts[i] = line
80+
81+
if option.Value == richOptions.Default {
82+
defaultOpt = line
83+
}
7984
}
8085

8186
selected, err := Select(inv, SelectOptions{
8287
Options: opts,
83-
Default: richOptions.Default,
88+
Default: defaultOpt,
8489
Size: richOptions.Size,
8590
HideSearch: richOptions.HideSearch,
8691
})

cli/tokens.go

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package cli
33
import (
44
"fmt"
55
"os"
6-
"strings"
76
"time"
87

98
"golang.org/x/exp/slices"
@@ -67,14 +66,7 @@ func (r *RootCmd) createToken() *clibase.Cmd {
6766
return xerrors.Errorf("create tokens: %w", err)
6867
}
6968

70-
cliui.Infof(
71-
inv.Stdout,
72-
"Here is your token. 🪄\n\n",
73-
)
74-
cliui.Infof(inv.Stdout, cliui.Styles.Code.Render(strings.TrimSpace(res.Key))+"\n\n")
75-
cliui.Infof(inv.Stdout,
76-
"You can use this token by setting the --%s CLI flag, the %s environment variable, or the %q HTTP header.", varToken, envSessionToken, codersdk.SessionTokenHeader,
77-
)
69+
_, _ = fmt.Fprintln(inv.Stdout, res.Key)
7870

7971
return nil
8072
},

cli/tokens_test.go

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import (
44
"bytes"
55
"context"
66
"encoding/json"
7-
"regexp"
87
"testing"
98

109
"github.com/stretchr/testify/require"
@@ -41,11 +40,7 @@ func TestTokens(t *testing.T) {
4140
require.NoError(t, err)
4241
res = buf.String()
4342
require.NotEmpty(t, res)
44-
// find API key in format "XXXXXXXXXX-XXXXXXXXXXXXXXXXXXXXXX"
45-
r := regexp.MustCompile("[a-zA-Z0-9]{10}-[a-zA-Z0-9]{22}")
46-
require.Regexp(t, r, res)
47-
key := r.FindString(res)
48-
id := key[:10]
43+
id := res[:10]
4944

5045
inv, root = clitest.New(t, "tokens", "ls")
5146
clitest.SetupConfig(t, client, root)

coderd/rbac/authz.go

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,10 @@ func Filter[O Objecter](ctx context.Context, auth Authorizer, subject Subject, a
137137
err := auth.Authorize(ctx, subject, action, o.RBACObject())
138138
if err == nil {
139139
filtered = append(filtered, o)
140+
} else if !IsUnauthorizedError(err) {
141+
// If the error is not the expected "Unauthorized" error, then
142+
// it is something unexpected.
143+
return nil, err
140144
}
141145
}
142146
return filtered, nil
@@ -155,6 +159,10 @@ func Filter[O Objecter](ctx context.Context, auth Authorizer, subject Subject, a
155159
err := prepared.Authorize(ctx, rbacObj)
156160
if err == nil {
157161
filtered = append(filtered, object)
162+
} else if !IsUnauthorizedError(err) {
163+
// If the error is not the expected "Unauthorized" error, then
164+
// it is something unexpected.
165+
return nil, err
158166
}
159167
}
160168

@@ -319,7 +327,8 @@ func (a RegoAuthorizer) authorize(ctx context.Context, subject Subject, action A
319327

320328
results, err := a.query.Eval(ctx, rego.EvalParsedInput(astV))
321329
if err != nil {
322-
return ForbiddenWithInternal(xerrors.Errorf("eval rego: %w", err), subject, action, object, results)
330+
err = correctCancelError(err)
331+
return xerrors.Errorf("evaluate rego: %w", err)
323332
}
324333

325334
if !results.Allowed() {
@@ -430,7 +439,8 @@ EachQueryLoop:
430439
// We need to eval each query with the newly known fields.
431440
results, err := q.Eval(ctx, rego.EvalParsedInput(parsed))
432441
if err != nil {
433-
continue EachQueryLoop
442+
err = correctCancelError(err)
443+
return xerrors.Errorf("eval error: %w", err)
434444
}
435445

436446
// If there are no results, then the query is false. This is because rego

coderd/rbac/authz_internal_test.go

Lines changed: 60 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -30,18 +30,68 @@ func (w fakeObject) RBACObject() Object {
3030
}
3131
}
3232

33+
// objectBomb is a wrapper around an Objecter that calls a function when
34+
// RBACObject is called.
35+
type objectBomb struct {
36+
Objecter
37+
bomb func()
38+
}
39+
40+
func (o *objectBomb) RBACObject() Object {
41+
o.bomb()
42+
return o.Objecter.RBACObject()
43+
}
44+
3345
func TestFilterError(t *testing.T) {
3446
t.Parallel()
35-
auth := NewAuthorizer(prometheus.NewRegistry())
36-
subject := Subject{
37-
ID: uuid.NewString(),
38-
Roles: RoleNames{},
39-
Groups: []string{},
40-
Scope: ScopeAll,
41-
}
47+
_ = objectBomb{}
4248

43-
_, err := Filter(context.Background(), auth, subject, ActionRead, []Object{ResourceUser, ResourceWorkspace})
44-
require.ErrorContains(t, err, "object types must be uniform")
49+
t.Run("DifferentResourceTypes", func(t *testing.T) {
50+
t.Parallel()
51+
52+
auth := NewAuthorizer(prometheus.NewRegistry())
53+
subject := Subject{
54+
ID: uuid.NewString(),
55+
Roles: RoleNames{},
56+
Groups: []string{},
57+
Scope: ScopeAll,
58+
}
59+
60+
_, err := Filter(context.Background(), auth, subject, ActionRead, []Object{ResourceUser, ResourceWorkspace})
61+
require.ErrorContains(t, err, "object types must be uniform")
62+
})
63+
64+
t.Run("CancelledContext", func(t *testing.T) {
65+
t.Parallel()
66+
t.Skipf("This test is racy as rego eval checks the ctx canceled in a go routine. " +
67+
"It is a coin flip if the query finishes before the 'cancel' is checked. " +
68+
"So sometimes the 'Authorize' call succeeds even if ctx is canceled.")
69+
70+
auth := NewAuthorizer(prometheus.NewRegistry())
71+
subject := Subject{
72+
ID: uuid.NewString(),
73+
Roles: RoleNames{
74+
RoleOwner(),
75+
},
76+
Groups: []string{},
77+
Scope: ScopeAll,
78+
}
79+
80+
ctx, cancel := context.WithCancel(context.Background())
81+
defer cancel()
82+
objects := []Objecter{
83+
ResourceUser,
84+
ResourceUser,
85+
&objectBomb{
86+
Objecter: ResourceUser,
87+
bomb: cancel,
88+
},
89+
ResourceUser,
90+
}
91+
92+
_, err := Filter(ctx, auth, subject, ActionRead, objects)
93+
require.ErrorIs(t, err, context.Canceled)
94+
})
4595
}
4696

4797
// TestFilter ensures the filter acts the same as an individual authorize.
@@ -170,7 +220,7 @@ func TestFilter(t *testing.T) {
170220
localObjects := make([]fakeObject, len(objects))
171221
copy(localObjects, objects)
172222

173-
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitShort)
223+
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitMedium)
174224
defer cancel()
175225
auth := NewAuthorizer(prometheus.NewRegistry())
176226

coderd/rbac/error.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
package rbac
22

33
import (
4+
"context"
45
"errors"
56
"flag"
67
"fmt"
78

89
"github.com/open-policy-agent/opa/rego"
10+
"github.com/open-policy-agent/opa/topdown"
11+
"golang.org/x/xerrors"
912
)
1013

1114
const (
@@ -97,3 +100,17 @@ func (*UnauthorizedError) As(target interface{}) bool {
97100
}
98101
return false
99102
}
103+
104+
// correctCancelError will return the correct error for a canceled context. This
105+
// is because rego changes a canceled context to a topdown.CancelErr. This error
106+
// is not helpful if the code is "canceled". To make the error conform with the
107+
// rest of our canceled errors, we will convert the error to a context.Canceled
108+
// error. No good information is lost, as the topdown.CancelErr provides the
109+
// location of the query that was canceled, which does not matter.
110+
func correctCancelError(err error) error {
111+
e := new(topdown.Error)
112+
if xerrors.As(err, &e) || e.Code == topdown.CancelErr {
113+
return context.Canceled
114+
}
115+
return err
116+
}

docs/admin/appearance.md

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# Appearance
2+
3+
## Support Links
4+
5+
Support links let admins adjust the user dropdown menu to include links referring to internal company resources. The menu section replaces the original menu positions: documentation, report a bug to GitHub, or join the Discord server.
6+
7+
![support links](../images/admin/support-links.png)
8+
9+
Custom links can be set in the deployment configuration using the `-c <yamlFile>`
10+
flag to `coder server`.
11+
12+
```yaml
13+
supportLinks:
14+
- name: "On-call 🔥"
15+
target: "http://on-call.example.internal"
16+
icon: "bug"
17+
- name: "😉 Getting started with Go!"
18+
target: "https://go.dev/"
19+
- name: "Community"
20+
target: "https://github.com/coder/coder"
21+
icon: "chat"
22+
```
23+
24+
## Icons
25+
26+
The link icons are optional, and limited to: `bug`, `chat`, and `docs`.
27+
28+
## Service Banners (enterprise)
29+
30+
Service Banners let admins post important messages to all site users. Only Site Owners may set the service banner.
31+
32+
![service banners](../images/admin/service-banners.png)
33+
34+
You can access the Service Banner settings by navigating to
35+
`Deployment > Service Banners`.
36+
37+
## Up next
38+
39+
- [Enterprise](../enterprise.md)

docs/admin/service-banners.md

Lines changed: 0 additions & 12 deletions
This file was deleted.

docs/enterprise.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ trial](https://coder.com/trial).
1414
| Cost Control | [Quotas](./admin/quotas.md) |||
1515
| Cost Control | [Max Workspace Autostop](./templates/README.md#configure-max-workspace-autostop) |||
1616
| Deployment | [High Availability](./admin/high-availability.md) |||
17-
| Deployment | [Service Banners](./admin/service-banners.md) |||
17+
| Deployment | [Appearance](./admin/appearance.md) |||
1818
| Deployment | Isolated Terraform Runners |||
1919

2020
> Previous plans to restrict OIDC and Git Auth features in OSS have been removed

docs/images/admin/support-links.png

52.7 KB
Loading

docs/install/docker.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ an PostgreSQL container and volume.
8888

8989
### Docker-based workspace is stuck in "Connecting..."
9090

91-
Ensure you have an externally-reachable `CODER_ACCESS_URL` set. See [troubleshooting templates](../templates.md#creating-and-troubleshooting-templates) for more steps.
91+
Ensure you have an externally-reachable `CODER_ACCESS_URL` set. See [troubleshooting templates](../templates/README.md#troubleshooting-templates) for more steps.
9292

9393
### Permission denied while trying to connect to the Docker daemon socket
9494

docs/manifest.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -335,9 +335,9 @@
335335
"icon_path": "./images/icons/speed.svg"
336336
},
337337
{
338-
"title": "Service Banners",
339-
"description": "Learn how to configure Service Banners",
340-
"path": "./admin/service-banners.md",
338+
"title": "Appearance",
339+
"description": "Learn how to configure the appearance of Coder",
340+
"path": "./admin/appearance.md",
341341
"icon_path": "./images/icons/info.svg",
342342
"state": "enterprise"
343343
},

docs/templates/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ the Coder server runs an additional [terraform apply](https://www.terraform.io/c
194194
informing the Coder provider that the workspace has a new transition state.
195195

196196
This template sample has one persistent resource (docker volume) and one
197-
ephemeral resource (docker image).
197+
ephemeral resource (docker container).
198198

199199
```hcl
200200
data "coder_workspace" "me" {

docs/templates/agent-metadata.md

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ resource "coder_agent" "main" {
7070
distributions and provides virtual memory, CPU and IO statistics. Running `top`
7171
produces output that looks like:
7272

73-
```
73+
```text
7474
%Cpu(s): 65.8 us, 4.4 sy, 0.0 ni, 29.3 id, 0.3 wa, 0.0 hi, 0.2 si, 0.0 st
7575
MiB Mem : 16009.0 total, 493.7 free, 4624.8 used, 10890.5 buff/cache
7676
MiB Swap: 0.0 total, 0.0 free, 0.0 used. 11021.3 avail Mem
@@ -80,7 +80,7 @@ MiB Swap: 0.0 total, 0.0 free, 0.0 used. 11021.3 avail Mem
8080
distributions and provides virtual memory, CPU and IO statistics. Running `vmstat`
8181
produces output that looks like:
8282

83-
```
83+
```text
8484
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
8585
r b swpd free buff cache si so bi bo in cs us sy id wa st
8686
0 0 19580 4781680 12133692 217646944 0 2 4 32 1 0 1 1 98 0 0
@@ -91,8 +91,29 @@ than `vmstat` but often not included in base images. It is easily installed by
9191
most package managers under the name `dstat`. The output of running `dstat 1 1` looks
9292
like:
9393

94-
```
94+
```text
9595
--total-cpu-usage-- -dsk/total- -net/total- ---paging-- ---system--
9696
usr sys idl wai stl| read writ| recv send| in out | int csw
9797
1 1 98 0 0|3422k 25M| 0 0 | 153k 904k| 123k 174k
9898
```
99+
100+
## DB Write Load
101+
102+
Agent metadata can generate a significant write load and overwhelm your
103+
database if you're not careful. The approximate writes per second can be
104+
calculated using the formula:
105+
106+
```text
107+
(metadata_count * num_running_agents * 2) / metadata_avg_interval
108+
```
109+
110+
For example, let's say you have
111+
112+
- 10 running agents
113+
- each with 6 metadata snippets
114+
- with an average interval of 4 seconds
115+
116+
You can expect `(10 * 6 * 2) / 4` or 30 writes per second.
117+
118+
One of the writes is to the `UNLOGGED` `workspace_agent_metadata` table and
119+
the other to the `NOTIFY` query that enables live stats streaming in the UI.

helm/templates/coder.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ spec:
2727
metadata:
2828
labels:
2929
{{- include "coder.labels" . | nindent 8 }}
30+
{{- with .Values.coder.podLabels }}
31+
{{- toYaml . | nindent 8 }}
32+
{{- end }}
3033
annotations:
3134
{{- toYaml .Values.coder.podAnnotations | nindent 8 }}
3235
spec:

0 commit comments

Comments
 (0)