Skip to content

Add IdP directory reads, email invites, and a member picker - #149

Merged
HiranAdikari merged 1 commit into
wso2:controlplanefrom
HiranAdikari:feat/idp-directory
Jun 11, 2026
Merged

Add IdP directory reads, email invites, and a member picker#149
HiranAdikari merged 1 commit into
wso2:controlplanefrom
HiranAdikari:feat/idp-directory

Conversation

@HiranAdikari

@HiranAdikari HiranAdikari commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

What this does

Inviting someone to a tenant previously required pasting their raw OIDC sub — an opaque UUID the inviter had to dig out of the invitee's JWT. This PR lets dc-api read users and groups from the IdP (read-only, over SCIM2), so inviters can grant roles by email or by browsing a member picker, the way Azure's "Add role assignment" works.

Privacy guardrails (enforced in code)

Directory reads are proxied live and never persisted — the database stores only the OIDC sub and a display alias copied once at grant time. Responses expose minimal fields only (name, email, sub, group names). Directory listing is gated to principals holding authorization/roleAssignments/write, and the machine-to-machine credential carries read-only VIEW scopes. The feature is entirely dark when the DCAPI_IDP_* config is unset. Recorded as decision 8 in docs/decisions.md.

The pieces

dc-api — new internal/directory package (Provider interface + SCIM2 client with OAuth2 client_credentials and a short-TTL cache), configured by four optional DCAPI_IDP_* variables; completely dark when unset. POST …/role-assignments accepts user_email as an alternative to user_sub (resolved to the sub at grant time; 422 when the email doesn't match exactly one user or no directory is configured). New GET /v1/tenants/{id}/directory/users|groups endpoints: paginated, filterable, 501 when unconfigured (the feature-detection signal clients probe), 502 with a generic body on IdP failure (upstream detail only in server logs).

cloud-ui — the Add role assignment dialog gains an Azure-style member picker: a panel listing the directory on open with search and pagination; picking a user pins the resolved sub and uses their IdP display name as the alias (the manual display-name field is gone). Deployments without a directory keep the old raw-sub input.

dcctltenant member create alice@example.com --role Contributor now works (email is the documented primary form). The member commands were also migrated off the removed v1 members API onto role-assignments with RBAC v2 role keys, and the generated client was refreshed from the current spec.

Deployment wiring — the Flux base carries the new config (dc-api-config placeholders + optional secretKeyRef entries; absent values keep the feature dark), the consumer overlay template documents how to enable it, and init-flux.sh seal auto-pulls the directory credential from the asgardeo-auth layer's terraform outputs. The seal flow also now preserves the live Postgres password and BFF session secret on re-runs (re-sealing a live environment used to rotate the DB password out from under dc-api) and drops the retired ARC runner PAT, whose orphaned SealedSecret failed the whole platform Kustomization apply.

Also fixed in passing: the contract-test tag list still referenced the v1 members tag, which no longer exists in the spec — role-assignment operations had silently dropped out of contract coverage. The tag is now roleAssignments (+ directory), raising covered operations from 30 to 50.

Verification

Unit: dc-api suite green including 9 SCIM2 client tests (httptest mock IdP) and 20 handler tests. Integration: 13 new tests for email invites + directory endpoints, run green in cluster-free mode against real Postgres. Contract: schemathesis, 50 operations / 4864 generated cases, 0 failures. Live: verified end-to-end on a local stack against a mock SCIM2 IdP — directory list/filter/paging, email invite happy path, ambiguous and unknown email 422s, dark-mode 501/422, raw-sub regression, dcctl CLI flow, and a DB check confirming only the sub and alias are persisted. cloud-ui: tsc, eslint, vitest clean; dcctl: builds with go vet clean.

Note: rebased on controlplane after #147 merged — the diff is now the feature only.

🤖 Generated with Claude Code

@coderabbitai

coderabbitai Bot commented Jun 10, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 2cdf2322-886e-43c5-8841-09ae5b76d976

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@HiranAdikari
HiranAdikari force-pushed the feat/idp-directory branch 3 times, most recently from 77523cc to 3ad00fb Compare June 11, 2026 08:04
Inviting a member previously required pasting the raw OIDC sub from
the invitee's JWT. dc-api now supports an optional read-only SCIM2
directory provider (DCAPI_IDP_* config, dark when unset): invites
accept an email that is resolved to the sub at invite time, owner-
gated directory endpoints list users and groups with minimal fields,
cloud-ui's grant dialog gains a directory-backed member picker, and
dcctl tenant member commands accept the email form. Reads are proxied
live and never persisted; the database keeps storing only the sub and
display alias.

The Flux base wires the new config (placeholders keep the feature
dark), the consumer overlay template documents how to enable it, and
init-flux.sh seal auto-pulls the directory credential from the
asgardeo-auth layer's terraform outputs. The seal flow also now
preserves the live Postgres password and BFF session secret on
re-runs, so re-sealing a live environment no longer rotates the
database password out from under dc-api.
@HiranAdikari
HiranAdikari merged commit 687d809 into wso2:controlplane Jun 11, 2026
8 checks passed
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.

2 participants