From 5256d95d8960d205994544dfec8d1ca1e173b361 Mon Sep 17 00:00:00 2001 From: Nikola Jokic Date: Mon, 28 Sep 2026 10:23:50 +0200 Subject: [PATCH] Fix patch permissions in generated controller RBAC (#4686) --- config/rbac/role.yaml | 15 +---- config/rbac/role_test.go | 64 +++++++++++++++++++ .../autoscalinglistener_controller.go | 8 +-- 3 files changed, 71 insertions(+), 16 deletions(-) create mode 100644 config/rbac/role_test.go diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml index dc0becfd..ba822296 100644 --- a/config/rbac/role.yaml +++ b/config/rbac/role.yaml @@ -17,6 +17,8 @@ rules: - persistentvolumeclaims - pods - pods/finalizers + - secrets + - serviceaccounts verbs: - create - delete @@ -42,18 +44,6 @@ rules: - pods/status verbs: - get -- apiGroups: - - "" - resources: - - secrets - - serviceaccounts - verbs: - - create - - delete - - get - - list - - update - - watch - apiGroups: - actions.github.com resources: @@ -167,5 +157,6 @@ rules: - delete - get - list + - patch - update - watch diff --git a/config/rbac/role_test.go b/config/rbac/role_test.go new file mode 100644 index 00000000..7884000d --- /dev/null +++ b/config/rbac/role_test.go @@ -0,0 +1,64 @@ +/* +Copyright 2026 The actions-runner-controller authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package rbac_test + +import ( + "os" + "slices" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + rbacv1 "k8s.io/api/rbac/v1" + "sigs.k8s.io/yaml" +) + +func TestManagerRolePermissions(t *testing.T) { + t.Parallel() + + data, err := os.ReadFile("role.yaml") + require.NoError(t, err) + + var role rbacv1.ClusterRole + require.NoError(t, yaml.UnmarshalStrict(data, &role)) + + for _, tc := range []struct { + apiGroup string + resource string + }{ + {apiGroup: "", resource: "secrets"}, + {apiGroup: "", resource: "serviceaccounts"}, + {apiGroup: rbacv1.GroupName, resource: "roles"}, + {apiGroup: rbacv1.GroupName, resource: "rolebindings"}, + } { + t.Run(tc.resource, func(t *testing.T) { + t.Parallel() + + var verbs []string + for _, rule := range role.Rules { + if slices.Contains(rule.APIGroups, tc.apiGroup) && + slices.Contains(rule.Resources, tc.resource) && + len(rule.ResourceNames) == 0 { + verbs = append(verbs, rule.Verbs...) + } + } + + assert.Subset(t, verbs, []string{"create", "delete", "get", "list", "patch", "update", "watch"}, + "manager role must allow both initial creation and reconciliation of %s", tc.resource) + }) + } +} diff --git a/controllers/actions.github.com/autoscalinglistener_controller.go b/controllers/actions.github.com/autoscalinglistener_controller.go index c9d2d83e..c9990e0a 100644 --- a/controllers/actions.github.com/autoscalinglistener_controller.go +++ b/controllers/actions.github.com/autoscalinglistener_controller.go @@ -68,10 +68,10 @@ type AutoscalingListenerReconciler struct { // +kubebuilder:rbac:groups=core,resources=pods,verbs=get;list;watch;create;update;patch;delete // +kubebuilder:rbac:groups=core,resources=pods/status,verbs=get -// +kubebuilder:rbac:groups=core,resources=secrets,verbs=get;list;watch;create;update -// +kubebuilder:rbac:groups=core,resources=serviceaccounts,verbs=get;list;watch;create;update -// +kubebuilder:rbac:groups=rbac.authorization.k8s.io,resources=roles,verbs=create;delete;get;list;watch;update -// +kubebuilder:rbac:groups=rbac.authorization.k8s.io,resources=rolebindings,verbs=create;delete;get;list;watch;update +// +kubebuilder:rbac:groups=core,resources=secrets,verbs=get;list;watch;create;update;patch +// +kubebuilder:rbac:groups=core,resources=serviceaccounts,verbs=get;list;watch;create;update;patch +// +kubebuilder:rbac:groups=rbac.authorization.k8s.io,resources=roles,verbs=create;delete;get;list;watch;update;patch +// +kubebuilder:rbac:groups=rbac.authorization.k8s.io,resources=rolebindings,verbs=create;delete;get;list;watch;update;patch // +kubebuilder:rbac:groups=actions.github.com,resources=autoscalinglisteners,verbs=get;list;watch;create;update;patch;delete // +kubebuilder:rbac:groups=actions.github.com,resources=autoscalinglisteners/status,verbs=get;update;patch // +kubebuilder:rbac:groups=actions.github.com,resources=autoscalinglisteners/finalizers,verbs=update