package permission import "strings" // Role is a platform-level role carried in OIDC groups. type Role string const ( RoleAdmin Role = "admin" RoleUser Role = "user" RoleService Role = "service" ) // Resource is a suite module protected by resource-scoped permissions. type Resource string const ( ResourceDrive Resource = "drive" ResourcePhotos Resource = "photos" ResourceContacts Resource = "contacts" ResourceCalendar Resource = "calendar" ) // Level is a resource permission with read < write < admin ordering. type Level int const ( LevelRead Level = iota + 1 LevelWrite LevelAdmin ) func (l Level) String() string { switch l { case LevelRead: return "read" case LevelWrite: return "write" case LevelAdmin: return "admin" default: return "unknown" } } func ParseLevel(s string) (Level, bool) { switch strings.ToLower(strings.TrimSpace(s)) { case "read": return LevelRead, true case "write": return LevelWrite, true case "admin": return LevelAdmin, true default: return 0, false } } func levelRank(l Level) int { return int(l) } // HasRole reports whether groups grant the given platform role. func HasRole(groups []string, role Role) bool { want := string(role) for _, g := range groups { g = strings.ToLower(strings.TrimSpace(g)) if g == want || g == "role:"+want { return true } } return false } // HasAnyRole reports whether groups grant at least one of the roles. func HasAnyRole(groups []string, roles ...Role) bool { for _, role := range roles { if HasRole(groups, role) { return true } } return false } // HasPermission reports whether groups grant at least the required level on resource. // Platform admins bypass resource checks. Higher levels satisfy lower ones. func HasPermission(groups []string, resource Resource, required Level) bool { if HasRole(groups, RoleAdmin) { return true } want := string(resource) max := Level(0) for _, g := range groups { g = strings.ToLower(strings.TrimSpace(g)) prefix := want + ":" if !strings.HasPrefix(g, prefix) { continue } level, ok := ParseLevel(strings.TrimPrefix(g, prefix)) if !ok { continue } if levelRank(level) > levelRank(max) { max = level } } return levelRank(max) >= levelRank(required) }