Skip to content

Commit 956f3ec

Browse files
committed
chore: change max share level on existing port shares
1 parent b342bd7 commit 956f3ec

File tree

9 files changed

+232
-1
lines changed

9 files changed

+232
-1
lines changed

coderd/database/dbauthz/dbauthz.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -895,6 +895,19 @@ func (q *querier) DeleteWorkspaceAgentPortShare(ctx context.Context, arg databas
895895
return q.db.DeleteWorkspaceAgentPortShare(ctx, arg)
896896
}
897897

898+
func (q *querier) DeleteWorkspaceAgentPortSharesByTemplate(ctx context.Context, templateID uuid.UUID) error {
899+
template, err := q.db.GetTemplateByID(ctx, templateID)
900+
if err != nil {
901+
return err
902+
}
903+
904+
if err := q.authorizeContext(ctx, rbac.ActionUpdate, template); err != nil {
905+
return err
906+
}
907+
908+
return q.db.DeleteWorkspaceAgentPortSharesByTemplate(ctx, templateID)
909+
}
910+
898911
func (q *querier) FavoriteWorkspace(ctx context.Context, id uuid.UUID) error {
899912
fetch := func(ctx context.Context, id uuid.UUID) (database.Workspace, error) {
900913
return q.db.GetWorkspaceByID(ctx, id)
@@ -2538,6 +2551,19 @@ func (q *querier) ListWorkspaceAgentPortShares(ctx context.Context, workspaceID
25382551
return q.db.ListWorkspaceAgentPortShares(ctx, workspaceID)
25392552
}
25402553

2554+
func (q *querier) ReduceWorkspaceAgentShareLevelToAuthenticatedByTemplate(ctx context.Context, templateID uuid.UUID) error {
2555+
template, err := q.db.GetTemplateByID(ctx, templateID)
2556+
if err != nil {
2557+
return err
2558+
}
2559+
2560+
if err := q.authorizeContext(ctx, rbac.ActionUpdate, template); err != nil {
2561+
return err
2562+
}
2563+
2564+
return q.db.ReduceWorkspaceAgentShareLevelToAuthenticatedByTemplate(ctx, templateID)
2565+
}
2566+
25412567
func (q *querier) RegisterWorkspaceProxy(ctx context.Context, arg database.RegisterWorkspaceProxyParams) (database.WorkspaceProxy, error) {
25422568
fetch := func(ctx context.Context, arg database.RegisterWorkspaceProxyParams) (database.WorkspaceProxy, error) {
25432569
return q.db.GetWorkspaceProxyByID(ctx, arg.ID)

coderd/database/dbmem/dbmem.go

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1312,6 +1312,30 @@ func (q *FakeQuerier) DeleteWorkspaceAgentPortShare(_ context.Context, arg datab
13121312
return nil
13131313
}
13141314

1315+
func (q *FakeQuerier) DeleteWorkspaceAgentPortSharesByTemplate(ctx context.Context, templateID uuid.UUID) error {
1316+
err := validateDatabaseType(templateID)
1317+
if err != nil {
1318+
return err
1319+
}
1320+
1321+
q.mutex.Lock()
1322+
defer q.mutex.Unlock()
1323+
1324+
for _, workspace := range q.workspaces {
1325+
if workspace.TemplateID != templateID {
1326+
continue
1327+
}
1328+
for i, share := range q.workspaceAgentPortShares {
1329+
if share.WorkspaceID != workspace.ID {
1330+
continue
1331+
}
1332+
q.workspaceAgentPortShares = append(q.workspaceAgentPortShares[:i], q.workspaceAgentPortShares[i+1:]...)
1333+
}
1334+
}
1335+
1336+
return nil
1337+
}
1338+
13151339
func (q *FakeQuerier) FavoriteWorkspace(_ context.Context, arg uuid.UUID) error {
13161340
err := validateDatabaseType(arg)
13171341
if err != nil {
@@ -6047,6 +6071,33 @@ func (q *FakeQuerier) ListWorkspaceAgentPortShares(_ context.Context, workspaceI
60476071
return shares, nil
60486072
}
60496073

6074+
func (q *FakeQuerier) ReduceWorkspaceAgentShareLevelToAuthenticatedByTemplate(_ context.Context, templateID uuid.UUID) error {
6075+
err := validateDatabaseType(templateID)
6076+
if err != nil {
6077+
return err
6078+
}
6079+
6080+
q.mutex.Lock()
6081+
defer q.mutex.Unlock()
6082+
6083+
for _, workspace := range q.workspaces {
6084+
if workspace.TemplateID != templateID {
6085+
continue
6086+
}
6087+
for i, share := range q.workspaceAgentPortShares {
6088+
if share.WorkspaceID != workspace.ID {
6089+
continue
6090+
}
6091+
if share.ShareLevel == database.AppSharingLevelPublic {
6092+
share.ShareLevel = database.AppSharingLevelAuthenticated
6093+
}
6094+
q.workspaceAgentPortShares[i] = share
6095+
}
6096+
}
6097+
6098+
return nil
6099+
}
6100+
60506101
func (q *FakeQuerier) RegisterWorkspaceProxy(_ context.Context, arg database.RegisterWorkspaceProxyParams) (database.WorkspaceProxy, error) {
60516102
q.mutex.Lock()
60526103
defer q.mutex.Unlock()

coderd/database/dbmetrics/dbmetrics.go

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

coderd/database/dbmock/dbmock.go

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

coderd/database/querier.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/database/queries.sql.go

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

coderd/database/queries/workspaceagentportshare.sql

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,9 @@ DELETE FROM workspace_agent_port_share WHERE workspace_id = $1 AND agent_name =
1111
INSERT INTO workspace_agent_port_share (workspace_id, agent_name, port, share_level)
1212
VALUES ($1, $2, $3, $4)
1313
ON CONFLICT (workspace_id, agent_name, port) DO UPDATE SET share_level = $4 RETURNING *;
14+
15+
-- name: ReduceWorkspaceAgentShareLevelToAuthenticatedByTemplate :exec
16+
UPDATE workspace_agent_port_share SET share_level = 'authenticated' WHERE share_level = 'public' AND workspace_id IN (SELECT id FROM workspaces WHERE template_id = $1);
17+
18+
-- name: DeleteWorkspaceAgentPortSharesByTemplate :exec
19+
DELETE FROM workspace_agent_port_share WHERE workspace_id IN (SELECT id FROM workspaces WHERE template_id = $1);

coderd/templates.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -694,6 +694,21 @@ func (api *API) patchTemplateMeta(rw http.ResponseWriter, r *http.Request) {
694694
delete(groupACL, template.OrganizationID.String())
695695
}
696696

697+
if template.MaxPortSharingLevel != maxPortShareLevel {
698+
switch maxPortShareLevel {
699+
case database.AppSharingLevelOwner:
700+
err = tx.DeleteWorkspaceAgentPortSharesByTemplate(ctx, template.ID)
701+
if err != nil {
702+
return xerrors.Errorf("delete workspace agent port shares by template: %w", err)
703+
}
704+
case database.AppSharingLevelAuthenticated:
705+
err = tx.ReduceWorkspaceAgentShareLevelToAuthenticatedByTemplate(ctx, template.ID)
706+
if err != nil {
707+
return xerrors.Errorf("reduce workspace agent share level to authenticated by template: %w", err)
708+
}
709+
}
710+
}
711+
697712
var err error
698713
err = tx.UpdateTemplateMetaByID(ctx, database.UpdateTemplateMetaByIDParams{
699714
ID: template.ID,

enterprise/coderd/templates_test.go

Lines changed: 72 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222
"github.com/coder/coder/v2/enterprise/coderd/license"
2323
"github.com/coder/coder/v2/enterprise/coderd/schedule"
2424
"github.com/coder/coder/v2/provisioner/echo"
25+
"github.com/coder/coder/v2/provisionersdk/proto"
2526
"github.com/coder/coder/v2/testutil"
2627
)
2728

@@ -143,9 +144,12 @@ func TestTemplates(t *testing.T) {
143144
t.Run("MaxPortShareLevel", func(t *testing.T) {
144145
t.Parallel()
145146

147+
cfg := coderdtest.DeploymentValues(t)
148+
cfg.Experiments = []string{"shared-ports"}
146149
owner, user := coderdenttest.New(t, &coderdenttest.Options{
147150
Options: &coderdtest.Options{
148151
IncludeProvisionerDaemon: true,
152+
DeploymentValues: cfg,
149153
},
150154
LicenseOptions: &coderdenttest.LicenseOptions{
151155
Features: license.Features{
@@ -154,9 +158,43 @@ func TestTemplates(t *testing.T) {
154158
},
155159
})
156160
client, _ := coderdtest.CreateAnotherUser(t, owner, user.OrganizationID, rbac.RoleTemplateAdmin())
157-
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
161+
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{
162+
Parse: echo.ParseComplete,
163+
ProvisionPlan: echo.PlanComplete,
164+
ProvisionApply: []*proto.Response{{
165+
Type: &proto.Response_Log{
166+
Log: &proto.Log{
167+
Level: proto.LogLevel_INFO,
168+
Output: "example",
169+
},
170+
},
171+
}, {
172+
Type: &proto.Response_Apply{
173+
Apply: &proto.ApplyComplete{
174+
Resources: []*proto.Resource{{
175+
Name: "some",
176+
Type: "example",
177+
Agents: []*proto.Agent{{
178+
Id: "something",
179+
Auth: &proto.Agent_Token{
180+
Token: uuid.NewString(),
181+
},
182+
Name: "test",
183+
}},
184+
}, {
185+
Name: "another",
186+
Type: "example",
187+
}},
188+
},
189+
},
190+
}},
191+
})
158192
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
159193
coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID)
194+
ws := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID)
195+
coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, ws.LatestBuild.ID)
196+
ws, err := client.Workspace(context.Background(), ws.ID)
197+
require.NoError(t, err)
160198

161199
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
162200
defer cancel()
@@ -175,6 +213,39 @@ func TestTemplates(t *testing.T) {
175213
MaxPortShareLevel: &level,
176214
})
177215
require.ErrorContains(t, err, "invalid max port sharing level")
216+
217+
// Create public port share
218+
_, err = client.UpsertWorkspaceAgentPortShare(ctx, ws.ID, codersdk.UpsertWorkspaceAgentPortShareRequest{
219+
AgentName: ws.LatestBuild.Resources[0].Agents[0].Name,
220+
Port: 8080,
221+
ShareLevel: codersdk.WorkspaceAgentPortShareLevelPublic,
222+
})
223+
require.NoError(t, err)
224+
225+
// Reduce max level to authenticated
226+
level = codersdk.WorkspaceAgentPortShareLevelAuthenticated
227+
_, err = client.UpdateTemplateMeta(ctx, template.ID, codersdk.UpdateTemplateMeta{
228+
MaxPortShareLevel: &level,
229+
})
230+
require.NoError(t, err)
231+
232+
// Ensure previously public port is now authenticated
233+
wpsr, err := client.GetWorkspaceAgentPortShares(ctx, ws.ID)
234+
require.NoError(t, err)
235+
require.Len(t, wpsr.Shares, 1)
236+
assert.Equal(t, codersdk.WorkspaceAgentPortShareLevelAuthenticated, wpsr.Shares[0].ShareLevel)
237+
238+
// reduce max level to owner
239+
level = codersdk.WorkspaceAgentPortShareLevelOwner
240+
_, err = client.UpdateTemplateMeta(ctx, template.ID, codersdk.UpdateTemplateMeta{
241+
MaxPortShareLevel: &level,
242+
})
243+
require.NoError(t, err)
244+
245+
// Ensure previously authenticated port is removed
246+
wpsr, err = client.GetWorkspaceAgentPortShares(ctx, ws.ID)
247+
require.NoError(t, err)
248+
require.Empty(t, wpsr.Shares)
178249
})
179250

180251
t.Run("BlockDisablingAutoOffWithMaxTTL", func(t *testing.T) {

0 commit comments

Comments
 (0)