-
Notifications
You must be signed in to change notification settings - Fork 3.9k
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
sql: refactor pg_builtin to use actual grant options #74172
Conversation
pkg/sql/privilege/privilege.go
Outdated
// | ||
// res = check(SELECT) || (check(UPDATE) && check(GRANT)) || check(DELETE) | ||
// | ||
type Priv struct { |
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.
Made this public and moved from builtins
to privilege
because I thought it made more sense for function signatures that were using privilege.Kind
to use privilege.Priv
instead of builtins.Priv
.
pkg/sql/resolver.go
Outdated
@@ -314,6 +314,14 @@ func (p *planner) HasPrivilege( | |||
return false, err | |||
} | |||
|
|||
err = p.CheckGrantOptionsForUser(ctx, desc, []privilege.Kind{priv.Kind}, priv.GrantOption) |
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.
Is this correct?
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.
i think instead it should look like:
if priv.GrantOption {
err = p.CheckGrantOptionsForUser(..., true /* isGrant */)
// rest of the error checking logic
}
also, it might need to be done as part of (or more similarly to) hasPrivilegeFunc below.
best way to make sure it's working right is to run the logic tests:
make testbaselogic FILES='privilege_builtins'
(could also be with bazel)
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.
Also, does this need to be wrapped in a version gate to only work in the new version (reverse of this #74172 (comment))?
pkg/sql/sem/builtins/pg_builtins.go
Outdated
if priv.grantOption { | ||
// grantOption is set, so AND the result with check(GRANT). | ||
d, err = check(privilege.GRANT) | ||
if oldVersion { //todo |
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.
What is the best way to get this context from here?
p.ExecCfg().Settings.Version.IsActive(ctx, clusterversion.DefaultPrivileges)
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.
hm yeah, we don't have a planner
here. let me think about it. perhaps the version gate needs to be done deeper in the stack?
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.
nit on commit message title -- it shouldn't include the issue number
pkg/sql/sem/builtins/pg_builtins.go
Outdated
if priv.grantOption { | ||
// grantOption is set, so AND the result with check(GRANT). | ||
d, err = check(privilege.GRANT) | ||
if oldVersion { //todo |
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.
hm yeah, we don't have a planner
here. let me think about it. perhaps the version gate needs to be done deeper in the stack?
pkg/sql/resolver.go
Outdated
@@ -314,6 +314,14 @@ func (p *planner) HasPrivilege( | |||
return false, err | |||
} | |||
|
|||
err = p.CheckGrantOptionsForUser(ctx, desc, []privilege.Kind{priv.Kind}, priv.GrantOption) |
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.
i think instead it should look like:
if priv.GrantOption {
err = p.CheckGrantOptionsForUser(..., true /* isGrant */)
// rest of the error checking logic
}
also, it might need to be done as part of (or more similarly to) hasPrivilegeFunc below.
best way to make sure it's working right is to run the logic tests:
make testbaselogic FILES='privilege_builtins'
(could also be with bazel)
"UPDATE WITH GRANT OPTION": {privilege.UPDATE, true}, | ||
"REFERENCES": {privilege.SELECT, false}, | ||
"REFERENCES WITH GRANT OPTION": {privilege.SELECT, true}, | ||
"SELECT": {Kind: privilege.SELECT}, |
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.
These lines were generating errors like this during ./dev build
compilepkg: nogo: errors found by nogo during build-time code analysis:
/var/folders/hc/gng26svn1yq13l017705xqjr0000gq/T/rules_go_work-3414600577/github.com/cockroachdb/cockroach/pkg/sql/sem/builtins/pg_builtins.go:559:19: github.com/cockroachdb/cockroach/pkg/sql/privilege.Priv composite literal uses unkeyed fields (composites)
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.
Reviewable status: complete! 0 of 0 LGTMs obtained (waiting on @ecwall and @rafiss)
-- commits, line 4 at r2:
The sentence here would be a good fit for the main commit message body. The release notes are written for users -- so the release note should not include internal implementation details like the names of structs or variables.
pkg/sql/resolver.go, line 306 at r2 (raw file):
specifier tree.HasPrivilegeSpecifier, user security.SQLUsername, priv privilege.Priv,
i think this refactor will end up being pretty invasive. it will need a lot of the usages of this function to be updated. that might be OK -- but i think that refactor should be done separately from this PR. so i prefer to keep this as privilege.Kind
for now.
pkg/sql/privilege/privilege.go, line 85 at r1 (raw file):
Previously, ecwall (Evan Wall) wrote…
Made this public and moved from
builtins
toprivilege
because I thought it made more sense for function signatures that were usingprivilege.Kind
to useprivilege.Priv
instead ofbuiltins.Priv
.
this is a good point to think about. i feel like as long as this struct is only used within the builtins package, it would be better to keep it there and keep it non-visible
builtins.priv
makes sense to me -- it's the representation of a privilege that is relevant for builtin functions. (also the comment on it is very specific for builtin functions too)
pkg/sql/privilege/privilege.go, line 59 at r2 (raw file):
// construction, there is no need for a separate GRANT privilege. // // In CockroachDB, there exists a distinct GRANT privilege and no concept of
this comment paragraph and the next one need to be updated. it should mention that we do match the postgres "grant option" behavior
pkg/sql/sem/builtins/pg_builtins.go, line 557 at r1 (raw file):
Previously, rafiss (Rafi Shamim) wrote…
hm yeah, we don't have a
planner
here. let me think about it. perhaps the version gate needs to be done deeper in the stack?
i think the best way is to not do the version gate here at all.
instead, we can remove the check for GRANT in this part of the code. then we add the version gate to the hasPrivilege
function in pg_builtins.go. on the old version, if priv.GrantOption
is true, that function should check for the GRANT privilege, but on the new version it should check for the grant option.
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.
Reviewable status: complete! 0 of 0 LGTMs obtained (waiting on @ecwall and @rafiss)
pkg/sql/sem/builtins/pg_builtins.go, line 1449 at r2 (raw file):
Previously, ecwall (Evan Wall) wrote…
These lines were generating errors like this during
./dev build
compilepkg: nogo: errors found by nogo during build-time code analysis: /var/folders/hc/gng26svn1yq13l017705xqjr0000gq/T/rules_go_work-3414600577/github.com/cockroachdb/cockroach/pkg/sql/sem/builtins/pg_builtins.go:559:19: github.com/cockroachdb/cockroach/pkg/sql/privilege.Priv composite literal uses unkeyed fields (composites)
yeah, i think since the Priv
struct was made public, the linter now requires the field names to be spelled out fully
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.
Reviewable status: complete! 0 of 0 LGTMs obtained (waiting on @ecwall and @rafiss)
Previously, rafiss (Rafi Shamim) wrote…
The sentence here would be a good fit for the main commit message body. The release notes are written for users -- so the release note should not include internal implementation details like the names of structs or variables.
Ok, good to know.
pkg/sql/resolver.go, line 306 at r2 (raw file):
Previously, rafiss (Rafi Shamim) wrote…
i think this refactor will end up being pretty invasive. it will need a lot of the usages of this function to be updated. that might be OK -- but i think that refactor should be done separately from this PR. so i prefer to keep this as
privilege.Kind
for now.
The privilege.Kind -> privilege.Priv refactor is required for this check
Line 325 in dd8a8d8
if priv.GrantOption { |
pkg/sql/privilege/privilege.go, line 85 at r1 (raw file):
Previously, rafiss (Rafi Shamim) wrote…
this is a good point to think about. i feel like as long as this struct is only used within the builtins package, it would be better to keep it there and keep it non-visible
builtins.priv
makes sense to me -- it's the representation of a privilege that is relevant for builtin functions. (also the comment on it is very specific for builtin functions too)
It is passed down and eventually used in resolver.go (
Line 325 in dd8a8d8
if priv.GrantOption { |
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.
Reviewable status: complete! 0 of 0 LGTMs obtained (waiting on @ecwall and @rafiss)
pkg/sql/resolver.go, line 306 at r2 (raw file):
Previously, ecwall (Evan Wall) wrote…
The privilege.Kind -> privilege.Priv refactor is required for this check
(not sure how to link in reviewable).Line 325 in dd8a8d8
if priv.GrantOption {
i was suggesting to do the check in hasPrivilege in pg_builtins.go , and undo all the changes in resolver.go. this would also allow the priv
struct to remain private in the builtins
package. but i think what you're doing here is better. i was also wrong about this refactor being invasive; the function is only used in one place. (i remember now that i checked this when writing up the github issue)
pkg/sql/resolver.go, line 326 at r3 (raw file):
} /*if priv.GrantOption { todo err = p.CheckGrantOptionsForUser(ctx, desc, []privilege.Kind{priv.Kind}, true)
so here we could have:
if priv.GrantOption {
if !p.ExecCfg().Settings.Version.IsActive(ctx, clusterversion.ValidateGrantOption) {
ctx.Planner.CheckPrivilegeForUser( ... GRANT)
} else {
ctx.Planner.CheckGrantOptionsForUser( ... )
}
(of course, with the correct error handling)
pkg/sql/privilege/privilege.go, line 85 at r1 (raw file):
Previously, ecwall (Evan Wall) wrote…
It is passed down and eventually used in resolver.go (
). Is there a different place I should be checking priv.GrantOption?Line 325 in dd8a8d8
if priv.GrantOption {
my suggestion was to call CheckGrantOptions
from the HasPrivilege
function of builtins.go -- but after thinking a bit more i think that maybe what you're doing now is better
pkg/sql/sem/builtins/pg_builtins.go, line 557 at r1 (raw file):
Previously, rafiss (Rafi Shamim) wrote…
i think the best way is to not do the version gate here at all.
instead, we can remove the check for GRANT in this part of the code. then we add the version gate to the
hasPrivilege
function in pg_builtins.go. on the old version, ifpriv.GrantOption
is true, that function should check for the GRANT privilege, but on the new version it should check for the grant option.
my bad; actually let's do the version gate in planner.HasPrivilege
. see my comment there.
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.
Reviewable status: complete! 0 of 0 LGTMs obtained (waiting on @ecwall, @rafiss, and @stevendanna)
pkg/sql/privilege/privilege.go, line 50 at r4 (raw file):
// Privilege represents a privilege parsed from an Access Privilege Inquiry // Function's privilege string argument. type Privilege struct {
It seems like postgres doesn't have a term for a container concept like this around the privilege (what we call Kind) and its grant option so I think calling it Privilege is fine unless you have a better name.
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.
Reviewable status: complete! 0 of 0 LGTMs obtained (waiting on @ecwall and @rafiss)
a discussion (no related file):
Is this function still needed? Or can it be replaced by calling check
inside runPrivilegeChecks
?
func runSinglePrivilegeCheck(
priv privilege.Privilege, check func(privilege.Privilege) (tree.Datum, error),
) (tree.Datum, error) {
d, err := check(priv)
if err != nil {
return nil, err
}
switch d {
case tree.DBoolFalse, tree.DNull:
case tree.DBoolTrue:
if priv.GrantOption {
// GrantOption is set, so AND the result with check(GRANT).
d, err = check(privilege.Privilege{Kind: privilege.GRANT})
if err != nil {
return nil, err
}
switch d {
case tree.DBoolFalse, tree.DBoolTrue, tree.DNull:
default:
return nil, errors.AssertionFailedf(
"unexpected privilege check result %v", d)
}
}
default:
return nil, errors.AssertionFailedf(
"unexpected privilege check result %v", d)
}
return d, nil
}
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.
could you update the PR description so it summarizes the commits? or you could just copy the commit messages into the PR description
Reviewable status: complete! 0 of 0 LGTMs obtained (waiting on @ecwall and @rafiss)
-- commits, line 2 at r5:
the first commit message title should be updated -- this commit is just a refactor
pkg/sql/resolver.go, line 324 at r6 (raw file):
err = p.CheckPrivilegeForUser(ctx, desc, privilege.GRANT, user) } else { err = p.CheckGrantOptionsForUser(ctx, desc, []privilege.Kind{priv.Kind}, true)
nit: when passing in constant values to a function, the parameter name should be documented, like this:
p.CheckGrantOptionsForUser(ctx, desc, []privilege.Kind{priv.Kind}, true /* isGrant */)
pkg/sql/resolver.go, line 329 at r6 (raw file):
} if err != nil { if pgerror.GetPGCode(err) == pgcode.InsufficientPrivilege {
we'll need to be a bit careful with the error handling here. i believe a different code is returned by CheckGrantOptionsForUser
pkg/sql/privilege/privilege.go, line 50 at r4 (raw file):
Previously, ecwall (Evan Wall) wrote…
It seems like postgres doesn't have a term for a container concept like this around the privilege (what we call Kind) and its grant option so I think calling it Privilege is fine unless you have a better name.
sounds good
pkg/sql/sem/builtins/pg_builtins.go, line 559 at r6 (raw file):
if priv.GrantOption { // GrantOption is set, so AND the result with check(GRANT). d, err = check(privilege.Privilege{Kind: privilege.GRANT})
this should be removed in the 2nd commit, since this is now checked in HasPrivilege
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.
Reviewable status: complete! 0 of 0 LGTMs obtained (waiting on @ecwall and @rafiss)
pkg/sql/resolver.go, line 329 at r6 (raw file):
Previously, rafiss (Rafi Shamim) wrote…
we'll need to be a bit careful with the error handling here. i believe a different code is returned by CheckGrantOptionsForUser
Changed it to WarningPrivilegeNotGranted for that case.
pkg/sql/privilege/privilege.go, line 59 at r2 (raw file):
Previously, rafiss (Rafi Shamim) wrote…
this comment paragraph and the next one need to be updated. it should mention that we do match the postgres "grant option" behavior
Updated
pkg/sql/sem/builtins/pg_builtins.go, line 559 at r6 (raw file):
Previously, rafiss (Rafi Shamim) wrote…
this should be removed in the 2nd commit, since this is now checked in
HasPrivilege
I added a todo above with details.
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.
Reviewable status: complete! 0 of 0 LGTMs obtained (waiting on @ecwall and @rafiss)
pkg/sql/resolver.go, line 324 at r6 (raw file):
Previously, rafiss (Rafi Shamim) wrote…
nit: when passing in constant values to a function, the parameter name should be documented, like this:
p.CheckGrantOptionsForUser(ctx, desc, []privilege.Kind{priv.Kind}, true /* isGrant */)
Updated
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.
Reviewable status: complete! 0 of 0 LGTMs obtained (waiting on @ecwall and @rafiss)
pkg/sql/resolver.go, line 329 at r6 (raw file):
Previously, ecwall (Evan Wall) wrote…
Changed it to WarningPrivilegeNotGranted for that case.
Actually it looks like that was causing tests to fail so I changed it back.
Refactor builtins.priv -> privilege.Privilege. Replace privilege.Kind with privilege.Privilege in functions that need access to privilege.Privilege.GrantOption. Release note: None
The builtins has_table_privilege, has_column_privilege, has_any_column_privilege now use privileges.Priv.GrantOption instead of privileges.Kind.GRANT. Release note: None
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.
lgtm!
Reviewed 1 of 6 files at r4, 1 of 1 files at r5, 1 of 4 files at r7, 1 of 3 files at r10, 2 of 2 files at r11, all commit messages.
Reviewable status: complete! 0 of 0 LGTMs obtained (waiting on @ecwall and @rafiss)
bors r=rafiss |
Build failed (retrying...): |
Build succeeded: |
refs #73129
The builtins has_table_privilege, has_column_privilege,
has_any_column_privilege now use privileges.Priv.GrantOption instead
of privileges.Kind.GRANT.
Refactor builtins.priv -> privilege.Privilege.
Replace privilege.Kind with privilege.Privilege in functions that need
access to privilege.Privilege.GrantOption.