Thanks to visit codestin.com
Credit goes to github.com

Skip to content

feat: Implement view for workspace builds to include rbac info #6371

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

Closed
wants to merge 13 commits into from

Conversation

Emyrk
Copy link
Member

@Emyrk Emyrk commented Feb 28, 2023

Using Go templates instead: #6429

What is this

Creates a view for workspace builds to add RBAC information to the object directly, removing the need for an extra database query.

This does create 2 WorkspaceBuild objects. One is WorkspaceBuild and one is WorkspacBuildThin. The thin version is returned by inserts/updates because you cannot insert into a view. I just expand the returned value immediately:

// Assign owning fields.
workspaceBuild = thinBuild.WithWorkspace(workspace)

To return WorkspaceBuild with joined fields, it gets complicated with either a postgres function or rule.

Why do this?

Currently workspace_builds require fetching the related workspace to run RBAC checks. This requires an extra DB round trip. Instead, we should join this information to the build.

Cost

The cost of a view is using migrations to maintain the view. If a column is added to workspace_builds table, we need to update the view.

Alternative (please read this part!)

I was originally removing SQLc and just using SQLx directly. To reuse join information, I was going to use go templates. This required a bit of infrastructure to pull the queries into Golang. The final interface for this little package was quite clean.

Downsides

The go templates do not have great syntax highlighting support. On Goland, you can get a pretty good experience, but not on vs-code which a lot of our team uses.

The go template syntax highlighting breaks if you use go templates for dynamic queries, which is the alternative to using a view. This means making this a template looks like this.

{{ define "workspace_builds_rbac" }}
(
SELECT
	workspace_builds.*,
	workspaces.organization_id AS organization_id,
	workspaces.owner_id AS workspace_owner_id
FROM
	workspace_builds
INNER JOIN
	workspaces ON workspace_builds.workspace_id = workspaces.id
)
{{ end }}

-- To use the template above
{{ define "GetWorkspaceBuildByID" }}
SELECT
	*
FROM 
	{{ template "workspace_builds_rbac" }}
WHERE
	id = @build_id
{{ end }}

If this is preferred, I can go back to the sqlx route.

Upsides

  • We can do dynamic queries. All CASE WHEN can be removed into go template conditionals that conditionally write additional WHERE clauses.
  • Anonymously embedded structs for joined data.

Removes the need to fetch the workspace to run an rbac check.
@Emyrk Emyrk marked this pull request as draft February 28, 2023 16:18
Comment on lines 1181 to 1183
func (q *querier) GetLatestWorkspaceBuildByWorkspaceID(ctx context.Context, workspaceID uuid.UUID) (database.WorkspaceBuild, error) {
if _, err := q.GetWorkspaceByID(ctx, workspaceID); err != nil {
return database.WorkspaceBuild{}, err
}
return q.db.GetLatestWorkspaceBuildByWorkspaceID(ctx, workspaceID)
return fetch(q.log, q.auth, q.db.GetLatestWorkspaceBuildByWorkspaceID)(ctx, workspaceID)
}
Copy link
Member Author

Choose a reason for hiding this comment

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

This is the diff we are going for. Before we had to do a workspace fetch, now we do not.

This happens for a lot of objects (template versions, provisoner jobs, params, etc). workspace_builds is just the first I am doing as an example. If this pattern works, I will continue to work on others.

@Emyrk Emyrk marked this pull request as ready for review February 28, 2023 17:46
@Emyrk Emyrk requested a review from kylecarbs February 28, 2023 19:23
@Emyrk Emyrk requested a review from a team March 1, 2023 22:52
@deansheather deansheather self-requested a review March 2, 2023 14:06
@deansheather
Copy link
Member

The go templates do not have great syntax highlighting support. On Goland, you can get a pretty good experience, but not on vs-code which a lot of our team uses.

Are there any workarounds to get VSCode to highlight the files nicely? Like maybe naming the template file .sql or something?

@deansheather
Copy link
Member

Or perhaps we could update the workspace config file to add a custom syntax highlighting grammar or something?

Copy link
Member

@deansheather deansheather left a comment

Choose a reason for hiding this comment

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

It'd be nice if the full object with the extra RBAC-required fields wasn't returned from the querier at all (to avoid having two objects), but I understand that is difficult because of sqlc. The templating approach seems better in that regard, but it definitely needs to have syntax highlighting to work.

Comment on lines 1337 to 1340
w, err := q.db.GetWorkspaceByID(ctx, arg.WorkspaceID)
if err != nil {
return database.WorkspaceBuild{}, err
return database.WorkspaceBuildThin{}, err
}
Copy link
Member

Choose a reason for hiding this comment

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

Since you still have the workspace here, this doesn't need to be thin right? Or is it a requirement because of the sqlc generating the interface?

Copy link
Member Author

Choose a reason for hiding this comment

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

It's because of SQLc interface

@Emyrk
Copy link
Member Author

Emyrk commented Mar 2, 2023

It'd be nice if the full object with the extra RBAC-required fields wasn't returned from the querier at all (to avoid having two objects), but I understand that is difficult because of sqlc.

It is actually because we use RETURNING * on inserts and updates. You cannot insert into a view, so the returned fields will always omit the joined data.

Now one way around this is to leave the sqlc interface when using dbauthz and making sure Thin is only used internally to the dbauthz/dbfake layer:

func (q *querier) InsertWorkspaceBuild(ctx context.Context, arg database.InsertWorkspaceBuildParams) (database.WorkspaceBuildThin, error) {
w, err := q.db.GetWorkspaceByID(ctx, arg.WorkspaceID)
if err != nil {
return database.WorkspaceBuildThin{}, err
}
var action rbac.Action = rbac.ActionUpdate
if arg.Transition == database.WorkspaceTransitionDelete {
action = rbac.ActionDelete
}
if err = q.authorizeContext(ctx, action, w); err != nil {
return database.WorkspaceBuildThin{}, err
}
return q.db.InsertWorkspaceBuild(ctx, arg)
}

This is because rbac requires a fetch before we insert/update anyway.

@Emyrk
Copy link
Member Author

Emyrk commented Mar 2, 2023

The go templates do not have great syntax highlighting support. On Goland, you can get a pretty good experience, but not on vs-code which a lot of our team uses.

Are there any workarounds to get VSCode to highlight the files nicely? Like maybe naming the template file .sql or something?

I tried for a long time. I can make it .sql or add a file association in vscode to look at gosql files as SQL. The problem is it still doesn't recognize go templates, so you will have highlighting issues when they mix.

@Emyrk
Copy link
Member Author

Emyrk commented Mar 7, 2023

Going with #6429

@Emyrk Emyrk closed this Mar 7, 2023
@github-actions github-actions bot locked and limited conversation to collaborators Mar 7, 2023
@Emyrk Emyrk deleted the stevenmasley/rbac_views branch April 17, 2023 20:13
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.

2 participants