From 3aebc996352ba9bb83279f262a2715d2b80187d8 Mon Sep 17 00:00:00 2001 From: Mukul Sharma Date: Wed, 9 Sep 2026 15:16:16 +0530 Subject: [PATCH] Grant deployer StatefulSet rights, for apps with persistent storage MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit toolshed deploys an app that asked for a persistent volume as a StatefulSet with a volumeClaimTemplate rather than a Deployment (internal/deploy.Client.ensureStatefulSet). Without this the deployer gets "forbidden" the moment anyone creates one — the two-repositories drift internal/deploy/kubernetes.go's own package doc warns about, and the same way the custom-domains Ingress rights were missed until after that feature shipped. Delete is included deliberately, not for tidiness: a Deployment and a StatefulSet share the app's selector, so switching an app between stateless and stateful must remove whichever controller it no longer is, or both stay alive fighting over the same pods. persistentvolumeclaims is read-only. The claims are created by the StatefulSet's own volumeClaimTemplates, never directly by toolshed, and deleting one would destroy an app's data — so there is no reason for this credential to be able to. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01Wajog7nELA3i8JWTjxYGHF --- extra-manifests/toolshed-deployer-rbac.yaml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/extra-manifests/toolshed-deployer-rbac.yaml b/extra-manifests/toolshed-deployer-rbac.yaml index d24a966..644934e 100644 --- a/extra-manifests/toolshed-deployer-rbac.yaml +++ b/extra-manifests/toolshed-deployer-rbac.yaml @@ -57,6 +57,19 @@ rules: - apiGroups: ["apps"] resources: ["deployments"] verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] + # An app with persistent storage is a StatefulSet instead of a Deployment + # (internal/deploy.Client.ensureStatefulSet). Delete is needed on both: + # switching an app between stateless and stateful must remove whichever + # controller it no longer is, or the two fight over the same pods. + - apiGroups: ["apps"] + resources: ["statefulsets"] + verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] + # Read-only. The claims themselves are created by the StatefulSet's own + # volumeClaimTemplates, never directly here — this is only to observe + # them, and deleting one would destroy an app's data. + - apiGroups: [""] + resources: ["persistentvolumeclaims"] + verbs: ["get", "list", "watch"] # The policy that stops one app reaching another. - apiGroups: ["networking.k8s.io"] resources: ["networkpolicies"]