Skip to content

fix: make update_user_status idempotent for already-suspended accounts#94

Open
c1-dev-bot[bot] wants to merge 1 commit into
mainfrom
fix/cxp-429-idempotent-update-user-status
Open

fix: make update_user_status idempotent for already-suspended accounts#94
c1-dev-bot[bot] wants to merge 1 commit into
mainfrom
fix/cxp-429-idempotent-update-user-status

Conversation

@c1-dev-bot
Copy link
Copy Markdown

@c1-dev-bot c1-dev-bot Bot commented Apr 3, 2026

Summary

  • Add idempotency check to updateUserStatus action handler so that attempting to suspend an already-suspended user (or unsuspend an already-active user) returns success instead of making a redundant API call
  • This matches the existing pattern in disableUserActionHandler and enableUserActionHandler which already have this check
  • The update_user_status action was the only user-status action missing this idempotency guard, causing failures when the account lifecycle workflow tried to disable an already-suspended Google Workspace account

Fixes: CXP-429

Test plan

  • Verify existing TestDisableEnableUser_IdempotentAndPayload tests pass
  • Verify that calling update_user_status with is_suspended=true on an already-suspended user returns success without error
  • Verify that calling update_user_status with is_suspended=false on an already-active user returns success without error
  • Verify that normal suspend/unsuspend operations still work correctly

Automated PR Notice

This PR was automatically created by c1-dev-bot as a potential implementation.

This code requires:

  • Human review of the implementation approach
  • Manual testing to verify correctness
  • Approval from the appropriate team before merging

Add an idempotency check to updateUserStatus that fetches the current
user state before attempting to update. If the user is already in the
desired suspended/active state, return success without making an API
call. This matches the pattern already used by disableUserActionHandler
and enableUserActionHandler.

Fixes: CXP-429
@c1-dev-bot c1-dev-bot Bot requested a review from a team April 3, 2026 17:23
@linear
Copy link
Copy Markdown

linear Bot commented Apr 3, 2026

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 3, 2026

Claude finished @c1-dev-bot[bot]'s task in 44s —— View job


PR Review: make updateUserStatus idempotent

  • Read the PR diff and changed files
  • Review existing idempotency patterns for context
  • Post review feedback

Verdict: Approve — This is a clean, correct change that follows the established pattern.

What the PR does

Adds an idempotency guard to updateUserStatus (lines 39-49 of actions.go) so that attempting to suspend an already-suspended user (or unsuspend an already-active user) returns success without making a redundant API call. This matches the existing pattern used by disableUserActionHandler (line 82-91) and enableUserActionHandler (line 118-127).

Review

Correctness — The logic is sound. GetUserForProvisioning fetches the current user state, and if u.Suspended == isSuspended, the user is already in the desired state, so we short-circuit with a success response. This is exactly the same pattern as the other two handlers.

Consistency — The implementation is consistent with disableUserActionHandler and enableUserActionHandler in:

  • Error message format (google-workspace: prefix, %w wrapping)
  • Response structure (success: true structpb)
  • Flow (fetch → check → early return or update)

No issues found:

  • Error handling is correct — propagates the GetUserForProvisioning error properly
  • The err variable reuse (err :=err =) is handled correctly since the first err is declared by the new code and reused by the existing UpdateUser call
  • No nil pointer risks — GetUserForProvisioning returns an error if the user doesn't exist

Minor observation (not blocking): The response struct on the early-return path (line 45) uses structpb.Struct{...} directly, while the normal path (line 60) also uses the same pattern. Both are fine and consistent with the other handlers.

Overall this is a minimal, well-scoped fix that eliminates the failure described in CXP-429.


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.

0 participants