mirror of
https://github.com/coralogix/cx-cli.git
synced 2026-09-14 16:15:45 +08:00
da9745ff48
## Context
`cx iam users search` (and `get`/`create`/`update`/`set-status`) was
broken for most real-world API keys. Users with full user-management
scopes were hitting one of two errors — either an explicit SAML scope
rejection or a silent empty result — even on teams with many users.
Root-caused to two independent bugs in the team ID resolution and search
request construction.
## Linked Issues
FORGE-246
## Design
Every users API call needs the team ID embedded in the path
(`/aaa/teams/v2/{team_id}/...`), so the CLI must resolve it client-side
first. Previously this was done by calling the SAML configuration
endpoint (`GET /aaa/team-saml/v1/configuration`) and reading `team_id`
out of the response. That endpoint requires a SAML-specific scope
unrelated to user management.
The replacement is `GET /identity/whoami`, which returns `team_id` +
`team_name` + `user_name` and is readable by every API key regardless of
scopes. The `cases` command already used this exact approach for its own
team-user lookups; the logic is now extracted into a shared
`src/identity.rs` module so both commands use a single implementation
with no cross-command dependency.
The `pageSize` fix is simpler: the search endpoint silently returns
`{"users": [], "totalCount": 0}` when `pageSize` is absent from the
query string. The fix always sends `pageSize` (defaulting to 300 when
the caller doesn't specify one), matching how `cases` calls the same
endpoint.
## Key Decisions
- **`src/identity.rs` as the shared home** — neutral location in the
top-level `src/` infra layer avoids an awkward cross-command import
(users importing from cases) and keeps CODEOWNERS clean. Both commands
point at `crate::identity::resolve_team_id`.
- **Default `pageSize=300`** — same value `cases` uses for the same
endpoint. The search endpoint has no documented default and silently
returns empty without it, so a hardcoded safe default is the right call.
- **SAML module untouched** — `src/commands/saml/` remains a standalone
command. Only `users`'s dependency on it is removed.
## Changes
- `cx iam users search` no longer fails with "Cannot resolve team ID:
API key lacks SAML scope" — team ID is now resolved via
`/identity/whoami`
- `cx iam users search` now returns results on teams that have users
(was silently returning empty due to missing `pageSize`)
- `cx iam users search --page-size N` still works; user-supplied value
is forwarded as before
- `src/identity.rs` (new): `Whoami` struct + `pub async fn
resolve_team_id(client)` backed by `GET /identity/whoami`
- `src/commands/cases/api.rs`: private `Whoami`, `WHOAMI_BASE`, and
`resolve_team_id` removed; `list_teammates` delegates to the shared
helper — no behavioral change
- `src/commands/users/mod.rs`: SAML-based `resolve_team_id` and
`SamlApi` import removed; all 5 operation handlers use
`crate::identity::resolve_team_id`
## Testing
- `cargo fmt --check && cargo clippy --locked -- -D warnings && cargo
test --locked` — all pass, 0 failures
- Integration test `tests/users/main.rs` updated: SAML mock replaced
with `/identity/whoami` mock, `pageSize=300` query param matcher added
- Manual `cargo run -- iam users search --profile test` against stg1:
previously failed with SAML error, now returns results correctly
- Raw `curl` against `GET /aaa/teams/v2/{team_id}/search` confirmed the
`pageSize` requirement: without it the API returns
`{"users":[],"totalCount":0}`; with `?pageSize=100` it returns the full
user list
## Risks & Rollout
Low risk. Both `/identity/whoami` and the users search endpoint are
already called by `cx cases` in production. The change is a client-side
fix with no server-side impact. Rollback is a revert of this PR.
## Out of Scope / Follow-ups
- `cx iam users search` is still single-page (like other `iam`
subcommands). Auto-pagination across all pages (like `cases
list_teammates` does) is a separate feature decision.
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>