package intentflow import ( "strconv" "strings" ) // AllowAllProjects is the wildcard sentinel for INTENT_PLAN_PROJECT_ALLOWLIST=*. const AllowAllProjects int64 = -1 // ParseProjectAllowlist parses a comma-separated project ID list. // Empty string → deny elevated tiers. "*" → allow all. Invalid tokens are skipped. func ParseProjectAllowlist(raw string) []int64 { raw = strings.TrimSpace(raw) if raw == "" { return nil } if raw == "*" { return []int64{AllowAllProjects} } parts := strings.Split(raw, ",") out := make([]int64, 0, len(parts)) seen := map[int64]struct{}{} for _, p := range parts { p = strings.TrimSpace(p) if p == "" || p == "*" { if p == "*" { return []int64{AllowAllProjects} } continue } id, err := strconv.ParseInt(p, 10, 64) if err != nil || id <= 0 { continue } if _, ok := seen[id]; ok { continue } seen[id] = struct{}{} out = append(out, id) } return out } // ProjectAllowed reports whether elevated plan tiers may act for projectID. // Legacy tier always returns true (no allowlist gate). Empty allowlist denies. func (f FeatureFlags) ProjectAllowed(projectID int64) bool { if f.PlanTier == TierLegacy || f.PlanTier == "" { return true } if len(f.ProjectAllowlist) == 0 { return false } for _, id := range f.ProjectAllowlist { if id == AllowAllProjects { return true } if id == projectID { return true } } return false }