chore: implement typed database for custom permissions (breaks existing custom roles) (#13457)

* chore: typed database custom permissions
* add migration to fix any custom roles out there
This commit is contained in:
Steven Masley
2024-06-04 09:27:44 -05:00
committed by GitHub
parent 168d2d6ba0
commit e3206612e1
17 changed files with 256 additions and 266 deletions
+23 -57
View File
@@ -2,7 +2,6 @@ package rolestore
import (
"context"
"encoding/json"
"net/http"
"github.com/google/uuid"
@@ -96,6 +95,20 @@ func Expand(ctx context.Context, db database.Store, names []string) (rbac.Roles,
return roles, nil
}
func convertPermissions(dbPerms []database.CustomRolePermission) []rbac.Permission {
n := make([]rbac.Permission, 0, len(dbPerms))
for _, dbPerm := range dbPerms {
n = append(n, rbac.Permission{
Negate: dbPerm.Negate,
ResourceType: dbPerm.ResourceType,
Action: dbPerm.Action,
})
}
return n
}
// ConvertDBRole should not be used by any human facing apis. It is used
// for authz purposes.
func ConvertDBRole(dbRole database.CustomRole) (rbac.Role, error) {
name := dbRole.Name
if dbRole.OrganizationID.Valid {
@@ -104,68 +117,21 @@ func ConvertDBRole(dbRole database.CustomRole) (rbac.Role, error) {
role := rbac.Role{
Name: name,
DisplayName: dbRole.DisplayName,
Site: nil,
Site: convertPermissions(dbRole.SitePermissions),
Org: nil,
User: nil,
User: convertPermissions(dbRole.UserPermissions),
}
err := json.Unmarshal(dbRole.SitePermissions, &role.Site)
if err != nil {
return role, xerrors.Errorf("unmarshal site permissions: %w", err)
// Org permissions only make sense if an org id is specified.
if len(dbRole.OrgPermissions) > 0 && dbRole.OrganizationID.UUID == uuid.Nil {
return rbac.Role{}, xerrors.Errorf("role has organization perms without an org id specified")
}
err = json.Unmarshal(dbRole.OrgPermissions, &role.Org)
if err != nil {
return role, xerrors.Errorf("unmarshal org permissions: %w", err)
}
err = json.Unmarshal(dbRole.UserPermissions, &role.User)
if err != nil {
return role, xerrors.Errorf("unmarshal user permissions: %w", err)
if dbRole.OrganizationID.UUID != uuid.Nil {
role.Org = map[string][]rbac.Permission{
dbRole.OrganizationID.UUID.String(): convertPermissions(dbRole.OrgPermissions),
}
}
return role, nil
}
func ConvertRoleToDB(role rbac.Role) (database.CustomRole, error) {
roleName, orgIDStr, err := rbac.RoleSplit(role.Name)
if err != nil {
return database.CustomRole{}, xerrors.Errorf("split role %q: %w", role.Name, err)
}
dbRole := database.CustomRole{
Name: roleName,
DisplayName: role.DisplayName,
}
if orgIDStr != "" {
orgID, err := uuid.Parse(orgIDStr)
if err != nil {
return database.CustomRole{}, xerrors.Errorf("parse org id %q: %w", orgIDStr, err)
}
dbRole.OrganizationID = uuid.NullUUID{
UUID: orgID,
Valid: true,
}
}
siteData, err := json.Marshal(role.Site)
if err != nil {
return dbRole, xerrors.Errorf("marshal site permissions: %w", err)
}
dbRole.SitePermissions = siteData
orgData, err := json.Marshal(role.Org)
if err != nil {
return dbRole, xerrors.Errorf("marshal org permissions: %w", err)
}
dbRole.OrgPermissions = orgData
userData, err := json.Marshal(role.User)
if err != nil {
return dbRole, xerrors.Errorf("marshal user permissions: %w", err)
}
dbRole.UserPermissions = userData
return dbRole, nil
}