diff --git a/console-web/app/(dashboard)/tenants/[namespace]/[name]/tenant-detail-client.tsx b/console-web/app/(dashboard)/tenants/[namespace]/[name]/tenant-detail-client.tsx index 10468f7..a55fcc3 100644 --- a/console-web/app/(dashboard)/tenants/[namespace]/[name]/tenant-detail-client.tsx +++ b/console-web/app/(dashboard)/tenants/[namespace]/[name]/tenant-detail-client.tsx @@ -210,6 +210,7 @@ export function TenantDetailClient({ namespace, name, initialTab, initialYamlEdi const [secCtxLoaded, setSecCtxLoaded] = useState(false) const [secCtxLoading, setSecCtxLoading] = useState(false) const [secCtxSaving, setSecCtxSaving] = useState(false) + const [secCtxDelegated, setSecCtxDelegated] = useState(false) const [secCtx, setSecCtx] = useState({ runAsUser: "", runAsGroup: "", @@ -337,6 +338,7 @@ export function TenantDetailClient({ namespace, name, initialTab, initialYamlEdi useEffect(() => { setSecCtxLoaded(false) + setSecCtxDelegated(false) setSecCtxDirty(cleanSecurityContextDirtyFields()) }, [namespace, name]) @@ -350,6 +352,7 @@ export function TenantDetailClient({ namespace, name, initialTab, initialYamlEdi fsGroup: data.fsGroup?.toString() ?? "", runAsNonRoot: data.runAsNonRoot === null ? "default" : data.runAsNonRoot ? "true" : "false", }) + setSecCtxDelegated(data.operatorDefaultsDelegated) setSecCtxDirty(cleanSecurityContextDirtyFields()) } catch (e) { const err = e as ApiError @@ -362,6 +365,10 @@ export function TenantDetailClient({ namespace, name, initialTab, initialYamlEdi const handleSaveSecurityContext = async (e: React.FormEvent) => { e.preventDefault() + if (secCtxDelegated) { + toast.error(t("Platform-delegated security contexts can only be changed in Raw YAML.")) + return + } setSecCtxSaving(true) try { await api.updateSecurityContext(namespace, name, buildSecurityContextUpdate(secCtx, secCtxDirty)) @@ -1300,6 +1307,18 @@ export function TenantDetailClient({ namespace, name, initialTab, initialYamlEdi ) : (
+ {secCtxDelegated && ( +
+

+ {t( + "Security defaults are delegated to platform admission. Effective UID/GID and runAsNonRoot values are platform-owned.", + )} +

+ +
+ )}
@@ -1307,6 +1326,7 @@ export function TenantDetailClient({ namespace, name, initialTab, initialYamlEdi type="number" placeholder="10001" value={secCtx.runAsUser} + disabled={secCtxDelegated} onChange={(e) => { setSecCtx((s) => ({ ...s, runAsUser: e.target.value })) setSecCtxDirty((dirty) => ({ ...dirty, runAsUser: true })) @@ -1319,6 +1339,7 @@ export function TenantDetailClient({ namespace, name, initialTab, initialYamlEdi type="number" placeholder="10001" value={secCtx.runAsGroup} + disabled={secCtxDelegated} onChange={(e) => { setSecCtx((s) => ({ ...s, runAsGroup: e.target.value })) setSecCtxDirty((dirty) => ({ ...dirty, runAsGroup: true })) @@ -1331,6 +1352,7 @@ export function TenantDetailClient({ namespace, name, initialTab, initialYamlEdi type="number" placeholder="10001" value={secCtx.fsGroup} + disabled={secCtxDelegated} onChange={(e) => { setSecCtx((s) => ({ ...s, fsGroup: e.target.value })) setSecCtxDirty((dirty) => ({ ...dirty, fsGroup: true })) @@ -1344,6 +1366,7 @@ export function TenantDetailClient({ namespace, name, initialTab, initialYamlEdi