Skip to content

feat: resolve client roles in import UserBlueprint.roles - #37

Merged
NathaelB merged 2 commits into
mainfrom
feat/import-client-role-assignment
Sep 3, 2026
Merged

feat: resolve client roles in import UserBlueprint.roles#37
NathaelB merged 2 commits into
mainfrom
feat/import-client-role-assignment

Conversation

@NathaelB

@NathaelB NathaelB commented Sep 3, 2026

Copy link
Copy Markdown
Member

Summary

UserBlueprint.roles entries can now reference a client role, qualified as client_id:role_name; a plain, unqualified name still resolves as a realm role (fully backward compatible with existing blueprint files). Client role ids are tracked the same way realm role ids already were, including a backfill pass for client roles that already existed before this import run.

An unresolved client role reference (client or role not found) fails the import loudly with a new ImportError::UnresolvedClientRole, per the issue's "Expected behaviour" — deliberately different from an unresolved realm role, which keeps its existing warn-and-skip behavior so I'm not silently changing semantics existing files already rely on.

Issue

Closes #26.

Stacked on #36#35

Branched from feat/import-client-blueprint-fields (#36), which is itself on fix/import-conflict-detection (#35) — same reasoning as before: this touches the same apply.rs region. Merge in order: #35, #36, then this one.

Verification

Ran live against a local FerrisKey server:

  • Imported a realm with a client (smoke-crole-client) owning a role (viewer) and a user referencing it as smoke-crole-client:viewer — report showed role_assignments: 1, and user roles confirmed the user actually holds viewer.
  • This also confirms assign_user_role accepts a client role id through the exact same endpoint as a realm role id — no separate client-scoped assignment endpoint exists or is needed, consistent with the delete_role finding from fix: correct client-role create/delete (verified against a live server) #33.
  • Imported a user referencing a nonexistent nonexistent-client:phantom-role — import failed loudly with a clear message, as required, instead of silently warning.
  • Cleaned up all test fixtures afterward.

Test plan

  • cargo build --workspace
  • cargo test --workspace (76 passed, +2 new: parse_role_ref)
  • cargo clippy --workspace --all-targets --all-features -- -D warnings
  • Manual import against a running FerrisKey server, both the success and hard-failure paths (see above)

@NathaelB NathaelB self-assigned this Sep 3, 2026
@coderabbitai

coderabbitai Bot commented Sep 3, 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: defaults

Review profile: CHILL

Plan: Team

Run ID: 910b7d8e-fa6b-40f3-9735-1a7b35fd60f0

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

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.

… lifetimes

post_logout_redirect_uris, web_origins, PKCE requirement, the Device
Authorization grant toggle, and per-client token lifetimes were
missing from ClientBlueprint, so an import couldn't reproduce them and
they were lost on the next realm.

Adds the corresponding client endpoints (POST .../post-logout-redirects,
POST .../web-origins, PATCH .../clients/{id} for PKCE/lifetimes — the
latter only settable after creation, unlike the rest of a client's
fields) and applies them in apply.rs. All five stay optional so
existing blueprint files keep importing unchanged.

Keycloak/Zitadel sources default these fields rather than extracting
them: Keycloak carries the equivalent settings under a free-form
`attributes` map with Keycloak-specific keys, which is a separate
scope of work.
@NathaelB
NathaelB force-pushed the feat/import-client-blueprint-fields branch from 589207a to 64916be Compare September 3, 2026 00:30
UserBlueprint.roles only resolved realm roles: the role_ids table was
populated by create_role alone, so client roles created by
ClientBlueprint.roles could never be assigned to a user — an import
described an intent it couldn't carry out.

A role entry can now be qualified as `client_id:role_name` to reference
a client role; unqualified entries keep resolving as realm roles. An
unresolved client role reference fails the import loudly
(ImportError::UnresolvedClientRole) rather than being silently skipped
with a warning, per the issue's expected behaviour — this is
deliberately different from an unresolved realm role, which keeps its
existing warn-and-skip behavior to avoid changing established
semantics for existing files.

Verified live: assign_user_role accepts a client role id through the
same endpoint as a realm role id (no separate client-scoped assignment
endpoint needed) — role ids are unique across both scopes, consistent
with the delete_role finding in #33.
@NathaelB
NathaelB force-pushed the feat/import-client-role-assignment branch from 152ad79 to 94fc972 Compare September 3, 2026 00:30
Base automatically changed from feat/import-client-blueprint-fields to main September 3, 2026 00:47
@NathaelB
NathaelB merged commit 412df94 into main Sep 3, 2026
1 check passed
@NathaelB
NathaelB deleted the feat/import-client-role-assignment branch September 3, 2026 00:47
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.

A client role created by an import cannot be assigned to anyone

1 participant