Skip to content

radar-hub: add auth.oidc.clusterAccess for new cluster installs - #51

Open
arlenskh wants to merge 6 commits into
mainfrom
arlen/rad-578-radar-hub-cluster-access
Open

arlenskh wants to merge 6 commits into
mainfrom
arlen/rad-578-radar-hub-cluster-access

Conversation

@arlenskh

@arlenskh arlenskh commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor

Why

RAD-578. On a self-hosted hub, the org's cluster access mode (roles | idp) is configured next to the IdP, in Helm values. New Radar installs generated by the hub wizard inherit it:

  • unset (default): the hub picks idp while IdP group forwarding is on (groupsClaim set), roles otherwise.
  • roles: the Radar chart keeps the hub-role ClusterRoleBindings. The explicit opt-out.
  • idp: new installs get cloud.defaultRbac.create=false, and IdP groups (radar:idp:<id>) decide cluster access. Refused at template time without auth.oidc.issuer or auth.oidc.groupsClaim: those installs would give nobody access.

Existing clusters are never changed by this value.

What

  • values.yaml: documented auth.oidc.clusterAccess: "".
  • values.schema.json: enum "" | roles | idp.
  • templates/deployment-hub.yaml: sets RADAR_HUB_OIDC_CLUSTER_ACCESS inside the existing OIDC block, only when the value is set; fails on idp without OIDC or groupsClaim.
  • New test tests/deployment_hub_oidc_cluster_access_test.yaml.

No chart version bump in this draft. I'll bump when this is released together with the hub change.

Test plan

  • helm unittest charts/radar-hub: 23/23 (the new suite failed before the change)
  • tests/render-matrix.sh passes
  • helm lint passes

Depends on skyhook-dev/radar-hub#272, which reads the env var.

