support ALTER DEFAULT PRIVILEGES#2810
Conversation
|
|
Ito Test Report ❌17 test cases ran. 3 failed, 3 additional findings, 11 passed. Across 17 test cases, 11 passed and 6 failed: core default-privilege inheritance behaviors were mostly validated end-to-end (including tables, wildcard schemas, sequences, routines, a race scenario, and a non-enumerating unauthorized error path), and one previously unstable privilege-inheritance path now executes successfully in a stabilized environment. The most important confirmed defects are a critical startup crash on malformed auth.db deserialization, a high-severity legacy v1 auth.db role-ID collision issue that can break role lookups, and four medium-severity logic flaws (ALTER DEFAULT PRIVILEGES without FOR ROLE/USER being wrongly denied for non-superusers, in-memory/on-disk ACL drift when persistence fails, CREATE TABLE default ACL persistence asymmetry versus CREATE SEQUENCE, and ALTER INDEX ATTACH PARTITION parsing but always failing due to hardcoded unsupported execution). ❌ Failed (3)🟠 Default table privileges are not persisted during CREATE TABLE flow
Relevant code:
func (i *createTableDefaultPrivsIter) Next(ctx *sql.Context) (sql.Row, error) {
row, err := i.inner.Next(ctx)
if err == io.EOF && !i.applied {
i.applied = true
var applyErr error
auth.LockWrite(func() {
auth.ApplyDefaultPrivilegesForNewTable(i.ownerID, i.schemaName, i.tableName)
applyErr = auth.PersistChanges()
})
if applyErr != nil {
return nil, applyErr
}
}
return row, err
}
var authErr error
auth.LockWrite(func() {
ownerRole := auth.GetRole(ctx.Client().User)
if ownerRole.IsValid() {
auth.ApplyDefaultPrivilegesForNewSequence(ownerRole.ID(), c.sequence.Id.SchemaName(), c.sequence.Id.SequenceName())
}
authErr = auth.PersistChanges()
})
// ApplyDefaultPrivilegesForNewTable applies any matching default privileges to a newly created table.
// Must be called under LockWrite.
func ApplyDefaultPrivilegesForNewTable(ownerRoleID RoleID, schemaName, tableName string) {
for key, dpv := range globalDatabase.defaultPrivileges.Data {
if key.OwnerRole != ownerRoleID || key.ObjectType != PrivilegeObject_TABLE {
continue
}
if key.Schema != "" && key.Schema != schemaName {
continue
}
for granteeID, granteeValue := range dpv.Grantees {
for _, privilegeMap := range granteeValue.Privileges {
for grantedPriv, withGrantOption := range privilegeMap {🟠 No-FOR-ROLE statement denied before owner fallback resolution
Relevant code:
return vitess.InjectedStatement{
Auth: vitess.AuthInformation{
AuthType: auth.AuthType_CREATE,
TargetType: auth.AuthTargetType_AlterDefaultPrivilegesIdentifiers,
TargetNames: []string{node.TargetRole},
},
Statement: &pgnodes.AlterDefaultPrivileges{
case AuthTargetType_AlterDefaultPrivilegesIdentifiers:
nTargets := len(auth.TargetNames)
if nTargets > 1 {
return errors.Errorf("function identifiers has an unsupported count: %d", len(auth.TargetNames))
}
if state.role.IsSuperUser {
return nil
}
if nTargets == 1 && state.role.Name == auth.TargetNames[0] {
return nil
}
return errors.Errorf("permission denied for %s", auth.TargetNames[0])
func (n *AlterDefaultPrivileges) resolveOwnerRole(ctx *sql.Context) (auth.Role, error) {
// empty means current user
if n.OwnerRole == "" {
userRole := auth.GetRole(ctx.Client().User)
if !userRole.IsValid() {
return auth.Role{}, errors.Errorf(`role "%s" does not exist`, ctx.Client().User)
}
return userRole, nil🟠 Persist error after ALTER leaves in-memory and on-disk ACL drift
Relevant code:
var err error
auth.LockWrite(func() {
err = n.execute(ctx)
if err != nil {
return
}
err = auth.PersistChanges()
})
func PersistChanges() error {
if fileSystem != nil {
return fileSystem.WriteFile(authFileName, globalDatabase.serialize(), 0644)
}
// AddDefaultPrivilege adds a default privilege entry to the global database.
func AddDefaultPrivilege(key DefaultPrivilegeKey, grantee RoleID, privilege GrantedPrivilege, withGrantOption bool) {
dpv, ok := globalDatabase.defaultPrivileges.Data[key]
if !ok {
dpv = DefaultPrivilegeValue{
Key: key,
Grantees: make(map[RoleID]DefaultPrivilegeGranteeValue),
}
}
granteeValue, ok := dpv.Grantees[grantee]
if !ok {
granteeValue = DefaultPrivilegeGranteeValue{
Grantee: grantee,
Privileges: make(map[Privilege]map[GrantedPrivilege]bool),
}
}
privilegeMap, ok := granteeValue.Privileges[privilege.Privilege]
if !ok {✅ Passed (11)ℹ️ Additional Findings (3)
🟠 ALTER INDEX ATTACH PARTITION cannot execute
Relevant code:
| ALTER INDEX table_index_name ATTACH PARTITION db_object_name
{
$$.val = &tree.AlterIndex{Index: $3.tableIndexName(), Cmd: &tree.AlterIndexAttachPartition{Index: $6.unresolvedObjectName()}}
}
case *tree.AlterIndex:
return nodeAlterIndex(ctx, stmt)
func nodeAlterIndex(ctx *Context, node *tree.AlterIndex) (vitess.Statement, error) {
if node == nil {
return nil, nil
}
return NotYetSupportedError("ALTER INDEX is not yet supported")
}
|

















No description provided.