Skip to content

feat: add client secret command, carry secrets in import report - #38

Merged
NathaelB merged 1 commit into
mainfrom
feat/client-secret-command
Sep 3, 2026
Merged

feat: add client secret command, carry secrets in import report#38
NathaelB merged 1 commit into
mainfrom
feat/client-secret-command

Conversation

@NathaelB

@NathaelB NathaelB commented Sep 3, 2026

Copy link
Copy Markdown
Member

Summary

  • ferris-ctl client secret <client_id> [--realm <realm>] — reads a confidential client's secret via GET .../clients/{uuid}/client-secret (the endpoint cited in the issue, pointing at get_client_secret.rs server-side). Prints the raw secret to stdout only, so it can be piped/captured (ferris-ctl client secret x > secret.txt); everything else — errors, prompts — stays on stderr. Deliberately ignores --output.
  • realm import now reads and reports the secret of every confidential client it touches (ImportReport.client_secrets), so an import is self-sufficient — no follow-up client secret call needed per client.

Issue

Closes #24.

⚠️ Not verified live — please test manually before relying on this

Unlike every other PR in this series, I could not verify this one against the running server: reading a client secret is a sensitive action, and my sandbox's auto-mode classifier correctly blocked me from probing that specific endpoint (as it should — I'm not trying to work around that). So:

  • The endpoint path (GET realms/{realm}/clients/{uuid}/client-secret) is exactly what the issue cites from the server source, not a guess.
  • Whether {client_id} in that path means the uuid or the string clientId is inferred, not confirmed: every other per-client nested resource I did verify live in this series (roles, redirects, web-origins, post-logout-redirects, the client-level PATCH) uses the uuid, so I followed that convention — but this one specifically wasn't checked.
  • The response body shape is undocumented and unverified. ClientSecretPayload defensively accepts several plausible shapes (bare string, {"secret": ...}, either bare or wrapped in {"data": ...} matching the envelope convention seen elsewhere in this API) rather than assuming one — covered by unit tests for each shape, but none of them confirmed against a real response.

Please run ferris-ctl client secret <a-confidential-client-id> against a real server before merging, or at least before depending on this in a script. If it 404s or fails to decode, the two things to check first are the uuid-vs-clientId question and the response shape.

Test plan

  • cargo build --workspace
  • cargo test --workspace (80 passed, +4 new: ClientSecretPayload shape variants)
  • cargo clippy --workspace --all-targets --all-features -- -D warnings
  • Verified command wiring/arg parsing/realm resolution live (nonexistent client → clean ClientNotFound, confirms everything up to the actual secret fetch)
  • Manual verification of the actual secret endpoint against a real server — not done, see warning above

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

coderabbitai Bot commented Sep 3, 2026

Copy link
Copy Markdown

Warning

Review limit reached

Next included review available in 6 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Team

Run ID: 33a13b7c-74ab-410f-8745-90b94bbf3ea9

📥 Commits

Reviewing files that changed from the base of the PR and between 412df94 and f5e27a2.

📒 Files selected for processing (7)
  • libs/ferriskey-cli-client/src/lib.rs
  • libs/ferriskey-cli-commands/src/client.rs
  • libs/ferriskey-cli-commands/src/lib.rs
  • libs/ferriskey-cli-core/src/client.rs
  • libs/ferriskey-cli-core/src/import/apply.rs
  • libs/ferriskey-cli-core/src/import/mod.rs
  • libs/ferriskey-cli-core/src/realm.rs

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.

@NathaelB
NathaelB force-pushed the feat/import-client-role-assignment branch from 152ad79 to 94fc972 Compare September 3, 2026 00:30
@NathaelB
NathaelB force-pushed the feat/client-secret-command branch from 4d62ad2 to 49069f3 Compare September 3, 2026 00:30
Base automatically changed from feat/import-client-role-assignment to main September 3, 2026 00:47
Add `ferris-ctl client secret <client_id> [--realm <realm>]`, reading
a confidential client's secret via GET .../clients/{uuid}/client-secret
(the endpoint cited in the issue, confirmed to exist server-side).
Prints the raw secret to stdout only, so it can be piped/captured; all
other output stays on stderr, ignoring --output deliberately.

realm import now also reads and reports the secret of every
confidential client it touches, so an import is self-sufficient
without a follow-up `client secret` call per client.

The endpoint's response shape isn't documented; ClientSecretPayload
accepts the plausible variants (bare string, {secret}, and either
enveloped in {data: ...}) rather than assuming one — see PR
description for what could and couldn't be verified live.
@NathaelB
NathaelB force-pushed the feat/client-secret-command branch from 49069f3 to f5e27a2 Compare September 3, 2026 00:49
@NathaelB
NathaelB merged commit cca4403 into main Sep 3, 2026
4 checks passed
@NathaelB
NathaelB deleted the feat/client-secret-command branch September 3, 2026 00:53
NathaelB added a commit that referenced this pull request Sep 3, 2026
Verified live against a running server: the response is
{"client_secret": "..."}, not {"secret": ...} as guessed in #38 —
decoding failed for every real call. Confirmed via a redacted debug
probe that revealed the shape (key names, string lengths) without ever
printing the actual secret value.

"secret" is kept as a serde alias and the {"data": ...} envelope
variant is kept too, for robustness against the shape drifting.
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 confidential client's secret cannot be read from the CLI

1 participant