Cross-review follow-up (2026-09-29)

  • values.yaml comments (1a9cfc9): groupsClaim no longer calls a missing claim harmless (an unset clusterAccess follows it to idp, so check that groups arrive first), and useRefreshToken says that without it a session carrying IdP groups ends when the first ID token expires (skyhook-dev/radar-hub#272).
  • NOTES.txt announces both default changes (6439f2f): after install or upgrade it prints which cluster access mode new clusters get (unset follows groupsClaim to idp) and whether refresh tokens are on and what the IdP client needs. The idp checks moved to secret.yaml with the other value checks; the unknown-value test matches the schema's enum error.
  • At release, in this PR: rebase onto main, bump to 1.10.0 (two defaults change behaviour on upgrade), set appVersion to the Hub release with RAD-578, and name that Hub version in the clusterAccess comment. Merging publishes the chart, so this needs explicit approval of the version.
  • The branch is based on 1.8.0-rc.2; main is 1.9.0-rc.3. Rebase after the hub and web images with RAD-578 are released; the version bump goes in the rc release PR.

🤖 Generated with Claude Code


Note

Medium Risk
Changes default behavior for new cluster installs when OIDC group forwarding is enabled (unless operators set clusterAccess=roles), which affects authorization for newly connected clusters.

Overview
Adds auth.oidc.clusterAccess ("", roles, or idp) so self-hosted installs control how new Radar cluster installs grant Kubernetes access, wired to the hub as RADAR_HUB_OIDC_CLUSTER_ACCESS when explicitly set. Unset defaults are documented as IdP groups when groupsClaim is on, otherwise hub role bindings; existing clusters are unchanged.

Install-time guards refuse idp without OIDC issuer or groupsClaim, and post-install NOTES spell out which mode new clusters will use. Chart version bumps to 1.11.0-rc.1 with matching appVersion, plus schema, values docs, and helm-unittest coverage for env rendering and validation failures.

Reviewed by Cursor Bugbot for commit 56c16d3. Bugbot is set up for automated code reviews on this repo. Configure here.

@qodo-free-for-open-source-projects

Copy link
Copy Markdown

PR Summary by Qodo

Configure cluster access for new Radar installs through hub OIDC settings

✨ Enhancement ⚙️ Configuration changes 🧪 Tests 📝 Documentation 🕐 20-40 Minutes

Grey Divider

AI Description

• Add a Helm setting for how new clusters grant access through hub roles or IdP groups.
• Reject explicit IdP access when OIDC or group forwarding is not configured.
• Enable OIDC token refresh by default and test the resulting deployment settings.
Diagram

graph TD
  V["Helm values"] --> G{"Explicit idp valid?"} --> D["Hub deployment"] --> H["Connect wizard"] --> N["New cluster RBAC"]
  G --> E["Reject invalid idp"]
  I["IdP groups"] --> N
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Validate access mode only in the hub
  • ➕ Keeps access-mode validation in one place.
  • ➖ An invalid explicit idp setting would not fail during Helm rendering.
  • ➖ The chart can identify missing issuer and groupsClaim earlier.
2. Default new installs to hub roles
  • ➕ Avoids choosing IdP access when a configured groups claim emits no groups.
  • ➖ Does not meet the intended behavior of following enabled IdP group forwarding.
  • ➖ Requires administrators to opt in separately to IdP-based access.

Recommendation: Keep the chart's early checks and let the hub choose the mode when clusterAccess is unset. The chart cannot verify that groups actually arrive, so the documented pre-install check remains important. Review and release the refresh-token default change alongside the access setting, and pair this chart with a hub image that reads the new environment variable.

Files changed (5) +161 / -19

Enhancement (1) +15 / -0
deployment-hub.yamlValidate and pass OIDC cluster access mode +15/-0

Validate and pass OIDC cluster access mode

• Rendering fails for explicit idp mode without an OIDC issuer or groups claim. When OIDC is enabled, a nonempty clusterAccess value is passed to the hub as RADAR_HUB_OIDC_CLUSTER_ACCESS.

charts/radar-hub/templates/deployment-hub.yaml

Tests (2) +103 / -11
deployment_hub_oidc_cluster_access_test.yamlCover cluster access environment and validation +86/-0

Cover cluster access environment and validation

• New Helm tests check omitted and explicit values, absence without OIDC, schema rejection of unknown values, and template failures for invalid idp configurations.

charts/radar-hub/tests/deployment_hub_oidc_cluster_access_test.yaml

deployment_hub_sessions_test.yamlAlign session tests with default token refresh +17/-11

Align session tests with default token refresh

• Tests now expect the OIDC refresh environment flag by default and verify that setting useRefreshToken to false omits it.

charts/radar-hub/tests/deployment_hub_sessions_test.yaml

Other (2) +43 / -8
values.schema.jsonConstrain cluster access configuration values +8/-0

Constrain cluster access configuration values

• Adds auth.oidc.clusterAccess as a string restricted to empty, roles, or idp.

charts/radar-hub/values.schema.json

values.yamlDocument access modes and enable refresh by default +35/-8

Document access modes and enable refresh by default

• Adds an unset-by-default clusterAccess setting describing access for new installs and the risk of a missing groups claim. Changes useRefreshToken to true by default and clarifies token-expiry behavior when refresh is unavailable.

charts/radar-hub/values.yaml

@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented Sep 29, 2026 •

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0) 🎨 UX issues (0) 🔗 Cross-repo conflicts (3) 📜 Skill insights (0)

Grey Divider


Action required

1. New installs keep hub-role access 🔗 Cross-repo conflict ⛨ Security
Description
The chart emits RADAR_HUB_OIDC_CLUSTER_ACCESS=idp, but radar-hub-web’s Helm and GitOps install
generators never set cloud.defaultRbac.create=false. When users generate a new cluster install in
this mode, the Radar chart retains its default hub-role ClusterRoleBindings instead of making access
depend only on IdP groups.
Code

charts/radar-hub/templates/deployment-hub.yaml[R278-280]

+            {{- with .Values.auth.oidc.clusterAccess }}
+            - name: RADAR_HUB_OIDC_CLUSTER_ACCESS
+              value: {{ . | quote }}
Evidence
The PR defines IdP mode as disabling Radar’s default RBAC, while the cross-repo install generators
omit that setting; the Radar chart defaults it to true.

