Skip to content
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: support ALTER DEFAULT PRIVILEGES IN SCHEMA #73576

Merged

Conversation

RichardJCai
Copy link
Contributor

@RichardJCai RichardJCai commented Dec 7, 2021

Release note (sql change):
Support ALTER DEFAULT PRIVILEGES IN SCHEMA <schemas...>
Users can now in addition to specifying default privileges globally
(within a database), specify default privileges in a specific schema.

When creating an object that has default privileges specified at
the database (global) and at the schema level, the union of the
default privileges are taken.

Resolves #67376

@RichardJCai RichardJCai requested review from a team and shermanCRL and removed request for a team December 7, 2021 21:58
@cockroach-teamcity
Copy link
Member

This change is Reviewable

@RichardJCai RichardJCai marked this pull request as draft December 7, 2021 21:59
@RichardJCai RichardJCai removed request for a team and shermanCRL December 7, 2021 21:59
@RichardJCai RichardJCai force-pushed the alter_default_privileges_in_schema branch 3 times, most recently from 76003f3 to f714b43 Compare December 8, 2021 21:03
@RichardJCai RichardJCai changed the title wip: alter default privileges in schema sql: support ALTER DEFAULT PRIVILEGES IN SCHEMA Dec 8, 2021
@RichardJCai RichardJCai force-pushed the alter_default_privileges_in_schema branch from f714b43 to bcd73e6 Compare December 8, 2021 21:15
@RichardJCai RichardJCai marked this pull request as ready for review December 8, 2021 21:15
@RichardJCai RichardJCai requested a review from a team as a code owner December 8, 2021 21:15
@RichardJCai RichardJCai requested review from rafiss and a team December 8, 2021 21:15
@RichardJCai RichardJCai force-pushed the alter_default_privileges_in_schema branch from bcd73e6 to fd3c7e3 Compare December 8, 2021 22:23
Copy link
Collaborator

@rafiss rafiss left a comment

Choose a reason for hiding this comment

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

Reviewable status: :shipit: complete! 0 of 0 LGTMs obtained (waiting on @rafiss and @RichardJCai)


docs/generated/eventlog.md, line 1562 at r1 (raw file):

| `RoleName` | Either role_name should be populated or for_all_roles should be true. The role having its default privileges altered. | yes |
| `ForAllRoles` | Identifies if FOR ALL ROLES is used. | no |
| `SchemaName` | The names of the affected schema. | yes |

nit: the field should be plural (SchemaNames) if it's a list


pkg/sql/drop_role.go, line 426 at r1 (raw file):

// accumulateDependentDefaultPrivileges checks for any default privileges
// that the users in userNames have and append them to the objectAndType array.
// Only one of db or sc should be non-nil.

this is a little brittle. why don't we instead make the parameter a catalog.DefaultPrivilegeDescriptor so that the caller has to call GetDefaultPrivilegeDescriptor?


pkg/sql/catalog/catprivilege/default_privilege.go, line 80 at r1 (raw file):

}

// Calls expandPrivileges before calling the function passed in and calls

nit: the function comment should be a full sentence, and should start with grantOrRevokeDefaultPrivilegesHelper calls ...


pkg/sql/catalog/catprivilege/default_privilege.go, line 171 at r1 (raw file):

