Skip to content

Commit 203c7f9

Browse files
Merge branch 'main' into main
2 parents 4090e60 + 7bb52e1 commit 203c7f9

Some content is hidden

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

68 files changed

+2507
-455
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.24.4"
7+
default: "1.24.6"
88
use-preinstalled-go:
99
description: "Whether to use preinstalled Go."
1010
default: "false"

agent/agentssh/x11_test.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ func TestServer_X11_EvictionLRU(t *testing.T) {
135135
t.Skip("X11 forwarding is only supported on Linux")
136136
}
137137

138-
ctx := testutil.Context(t, testutil.WaitLong)
138+
ctx := testutil.Context(t, testutil.WaitSuperLong)
139139
logger := testutil.Logger(t)
140140
fs := afero.NewMemMapFs()
141141

@@ -238,7 +238,9 @@ func TestServer_X11_EvictionLRU(t *testing.T) {
238238
payload := "hello world"
239239
go func() {
240240
conn, err := inproc.Dial(ctx, testutil.NewAddr("tcp", fmt.Sprintf("localhost:%d", agentssh.X11StartPort+agentssh.X11DefaultDisplayOffset)))
241-
assert.NoError(t, err)
241+
if !assert.NoError(t, err) {
242+
return
243+
}
242244
_, err = conn.Write([]byte(payload))
243245
assert.NoError(t, err)
244246
_ = conn.Close()

cli/cliui/select.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -349,7 +349,11 @@ func RichMultiSelect(inv *serpent.Invocation, richOptions RichMultiSelectOptions
349349
}
350350

351351
// Check selected option, convert descriptions (line) to values
352-
var results []string
352+
//
353+
// The function must return an initialized empty array, since it is later marshaled
354+
// into JSON. Otherwise, `var results []string` would be marshaled to "null".
355+
// See: https://github.com/golang/go/issues/27589
356+
results := []string{}
353357
for _, sel := range selected {
354358
custom := true
355359
for i, option := range richOptions.Options {

cli/cliui/select_test.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,17 @@ func TestRichMultiSelect(t *testing.T) {
111111
allowCustom: true,
112112
want: []string{"aaa", "bbb"},
113113
},
114+
{
115+
name: "NoOptionSelected",
116+
options: []codersdk.TemplateVersionParameterOption{
117+
{Name: "AAA", Description: "This is AAA", Value: "aaa"},
118+
{Name: "BBB", Description: "This is BBB", Value: "bbb"},
119+
{Name: "CCC", Description: "This is CCC", Value: "ccc"},
120+
},
121+
defaults: []string{},
122+
allowCustom: false,
123+
want: []string{},
124+
},
114125
}
115126

116127
for _, tt := range tests {

cli/server.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ import (
5555

5656
"cdr.dev/slog"
5757
"cdr.dev/slog/sloggers/sloghuman"
58+
"github.com/coder/coder/v2/coderd/pproflabel"
5859
"github.com/coder/pretty"
5960
"github.com/coder/quartz"
6061
"github.com/coder/retry"
@@ -1459,14 +1460,14 @@ func newProvisionerDaemon(
14591460
tracer := coderAPI.TracerProvider.Tracer(tracing.TracerName)
14601461
terraformClient, terraformServer := drpcsdk.MemTransportPipe()
14611462
wg.Add(1)
1462-
go func() {
1463+
pproflabel.Go(ctx, pproflabel.Service(pproflabel.ServiceTerraformProvisioner), func(ctx context.Context) {
14631464
defer wg.Done()
14641465
<-ctx.Done()
14651466
_ = terraformClient.Close()
14661467
_ = terraformServer.Close()
1467-
}()
1468+
})
14681469
wg.Add(1)
1469-
go func() {
1470+
pproflabel.Go(ctx, pproflabel.Service(pproflabel.ServiceTerraformProvisioner), func(ctx context.Context) {
14701471
defer wg.Done()
14711472
defer cancel()
14721473

@@ -1485,7 +1486,7 @@ func newProvisionerDaemon(
14851486
default:
14861487
}
14871488
}
1488-
}()
1489+
})
14891490

14901491
connector[string(database.ProvisionerTypeTerraform)] = sdkproto.NewDRPCProvisionerClient(terraformClient)
14911492
default:

coderd/apidoc/docs.go

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

coderd/apidoc/swagger.json

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

coderd/autobuild/lifecycle_executor.go

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020

2121
"cdr.dev/slog"
2222
"github.com/coder/coder/v2/coderd/files"
23+
"github.com/coder/coder/v2/coderd/pproflabel"
2324

2425
"github.com/coder/coder/v2/coderd/audit"
2526
"github.com/coder/coder/v2/coderd/database"
@@ -107,10 +108,10 @@ func (e *Executor) WithStatsChannel(ch chan<- Stats) *Executor {
107108
// tick from its channel. It will stop when its context is Done, or when
108109
// its channel is closed.
109110
func (e *Executor) Run() {
110-
go func() {
111+
pproflabel.Go(e.ctx, pproflabel.Service(pproflabel.ServiceLifecycles), func(ctx context.Context) {
111112
for {
112113
select {
113-
case <-e.ctx.Done():
114+
case <-ctx.Done():
114115
return
115116
case t, ok := <-e.tick:
116117
if !ok {
@@ -120,15 +121,15 @@ func (e *Executor) Run() {
120121
e.metrics.autobuildExecutionDuration.Observe(stats.Elapsed.Seconds())
121122
if e.statsCh != nil {
122123
select {
123-
case <-e.ctx.Done():
124+
case <-ctx.Done():
124125
return
125126
case e.statsCh <- stats:
126127
}
127128
}
128-
e.log.Debug(e.ctx, "run stats", slog.F("elapsed", stats.Elapsed), slog.F("transitions", stats.Transitions))
129+
e.log.Debug(ctx, "run stats", slog.F("elapsed", stats.Elapsed), slog.F("transitions", stats.Transitions))
129130
}
130131
}
131-
}()
132+
})
132133
}
133134

134135
func (e *Executor) runOnce(t time.Time) Stats {

coderd/coderd.go

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,14 @@ import (
1414
"net/url"
1515
"path/filepath"
1616
"regexp"
17+
"runtime/pprof"
1718
"strings"
1819
"sync"
1920
"sync/atomic"
2021
"time"
2122

2223
"github.com/coder/coder/v2/coderd/oauth2provider"
24+
"github.com/coder/coder/v2/coderd/pproflabel"
2325
"github.com/coder/coder/v2/coderd/prebuilds"
2426
"github.com/coder/coder/v2/coderd/wsbuilder"
2527

@@ -852,6 +854,7 @@ func New(options *Options) *API {
852854

853855
r.Use(
854856
httpmw.Recover(api.Logger),
857+
httpmw.WithProfilingLabels,
855858
tracing.StatusWriterMiddleware,
856859
tracing.Middleware(api.TracerProvider),
857860
httpmw.AttachRequestID,
@@ -1339,7 +1342,13 @@ func New(options *Options) *API {
13391342
).Get("/connection", api.workspaceAgentConnectionGeneric)
13401343
r.Route("/me", func(r chi.Router) {
13411344
r.Use(workspaceAgentInfo)
1342-
r.Get("/rpc", api.workspaceAgentRPC)
1345+
r.Group(func(r chi.Router) {
1346+
r.Use(
1347+
// Override the request_type for agent rpc traffic.
1348+
httpmw.WithStaticProfilingLabels(pprof.Labels(pproflabel.RequestTypeTag, "agent-rpc")),
1349+
)
1350+
r.Get("/rpc", api.workspaceAgentRPC)
1351+
})
13431352
r.Patch("/logs", api.patchWorkspaceAgentLogs)
13441353
r.Patch("/app-status", api.patchWorkspaceAgentAppStatus)
13451354
// Deprecated: Required to support legacy agents
@@ -1415,7 +1424,8 @@ func New(options *Options) *API {
14151424
r.Get("/timings", api.workspaceTimings)
14161425
r.Route("/acl", func(r chi.Router) {
14171426
r.Use(
1418-
httpmw.RequireExperiment(api.Experiments, codersdk.ExperimentWorkspaceSharing))
1427+
httpmw.RequireExperiment(api.Experiments, codersdk.ExperimentWorkspaceSharing),
1428+
)
14191429

14201430
r.Patch("/", api.patchWorkspaceACL)
14211431
})

coderd/database/dbauthz/dbauthz.go

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1387,6 +1387,14 @@ func (q *querier) CountUnreadInboxNotificationsByUserID(ctx context.Context, use
13871387
return q.db.CountUnreadInboxNotificationsByUserID(ctx, userID)
13881388
}
13891389

1390+
func (q *querier) CreateUserSecret(ctx context.Context, arg database.CreateUserSecretParams) (database.UserSecret, error) {
1391+
obj := rbac.ResourceUserSecret.WithOwner(arg.UserID.String())
1392+
if err := q.authorizeContext(ctx, policy.ActionCreate, obj); err != nil {
1393+
return database.UserSecret{}, err
1394+
}
1395+
return q.db.CreateUserSecret(ctx, arg)
1396+
}
1397+
13901398
// TODO: Handle org scoped lookups
13911399
func (q *querier) CustomRoles(ctx context.Context, arg database.CustomRolesParams) ([]database.CustomRole, error) {
13921400
roleObject := rbac.ResourceAssignRole
@@ -1657,6 +1665,19 @@ func (q *querier) DeleteTailnetTunnel(ctx context.Context, arg database.DeleteTa
16571665
return q.db.DeleteTailnetTunnel(ctx, arg)
16581666
}
16591667

1668+
func (q *querier) DeleteUserSecret(ctx context.Context, id uuid.UUID) error {
1669+
// First get the secret to check ownership
1670+
secret, err := q.GetUserSecret(ctx, id)
1671+
if err != nil {
1672+
return err
1673+
}
1674+
1675+
if err := q.authorizeContext(ctx, policy.ActionDelete, secret); err != nil {
1676+
return err
1677+
}
1678+
return q.db.DeleteUserSecret(ctx, id)
1679+
}
1680+
16601681
func (q *querier) DeleteWebpushSubscriptionByUserIDAndEndpoint(ctx context.Context, arg database.DeleteWebpushSubscriptionByUserIDAndEndpointParams) error {
16611682
if err := q.authorizeContext(ctx, policy.ActionDelete, rbac.ResourceWebpushSubscription.WithOwner(arg.UserID.String())); err != nil {
16621683
return err
@@ -3075,6 +3096,28 @@ func (q *querier) GetUserNotificationPreferences(ctx context.Context, userID uui
30753096
return q.db.GetUserNotificationPreferences(ctx, userID)
30763097
}
30773098

3099+
func (q *querier) GetUserSecret(ctx context.Context, id uuid.UUID) (database.UserSecret, error) {
3100+
// First get the secret to check ownership
3101+
secret, err := q.db.GetUserSecret(ctx, id)
3102+
if err != nil {
3103+
return database.UserSecret{}, err
3104+
}
3105+
3106+
if err := q.authorizeContext(ctx, policy.ActionRead, secret); err != nil {
3107+
return database.UserSecret{}, err
3108+
}
3109+
return secret, nil
3110+
}
3111+
3112+
func (q *querier) GetUserSecretByUserIDAndName(ctx context.Context, arg database.GetUserSecretByUserIDAndNameParams) (database.UserSecret, error) {
3113+
obj := rbac.ResourceUserSecret.WithOwner(arg.UserID.String())
3114+
if err := q.authorizeContext(ctx, policy.ActionRead, obj); err != nil {
3115+
return database.UserSecret{}, err
3116+
}
3117+
3118+
return q.db.GetUserSecretByUserIDAndName(ctx, arg)
3119+
}
3120+
30783121
func (q *querier) GetUserStatusCounts(ctx context.Context, arg database.GetUserStatusCountsParams) ([]database.GetUserStatusCountsRow, error) {
30793122
if err := q.authorizeContext(ctx, policy.ActionRead, rbac.ResourceUser); err != nil {
30803123
return nil, err
@@ -4153,6 +4196,14 @@ func (q *querier) ListProvisionerKeysByOrganizationExcludeReserved(ctx context.C
41534196
return fetchWithPostFilter(q.auth, policy.ActionRead, q.db.ListProvisionerKeysByOrganizationExcludeReserved)(ctx, organizationID)
41544197
}
41554198

4199+
func (q *querier) ListUserSecrets(ctx context.Context, userID uuid.UUID) ([]database.UserSecret, error) {
4200+
obj := rbac.ResourceUserSecret.WithOwner(userID.String())
4201+
if err := q.authorizeContext(ctx, policy.ActionRead, obj); err != nil {
4202+
return nil, err
4203+
}
4204+
return q.db.ListUserSecrets(ctx, userID)
4205+
}
4206+
41564207
func (q *querier) ListWorkspaceAgentPortShares(ctx context.Context, workspaceID uuid.UUID) ([]database.WorkspaceAgentPortShare, error) {
41574208
workspace, err := q.db.GetWorkspaceByID(ctx, workspaceID)
41584209
if err != nil {
@@ -4866,6 +4917,19 @@ func (q *querier) UpdateUserRoles(ctx context.Context, arg database.UpdateUserRo
48664917
return q.db.UpdateUserRoles(ctx, arg)
48674918
}
48684919

4920+
func (q *querier) UpdateUserSecret(ctx context.Context, arg database.UpdateUserSecretParams) (database.UserSecret, error) {
4921+
// First get the secret to check ownership
4922+
secret, err := q.db.GetUserSecret(ctx, arg.ID)
4923+
if err != nil {
4924+
return database.UserSecret{}, err
4925+
}
4926+
4927+
if err := q.authorizeContext(ctx, policy.ActionUpdate, secret); err != nil {
4928+
return database.UserSecret{}, err
4929+
}
4930+
return q.db.UpdateUserSecret(ctx, arg)
4931+
}
4932+
48694933
func (q *querier) UpdateUserStatus(ctx context.Context, arg database.UpdateUserStatusParams) (database.User, error) {
48704934
fetch := func(ctx context.Context, arg database.UpdateUserStatusParams) (database.User, error) {
48714935
return q.db.GetUserByID(ctx, arg.ID)
@@ -5376,6 +5440,26 @@ func (q *querier) UpsertWorkspaceAppAuditSession(ctx context.Context, arg databa
53765440
return q.db.UpsertWorkspaceAppAuditSession(ctx, arg)
53775441
}
53785442

5443+
func (q *querier) ValidateGroupIDs(ctx context.Context, groupIDs []uuid.UUID) (database.ValidateGroupIDsRow, error) {
5444+
// This check is probably overly restrictive, but the "correct" check isn't
5445+
// necessarily obvious. It's only used as a verification check for ACLs right
5446+
// now, which are performed as system.
5447+
if err := q.authorizeContext(ctx, policy.ActionRead, rbac.ResourceSystem); err != nil {
5448+
return database.ValidateGroupIDsRow{}, err
5449+
}
5450+
return q.db.ValidateGroupIDs(ctx, groupIDs)
5451+
}
5452+
5453+
func (q *querier) ValidateUserIDs(ctx context.Context, userIDs []uuid.UUID) (database.ValidateUserIDsRow, error) {
5454+
// This check is probably overly restrictive, but the "correct" check isn't
5455+
// necessarily obvious. It's only used as a verification check for ACLs right
5456+
// now, which are performed as system.
5457+
if err := q.authorizeContext(ctx, policy.ActionRead, rbac.ResourceSystem); err != nil {
5458+
return database.ValidateUserIDsRow{}, err
5459+
}
5460+
return q.db.ValidateUserIDs(ctx, userIDs)
5461+
}
5462+
53795463
func (q *querier) GetAuthorizedTemplates(ctx context.Context, arg database.GetTemplatesWithFilterParams, _ rbac.PreparedAuthorized) ([]database.Template, error) {
53805464
// TODO Delete this function, all GetTemplates should be authorized. For now just call getTemplates on the authz querier.
53815465
return q.GetTemplatesWithFilter(ctx, arg)

0 commit comments

Comments
 (0)