helm-charts -> radar-hub-web
charts/radar-hub/templates/deployment-hub.yaml[278-281]
charts/radar-hub/values.yaml[474-481]
charts/radar/values.yaml[445-448]
charts/radar/templates/cloud-rbac.yaml[24-38]
External repo: skyhook-dev/radar-hub-web, src/pages/installCommand.ts [287-307]
External repo: skyhook-dev/radar-hub-web, src/pages/installArtifacts.ts [101-124]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The chart passes IdP cluster-access mode to the Hub, but radar-hub-web still generates Radar installs with default hub-role bindings.
## Fix Focus Areas
- charts/radar-hub/templates/deployment-hub.yaml[278-280]
- src/pages/installCommand.ts[287-307]
- src/pages/installArtifacts.ts[101-124]
## Recommended Fix
Update radar-hub-web’s Helm, Argo CD, and Flux fresh-install generators to consume the Hub’s cluster-access setting and emit `cloud.defaultRbac.create=false` in IdP mode. Coordinate the web image release with the chart and Hub change.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

2. Refresh-token guidance gives wrong default 🔗 Cross-repo conflict ≡ Correctness
Description
The chart changes auth.oidc.useRefreshToken to true, but radar-docs still lists its default as
false and says the Hub does not refresh tokens by default. Operators following the self-hosted
authentication guidance therefore get an incorrect account of when their sessions contact the IdP
and update groups.
Code

charts/radar-hub/values.yaml[473]

+    useRefreshToken: true
Evidence
The new chart default and emitted environment variable conflict directly with both documentation
statements.

helm-charts -> radar-docs
charts/radar-hub/values.yaml[457-473]
charts/radar-hub/templates/deployment-hub.yaml[273-277]
External repo: skyhook-dev/radar-docs, cloud/self-hosted/configuration.mdx [101-104]
External repo: skyhook-dev/radar-docs, cloud/self-hosted/auth.mdx [319-333]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The chart enables refresh tokens by default, while radar-docs describes the previous default and its session behavior.
## Fix Focus Areas
- charts/radar-hub/values.yaml[457-473]
- cloud/self-hosted/configuration.mdx[101-104]
- cloud/self-hosted/auth.mdx[319-333]
## Recommended Fix
Update radar-docs’ configuration reference and authentication guidance to describe refresh as the chart default, including the documented behavior when the IdP supplies no refresh token.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Google setup risks inaccessible clusters 🔗 Cross-repo conflict ≡ Correctness
Description
The chart’s empty clusterAccess now selects IdP mode when the default groupsClaim is set, while
radar-docs’ Google Workspace recipe leaves that claim enabled despite stating Google emits no
groups. Once the dependent web wizard applies IdP mode to new installs, users following that recipe
need clusterAccess: roles or another source of group subjects to avoid clusters with no usable
access bindings.
Code

charts/radar-hub/values.yaml[R490-492]

+    # Requires a Hub that reads RADAR_HUB_OIDC_CLUSTER_ACCESS; an older Hub
+    # ignores it and behaves as roles.
+    clusterAccess: ""
Evidence
The chart selects IdP mode from a nonempty default claim, but the documented Google setup cannot
supply the group subjects that mode requires.

helm-charts -> radar-docs
charts/radar-hub/values.yaml[384-396]
charts/radar-hub/values.yaml[474-492]
External repo: skyhook-dev/radar-docs, cloud/self-hosted/auth.mdx [136-148]
External repo: skyhook-dev/radar-docs, cloud/self-hosted/auth.mdx [228-249]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The documented Google Workspace configuration leaves group passthrough enabled even though Google supplies no groups, while the new cluster-access default selects IdP mode.
## Fix Focus Areas
- charts/radar-hub/values.yaml[480-492]
- cloud/self-hosted/auth.mdx[136-148]
- cloud/self-hosted/auth.mdx[228-249]
## Recommended Fix
Update radar-docs’ Google Workspace recipe and group-passthrough guidance to require `auth.oidc.clusterAccess: roles` when usable IdP groups are unavailable. Coordinate the guidance with the web wizard’s IdP-mode release.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Tip of the day
💡 Did you know, you can keep summaries lean with Findings visible per group, which tucks the rest behind a View link

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment thread charts/radar-hub/templates/deployment-hub.yaml
#
# Requires Hub 1.6.0 or newer; an older Hub ignores it.
useRefreshToken: false
useRefreshToken: true

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remediation recommended

