diff --git a/charts/nudgebee-agent/templates/forwarder-service-account.yaml b/charts/nudgebee-agent/templates/forwarder-service-account.yaml index e4d437f8..ffb82da1 100644 --- a/charts/nudgebee-agent/templates/forwarder-service-account.yaml +++ b/charts/nudgebee-agent/templates/forwarder-service-account.yaml @@ -120,7 +120,12 @@ rules: - {{ if .Values.openshift.createScc }}"{{ include "nudgebee-agent.fullname" . }}-scc"{{ else }}{{ .Values.openshift.sccName | quote }}{{ end }} {{- end }} -{{- if (.Capabilities.APIVersions.Has "argoproj.io/v1alpha1/Rollout") }} + # Argo Rollouts permissions are granted unconditionally (same rationale as + # karpenter below): an RBAC rule for an absent CRD is inert and becomes + # active the moment Argo Rollouts is installed. Gating on .Capabilities left + # clusters that installed the CRD after this chart without rollouts RBAC + # until the next helm upgrade, so kubewatch could never emit Rollout change + # events. kubewatch probes the CRD before watching, so the grant is safe. - apiGroups: - argoproj.io resources: @@ -129,7 +134,6 @@ rules: - get - list - watch -{{- end }} # Karpenter permissions are granted unconditionally. An RBAC rule for an # absent CRD is inert and becomes active the moment karpenter is installed. diff --git a/charts/nudgebee-agent/templates/runner-service-account-readonly.yaml b/charts/nudgebee-agent/templates/runner-service-account-readonly.yaml index ca2f017c..13e75af0 100644 --- a/charts/nudgebee-agent/templates/runner-service-account-readonly.yaml +++ b/charts/nudgebee-agent/templates/runner-service-account-readonly.yaml @@ -251,7 +251,9 @@ rules: - nodes verbs: ["get", "list"] -{{- if (.Capabilities.APIVersions.Has "argoproj.io/v1alpha1/Rollout") }} + # Argo Rollouts read permissions are granted unconditionally. An RBAC rule + # for an absent CRD is inert and becomes active the moment Argo Rollouts is + # installed (see runner-service-account.yaml for the full rationale). - apiGroups: - argoproj.io resources: @@ -260,7 +262,6 @@ rules: - get - list - watch -{{- end }} # Karpenter read permissions are granted unconditionally. An RBAC rule for # an absent CRD is inert and becomes active the moment karpenter is diff --git a/charts/nudgebee-agent/templates/runner-service-account.yaml b/charts/nudgebee-agent/templates/runner-service-account.yaml index 0e53f882..03a969ac 100644 --- a/charts/nudgebee-agent/templates/runner-service-account.yaml +++ b/charts/nudgebee-agent/templates/runner-service-account.yaml @@ -434,21 +434,30 @@ rules: - delete {{- end }} -{{- if (.Capabilities.APIVersions.Has "argoproj.io/v1alpha1/Rollout") }} + # Argo Rollouts permissions are granted unconditionally (same rationale as + # karpenter below): an RBAC rule for an absent CRD is inert and becomes + # active the moment Argo Rollouts is installed. Gating on .Capabilities left + # clusters that installed the CRD after this chart without rollouts RBAC + # until the next helm upgrade (and never worked under GitOps/templated + # installs). The runner probes the CRD before registering informers, so the + # grant is safe. Write verbs are gated behind runner.enableWritePermissions. - apiGroups: - argoproj.io resources: - rollouts + - rollouts/scale verbs: - get - list - watch - patch - update + # delete is unconditional for parity with the apps workloads block above + # (delete_workload treats Deployment and Rollout identically); create + # stays gated like create for apps kinds. + - delete {{- if .Values.runner.enableWritePermissions }} - create - - delete -{{- end }} {{- end }} # Karpenter read permissions are granted unconditionally. An RBAC rule for an diff --git a/charts/nudgebee-agent/values.yaml b/charts/nudgebee-agent/values.yaml index 7b81d9a2..f4479af0 100644 --- a/charts/nudgebee-agent/values.yaml +++ b/charts/nudgebee-agent/values.yaml @@ -65,7 +65,7 @@ runnerServiceAccount: runner: image: repository: ghcr.io/nudgebee/nudgebee-agent - tag: 2026-07-15T16-09-55_6d1cadca59e43257a6b45048731c4a4c105b8699 + tag: 2026-07-16T09-02-10_585a6253271b189078eb2edbcad9ee65cf82e685 # Image template the pod_profiler action launches debugger pods from. # The agent substitutes `{}` for the variant (bpf, jvm, python, perf, ruby). # Surfaces as PROFILER_IMAGE; leave empty to fall back to the binary default. diff --git a/runner/pkg/discovery/service.go b/runner/pkg/discovery/service.go index c58907c6..bb3ac37b 100644 --- a/runner/pkg/discovery/service.go +++ b/runner/pkg/discovery/service.go @@ -326,8 +326,9 @@ var rolloutGVR = schema.GroupVersionResource{Group: "argoproj.io", Version: "v1a // RegisterRollouts wires an Argo Rollout dynamic informer so Rollouts reach // the backend inventory like Deployments do. Returns false (with a log) when -// the Rollout CRD is not served or the agent lacks list RBAC — the chart only -// grants rollouts RBAC when the CRD existed at install time, and registering +// the Rollout CRD is not served or the agent lacks list RBAC — the chart now +// grants rollouts RBAC unconditionally, but releases rendered before that +// change (or with a trimmed clusterrole) may still lack it, and registering // an informer that can't list would block WaitForCacheSync forever and stall // all discovery. Call before Run(). // @@ -346,7 +347,7 @@ func (s *Service) RegisterRollouts(ctx context.Context, dyn dynamic.Interface) b probeCtx, cancel := context.WithTimeout(ctx, 10*time.Second) defer cancel() if _, err := dyn.Resource(rolloutGVR).Namespace(metav1.NamespaceAll).List(probeCtx, metav1.ListOptions{Limit: 1}); err != nil { - s.logger.Warn("rollout discovery disabled: list probe failed (rollouts RBAC missing? chart gates it on the CRD existing at install time)", "err", err) + s.logger.Warn("rollout discovery disabled: list probe failed (rollouts RBAC missing? upgrade the chart — older releases gated it on the CRD existing at render time)", "err", err) return false } if s.dynFactory == nil {