-
Notifications
You must be signed in to change notification settings - Fork 26
Support X-Trino-Role header
#322
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
base: main
Are you sure you want to change the base?
Conversation
Reviewer's GuideThis PR implements support for the X-Trino-Role header by extending the frontend configuration UI and type definitions, adding a Role field in the backend settings model, propagating the role value through the datasource context, and injecting it into SQL query arguments. Entity relationship diagram for updated TrinoDatasourceSettings modelerDiagram
TrinoDatasourceSettings {
string ClientId
string ClientSecret
string ImpersonationUser
string Role
string ClientTags
}
Class diagram for updated TrinoDataSourceOptions and TrinoDatasourceSettingsclassDiagram
class TrinoDataSourceOptions {
tokenUrl?: string
clientId?: string
impersonationUser?: string
role?: string
clientTags?: string
}
class TrinoDatasourceSettings {
ClientId string
ClientSecret string
ImpersonationUser string
Role string
ClientTags string
}
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey there - I've reviewed your changes and they look great!
Prompt for AI Agents
Please address the comments from this code review:
## Individual Comments
### Comment 1
<location> `pkg/trino/datasource-context.go:45-46` </location>
<code_context>
ctx = context.WithValue(ctx, trinoUserHeader, user)
}
+ if settings.Role != "" {
+ ctx = context.WithValue(ctx, trinoRoleHeader, "system=ROLE{"+settings.Role+"}")
+ }
+
</code_context>
<issue_to_address>
**🚨 suggestion (security):** Consider validating the Role value before formatting.
If settings.Role is user-supplied, ensure it is validated or sanitized to prevent malformed or unexpected header values.
Suggested implementation:
```golang
if settings.Role != "" {
role := sanitizeRole(settings.Role)
if role != "" {
ctx = context.WithValue(ctx, trinoRoleHeader, "system=ROLE{"+role+"}")
}
}
```
```golang
const (
accessTokenKey = "accessToken"
trinoUserHeader = "X-Trino-User"
trinoRoleHeader = "X-Trino-Role"
trinoClientTagsKey = "X-Trino-Client-Tags"
bearerPrefix = "Bearer "
)
// sanitizeRole ensures the role value is safe for use in the header.
// Only allows alphanumeric and underscores, returns empty string if invalid.
func sanitizeRole(role string) string {
for _, r := range role {
if !(r >= 'a' && r <= 'z') && !(r >= 'A' && r <= 'Z') && !(r >= '0' && r <= '9') && r != '_' {
return ""
}
}
return role
}
```
</issue_to_address>
### Comment 2
<location> `pkg/trino/datasource.go:97-98` </location>
<code_context>
args = append(args, sql.Named(accessTokenKey, accessToken.(string)))
}
+ if role != nil {
+ args = append(args, sql.Named(trinoRoleHeader, role.(string)))
+ }
+
</code_context>
<issue_to_address>
**issue (bug_risk):** Type assertion on role could panic if not a string.
Use a type check or type switch before asserting role as a string to prevent runtime panics.
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
|
Can you add an e2e test that'd verify this works? |
|
in progress. |
a6f9187 to
599f44b
Compare
599f44b to
69759bd
Compare
|
@nineinchnick Could you let me know when you might have time to review this? |
69759bd to
91e6b3e
Compare
| test('test with role', async ({ page }) => { | ||
| await login(page); | ||
| await goToTrinoSettings(page); | ||
| await setupDataSourceWithRole(page, '},system=ALL,hive=ROLE{admin'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
how you can set a role like this?
| await expect(page.getByText(/Access Denied: Cannot show roles/)).toBeVisible(); | ||
| }); | ||
|
|
||
| async function runRoleQuery(page: Page) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why utility functions are on top and why some are on the bottom?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The good practice, at least in trino java code to put utility functions on the bottom.
I'd put setupDataSourceWithRole on the bottom too, but very similar functions were on the top, so it looks there more natural.
Please let me know if you have an idea how to improve that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can reorder functions in this file in a separate commit
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's not for free - the git history of the file will be overriden.
| } | ||
|
|
||
| if settings.Role != "" { | ||
| ctx = context.WithValue(ctx, trinoRoleHeader, "system=ROLE{"+settings.Role+"}") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note there's an open PR to support roles directly in the Go driver: trinodb/trino-go-client#144
It's not required here, but we had a discussion there about the format in which to specify roles. We tried being consistent with other drivers, like JDBC and Python.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds good to me. What is the golden standard here we should follow? https://trino.io/docs/current/client/jdbc.html ?
Authorization roles to use for catalogs, specified as a list of key-value pairs for the catalog and role. For example, catalog1:roleA;catalog2:roleB sets roleA for catalog1 and roleB for catalog2.
That makes sense. As I understand for system role we simply say system:sysadmin. @ssheikin that sounds like good way to expose support to all kind of roles and makes it easy to test.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@nineinchnick @kokosing
This was my initial approach. In order to reduce scope and moving parts the PR was simplified.
The current PR allows to specify system role in a very simple format.
An improvement to set roles for catalogs in the jdbc compliant format may follow up.
The code for http client header is identical to #309
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was my initial approach.
Hm... I was under impression that initial approach was similar, but a bit different than in JDBC. That your approach followed the protocol implementation, not the JDBC format.
An improvement to set roles for catalogs in the jdbc compliant format may follow up.
I think this is part of the protocol (UX), changing semantics of the field seems like a breaking change. If it is not a big deal I would prefer to do it once and don't come if not needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
solves
Summary by Sourcery
Support the X-Trino-Role header by allowing users to specify a role in the data source config and passing it through backend context into SQL requests.
New Features:
X-Trino-Roleheader in SQL queriesEnhancements:
rolefield