Skip to content

chore: join owner, template, and org in new workspace view #15116

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 23 commits into from
Oct 22, 2024

Conversation

Emyrk
Copy link
Member

@Emyrk Emyrk commented Oct 16, 2024

Closes #15114

What this does

Joins in fields like username, avatar_url, organization_name, template_name to workspaces via a view.

Views are a nuisance to maintain, however they have become the only clean way to handle RBAC related objects for:

If this is not done, the backend has to do multiple fetches when trying to retrieve information always displayed like the Owner's username. These fetches have the RBAC issue that they require the READ permission the related object, which gets even more complicated with custom roles.

Without these joins, if you give READ permission to a workspace in an org, it also requires the permission to READ the user only to fetch the username & avatar. When using custom roles, these implicit links are confusing to use, and have caused a reported error.

We can further make this better, as some overfetching is still done, but this change is already a lot.

What this costs

We have to maintain yet another view. Insert rant about SQLc supporting client-side views that update with the schema.

RBAC Change

Giving READ to a workspace now lets you see all these fields without needing perms to the related objects.

-- Owner
coalesce(visible_users.avatar_url, '') AS owner_avatar_url,
coalesce(visible_users.username, '') AS owner_username,
-- Organization
coalesce(organizations.name, '') AS organization_name,
coalesce(organizations.display_name, '') AS organization_display_name,
coalesce(organizations.icon, '') AS organization_icon,
coalesce(organizations.description, '') AS organization_description,
      -- Template
coalesce(templates.name, '') AS template_name,
coalesce(templates.display_name, '') AS template_display_name,
coalesce(templates.icon, '') AS template_icon,
coalesce(templates.description, '') AS template_description

Guardrails

Converting to WorkspaceTable is guarded to stay in sync with the view. If you update the view, but not the converter function, this test will fail.

// TestWorkspaceTableConvert verifies all workspace fields are converted
// when reducing a `Workspace` to a `WorkspaceTable`.
// This test is a guard rail to prevent developer oversight mistakes.
func TestWorkspaceTableConvert(t *testing.T) {
.

And static structs are also guarded. Does the same as above, but ignores the converter function.

func TestViewSubsetWorkspace(t *testing.T) {

We use WorkspaceTable for audit logs, since fields like Username are mutable, it would not make sense to include in the audit log with a workspace. It is sourced from the mutable field of Users.

@Emyrk Emyrk force-pushed the stevenmasley/workspace_org_view branch from af796d7 to e1cb2cf Compare October 18, 2024 14:08
@Emyrk Emyrk marked this pull request as ready for review October 18, 2024 14:40
@Emyrk Emyrk changed the title chore: new workspace view to join in owner, template, and org chore: join owner, template, and org in new workspace view Oct 18, 2024
Copy link
Member

@johnstcn johnstcn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

submitting partial review now

| WorkspaceBuild<br><i>start, stop</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody><tr><td>build_number</td><td>false</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>daily_cost</td><td>false</td></tr><tr><td>deadline</td><td>false</td></tr><tr><td>id</td><td>false</td></tr><tr><td>initiator_by_avatar_url</td><td>false</td></tr><tr><td>initiator_by_username</td><td>false</td></tr><tr><td>initiator_id</td><td>false</td></tr><tr><td>job_id</td><td>false</td></tr><tr><td>max_deadline</td><td>false</td></tr><tr><td>provisioner_state</td><td>false</td></tr><tr><td>reason</td><td>false</td></tr><tr><td>template_version_id</td><td>true</td></tr><tr><td>transition</td><td>false</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>workspace_id</td><td>false</td></tr></tbody></table> |
| WorkspaceProxy<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody><tr><td>created_at</td><td>true</td></tr><tr><td>deleted</td><td>false</td></tr><tr><td>derp_enabled</td><td>true</td></tr><tr><td>derp_only</td><td>true</td></tr><tr><td>display_name</td><td>true</td></tr><tr><td>icon</td><td>true</td></tr><tr><td>id</td><td>true</td></tr><tr><td>name</td><td>true</td></tr><tr><td>region_id</td><td>true</td></tr><tr><td>token_hashed_secret</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>url</td><td>true</td></tr><tr><td>version</td><td>true</td></tr><tr><td>wildcard_hostname</td><td>true</td></tr></tbody></table> |
| WorkspaceTable<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody><tr><td>automatic_updates</td><td>true</td></tr><tr><td>autostart_schedule</td><td>true</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>deleted</td><td>false</td></tr><tr><td>deleting_at</td><td>true</td></tr><tr><td>dormant_at</td><td>true</td></tr><tr><td>favorite</td><td>true</td></tr><tr><td>id</td><td>true</td></tr><tr><td>last_used_at</td><td>false</td></tr><tr><td>name</td><td>true</td></tr><tr><td>organization_id</td><td>false</td></tr><tr><td>owner_id</td><td>true</td></tr><tr><td>template_id</td><td>true</td></tr><tr><td>ttl</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr></tbody></table> |
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we keep the old resource name? I don't think admins care if there is a difference between a change to a WorkspaceTable or a change to a Workspace?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The type is still workspace to admins:

case database.WorkspaceTable:
return database.ResourceTypeWorkspace

It is just WorkspaceTable in Go

@Emyrk Emyrk requested a review from johnstcn October 21, 2024 16:14
// Handle some special cases
switch v.Type() {
case reflect.TypeOf(time.Time{}):
v.Set(reflect.ValueOf(time.Date(2020, 5, 2, 5, 19, 21, 30, time.UTC)))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: use a non-UTC timezone

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am going to be lazy here.

@Emyrk Emyrk force-pushed the stevenmasley/workspace_org_view branch from b05b00c to 6e448d8 Compare October 22, 2024 14:05
@Emyrk Emyrk merged commit 343f8ec into main Oct 22, 2024
27 checks passed
@Emyrk Emyrk deleted the stevenmasley/workspace_org_view branch October 22, 2024 14:20
@github-actions github-actions bot locked and limited conversation to collaborators Oct 22, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

RBAC error when viewing all users' workspaces
2 participants