// the default privilege descriptor from the database or both the db and schema.
func CreatePrivilegesFromDefaultPrivileges(
	defaultPrivilegeDescriptors []catalog.DefaultPrivilegeDescriptor,

why use a slice here instead of passing in one arg for the dbDefaultPrivs and another arg for schemaDefaultPrivs


pkg/sql/catalog/catprivilege/default_privilege_test.go, line 165 at r1 (raw file):

	for _, tc := range testCases {
		defaultPrivilegeDescriptor := MakeNewDatabaseDefaultPrivilegeDescriptor()

after seeing this a few times, i wonder if it would be more readable to have one MakeDefaultPrivilegeDescriptor that accepts a descriptorType parameter?

also nit: MakeNewXyz is redundant; i think MakeXyz is sufficient.


pkg/sql/catalog/catprivilege/default_privilege_test.go, line 379 at r1 (raw file):

		// for a schema.
		if newPrivileges.CheckPrivilege(creatorUser, privilege.ALL) {
			t.Errorf("expected creator to have not ALL privileges on %s", targetObject)

nit: "to have not ALL" is confusing. is there a typo?

also, just to clarify, this check is different than the "base" schema privileges that the "public" role has?


pkg/sql/catalog/descpb/privilege.proto, line 93 at r1 (raw file):

  option (gogoproto.equal) = true;
  repeated DefaultPrivilegesForRole default_privileges_per_role = 1 [(gogoproto.nullable) = false];
  enum DefaultPrivilegeDescriptorType {

hm, since we're adding this to the proto, does that mean all the logic that looks at this enum needs to be version gated? maybe it can be avoided if the deserialization logic defaults to setting this to 0?


pkg/sql/logictest/testdata/logic_test/alter_default_privileges_in_schema, line 120 at r1 (raw file):

statement ok
ALTER DEFAULT PRIVILEGES FOR ROLE testuser IN SCHEMA s, public REVOKE ALL ON TABLES FROM testuser2;
ALTER DEFAULT PRIVILEGES FOR ALL ROLES IN SCHEMA s, public GRANT SELECT ON TABLES TO testuser2;

just to confirm, does this cover the case where default privs on (db+schema) overrides default privs on db? and make sure the override is actually per-schema?


pkg/sql/logictest/testdata/logic_test/alter_default_privileges_in_schema, line 161 at r1 (raw file):

test           public       t9          admin      ALL
test           public       t9          root       ALL
test           public       t9          testuser   CREATE

i think this is unrelated to your current work, but what does CREATE really mean here? isn't CREATE a DB privilege? so why are schema and table_name set?


pkg/sql/logictest/testdata/logic_test/alter_default_privileges_in_schema, line 193 at r1 (raw file):


# Default privileges for schemas have no defaults - no privileges are defined
# initially.

i thought we had CREATE granted to public by default? (ref #70266)


pkg/util/log/eventpb/privilege_events.proto, line 138 at r1 (raw file):

  // Identifies if FOR ALL ROLES is used.
  bool for_all_roles = 6 [(gogoproto.jsontag) = ",omitempty"];
  // The names of the affected schema.

nit: should be name not names

Copy link
Contributor Author

@RichardJCai RichardJCai left a comment

Choose a reason for hiding this comment

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

Reviewable status: :shipit: complete! 0 of 0 LGTMs obtained (waiting on @rafiss)


docs/generated/eventlog.md, line 1562 at r1 (raw file):

Previously, rafiss (Rafi Shamim) wrote…

nit: the field should be plural (SchemaNames) if it's a list

Oops this actual should just be one schema right now.


pkg/sql/drop_role.go, line 426 at r1 (raw file):

Previously, rafiss (Rafi Shamim) wrote…

this is a little brittle. why don't we instead make the parameter a catalog.DefaultPrivilegeDescriptor so that the caller has to call GetDefaultPrivilegeDescriptor?

That's much nicer good call.


pkg/sql/catalog/catprivilege/default_privilege.go, line 80 at r1 (raw file):

Previously, rafiss (Rafi Shamim) wrote…

nit: the function comment should be a full sentence, and should start with grantOrRevokeDefaultPrivilegesHelper calls ...

Done


pkg/sql/catalog/catprivilege/default_privilege.go, line 171 at r1 (raw file):

Previously, rafiss (Rafi Shamim) wrote…

why use a slice here instead of passing in one arg for the dbDefaultPrivs and another arg for schemaDefaultPrivs

Good call, done.


pkg/sql/catalog/catprivilege/default_privilege_test.go, line 165 at r1 (raw file):

Previously, rafiss (Rafi Shamim) wrote…

after seeing this a few times, i wonder if it would be more readable to have one MakeDefaultPrivilegeDescriptor that accepts a descriptorType parameter?

also nit: MakeNewXyz is redundant; i think MakeXyz is sufficient.

Done


pkg/sql/catalog/catprivilege/default_privilege_test.go, line 379 at r1 (raw file):

Previously, rafiss (Rafi Shamim) wrote…

nit: "to have not ALL" is confusing. is there a typo?

also, just to clarify, this check is different than the "base" schema privileges that the "public" role has?

Reworded to creator should not have ALL privileges

This check is different.
I checked with PG there is no "default" / preset privileges for default privileges on schemas.


pkg/sql/catalog/descpb/privilege.proto, line 93 at r1 (raw file):

Previously, rafiss (Rafi Shamim) wrote…

hm, since we're adding this to the proto, does that mean all the logic that looks at this enum needs to be version gated? maybe it can be avoided if the deserialization logic defaults to setting this to 0?

I think the DefaultPrivilegeDescriptorType will resolve to 0 on older versions so that should be okay. I'll double check.


pkg/sql/logictest/testdata/logic_test/alter_default_privileges_in_schema, line 120 at r1 (raw file):

Previously, rafiss (Rafi Shamim) wrote…

just to confirm, does this cover the case where default privs on (db+schema) overrides default privs on db? and make sure the override is actually per-schema?

It's not override it's actually the union of the privileges on the db and schema

# When creating an object, take the union of the default privileges on
# the schema and the database.
# In the following test cases, testuser2 should have INSERT and SELECT.
statement ok
ALTER DEFAULT PRIVILEGES FOR ROLE testuser GRANT INSERT ON TABLES TO testuser2

statement ok
CREATE TABLE t2()

query TTTTT colnames
SHOW GRANTS ON t2
----
database_name  schema_name  table_name  grantee    privilege_type
test           public       t2          admin      ALL
test           public       t2          root       ALL
test           public       t2          testuser   ALL
test           public       t2          testuser2  INSERT
test           public       t2          testuser2  SELECT

this case covers that


pkg/sql/logictest/testdata/logic_test/alter_default_privileges_in_schema, line 161 at r1 (raw file):

Previously, rafiss (Rafi Shamim) wrote…

i think this is unrelated to your current work, but what does CREATE really mean here? isn't CREATE a DB privilege? so why are schema and table_name set?

I think CREATE on table was used to substitute for some owner privileges, ie since we didn't have the concept of ownership before, you needed CREATE to alter or drop the table. CREATE still lets you do those things.


pkg/sql/logictest/testdata/logic_test/alter_default_privileges_in_schema, line 193 at r1 (raw file):

Previously, rafiss (Rafi Shamim) wrote…

i thought we had CREATE granted to public by default? (ref #70266)

I believe thats on the public schema


pkg/util/log/eventpb/privilege_events.proto, line 138 at r1 (raw file):

Previously, rafiss (Rafi Shamim) wrote…

nit: should be name not names

Done

@RichardJCai RichardJCai force-pushed the alter_default_privileges_in_schema branch 2 times, most recently from 0ae581c to bfab08b Compare December 14, 2021 19:04
Copy link
Collaborator

@rafiss rafiss left a comment

Choose a reason for hiding this comment

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

Reviewable status: :shipit: complete! 0 of 0 LGTMs obtained (waiting on @rafiss and @RichardJCai)


docs/generated/eventlog.md, line 1562 at r2 (raw file):

| `RoleName` | Either role_name should be populated or for_all_roles should be true. The role having its default privileges altered. | yes |
| `ForAllRoles` | Identifies if FOR ALL ROLES is used. | no |
| `SchemaName` | The names of the affected schema. | yes |

nit: should be "The name of the affected schema"


pkg/sql/drop_role.go, line 426 at r2 (raw file):

// accumulateDependentDefaultPrivileges checks for any default privileges
// that the users in userNames have and append them to the objectAndType array.
// Only one of db or sc should be non-nil.

nit: update comment that describes the params


pkg/sql/catalog/descpb/privilege.proto, line 93 at r1 (raw file):

Previously, RichardJCai (Richard Cai) wrote…

I think the DefaultPrivilegeDescriptorType will resolve to 0 on older versions so that should be okay. I'll double check.

is there already a mixed-version test for this? i think that should be sufficient


pkg/sql/logictest/testdata/logic_test/alter_default_privileges_in_schema, line 193 at r1 (raw file):

Previously, RichardJCai (Richard Cai) wrote…

I believe thats on the public schema

ah right, so that would be seen from show grants on schema public; right? i think we'd want a test for that too, although i guess that might be considered out of scope for this PR. would you be open to adding that as a separate commit?

Copy link
Contributor Author

@RichardJCai RichardJCai left a comment

Choose a reason for hiding this comment

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

Reviewable status: :shipit: complete! 0 of 0 LGTMs obtained (waiting on @rafiss)


docs/generated/eventlog.md, line 1562 at r2 (raw file):

Previously, rafiss (Rafi Shamim) wrote…

nit: should be "The name of the affected schema"

It was updated in r3 I think you saw an older commit.


pkg/sql/drop_role.go, line 426 at r2 (raw file):

Previously, rafiss (Rafi Shamim) wrote…

nit: update comment that describes the params

Oops done


pkg/sql/catalog/descpb/privilege.proto, line 93 at r1 (raw file):

Previously, rafiss (Rafi Shamim) wrote…

is there already a mixed-version test for this? i think that should be sufficient

func TestUnsetDefaultPrivilegeDescriptorType(t *testing.T) {
	emptyDefaultPrivilegeDescriptor := descpb.DefaultPrivilegeDescriptor{}

	// If Type is not set, it should resolve to
	// descpb.DefaultPrivilegeDescriptor_DATABASE by default.
	require.Equal(t, emptyDefaultPrivilegeDescriptor.Type, descpb.DefaultPrivilegeDescriptor_DATABASE)
}

is this test sufficient?

I think a mixed-version test is overkill and a little unclear.


pkg/sql/logictest/testdata/logic_test/alter_default_privileges_in_schema, line 193 at r1 (raw file):

Previously, rafiss (Rafi Shamim) wrote…

ah right, so that would be seen from show grants on schema public; right? i think we'd want a test for that too, although i guess that might be considered out of scope for this PR. would you be open to adding that as a separate commit?

Yeah I don't think that is relevant to this PR as it's not handled as a default privilege at all.
Right now that's hardcoded in descriptor.go

I can add a test for that in another logic test if you want.

	publicSchemaID, err := catalogkv.GenerateUniqueDescID(ctx, p.ExecCfg().DB, p.ExecCfg().Codec)
	if err != nil {
		return descpb.InvalidID, err
	}

	// Every database must be initialized with the public schema.
	// Create the SchemaDescriptor.
	// In postgres, the user "postgres" is the owner of the public schema in a
	// newly created db. Postgres and Public have USAGE and CREATE privileges.
	// In CockroachDB, root is our substitute for the postgres user.
	publicSchemaPrivileges := descpb.NewBasePrivilegeDescriptor(security.AdminRoleName())
	// By default, everyone has USAGE and CREATE on the public schema.
	publicSchemaPrivileges.Grant(security.PublicRoleName(), privilege.List{privilege.CREATE, privilege.USAGE}, false)
	publicSchemaDesc := schemadesc.NewBuilder(&descpb.SchemaDescriptor{
		ParentID:   dbID,
		Name:       tree.PublicSchema,
		ID:         publicSchemaID,
		Privileges: publicSchemaPrivileges,
		Version:    1,
	}).BuildCreatedMutableSchema()

@RichardJCai RichardJCai force-pushed the alter_default_privileges_in_schema branch 2 times, most recently from 585a43d to f125ed2 Compare December 15, 2021 17:30
Copy link
Collaborator

@rafiss rafiss left a comment

Choose a reason for hiding this comment

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

lgtm! but can you add in the error propagation?

Reviewable status: :shipit: complete! 0 of 0 LGTMs obtained (waiting on @rafiss and @RichardJCai)


pkg/sql/drop_role.go, line 432 at r4 (raw file):

	// The func we pass into ForEachDefaultPrivilegeForRole will never
	// err so no err will be returned.
	_ = defaultPrivilegeDescriptor.ForEachDefaultPrivilegeForRole(func(

didn't realize the error was getting swallowed here. even though we don't need it know it is more future-proof to propagate the error up (so accumulateDependentDefaultPrivileges should return an error). otherwise a future refactoring could easily lead to bad error handling.


pkg/sql/catalog/descpb/privilege.proto, line 93 at r1 (raw file):

Previously, RichardJCai (Richard Cai) wrote…
func TestUnsetDefaultPrivilegeDescriptorType(t *testing.T) {
	emptyDefaultPrivilegeDescriptor := descpb.DefaultPrivilegeDescriptor{}

	// If Type is not set, it should resolve to
	// descpb.DefaultPrivilegeDescriptor_DATABASE by default.
	require.Equal(t, emptyDefaultPrivilegeDescriptor.Type, descpb.DefaultPrivilegeDescriptor_DATABASE)
}

is this test sufficient?

I think a mixed-version test is overkill and a little unclear.

this is sufficient, thanks!


pkg/sql/logictest/testdata/logic_test/alter_default_privileges_in_schema, line 120 at r1 (raw file):

Previously, RichardJCai (Richard Cai) wrote…

It's not override it's actually the union of the privileges on the db and schema

# When creating an object, take the union of the default privileges on
# the schema and the database.
# In the following test cases, testuser2 should have INSERT and SELECT.
statement ok
ALTER DEFAULT PRIVILEGES FOR ROLE testuser GRANT INSERT ON TABLES TO testuser2

statement ok
CREATE TABLE t2()

query TTTTT colnames
SHOW GRANTS ON t2
----
database_name  schema_name  table_name  grantee    privilege_type
test           public       t2          admin      ALL
test           public       t2          root       ALL
test           public       t2          testuser   ALL
test           public       t2          testuser2  INSERT
test           public       t2          testuser2  SELECT

this case covers that

got it thanks for explaining


pkg/sql/logictest/testdata/logic_test/alter_default_privileges_in_schema, line 161 at r1 (raw file):

Previously, RichardJCai (Richard Cai) wrote…

I think CREATE on table was used to substitute for some owner privileges, ie since we didn't have the concept of ownership before, you needed CREATE to alter or drop the table. CREATE still lets you do those things.

done


pkg/sql/logictest/testdata/logic_test/alter_default_privileges_in_schema, line 193 at r1 (raw file):

Previously, RichardJCai (Richard Cai) wrote…

Yeah I don't think that is relevant to this PR as it's not handled as a default privilege at all.
Right now that's hardcoded in descriptor.go

I can add a test for that in another logic test if you want.

	publicSchemaID, err := catalogkv.GenerateUniqueDescID(ctx, p.ExecCfg().DB, p.ExecCfg().Codec)
	if err != nil {
		return descpb.InvalidID, err
	}

	// Every database must be initialized with the public schema.
	// Create the SchemaDescriptor.
	// In postgres, the user "postgres" is the owner of the public schema in a
	// newly created db. Postgres and Public have USAGE and CREATE privileges.
	// In CockroachDB, root is our substitute for the postgres user.
	publicSchemaPrivileges := descpb.NewBasePrivilegeDescriptor(security.AdminRoleName())
	// By default, everyone has USAGE and CREATE on the public schema.
	publicSchemaPrivileges.Grant(security.PublicRoleName(), privilege.List{privilege.CREATE, privilege.USAGE}, false)
	publicSchemaDesc := schemadesc.NewBuilder(&descpb.SchemaDescriptor{
		ParentID:   dbID,
		Name:       tree.PublicSchema,
		ID:         publicSchemaID,
		Privileges: publicSchemaPrivileges,
		Version:    1,
	}).BuildCreatedMutableSchema()

actually i'll just make a PR to add it so you don't have to context switch

Release note (sql change):
Support ALTER DEFAULT PRIVILEGES IN SCHEMA <schemas...>
Users can now in addition to specifying default privileges globally
(within a database), specify default privileges in a specific schema.

When creating an object that has default privileges specified at
the database (global) and at the schema level, the union of the
default privileges are taken.
@RichardJCai RichardJCai force-pushed the alter_default_privileges_in_schema branch from f125ed2 to e80372b Compare December 15, 2021 19:29
@RichardJCai
Copy link
Contributor Author

TFTR
bors r=rafiss

@craig
Copy link
Contributor

craig bot commented Dec 15, 2021

Build succeeded:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

sql: support ALTER DEFAULT PRIVILEGES IN SCHEMA
3 participants