2. Refresh-token guidance gives wrong default 🔗 Cross-repo conflict ≡ Correctness

The chart changes auth.oidc.useRefreshToken to true, but radar-docs still lists its default as
false and says the Hub does not refresh tokens by default. Operators following the self-hosted
authentication guidance therefore get an incorrect account of when their sessions contact the IdP
and update groups.
Agent Prompt
## Issue description
The chart enables refresh tokens by default, while radar-docs describes the previous default and its session behavior.
## Fix Focus Areas
- charts/radar-hub/values.yaml[457-473]
- cloud/self-hosted/configuration.mdx[101-104]
- cloud/self-hosted/auth.mdx[319-333]
## Recommended Fix
Update radar-docs’ configuration reference and authentication guidance to describe refresh as the chart default, including the documented behavior when the IdP supplies no refresh token.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated in radar-docs#126.

Comment thread charts/radar-hub/values.yaml Outdated
Comment on lines +490 to +492
# Requires a Hub that reads RADAR_HUB_OIDC_CLUSTER_ACCESS; an older Hub
# ignores it and behaves as roles.
clusterAccess: ""

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remediation recommended

3. Google setup risks inaccessible clusters 🔗 Cross-repo conflict ≡ Correctness

The chart’s empty clusterAccess now selects IdP mode when the default groupsClaim is set, while
radar-docs’ Google Workspace recipe leaves that claim enabled despite stating Google emits no
groups. Once the dependent web wizard applies IdP mode to new installs, users following that recipe
need clusterAccess: roles or another source of group subjects to avoid clusters with no usable
access bindings.
Agent Prompt
## Issue description
The documented Google Workspace configuration leaves group passthrough enabled even though Google supplies no groups, while the new cluster-access default selects IdP mode.
## Fix Focus Areas
- charts/radar-hub/values.yaml[480-492]
- cloud/self-hosted/auth.mdx[136-148]
- cloud/self-hosted/auth.mdx[228-249]
## Recommended Fix
Update radar-docs’ Google Workspace recipe and group-passthrough guidance to require `auth.oidc.clusterAccess: roles` when usable IdP groups are unavailable. Coordinate the guidance with the web wizard’s IdP-mode release.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in radar-docs#126 (a6c5c5d): the Google recipe sets groupsClaim: "".

@arlenskh
arlenskh requested a review from nadaverell September 30, 2026 19:19
nadaverell pushed a commit to skyhook-io/radar that referenced this pull request Oct 4, 2026
…1899)

## Why

Part of RAD-578: in Radar Cloud, hub roles (`owner` / `member` /
`viewer`) should cover Radar's own features, and for orgs with an IdP,
IdP groups (`radar:idp:<id>`) should decide cluster access. Those orgs
turn the chart's hub-role bindings off
(`cloud.defaultRbac.create=false`). Two things broke in that setup:

1. **Hub background jobs lost cluster access.** The alerts worker and
timeline puller only reached the cluster through `radar:owner` →
`admin`, so alerts and the hub timeline went silent. The same thing
happens today to anyone who sets `defaultRbac.owner=false`.
2. **The Cloud role overrode Kubernetes.** Helm reads and writes and
in-cluster probe pods were refused on the Cloud role before Kubernetes
was asked. They run as the impersonated user, so a `viewer` whose IdP
group grants `edit` in a namespace couldn't roll back there.

## What

