Skip to content

Commit 4724f79

Browse files
committed
claude be doing something certainly
1 parent 232c72f commit 4724f79

File tree

14 files changed

+409
-17
lines changed

14 files changed

+409
-17
lines changed

coderd/apidoc/docs.go

Lines changed: 4 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: 4 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/database/dump.sql

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
-- Remove 'organization' from the app_sharing_level enum
2+
3+
-- Drop the view that depends on the templates table
4+
DROP VIEW template_with_names;
5+
6+
CREATE TYPE new_app_sharing_level AS ENUM (
7+
'owner',
8+
'authenticated',
9+
'public'
10+
);
11+
12+
-- Update workspace_agent_port_share table to use old enum
13+
-- Convert any 'organization' values to 'authenticated' during downgrade
14+
ALTER TABLE workspace_agent_port_share
15+
ALTER COLUMN share_level TYPE new_app_sharing_level USING (
16+
CASE
17+
WHEN share_level = 'organization' THEN 'authenticated'::new_app_sharing_level
18+
ELSE share_level::text::new_app_sharing_level
19+
END
20+
);
21+
22+
-- Update workspace_apps table to use old enum
23+
-- Convert any 'organization' values to 'authenticated' during downgrade
24+
ALTER TABLE workspace_apps
25+
ALTER COLUMN sharing_level DROP DEFAULT,
26+
ALTER COLUMN sharing_level TYPE new_app_sharing_level USING (
27+
CASE
28+
WHEN sharing_level = 'organization' THEN 'authenticated'::new_app_sharing_level
29+
ELSE sharing_level::text::new_app_sharing_level
30+
END
31+
),
32+
ALTER COLUMN sharing_level SET DEFAULT 'owner'::new_app_sharing_level;
33+
34+
-- Update templates table to use old enum
35+
-- Convert any 'organization' values to 'authenticated' during downgrade
36+
ALTER TABLE templates
37+
ALTER COLUMN max_port_sharing_level DROP DEFAULT,
38+
ALTER COLUMN max_port_sharing_level TYPE new_app_sharing_level USING (
39+
CASE
40+
WHEN max_port_sharing_level = 'organization' THEN 'authenticated'::new_app_sharing_level
41+
ELSE max_port_sharing_level::text::new_app_sharing_level
42+
END
43+
),
44+
ALTER COLUMN max_port_sharing_level SET DEFAULT 'owner'::new_app_sharing_level;
45+
46+
-- Drop old enum and rename new one
47+
DROP TYPE app_sharing_level;
48+
ALTER TYPE new_app_sharing_level RENAME TO app_sharing_level;
49+
50+
-- Recreate the template_with_names view
51+
CREATE VIEW template_with_names AS
52+
SELECT
53+
templates.id,
54+
templates.created_at,
55+
templates.updated_at,
56+
templates.organization_id,
57+
templates.deleted,
58+
templates.name,
59+
templates.provisioner,
60+
templates.active_version_id,
61+
templates.description,
62+
templates.default_ttl,
63+
templates.created_by,
64+
templates.icon,
65+
templates.user_acl,
66+
templates.group_acl,
67+
templates.display_name,
68+
templates.allow_user_cancel_workspace_jobs,
69+
templates.allow_user_autostart,
70+
templates.allow_user_autostop,
71+
templates.failure_ttl,
72+
templates.time_til_dormant,
73+
templates.time_til_dormant_autodelete,
74+
templates.autostop_requirement_days_of_week,
75+
templates.autostop_requirement_weeks,
76+
templates.autostart_block_days_of_week,
77+
templates.require_active_version,
78+
templates.deprecated,
79+
templates.activity_bump,
80+
templates.max_port_sharing_level,
81+
templates.use_classic_parameter_flow,
82+
COALESCE(
83+
visible_users.avatar_url,
84+
''::text
85+
) AS created_by_avatar_url,
86+
COALESCE(
87+
visible_users.username,
88+
''::text
89+
) AS created_by_username,
90+
COALESCE(visible_users.name, ''::text) AS created_by_name,
91+
COALESCE(organizations.name, ''::text) AS organization_name,
92+
COALESCE(
93+
organizations.display_name,
94+
''::text
95+
) AS organization_display_name,
96+
COALESCE(organizations.icon, ''::text) AS organization_icon
97+
FROM (
98+
(
99+
templates
100+
LEFT JOIN visible_users ON (
101+
(
102+
templates.created_by = visible_users.id
103+
)
104+
)
105+
)
106+
LEFT JOIN organizations ON (
107+
(
108+
templates.organization_id = organizations.id
109+
)
110+
)
111+
);
112+
113+
COMMENT ON VIEW template_with_names IS 'Joins in the display name information such as username, avatar, and organization name.';
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
-- Add 'organization' to the app_sharing_level enum
2+
3+
-- Drop the view that depends on the templates table
4+
DROP VIEW template_with_names;
5+
6+
CREATE TYPE new_app_sharing_level AS ENUM (
7+
'owner',
8+
'authenticated',
9+
'organization',
10+
'public'
11+
);
12+
13+
-- Update workspace_agent_port_share table to use new enum
14+
ALTER TABLE workspace_agent_port_share
15+
ALTER COLUMN share_level TYPE new_app_sharing_level USING (share_level::text::new_app_sharing_level);
16+
17+
-- Update workspace_apps table to use new enum
18+
ALTER TABLE workspace_apps
19+
ALTER COLUMN sharing_level DROP DEFAULT,
20+
ALTER COLUMN sharing_level TYPE new_app_sharing_level USING (sharing_level::text::new_app_sharing_level),
21+
ALTER COLUMN sharing_level SET DEFAULT 'owner'::new_app_sharing_level;
22+
23+
-- Update templates table to use new enum
24+
ALTER TABLE templates
25+
ALTER COLUMN max_port_sharing_level DROP DEFAULT,
26+
ALTER COLUMN max_port_sharing_level TYPE new_app_sharing_level USING (max_port_sharing_level::text::new_app_sharing_level),
27+
ALTER COLUMN max_port_sharing_level SET DEFAULT 'owner'::new_app_sharing_level;
28+
29+
-- Drop old enum and rename new one
30+
DROP TYPE app_sharing_level;
31+
ALTER TYPE new_app_sharing_level RENAME TO app_sharing_level;
32+
33+
-- Recreate the template_with_names view
34+
CREATE VIEW template_with_names AS
35+
SELECT
36+
templates.id,
37+
templates.created_at,
38+
templates.updated_at,
39+
templates.organization_id,
40+
templates.deleted,
41+
templates.name,
42+
templates.provisioner,
43+
templates.active_version_id,
44+
templates.description,
45+
templates.default_ttl,
46+
templates.created_by,
47+
templates.icon,
48+
templates.user_acl,
49+
templates.group_acl,
50+
templates.display_name,
51+
templates.allow_user_cancel_workspace_jobs,
52+
templates.allow_user_autostart,
53+
templates.allow_user_autostop,
54+
templates.failure_ttl,
55+
templates.time_til_dormant,
56+
templates.time_til_dormant_autodelete,
57+
templates.autostop_requirement_days_of_week,
58+
templates.autostop_requirement_weeks,
59+
templates.autostart_block_days_of_week,
60+
templates.require_active_version,
61+
templates.deprecated,
62+
templates.activity_bump,
63+
templates.max_port_sharing_level,
64+
templates.use_classic_parameter_flow,
65+
COALESCE(
66+
visible_users.avatar_url,
67+
''::text
68+
) AS created_by_avatar_url,
69+
COALESCE(
70+
visible_users.username,
71+
''::text
72+
) AS created_by_username,
73+
COALESCE(visible_users.name, ''::text) AS created_by_name,
74+
COALESCE(organizations.name, ''::text) AS organization_name,
75+
COALESCE(
76+
organizations.display_name,
77+
''::text
78+
) AS organization_display_name,
79+
COALESCE(organizations.icon, ''::text) AS organization_icon
80+
FROM (
81+
(
82+
templates
83+
LEFT JOIN visible_users ON (
84+
(
85+
templates.created_by = visible_users.id
86+
)
87+
)
88+
)
89+
LEFT JOIN organizations ON (
90+
(
91+
templates.organization_id = organizations.id
92+
)
93+
)
94+
);
95+
96+
COMMENT ON VIEW template_with_names IS 'Joins in the display name information such as username, avatar, and organization name.';

