Skip to content

fix(users): send --role on users update instead of dropping it - #1

Open
joalves wants to merge 1 commit into
chore/release-pleasefrom
fix/users-update-role
Open

fix(users): send --role on users update instead of dropping it#1
joalves wants to merge 1 commit into
chore/release-pleasefrom
fix/users-update-role

Conversation

@joalves

@joalves joalves commented Jul 14, 2026

Copy link
Copy Markdown
Collaborator

The bug

abs users update <id> --role <role> accepts a --role option but silently ignores it. Running e.g. abs users update 256 --role 34 fails with:

Error: At least one update field is required

even though a role was provided — and when a name is also given, the role change is never sent to the API.

Root cause

In src/core/users/update.ts, updateUser() builds the request body from params.name only (split into first_name / last_name), then checks if (Object.keys(data).length === 0) throw new Error('At least one update field is required'). params.role is typed on UpdateUserParams but never added to data, so role updates are dropped before the request is ever made.

The fix

  • updateUser() now adds roles: [{ role_id }] to the request body when --role is provided, parses the option to a positive-integer role ID, and counts it toward the "at least one field" guard so --role X alone works.
  • Introduced an UpdateUserData type derived from the OpenAPI UpdateUserBody schema and used it for the core data object and the api-client updateUser(id, data) signature (previously Partial<User>, which has no roles field), so role updates are type-checked end to end.

Why roles: [{ role_id }] and not roles: [34]

The backend expects roles as an array of { role_id: number } objects for the user's global team. Confirmed from two sources, not by trial and error:

  • The OpenAPI schema: UpdateUserBody.data.roles is typed { role_id: number }[].
  • The backend handler: data.roles.map(({ role_id }) => ...) — it destructures role_id from each element, which is why a bare roles: [34] array fails (the backend reads undefined for role_id).

Testing

  • Extended src/core/users/users.test.ts: role-only update, name + role together, and invalid-role rejection.
  • Extended src/commands/users/users.test.ts: --role flows through the command wiring to updateUser(id, { roles: [{ role_id: 34 }] }).
  • Both suites pass; tsc compiles clean.
  • Verified end-to-end against the compiled output that abs users update 256 --role 34 produces updateUser(256, { roles: [{ role_id: 34 }] }) — the original "At least one update field is required" error is gone.

(Note: 3 pre-existing failures in src/lib/api/oauth-refresh.test.ts are unrelated to this change — they fail identically on the base branch.)

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • User updates now support assigning a role using the --role option.
    • Names and roles can be updated together in a single command.
  • Bug Fixes

    • Invalid role values are rejected with a clear error before any update is submitted.
    • User update requests now use the correct supported data format, improving reliability.

`abs users update <id> --role <role>` accepted a --role option but
silently ignored it: updateUser() in src/core/users/update.ts built the
request body from params.name only and never added params.role. As a
result `abs users update 256 --role 34` failed with "At least one update
field is required", and even with a name the role change was never sent.

The API expects roles as an array of `{ role_id: number }` objects for
the user's global team. This is confirmed by the OpenAPI UpdateUserBody
schema (`data.roles: { role_id: number }[]`) and the backend handler
which does `data.roles.map(({ role_id }) => ...)`. A bare `roles: [34]`
array is rejected (500), which is why passing the field naively fails.

Fix:
- update.ts now adds `roles: [{ role_id }]` to the request body when
  --role is provided, parsing the option to a positive integer role ID
  and counting it toward the "at least one field" guard so `--role X`
  alone works.
- Introduce an `UpdateUserData` type derived from the OpenAPI
  UpdateUserBody schema and use it for the core `data` object and the
  api-client `updateUser(id, data)` signature (previously `Partial<User>`,
  which has no `roles` field), so role updates are type-checked.

Tested: extended src/core/users/users.test.ts (role-only, name+role,
invalid-role) and src/commands/users/users.test.ts (--role wiring); both
suites pass. `tsc` compiles clean. Verified end-to-end against the
compiled output that `--role 34` sends `{ roles: [{ role_id: 34 }] }`.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 14, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

The user update API now uses the OpenAPI-derived UpdateUserData type. User updates accept a role option, validate it as a positive integer, and send it as roles: [{ role_id }]. Name and role updates can be combined, while empty or invalid updates remain rejected. Tests cover API payload construction, validation, and command behaviour.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Poem

I’m a rabbit with a role in sight,
Hopping payloads into shape just right.
Names and roles now travel as one,
Invalid numbers find nowhere to run.
Typed little fields, tested with care—
A carrot-bright update everywhere!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the main change: users update now sends --role instead of ignoring it.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/users-update-role

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint install timed out. The project may have too many dependencies for the sandbox.


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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
src/core/users/users.test.ts (1)

176-180: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Add boundary cases for invalid role values.

The test only covers the non-numeric path ("admin"). Add cases for 0, negative values, and fractional values to protect the positive-integer validation contract.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/core/users/users.test.ts` around lines 176 - 180, Add boundary-case
assertions to the invalid-role tests around updateUser: cover role values 0,
negative numbers, and fractional numbers, and verify each rejects with “Invalid
role” without calling mockClient.updateUser. Preserve the existing non-numeric
case and positive-integer validation contract.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@src/core/users/users.test.ts`:
- Around line 176-180: Add boundary-case assertions to the invalid-role tests
around updateUser: cover role values 0, negative numbers, and fractional
numbers, and verify each rejects with “Invalid role” without calling
mockClient.updateUser. Preserve the existing non-numeric case and
positive-integer validation contract.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 9a461c13-62ef-47e8-a321-5a81c8477808

📥 Commits

Reviewing files that changed from the base of the PR and between 8e8ccce and 32b4346.

📒 Files selected for processing (6)
  • src/api-client/api-client.ts
  • src/api-client/types.ts
  • src/commands/users/users.test.ts
  • src/core/users/update.ts
  • src/core/users/users.test.ts
  • src/lib/api/openapi-types.ts

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.

1 participant