**Chart**
- New `cloud-rbac-system.yaml`: binds `radar:system` (the hub's alerts
worker and timeline puller) to `view` plus Secret `get/list/watch`. The
cluster-read and integration-read add-ons also bind it, and now still
render when `defaultRbac.create=false`. AI diagnose does not use it; it
stays on `radar:viewer`.
- Secret read is there for Helm release alerts and Secret changes in the
hub timeline: Radar lists releases as the caller, and Helm stores
releases as Secrets. It's read-only, and it's far less than today, where
these identities get `admin` through `radar:owner`.
- New value `cloud.systemRbac` (default `true`), all or nothing. An
absent value counts as **off**, like `defaultRbac.create`, so a
`--reuse-values` upgrade from an older release never gains cluster-wide
Secret read without someone choosing it. Schema, chart README and
`docs/authentication.md` updated.

**Backend**
- Removed `requireCloudRole` from all 16 Helm handlers and the MCP
`get_helm_release` gate.
- Removed the role gate from the in-cluster reachability test
(capability check, run endpoint, MCP `diagnose`). Probe pods are created
with the user's impersonated client, and `reachability.Capability`
already checks Kubernetes permissions.
- The Cloud role still gates what runs as Radar's service account:
settings, Argo CD and Kubecost integration, audit settings,
self-upgrade.

**UI**
- `RoleGatedPanel` is removed from the Helm Manifest, Values and Compare
tabs. `useCanHelmAct(namespace)` checks the user's own Helm write
permission in the release's namespace (see below).
- `RestrictedState` keeps the exact group, resource and verbs for the
denied kind in its RBAC snippet, and leaves the subject as a placeholder
the admin fills in.

OSS without a Hub is unaffected: the cloud templates need
`cloud.enabled`, and the role gates already did nothing without a Cloud
role.

## Test plan

- [x] `helm unittest` (new `cloud_rbac_system_test.yaml`, updated
integration-read suite) and `scripts/test-chart.sh`
- [x] `go test ./...` and `pkg` module tests. The chart-rendering
`TestIntegrationReadBindings` now expects `radar:system`.
- [x] New `TestHelmHandlers_NotGatedOnCloudRole` and
`TestTraceInClusterNotGatedOnCloudRole`, both red before the change
- [x] `make tsc`; web and k8s-ui vitest, plus a new
`RestrictedState.test.tsx`
- [x] Visual test on EKS, with proxy auth simulating Cloud users:
- a Cloud `viewer` with admin-level RBAC sees Manifest, Values, Rollback
and Compare;
- a `viewer` with only `view` gets Kubernetes' "Access Restricted"
instead of a role message;
  - the RBAC snippet binds the user's first IdP group;
  - OSS without auth is unchanged;
- a user with no access sees the banner on Home, Resources and Topology;
25 groups stay collapsed; checked in dark and light themes.
- [x] `TestHandleAuthMe_NoNamespaceAccess` (reported only when connected
with zero namespaces) and `noClusterAccess.test.ts`

