Skip to content

Commit 338e300

Browse files
committed
Jobs, orgs, and extra methods implemented
1 parent d3affdc commit 338e300

File tree

5 files changed

+179
-18
lines changed

5 files changed

+179
-18
lines changed

coderd/authzquery/job.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,21 @@ func (q *AuthzQuerier) GetProvisionerJobByID(ctx context.Context, id uuid.UUID)
106106
return job, nil
107107
}
108108

109+
func (q *AuthzQuerier) GetProvisionerJobsByIDs(ctx context.Context, ids []uuid.UUID) ([]database.ProvisionerJob, error) {
110+
// TODO: This is missing authorization and is incorrect. This call is used by telemetry, and by 1 http route.
111+
// That http handler should find a better way to fetch these jobs with easier rbac authz.
112+
return q.database.GetProvisionerJobsByIDs(ctx, ids)
113+
}
114+
115+
func (q *AuthzQuerier) GetProvisionerLogsByIDBetween(ctx context.Context, arg database.GetProvisionerLogsByIDBetweenParams) ([]database.ProvisionerJobLog, error) {
116+
// Authorized read on job lets the actor also read the logs.
117+
_, err := q.GetProvisionerJobByID(ctx, arg.JobID)
118+
if err != nil {
119+
return nil, err
120+
}
121+
return q.database.GetProvisionerLogsByIDBetween(ctx, arg)
122+
}
123+
109124
func authorizedTemplateVersionFromJob(ctx context.Context, q *AuthzQuerier, job database.ProvisionerJob) (database.TemplateVersion, error) {
110125
switch job.Type {
111126
case database.ProvisionerJobTypeTemplateVersionDryRun:

coderd/authzquery/job_test.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,4 +91,23 @@ func (suite *MethodTestSuite) TestProvsionerJob() {
9191
asserts(v.RBACObject(tpl), []rbac.Action{rbac.ActionRead, rbac.ActionUpdate}))
9292
})
9393
})
94+
suite.Run("GetProvisionerJobsByIDs", func() {
95+
suite.RunMethodTest(func(t *testing.T, db database.Store) MethodCase {
96+
a := dbgen.ProvisionerJob(t, db, database.ProvisionerJob{})
97+
b := dbgen.ProvisionerJob(t, db, database.ProvisionerJob{})
98+
return methodCase(inputs([]uuid.UUID{a.ID, b.ID}), asserts())
99+
})
100+
})
101+
suite.Run("GetProvisionerLogsByIDBetween", func() {
102+
suite.RunMethodTest(func(t *testing.T, db database.Store) MethodCase {
103+
w := dbgen.Workspace(t, db, database.Workspace{})
104+
j := dbgen.ProvisionerJob(t, db, database.ProvisionerJob{
105+
Type: database.ProvisionerJobTypeWorkspaceBuild,
106+
})
107+
_ = dbgen.WorkspaceBuild(t, db, database.WorkspaceBuild{JobID: j.ID, WorkspaceID: w.ID})
108+
return methodCase(inputs(database.GetProvisionerLogsByIDBetweenParams{
109+
JobID: j.ID,
110+
}), asserts(w, rbac.ActionRead))
111+
})
112+
})
94113
}

coderd/authzquery/methods.go

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@ package authzquery
55
import (
66
"context"
77

8-
"github.com/google/uuid"
9-
108
"github.com/coder/coder/coderd/database"
119
"github.com/coder/coder/coderd/rbac"
1210
)
@@ -18,21 +16,6 @@ func (q *AuthzQuerier) GetProvisionerDaemons(ctx context.Context) ([]database.Pr
1816
return authorizedFetchSet(q.authorizer, fetch)(ctx, nil)
1917
}
2018

21-
func (q *AuthzQuerier) GetProvisionerJobsByIDs(ctx context.Context, ids []uuid.UUID) ([]database.ProvisionerJob, error) {
22-
// TODO: This is missing authorization and is incorrect. This call is used by telemetry, and by 1 http route.
23-
// That http handler should find a better way to fetch these jobs with easier rbac authz.
24-
return q.database.GetProvisionerJobsByIDs(ctx, ids)
25-
}
26-
27-
func (q *AuthzQuerier) GetProvisionerLogsByIDBetween(ctx context.Context, arg database.GetProvisionerLogsByIDBetweenParams) ([]database.ProvisionerJobLog, error) {
28-
// Authorized read on job lets the actor also read the logs.
29-
_, err := q.GetProvisionerJobByID(ctx, arg.JobID)
30-
if err != nil {
31-
return nil, err
32-
}
33-
return q.database.GetProvisionerLogsByIDBetween(ctx, arg)
34-
}
35-
3619
func (q *AuthzQuerier) GetDeploymentDAUs(ctx context.Context) ([]database.GetDeploymentDAUsRow, error) {
3720
if err := q.authorizeContext(ctx, rbac.ActionRead, rbac.ResourceUser.All()); err != nil {
3821
return nil, err

coderd/authzquery/methods_test.go

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ func (s *MethodTestSuite) RunMethodTest(testCaseF func(t *testing.T, db database
100100
az := authzquery.NewAuthzQuerier(db, rec, slog.Make())
101101
actor := rbac.Subject{
102102
ID: uuid.NewString(),
103-
Roles: rbac.RoleNames{},
103+
Roles: rbac.RoleNames{rbac.RoleOwner()},
104104
Groups: []string{},
105105
Scope: rbac.ScopeAll,
106106
}
@@ -255,3 +255,20 @@ func asserts(inputs ...any) []AssertRBAC {
255255
}
256256
return out
257257
}
258+
259+
func (suite *MethodTestSuite) TestExtraMethods() {
260+
suite.Run("GetProvisionerDaemons", func() {
261+
suite.RunMethodTest(func(t *testing.T, db database.Store) MethodCase {
262+
d, err := db.InsertProvisionerDaemon(context.Background(), database.InsertProvisionerDaemonParams{
263+
ID: uuid.New(),
264+
})
265+
require.NoError(t, err, "insert provisioner daemon")
266+
return methodCase(inputs(), asserts(d, rbac.ActionRead))
267+
})
268+
})
269+
suite.Run("GetDeploymentDAUs", func() {
270+
suite.RunMethodTest(func(t *testing.T, db database.Store) MethodCase {
271+
return methodCase(inputs(), asserts(rbac.ResourceUser.All(), rbac.ActionRead))
272+
})
273+
})
274+
}
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
package authzquery_test
2+
3+
import (
4+
"testing"
5+
6+
"github.com/google/uuid"
7+
8+
"github.com/coder/coder/coderd/database"
9+
"github.com/coder/coder/coderd/database/dbgen"
10+
"github.com/coder/coder/coderd/rbac"
11+
)
12+
13+
func (suite *MethodTestSuite) TestOrganization() {
14+
suite.Run("GetGroupsByOrganizationID", func() {
15+
suite.RunMethodTest(func(t *testing.T, db database.Store) MethodCase {
16+
o := dbgen.Organization(t, db, database.Organization{})
17+
a := dbgen.Group(t, db, database.Group{OrganizationID: o.ID})
18+
b := dbgen.Group(t, db, database.Group{OrganizationID: o.ID})
19+
return methodCase(inputs(o.ID), asserts(a, rbac.ActionRead, b, rbac.ActionRead))
20+
})
21+
})
22+
suite.Run("GetOrganizationByID", func() {
23+
suite.RunMethodTest(func(t *testing.T, db database.Store) MethodCase {
24+
o := dbgen.Organization(t, db, database.Organization{})
25+
return methodCase(inputs(o.ID), asserts(o, rbac.ActionRead))
26+
})
27+
})
28+
suite.Run("GetOrganizationByName", func() {
29+
suite.RunMethodTest(func(t *testing.T, db database.Store) MethodCase {
30+
o := dbgen.Organization(t, db, database.Organization{})
31+
return methodCase(inputs(o.Name), asserts(o, rbac.ActionRead))
32+
})
33+
})
34+
suite.Run("GetOrganizationIDsByMemberIDs", func() {
35+
suite.RunMethodTest(func(t *testing.T, db database.Store) MethodCase {
36+
o := dbgen.Organization(t, db, database.Organization{})
37+
u := dbgen.User(t, db, database.User{})
38+
var _ = o.ID
39+
// TODO: Implement this and do rbac check
40+
//mem := dbgen.OrganizationMember(t, db, database.OrganizationMember{OrganizationID: o.ID, UserID: u.ID})
41+
return methodCase(inputs([]uuid.UUID{u.ID}), asserts())
42+
})
43+
})
44+
suite.Run("GetOrganizationMemberByUserID", func() {
45+
suite.RunMethodTest(func(t *testing.T, db database.Store) MethodCase {
46+
o := dbgen.Organization(t, db, database.Organization{})
47+
u := dbgen.User(t, db, database.User{})
48+
// TODO: Implement this and do rbac check
49+
//mem := dbgen.OrganizationMember(t, db, database.OrganizationMember{OrganizationID: o.ID, UserID: u.ID})
50+
return methodCase(inputs(database.GetOrganizationMemberByUserIDParams{
51+
OrganizationID: o.ID,
52+
UserID: u.ID,
53+
}), asserts())
54+
})
55+
})
56+
suite.Run("GetOrganizationMembershipsByUserID", func() {
57+
suite.RunMethodTest(func(t *testing.T, db database.Store) MethodCase {
58+
o := dbgen.Organization(t, db, database.Organization{})
59+
u := dbgen.User(t, db, database.User{})
60+
var _ = o.ID
61+
// TODO: Implement this and do rbac check
62+
//mem := dbgen.OrganizationMember(t, db, database.OrganizationMember{OrganizationID: o.ID, UserID: u.ID})
63+
return methodCase(inputs(u.ID), asserts())
64+
})
65+
})
66+
suite.Run("GetOrganizations", func() {
67+
suite.RunMethodTest(func(t *testing.T, db database.Store) MethodCase {
68+
a := dbgen.Organization(t, db, database.Organization{})
69+
b := dbgen.Organization(t, db, database.Organization{})
70+
return methodCase(inputs(), asserts(a, rbac.ActionRead, b, rbac.ActionRead))
71+
})
72+
})
73+
suite.Run("GetOrganizationsByUserID", func() {
74+
suite.RunMethodTest(func(t *testing.T, db database.Store) MethodCase {
75+
o := dbgen.Organization(t, db, database.Organization{})
76+
u := dbgen.User(t, db, database.User{})
77+
var _ = o.ID
78+
// TODO: Implement this and do rbac check
79+
//mem := dbgen.OrganizationMember(t, db, database.OrganizationMember{OrganizationID: o.ID, UserID: u.ID})
80+
return methodCase(inputs(u.ID), asserts(u, rbac.ActionRead))
81+
})
82+
})
83+
suite.Run("InsertOrganization", func() {
84+
suite.RunMethodTest(func(t *testing.T, db database.Store) MethodCase {
85+
return methodCase(inputs(database.InsertOrganizationParams{
86+
ID: uuid.New(),
87+
Name: "random",
88+
}), asserts(rbac.ResourceOrganization, rbac.ActionCreate))
89+
})
90+
})
91+
suite.Run("InsertOrganizationMember", func() {
92+
suite.RunMethodTest(func(t *testing.T, db database.Store) MethodCase {
93+
o := dbgen.Organization(t, db, database.Organization{})
94+
u := dbgen.User(t, db, database.User{})
95+
96+
return methodCase(inputs(database.InsertOrganizationMemberParams{
97+
OrganizationID: o.ID,
98+
UserID: u.ID,
99+
Roles: []string{rbac.RoleOrgAdmin(o.ID)},
100+
}), asserts(
101+
rbac.ResourceRoleAssignment.InOrg(o.ID), rbac.ActionCreate,
102+
rbac.ResourceOrganizationMember.InOrg(o.ID).WithID(u.ID), rbac.ActionCreate),
103+
)
104+
})
105+
})
106+
suite.Run("UpdateMemberRoles", func() {
107+
suite.RunMethodTest(func(t *testing.T, db database.Store) MethodCase {
108+
o := dbgen.Organization(t, db, database.Organization{})
109+
u := dbgen.User(t, db, database.User{})
110+
// TODO: Implement this and do rbac check
111+
//mem := dbgen.OrganizationMember(t, db, database.OrganizationMember{
112+
// OrganizationID: o.ID,
113+
// UserID: u.ID,
114+
// Roles: []string{rbac.RoleOrgAdmin(o.ID)},
115+
//})
116+
117+
return methodCase(inputs(database.UpdateMemberRolesParams{
118+
GrantedRoles: []string{},
119+
UserID: u.ID,
120+
OrgID: o.ID,
121+
}), asserts(
122+
rbac.ResourceRoleAssignment.InOrg(o.ID), rbac.ActionDelete,
123+
rbac.ResourceOrganizationMember.InOrg(o.ID).WithID(u.ID), rbac.ActionCreate,
124+
))
125+
})
126+
})
127+
}

0 commit comments

Comments
 (0)