Skip to content

Commit c04d045

Browse files
authored
feat: RBAC provisionerdaemons and parameters (coder#1755)
* chore: Remove org_id from provisionerdaemons
1 parent 104d07f commit c04d045

18 files changed

+184
-63
lines changed

coderd/coderd.go

+8-2
Original file line numberDiff line numberDiff line change
@@ -131,14 +131,20 @@ func New(options *Options) *API {
131131
r.Get("/{hash}", api.fileByHash)
132132
r.Post("/", api.postFile)
133133
})
134+
r.Route("/provisionerdaemons", func(r chi.Router) {
135+
r.Use(
136+
apiKeyMiddleware,
137+
authRolesMiddleware,
138+
)
139+
r.Get("/", api.provisionerDaemons)
140+
})
134141
r.Route("/organizations/{organization}", func(r chi.Router) {
135142
r.Use(
136143
apiKeyMiddleware,
137144
httpmw.ExtractOrganizationParam(options.Database),
138145
authRolesMiddleware,
139146
)
140147
r.Get("/", api.organization)
141-
r.Get("/provisionerdaemons", api.provisionerDaemonsByOrganization)
142148
r.Post("/templateversions", api.postTemplateVersionsByOrganization)
143149
r.Route("/templates", func(r chi.Router) {
144150
r.Post("/", api.postTemplateByOrganization)
@@ -166,7 +172,7 @@ func New(options *Options) *API {
166172
})
167173
})
168174
r.Route("/parameters/{scope}/{id}", func(r chi.Router) {
169-
r.Use(apiKeyMiddleware)
175+
r.Use(apiKeyMiddleware, authRolesMiddleware)
170176
r.Post("/", api.postParameter)
171177
r.Get("/", api.parameters)
172178
r.Route("/{name}", func(r chi.Router) {

coderd/coderd_test.go

+51-13
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"net/http"
77
"strings"
88
"testing"
9+
"time"
910

1011
"github.com/go-chi/chi/v5"
1112
"github.com/stretchr/testify/assert"
@@ -45,9 +46,29 @@ func TestAuthorizeAllEndpoints(t *testing.T) {
4546
IncludeProvisionerD: true,
4647
})
4748
admin := coderdtest.CreateFirstUser(t, client)
48-
organization, err := client.Organization(context.Background(), admin.OrganizationID)
49+
// The provisioner will call to coderd and register itself. This is async,
50+
// so we wait for it to occur.
51+
require.Eventually(t, func() bool {
52+
provisionerds, err := client.ProvisionerDaemons(ctx)
53+
require.NoError(t, err)
54+
return len(provisionerds) > 0
55+
}, time.Second*10, time.Second)
56+
57+
provisionerds, err := client.ProvisionerDaemons(ctx)
58+
require.NoError(t, err, "fetch provisioners")
59+
require.Len(t, provisionerds, 1)
60+
61+
organization, err := client.Organization(ctx, admin.OrganizationID)
4962
require.NoError(t, err, "fetch org")
5063

64+
organizationParam, err := client.CreateParameter(ctx, codersdk.ParameterOrganization, organization.ID, codersdk.CreateParameterRequest{
65+
Name: "test-param",
66+
SourceValue: "hello world",
67+
SourceScheme: codersdk.ParameterSourceSchemeData,
68+
DestinationScheme: codersdk.ParameterDestinationSchemeProvisionerVariable,
69+
})
70+
require.NoError(t, err, "create org param")
71+
5172
// Setup some data in the database.
5273
version := coderdtest.CreateTemplateVersion(t, client, admin.OrganizationID, &echo.Responses{
5374
Parse: echo.ParseComplete,
@@ -118,18 +139,10 @@ func TestAuthorizeAllEndpoints(t *testing.T) {
118139
"GET:/api/v2/workspaceagents/{workspaceagent}/turn": {NoAuthorize: true},
119140

120141
// TODO: @emyrk these need to be fixed by adding authorize calls
121-
"GET:/api/v2/organizations/{organization}/provisionerdaemons": {NoAuthorize: true},
122-
"GET:/api/v2/organizations/{organization}/templates/{templatename}": {NoAuthorize: true},
123-
"POST:/api/v2/organizations/{organization}/templateversions": {NoAuthorize: true},
124-
"POST:/api/v2/organizations/{organization}/workspaces": {NoAuthorize: true},
125-
126-
"POST:/api/v2/parameters/{scope}/{id}": {NoAuthorize: true},
127-
"GET:/api/v2/parameters/{scope}/{id}": {NoAuthorize: true},
128-
"DELETE:/api/v2/parameters/{scope}/{id}/{name}": {NoAuthorize: true},
129-
130-
"POST:/api/v2/users/{user}/organizations": {NoAuthorize: true},
131-
132-
"GET:/api/v2/workspaces/{workspace}/watch": {NoAuthorize: true},
142+
"POST:/api/v2/organizations/{organization}/workspaces": {NoAuthorize: true},
143+
"POST:/api/v2/users/{user}/organizations": {NoAuthorize: true},
144+
"GET:/api/v2/workspaces/{workspace}/watch": {NoAuthorize: true},
145+
"POST:/api/v2/organizations/{organization}/templateversions": {NoAuthorize: true},
133146

134147
// These endpoints have more assertions. This is good, add more endpoints to assert if you can!
135148
"GET:/api/v2/organizations/{organization}": {AssertObject: rbac.ResourceOrganization.InOrg(admin.OrganizationID)},
@@ -251,6 +264,27 @@ func TestAuthorizeAllEndpoints(t *testing.T) {
251264
AssertAction: rbac.ActionRead,
252265
AssertObject: rbac.ResourceTemplate.InOrg(template.OrganizationID).WithID(template.ID.String()),
253266
},
267+
"GET:/api/v2/provisionerdaemons": {
268+
StatusCode: http.StatusOK,
269+
AssertObject: rbac.ResourceProvisionerDaemon.WithID(provisionerds[0].ID.String()),
270+
},
271+
272+
"POST:/api/v2/parameters/{scope}/{id}": {
273+
AssertAction: rbac.ActionUpdate,
274+
AssertObject: rbac.ResourceOrganization.WithID(organization.ID.String()),
275+
},
276+
"GET:/api/v2/parameters/{scope}/{id}": {
277+
AssertAction: rbac.ActionRead,
278+
AssertObject: rbac.ResourceOrganization.WithID(organization.ID.String()),
279+
},
280+
"DELETE:/api/v2/parameters/{scope}/{id}/{name}": {
281+
AssertAction: rbac.ActionUpdate,
282+
AssertObject: rbac.ResourceOrganization.WithID(organization.ID.String()),
283+
},
284+
"GET:/api/v2/organizations/{organization}/templates/{templatename}": {
285+
AssertAction: rbac.ActionRead,
286+
AssertObject: rbac.ResourceTemplate.InOrg(template.OrganizationID).WithID(template.ID.String()),
287+
},
254288

255289
// These endpoints need payloads to get to the auth part. Payloads will be required
256290
"PUT:/api/v2/users/{user}/roles": {StatusCode: http.StatusBadRequest, NoAuthorize: true},
@@ -292,6 +326,10 @@ func TestAuthorizeAllEndpoints(t *testing.T) {
292326
route = strings.ReplaceAll(route, "{hash}", file.Hash)
293327
route = strings.ReplaceAll(route, "{workspaceresource}", workspaceResources[0].ID.String())
294328
route = strings.ReplaceAll(route, "{templateversion}", version.ID.String())
329+
route = strings.ReplaceAll(route, "{templatename}", template.Name)
330+
// Only checking org scoped params here
331+
route = strings.ReplaceAll(route, "{scope}", string(organizationParam.Scope))
332+
route = strings.ReplaceAll(route, "{id}", organizationParam.ScopeID.String())
295333

296334
resp, err := client.Request(context.Background(), method, route, nil)
297335
require.NoError(t, err, "do req")

coderd/database/databasefake/databasefake.go

+4-5
Original file line numberDiff line numberDiff line change
@@ -1283,11 +1283,10 @@ func (q *fakeQuerier) InsertProvisionerDaemon(_ context.Context, arg database.In
12831283
defer q.mutex.Unlock()
12841284

12851285
daemon := database.ProvisionerDaemon{
1286-
ID: arg.ID,
1287-
CreatedAt: arg.CreatedAt,
1288-
OrganizationID: arg.OrganizationID,
1289-
Name: arg.Name,
1290-
Provisioners: arg.Provisioners,
1286+
ID: arg.ID,
1287+
CreatedAt: arg.CreatedAt,
1288+
Name: arg.Name,
1289+
Provisioners: arg.Provisioners,
12911290
}
12921291
q.provisionerDaemons = append(q.provisionerDaemons, daemon)
12931292
return daemon, nil

coderd/database/dump.sql

-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
ALTER TABLE provisioner_daemons ADD COLUMN organization_id uuid;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
ALTER TABLE provisioner_daemons DROP COLUMN organization_id;

coderd/database/modelmethods.go

+4
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,7 @@ func (m OrganizationMember) RBACObject() rbac.Object {
2222
func (o Organization) RBACObject() rbac.Object {
2323
return rbac.ResourceOrganization.InOrg(o.ID).WithID(o.ID.String())
2424
}
25+
26+
func (d ProvisionerDaemon) RBACObject() rbac.Object {
27+
return rbac.ResourceProvisionerDaemon.WithID(d.ID.String())
28+
}

coderd/database/models.go

+5-6
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/database/queries.sql.go

+7-13
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/database/queries/provisionerdaemons.sql

+1-2
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,11 @@ INSERT INTO
1717
provisioner_daemons (
1818
id,
1919
created_at,
20-
organization_id,
2120
"name",
2221
provisioners
2322
)
2423
VALUES
25-
($1, $2, $3, $4, $5) RETURNING *;
24+
($1, $2, $3, $4) RETURNING *;
2625

2726
-- name: UpdateProvisionerDaemonByID :exec
2827
UPDATE

0 commit comments

Comments
 (0)