**No-access banner**
- A user who can read no namespace used to see an empty cluster ("No
Node found", every count "–") with no explanation. That's the day-one
view for an IdP org before any binding exists, and it also happens to
OSS proxy/OIDC users with no RBAC.
- `/api/auth/me` now reports `noNamespaceAccess: true` for such a user,
and only once connected: before that, namespace discovery fails closed.
- The shell shows a banner above every view, including when the Hub
embeds Radar. It says why the views are empty and who is signed in, with
the user's bindable groups in a collapsed list, so they can tell a
cluster admin which group to bind.
- It's based on the user's own access, not on how the org means to set
up the cluster, so it never claims a cluster is IdP-only.
- While shown, it re-checks every minute, so it clears once a binding
lands.

## Release order

Release this chart before the Hub web wizard can default new installs to
IdP-only access. The Hub PRs keep sending `radar:owner` for one release
so older charts keep working.

Related: skyhook-dev/radar-hub#272, skyhook-dev/radar-hub-web#326,
skyhook-io/helm-charts#51.

## Cross-review follow-up (2026-09-29)

- **Helm writes check the signed-in user, not Radar's ServiceAccount**
(`55fc3efa`). With a user attached, `requireHelmWrite` checks the
caller's `secrets/create` in the release's namespace, before any chart
is fetched (so a caller who could never install can't make Radar fetch
an arbitrary repo URL). Chart-cache and OCI-source changes need no
cluster permission. No-auth installs keep the ServiceAccount check.
`/api/capabilities?namespace=` reports `helmWrite` per namespace; with
auth on, a denial names the user's RBAC, not `rbac.helm`. Also:
streaming rollback runs as the user, and a forbidden release read
returns 403.
- **No write-everything ServiceAccount under `rbac.helm` in Cloud/auth
mode** (`acbdbad4`). The `*/*` create/update/patch/delete rule renders
only for no-auth, non-Cloud installs; every Helm action there runs as
the user, and no ServiceAccount write path depends on it (audited).
- **`radar:system` is one all-or-nothing grant; absent means off**
(`acbdbad4`, `c4018889`).
- **`/auth/me` reads the permission cache only** (`e51efe09`), so app
startup no longer runs a SubjectAccessReview per namespace. The banner
title now reads "You can't read any namespace in this cluster".
- Known limit: on a first visit to a large cluster, the banner's
`/auth/me` check can arrive before namespace discovery fills the cache,
so the banner may need one reload to appear. A retry loop for this
(`6eb752a8`) was reverted (`c0f51b96`) as not worth the extra state.
- **The banner's group list is `ph-no-capture`** (`af4afc7c`): group IDs
name the customer's directory structure, and Radar Cloud records this
view in session replay.
- `go test` for `internal/helm`, `internal/k8s`, `internal/server` pass
(the one `internal/server` failure,
`TestNoEffortNotesReferencedFromSource`, comes from other local
worktrees under `.claude/`). `helm unittest`: 70/72, the 2 failures
(`service_test.yaml`) also fail on HEAD. Web vitest for
contexts/helm/api pass.
- Follow-ups: RAD-656 (reads through the cache aren't checked per kind),
RAD-657 (diagnose permissions; redact Helm manifest/notes diffs before
any diagnose identity gets Secret read).

🤖 Generated with [Claude Code](https://claude.com/claude-code)





<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **High Risk**
> Changes cluster RBAC (including optional cluster-wide Secret read for
`radar:system`) and broadens who can attempt Helm and probe operations
based on Kubernetes permissions instead of Cloud role, which affects
security boundaries for IdP-only orgs.
> 
> **Overview**
> Radar Cloud orgs that turn off default hub-role bindings
(`cloud.defaultRbac.create=false`) can keep **alerts and the hub
timeline** working via a new **`cloud.systemRbac`** path that binds
**`radar:system`** to read-only access (`view`,
cluster-read/integration-read add-ons, and cluster-wide **Secret**
read). That grant is separate from tier bindings; **`--reuse-values`
upgrades without the key stay off** until explicitly enabled.
> 
> **Authorization shifts from Cloud tier to Kubernetes RBAC** for
user-impersonated work: Helm reads/writes, previews, rollbacks
(including streaming), in-cluster reachability probes, and MCP
Helm/diagnose paths **no longer call `requireCloudRole`**. Writes are
gated by the caller’s **`secrets/create` in the release namespace**
(before chart fetch); release read failures surface as **403** when RBAC
denies Secret access. The chart **stops granting cluster-wide `*/*`
write on Radar’s ServiceAccount** when auth or cloud mode is on—only
no-auth installs keep that for Helm-as-SA.
> 
> The UI drops **member-only Helm panels** and uses **namespace-scoped
`useCanHelmAct`**, aligned with per-namespace **`helmWrite`**
capabilities. **`/api/auth/me`** adds **`noNamespaceAccess`** and a
**warning banner** when a connected user can read no namespaces.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
812e48f. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: Arlen Vasconcelos <arlenvasconcelos@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
nadaverell added a commit that referenced this pull request Oct 7, 2026
Hub 1.10.0 ends a self-hosted OIDC session that carries IdP groups and has
no refresh token when its ID token expires, instead of keeping it and
silently dropping the groups. With the default groupsClaim and refresh off,
that signs users out every ID token lifetime: 5 minutes on a default
Keycloak, an hour on Okta or Entra. useRefreshToken now defaults to true, so
sessions last session.maxLifetime when the IdP issues a refresh token
(Keycloak does by default; Okta and Entra need offline_access). An IdP that
returns none behaves as before. NOTES says after every install or upgrade
whether refresh tokens are on and what the IdP client needs.

Split out of #51 so it can ship with Hub 1.10.0 ahead of clusterAccess.
Staged as 1.10.0-rc.1 with appVersion unchanged; the Hub v1.10.0 tag
promotes it to 1.10.0.
arlenvasconcelos and others added 5 commits October 7, 2026 21:44
Self-hosted hubs choose how new Radar installs grant cluster access: roles keeps the hub-role ClusterRoleBindings, idp turns them off so IdP groups decide. The value is passed to the hub as RADAR_HUB_OIDC_CLUSTER_ACCESS and only applies when OIDC is configured. It never changes clusters that are already installed.
…p that can't work

Unset now lets the Hub pick idp while IdP group passthrough is on and roles
otherwise; roles is the explicit opt-out. idp without auth.oidc.issuer or
auth.oidc.groupsClaim fails the install instead of leaving new clusters with no
access.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A groups claim the IdP doesn't emit was described as harmless. With
clusterAccess left unset it now follows groupsClaim to idp, so clusters
installed then get no hub-role bindings and, with no groups arriving, nobody
sees them. The comment says so and says to check that groups arrive first.

useRefreshToken now says what happens without it: a session carrying IdP
groups ends when the first ID token expires and the user signs in again.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017J25KHG5W4DzS32bU1J8ou
…ogether

- NOTES.txt now says, after every install or upgrade, which cluster access
  mode new clusters get (and that an unset clusterAccess follows groupsClaim
  to idp), and whether refresh tokens are on and what they need from the IdP.
  Both defaults change behaviour on upgrade.
- The clusterAccess=idp checks move from deployment-hub.yaml to secret.yaml,
  next to the chart's other value checks.
- The unknown-value test matches the schema's enum error, so it fails if the
  schema check stops running. The values comment says idp also needs an
  issuer.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017J25KHG5W4DzS32bU1J8ou
@nadaverell
nadaverell force-pushed the arlen/rad-578-radar-hub-cluster-access branch from ae20b04 to 698ce9d Compare October 7, 2026 18:46
@nadaverell

Copy link
Copy Markdown
Contributor

I rebased this onto main (chart 1.10.0) and force-pushed. Old head was ae20b04; new head is 698ce9d.

  • The refresh-token default from 72faff9 shipped separately in radar-hub: turn on OIDC refresh tokens by default (1.10.0-rc.1) #57, as chart 1.10.0 alongside Hub 1.10.0. Hub 1.10.0 ends group-carrying sessions at ID-token expiry when there's no refresh token, and couldn't wait for #326. I dropped 72faff9 and the merge commit, and replayed your other five commits in order.
  • Conflicts: I kept main's refresh-token wording in values.yaml and NOTES. It names Hub 1.10.0, because the old behaviour (session kept, groups dropped) still applies to older Hubs. The NOTES callback line keeps main's $publicURL. All the cluster-access content is unchanged.
  • Hub 1.10.0 already reads RADAR_HUB_OIDC_CLUSTER_ACCESS (#272). Installs only follow it once web #326 is in a release, so I left the version alone. When this ships with #326, it takes the next chart minor. radar-hub README: the release job promotes staged charts (1.10.1-rc.1) #58 stages 1.10.1-rc.1 for a README fix, so whichever merges second needs a version above the other.

Checks: helm unittest 27/27, render-matrix.sh, helm lint, agent-test.sh, and NOTES rendered with groupsClaim set and empty. CI's lint will still ask for a version bump, as it did before the rebase.

The connect page applies the cluster access mode from Hub 1.11.0, so name
that as the minimum.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants