@@ -60,6 +60,10 @@ type Rule struct {
6060 // If not set, the Rule belongs to the generated ClusterRole.
6161 // If set, the Rule belongs to a Role, whose namespace is specified by this field.
6262 Namespace string `marker:",optional"`
63+ // FeatureGate specifies the feature gate that controls this RBAC rule.
64+ // If not set, the rule is always included.
65+ // If set, the rule is only included when the specified feature gate is enabled.
66+ FeatureGate string `marker:"featureGate,optional"`
6367}
6468
6569// ruleKey represents the resources and non-resources a Rule applies.
@@ -169,6 +173,10 @@ type Generator struct {
169173
170174 // Year specifies the year to substitute for " YEAR" in the header file.
171175 Year string `marker:",optional"`
176+
177+ // FeatureGates is a comma-separated list of feature gates to enable (e.g., "alpha=true,beta=false").
178+ // Only RBAC rules with matching feature gates will be included in the generated output.
179+ FeatureGates string `marker:",optional"`
172180}
173181
174182func (Generator ) RegisterMarkers (into * markers.Registry ) error {
@@ -179,9 +187,46 @@ func (Generator) RegisterMarkers(into *markers.Registry) error {
179187 return nil
180188}
181189
190+ // FeatureGateMap represents enabled feature gates as a map for efficient lookup
191+ type FeatureGateMap map [string ]bool
192+
193+ // parseFeatureGates parses a comma-separated feature gate string into a map
194+ // Format: "gate1=true,gate2=false,gate3=true"
195+ func parseFeatureGates (featureGates string ) FeatureGateMap {
196+ gates := make (FeatureGateMap )
197+ if featureGates == "" {
198+ return gates
199+ }
200+
201+ pairs := strings .Split (featureGates , "," )
202+ for _ , pair := range pairs {
203+ parts := strings .Split (strings .TrimSpace (pair ), "=" )
204+ if len (parts ) != 2 {
205+ continue
206+ }
207+ gateName := strings .TrimSpace (parts [0 ])
208+ gateValue := strings .TrimSpace (parts [1 ])
209+ gates [gateName ] = gateValue == "true"
210+ }
211+ return gates
212+ }
213+
214+ // shouldIncludeRule determines if an RBAC rule should be included based on feature gates
215+ func shouldIncludeRule (rule * Rule , enabledGates FeatureGateMap ) bool {
216+ if rule .FeatureGate == "" {
217+ // No feature gate specified, always include
218+ return true
219+ }
220+
221+ // Check if the feature gate is enabled
222+ enabled , exists := enabledGates [rule .FeatureGate ]
223+ return exists && enabled
224+ }
225+
182226// GenerateRoles generate a slice of objs representing either a ClusterRole or a Role object
183227// The order of the objs in the returned slice is stable and determined by their namespaces.
184- func GenerateRoles (ctx * genall.GenerationContext , roleName string ) ([]interface {}, error ) {
228+ func GenerateRoles (ctx * genall.GenerationContext , roleName string , featureGates string ) ([]interface {}, error ) {
229+ enabledGates := parseFeatureGates (featureGates )
185230 rulesByNSResource := make (map [string ][]* Rule )
186231 for _ , root := range ctx .Roots {
187232 markerSet , err := markers .PackageMarkers (ctx .Collector , root )
@@ -192,6 +237,12 @@ func GenerateRoles(ctx *genall.GenerationContext, roleName string) ([]interface{
192237 // group RBAC markers by namespace and separate by resource
193238 for _ , markerValue := range markerSet [RuleDefinition .Name ] {
194239 rule := markerValue .(Rule )
240+
241+ // Apply feature gate filtering
242+ if ! shouldIncludeRule (& rule , enabledGates ) {
243+ continue
244+ }
245+
195246 if len (rule .Resources ) == 0 {
196247 // Add a rule without any resource if Resources is empty.
197248 r := Rule {
@@ -201,6 +252,7 @@ func GenerateRoles(ctx *genall.GenerationContext, roleName string) ([]interface{
201252 URLs : rule .URLs ,
202253 Namespace : rule .Namespace ,
203254 Verbs : rule .Verbs ,
255+ FeatureGate : rule .FeatureGate ,
204256 }
205257 namespace := r .Namespace
206258 rulesByNSResource [namespace ] = append (rulesByNSResource [namespace ], & r )
@@ -214,6 +266,7 @@ func GenerateRoles(ctx *genall.GenerationContext, roleName string) ([]interface{
214266 URLs : rule .URLs ,
215267 Namespace : rule .Namespace ,
216268 Verbs : rule .Verbs ,
269+ FeatureGate : rule .FeatureGate ,
217270 }
218271 namespace := r .Namespace
219272 rulesByNSResource [namespace ] = append (rulesByNSResource [namespace ], & r )
@@ -367,7 +420,7 @@ func GenerateRoles(ctx *genall.GenerationContext, roleName string) ([]interface{
367420}
368421
369422func (g Generator ) Generate (ctx * genall.GenerationContext ) error {
370- objs , err := GenerateRoles (ctx , g .RoleName )
423+ objs , err := GenerateRoles (ctx , g .RoleName , g . FeatureGates )
371424 if err != nil {
372425 return err
373426 }
0 commit comments