coderd/database/models.go

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

coderd/workspaceapps/db.go

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,32 @@ func (p *DBTokenProvider) authorizeRequest(ctx context.Context, roles *rbac.Subj
316316
return false, warnings, nil
317317
}
318318

319+
// For organization level path-based apps, block access if path app sharing is disabled
320+
// and the user is not in the same organization
321+
if isPathApp &&
322+
sharingLevel == database.AppSharingLevelOrganization &&
323+
!p.DeploymentValues.Dangerous.AllowPathAppSharing.Value() {
324+
// Check if user is in the same organization as the workspace
325+
workspaceOrgID := dbReq.Workspace.OrganizationID
326+
inSameOrg := false
327+
expandedRoles, err := roles.Roles.Expand()
328+
if err != nil {
329+
return false, warnings, xerrors.Errorf("expand roles: %w", err)
330+
}
331+
for _, role := range expandedRoles {
332+
if _, ok := role.Org[workspaceOrgID.String()]; ok {
333+
inSameOrg = true
334+
break
335+
}
336+
}
337+
if !inSameOrg {
338+
if roles != nil && slices.Contains(roles.Roles.Names(), rbac.RoleOwner()) {
339+
warnings = append(warnings, "path-based apps with \"organization\" share level are only accessible by organization members (see --dangerous-allow-path-app-sharing)")
340+
}
341+
return false, warnings, nil
342+
}
343+
}
344+
319345
// Figure out which RBAC resource to check. For terminals we use execution
320346
// instead of application connect.
321347
var (
@@ -354,6 +380,27 @@ func (p *DBTokenProvider) authorizeRequest(ctx context.Context, roles *rbac.Subj
354380
if err == nil {
355381
return true, []string{}, nil
356382
}
383+
case database.AppSharingLevelOrganization:
384+
// Check if the user is a member of the same organization as the workspace
385+
// First check if they have permission to connect to their own workspace (enforces scopes)
386+
err := p.Authorizer.Authorize(ctx, *roles, rbacAction, rbacResourceOwned)
387+
if err != nil {
388+
return false, warnings, nil
389+
}
390+
391+
// Check if the user is a member of the workspace's organization
392+
workspaceOrgID := dbReq.Workspace.OrganizationID
393+
expandedRoles, err := roles.Roles.Expand()
394+
if err != nil {
395+
return false, warnings, xerrors.Errorf("expand roles: %w", err)
396+
}
397+
for _, role := range expandedRoles {
398+
if _, ok := role.Org[workspaceOrgID.String()]; ok {
399+
return true, []string{}, nil
400+
}
401+
}
402+
// User is not a member of the workspace's organization
403+
return false, warnings, nil
357404
case database.AppSharingLevelPublic:
358405
// We don't really care about scopes and stuff if it's public anyways.
359406
// Someone with a restricted-scope API key could just not submit the API

0 commit comments

Comments
 (0)