Skip to content

Conversation

@shirady
Copy link
Contributor

@shirady shirady commented Nov 30, 2025

Describe the Problem

Users name should be unique within the account, they aren’t distinguished by case.

Explain the Changes

  1. Pass the username in the create_user API.
  2. Edit the check for user already exists so it would be checked on the lowercase name of the requested account.
  3. Add new file for advanced test cases related to IAM and add this change into the tests case (the test file is based on test_iam_basic_integration).

Issues:

none

Testing Instructions:

Automatic test

Containerized

  1. Use the guide "Run Tests From coretest Locally" (link) for running the core tests.
  2. Run first tab: docker run -p 5432:5432 -e POSTGRESQL_ADMIN_PASSWORD=noobaa quay.io/sclorg/postgresql-15-c9s
  3. Run second tab: NOOBAA_LOG_LEVEL=all ./node_modules/.bin/mocha src/test/integration_tests/api/iam/test_iam_advanced_integration.js

NC:

  1. sudo NC_CORETEST=true ./node_modules/.bin/mocha src/test/integration_tests/api/iam/test_iam_advanced_integration.js
  2. sudo npx jest test_accountspace_fs.test.js (unit tests)
  • Doc added/updated
  • Tests added

Summary by CodeRabbit

  • New Features

    • Username is now a required parameter for account creation.
    • Username uniqueness is now enforced case-insensitively to prevent duplicate accounts.
    • Users can now update their username during account modifications.
  • Tests

    • Added integration tests validating username conflict scenarios during account creation and updates.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Nov 30, 2025

Walkthrough

The PR introduces username as a public parameter to the create_user API and propagates it through account creation and update flows. Username collision detection is now case-insensitive, checking against lowercase usernames. Integration tests verify the new validation behavior across creation and update operations.

Changes

Cohort / File(s) Summary
API Layer
src/api/account_api.js
Adds username (string) as a new public parameter to the create_user API payload
SDK Layer
src/sdk/accountspace_fs.js, src/sdk/accountspace_nb.js
accountspace_fs.js: Resolves owner account without params dependency; implements case-insensitive username existence check using username.toLowerCase(). accountspace_nb.js: Includes username from params in the request object.
Server Layer
src/server/system_services/account_server.js
Moves IAM_ACTIONS.CREATE_USER into owner branch; routes username from req.rpc_params.username instead of deriving from email; updates _check_username_already_exists call and ARN creation to use params-sourced username and iam_path; refactors update_user with guarded username-update logic.
Utility Layer
src/util/account_util.js
Changes _check_username_already_exists signature from (action, email, username) to (action, email_wrapped, username); delegates email lookup to new helper _check_if_account_exists_by_email(email_wrapped) performing case-insensitive email matching against stored accounts.
Integration Tests
src/test/integration_tests/api/iam/test_iam_basic_integration.js
Adds "IAM advanced integration tests" suite with "IAM CreateUser API" and "IAM UpdateUser API" sub-suites; tests verify case-insensitive username collision detection (original, lowercase, uppercase) and username update validation.

Sequence Diagram

sequenceDiagram
    participant Client
    participant API as API Layer
    participant Server as Account Server
    participant Util as Account Util
    participant Store as System Store

    Client->>API: create_user(username, email, ...)
    API->>Server: req.rpc_params.username
    Server->>Util: _check_username_already_exists(action, email, username)
    Util->>Util: _check_if_account_exists_by_email(email)
    Note over Util: Case-insensitive<br/>email search
    Util->>Store: Search accounts by email
    alt Account exists
        Store-->>Util: account
        Util->>Util: username.toLowerCase()
        Note over Util: Compare against<br/>existing username
        Util-->>Server: EntityAlreadyExists error
        Server-->>API: Error response
        API-->>Client: 409 Conflict
    else Account not found
        Store-->>Util: null
        Util-->>Server: Check passed
        Server->>Server: Create/update user with username
        Server->>Store: Persist account
        Store-->>Server: Success
        Server-->>API: Success response
        API-->>Client: 200 OK
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • src/util/account_util.js: Function signature change to _check_username_already_exists and new helper _check_if_account_exists_by_email require careful review of case-insensitive matching logic and its interaction with existing account lookups.
  • src/server/system_services/account_server.js: Verify parameter routing changes from req.rpc_params.username vs. derived sources; ensure IAM_ACTIONS assignment branch logic is correct in both create and update paths.
  • Cross-layer flow: Confirm username parameter flows correctly through API → SDK → Server → Util and that case-insensitive checks are consistently applied.

Possibly related PRs

Suggested reviewers

  • aayushchouhan09
  • naveenpaul1
  • liranmauda

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 28.57% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly references the main changes: enforcing case-insensitive username uniqueness checks for both CreateUser and UpdateUser operations.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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 and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7362470 and 0098e6d.

📒 Files selected for processing (8)
  • src/api/account_api.js (1 hunks)
  • src/sdk/accountspace_fs.js (1 hunks)
  • src/sdk/accountspace_nb.js (1 hunks)
  • src/server/system_services/account_server.js (2 hunks)
  • src/test/integration_tests/api/iam/test_iam_advanced_integration.js (1 hunks)
  • src/test/utils/index/index.js (1 hunks)
  • src/test/utils/index/nc_index.js (1 hunks)
  • src/util/account_util.js (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
src/test/**/*.*

⚙️ CodeRabbit configuration file

src/test/**/*.*: Ensure that the PR includes tests for the changes.

Files:

  • src/test/utils/index/nc_index.js
  • src/test/utils/index/index.js
  • src/test/integration_tests/api/iam/test_iam_advanced_integration.js
🧠 Learnings (3)
📚 Learning: 2025-11-19T15:03:42.260Z
Learnt from: shirady
Repo: noobaa/noobaa-core PR: 9291
File: src/server/common_services/auth_server.js:548-554
Timestamp: 2025-11-19T15:03:42.260Z
Learning: In src/server/common_services/auth_server.js, account objects are loaded directly from system_store (e.g., system_store.data.get_by_id()), so account.owner is an object ID reference with an ._id property, not a string. This differs from s3_rest.js where account.owner is a string due to RPC serialization.

Applied to files:

  • src/util/account_util.js
  • src/sdk/accountspace_fs.js
  • src/server/system_services/account_server.js
📚 Learning: 2025-11-13T07:56:23.620Z
Learnt from: shirady
Repo: noobaa/noobaa-core PR: 9281
File: src/server/system_services/account_server.js:1053-1058
Timestamp: 2025-11-13T07:56:23.620Z
Learning: In noobaa-core, account_server.js is only used in containerized deployments, not in NSFS/NC deployments. NSFS/NC deployments have separate account management code in src/manage_nsfs/ directory. Therefore, account_server.js only processes accounts from account_schema.js where owner is an objectid reference, never from nsfs_account_schema.js where owner is a string.

Applied to files:

  • src/sdk/accountspace_fs.js
  • src/server/system_services/account_server.js
📚 Learning: 2025-11-12T04:55:42.193Z
Learnt from: naveenpaul1
Repo: noobaa/noobaa-core PR: 9277
File: src/endpoint/s3/s3_rest.js:258-261
Timestamp: 2025-11-12T04:55:42.193Z
Learning: In the context of S3 REST requests (src/endpoint/s3/s3_rest.js), the account.owner field from req.object_sdk.requesting_account is already a string (account ID) because it comes from RPC serialization where owner._id.toString() is applied in account_server.js. No additional .toString() or ._id extraction is needed when passing account.owner to IAM utility functions.

Applied to files:

  • src/server/system_services/account_server.js
🧬 Code graph analysis (5)
src/sdk/accountspace_nb.js (1)
src/server/system_services/account_server.js (3)
  • params (328-328)
  • params (691-691)
  • params (955-955)
src/util/account_util.js (2)
src/sdk/accountspace_nb.js (1)
  • system_store (5-5)
src/test/utils/coretest/coretest.js (1)
  • system_store (49-49)
src/test/utils/index/nc_index.js (2)
src/sdk/accountspace_nb.js (1)
  • require (6-6)
src/util/account_util.js (4)
  • require (8-8)
  • require (14-14)
  • require (15-15)
  • require (16-17)
src/sdk/accountspace_fs.js (4)
src/server/system_services/account_server.js (2)
  • owner_account_id (1184-1184)
  • owner_account_id (1292-1292)
src/util/account_util.js (2)
  • owner_account_id (341-341)
  • owner_account_id (723-723)
src/endpoint/s3/s3_rest.js (1)
  • owner_account_id (337-337)
src/endpoint/iam/iam_utils.js (2)
  • owner_account_id (78-78)
  • owner_account_id (851-851)
src/server/system_services/account_server.js (1)
src/endpoint/iam/iam_constants.js (1)
  • IAM_ACTIONS (5-23)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: run-package-lock-validation
  • GitHub Check: run-jest-unit-tests
  • GitHub Check: Build Noobaa Image
🔇 Additional comments (9)
src/test/utils/index/index.js (1)

113-114: LGTM!

The new IAM advanced integration test is correctly added alongside the existing basic integration test.

src/sdk/accountspace_nb.js (1)

41-53: LGTM!

The username field is correctly added to the request object, aligning with the updated API schema.

src/api/account_api.js (1)

679-681: LGTM!

The username parameter is correctly added to the create_user API schema as an optional string field.

src/test/utils/index/nc_index.js (1)

28-29: LGTM!

The NC test bootstrap correctly includes the new advanced IAM integration test alongside the basic test.

src/test/integration_tests/api/iam/test_iam_advanced_integration.js (2)

30-74: Good test setup with comprehensive case-insensitive username testing.

The test suite correctly validates case-insensitive username uniqueness for both CreateUser and UpdateUser operations. The setup/teardown logic properly handles test isolation.


209-215: LGTM!

Simple and effective helper function for validating HTTP 200 responses.

src/util/account_util.js (1)

355-369: Case-insensitive username check implementation looks correct.

The new _check_if_account_exists_by_email helper properly performs case-insensitive email comparison by using toLowerCase() on both sides of the comparison. The null-safety with accounts || [] is a good defensive pattern.

src/sdk/accountspace_fs.js (1)

796-807: Verify case-insensitive handling in account name lookups.

The code converts username to lowercase before checking existence via is_account_exists_by_name(), but the implementation details of that method and how account names are stored cannot be confirmed. Ensure this method performs case-insensitive comparison internally or that account names are consistently stored in lowercase. Additionally, verify that other account lookups (e.g., _check_if_account_config_file_exists) use the same case-insensitive approach to avoid inconsistency.

src/server/system_services/account_server.js (1)

42-48: IAM create_user path now cleanly uses explicit username and case‑insensitive uniqueness

Using req.rpc_params.username for both the root‑account IAM check and ARN construction, while delegating the case‑insensitive uniqueness check to account_util._check_username_already_exists, looks correct and aligns with the new API contract. No additional changes needed here.

Signed-off-by: shirady <[email protected]>
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0098e6d and b0c05ca.

📒 Files selected for processing (2)
  • src/server/system_services/account_server.js (2 hunks)
  • src/test/integration_tests/api/iam/test_iam_advanced_integration.js (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/test/integration_tests/api/iam/test_iam_advanced_integration.js
🧰 Additional context used
🧠 Learnings (4)
📚 Learning: 2025-11-19T15:03:42.260Z
Learnt from: shirady
Repo: noobaa/noobaa-core PR: 9291
File: src/server/common_services/auth_server.js:548-554
Timestamp: 2025-11-19T15:03:42.260Z
Learning: In src/server/common_services/auth_server.js, account objects are loaded directly from system_store (e.g., system_store.data.get_by_id()), so account.owner is an object ID reference with an ._id property, not a string. This differs from s3_rest.js where account.owner is a string due to RPC serialization.

Applied to files:

  • src/server/system_services/account_server.js
📚 Learning: 2025-11-13T07:56:23.620Z
Learnt from: shirady
Repo: noobaa/noobaa-core PR: 9281
File: src/server/system_services/account_server.js:1053-1058
Timestamp: 2025-11-13T07:56:23.620Z
Learning: In noobaa-core, account_server.js is only used in containerized deployments, not in NSFS/NC deployments. NSFS/NC deployments have separate account management code in src/manage_nsfs/ directory. Therefore, account_server.js only processes accounts from account_schema.js where owner is an objectid reference, never from nsfs_account_schema.js where owner is a string.

Applied to files:

  • src/server/system_services/account_server.js
📚 Learning: 2025-11-12T04:55:42.193Z
Learnt from: naveenpaul1
Repo: noobaa/noobaa-core PR: 9277
File: src/endpoint/s3/s3_rest.js:258-261
Timestamp: 2025-11-12T04:55:42.193Z
Learning: In the context of S3 REST requests (src/endpoint/s3/s3_rest.js), the account.owner field from req.object_sdk.requesting_account is already a string (account ID) because it comes from RPC serialization where owner._id.toString() is applied in account_server.js. No additional .toString() or ._id extraction is needed when passing account.owner to IAM utility functions.

Applied to files:

  • src/server/system_services/account_server.js
📚 Learning: 2025-08-08T13:08:38.361Z
Learnt from: naveenpaul1
Repo: noobaa/noobaa-core PR: 9182
File: src/server/system_services/bucket_server.js:1324-1327
Timestamp: 2025-08-08T13:08:38.361Z
Learning: In src/server/system_services/bucket_server.js, the update_all_buckets_default_pool(req) handler expects req.rpc_params.pool_name to be a plain string (not a SensitiveString wrapper), so calling .unwrap() is not needed there.

Applied to files:

  • src/server/system_services/account_server.js
🧬 Code graph analysis (1)
src/server/system_services/account_server.js (1)
src/endpoint/iam/iam_constants.js (1)
  • IAM_ACTIONS (5-23)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Build Noobaa Image
  • GitHub Check: run-package-lock-validation
  • GitHub Check: run-jest-unit-tests
🔇 Additional comments (1)
src/server/system_services/account_server.js (1)

1237-1244: Past issue resolved: guarded computation looks correct.

The code now correctly guards email_new_username computation and the uniqueness check behind the is_username_update condition. This addresses the concern from the previous review about calling get_account_name_from_username with undefined when no username change is requested.

@shirady shirady force-pushed the iam-user-name-check branch from bbd49fe to e837a5d Compare November 30, 2025 11:47
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
src/test/integration_tests/api/iam/test_iam_advanced_integration.js (1)

145-165: Consider adding a test for updating to a different user's name.

The current UpdateUser tests validate case variants of the same user. For more comprehensive coverage, consider adding a test that creates two users and attempts to update one user's name to match the other user's name.

Example test structure:

mocha.it('update a user to another existing user name should fail', async function() {
    // Create a second user
    const secondUser = 'Alice';
    await iam_account.send(new CreateUserCommand({ UserName: secondUser }));
    try {
        // Try to update first user to second user's name
        const command = new UpdateUserCommand({
            UserName: username,
            NewUserName: secondUser,
        });
        await iam_account.send(command);
        assert.fail('update user to existing username - should throw an error');
    } catch (err) {
        assert.equal(err.Error.Code, IamError.EntityAlreadyExists.code);
    } finally {
        await iam_account.send(new DeleteUserCommand({ UserName: secondUser }));
    }
});
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 990cfe3 and bbd49fe.

📒 Files selected for processing (1)
  • src/test/integration_tests/api/iam/test_iam_advanced_integration.js (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
src/test/**/*.*

⚙️ CodeRabbit configuration file

src/test/**/*.*: Ensure that the PR includes tests for the changes.

Files:

  • src/test/integration_tests/api/iam/test_iam_advanced_integration.js
🧬 Code graph analysis (1)
src/test/integration_tests/api/iam/test_iam_advanced_integration.js (4)
src/sdk/accountspace_nb.js (1)
  • require (6-6)
src/test/utils/index/nc_index.js (1)
  • coretest (5-5)
src/test/utils/index/index.js (1)
  • coretest (5-5)
src/test/system_tests/test_utils.js (2)
  • is_nc_coretest (48-48)
  • TMP_PATH (23-23)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Build Noobaa Image
  • GitHub Check: run-jest-unit-tests
  • GitHub Check: run-package-lock-validation
🔇 Additional comments (7)
src/test/integration_tests/api/iam/test_iam_advanced_integration.js (7)

1-28: LGTM! Test setup and imports are well-structured.

The imports appropriately pull in necessary utilities, AWS SDK commands, and test infrastructure. The conditional setup for NC vs non-NC environments follows established patterns.


33-68: LGTM! Test account and IAM client setup is thorough.

The setup correctly handles both NC and non-NC test environments, properly unwraps sensitive credentials, and establishes the IAM client for subsequent tests.


81-143: Good test coverage for case-insensitive username collision in CreateUser.

The tests properly verify that usernames are unique in a case-insensitive manner by checking exact match, lowercase, and uppercase variants. The setup/teardown hooks ensure proper test isolation.


145-205: LGTM! UpdateUser tests correctly validate case-insensitive username handling.

The tests verify that:

  1. Updating to the same username succeeds (line 166-174)
  2. Updating to case variants of the existing username fails with EntityAlreadyExists (lines 176-204)

The previous review comments about incorrect assertion messages have been addressed.


210-216: LGTM! Helper function is well-documented.

The _check_status_code_ok helper provides a clean abstraction for response validation with appropriate JSDoc type annotation.


110-113: Verify error property access pattern matches SDK response structure.

The error access pattern err.Error.Code assumes a specific error structure. If the SDK throws a differently-structured error, accessing err.Error.Code could throw a TypeError. Verify this pattern is consistent with actual error responses from the IAM SDK in this codebase.


70-74: Missing await on async cleanup call.

fs_utils.folder_delete appears to be an async function based on standard Node.js patterns. Without await, the cleanup may not complete before the test process exits, potentially leaving orphaned test directories.

     mocha.after(async () => {
         if (is_nc_coretest) {
-            fs_utils.folder_delete(`${config_root}`);
+            await fs_utils.folder_delete(`${config_root}`);
         }
     });

Signed-off-by: shirady <[email protected]>
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/test/integration_tests/api/iam/test_iam_basic_integration.js (1)

930-955: Avoid coupling advanced suite to prior describe’s setup

iam_account is used here but only initialized in the before hook of the earlier "IAM basic integration tests - happy path" suite. This makes the advanced tests depend on that suite running first; using describe.only on this block (or running suites in isolation) will leave iam_account undefined.

Consider factoring the IAM client setup into a shared helper or a top-level before so each top-level suite can initialize iam_account independently.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e837a5d and 49d8434.

📒 Files selected for processing (1)
  • src/test/integration_tests/api/iam/test_iam_basic_integration.js (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
src/test/**/*.*

⚙️ CodeRabbit configuration file

src/test/**/*.*: Ensure that the PR includes tests for the changes.

Files:

  • src/test/integration_tests/api/iam/test_iam_basic_integration.js
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: run-package-lock-validation
  • GitHub Check: Build Noobaa Image
  • GitHub Check: run-jest-unit-tests
🔇 Additional comments (1)
src/test/integration_tests/api/iam/test_iam_basic_integration.js (1)

936-999: CreateUser case-insensitive duplicate tests look solid

The three CreateUser tests correctly cover:

  • duplicate creation with the exact same username
  • duplicate creation with lowercase
  • duplicate creation with uppercase

all asserting IamError.EntityAlreadyExists. This aligns well with the PR goal of enforcing case-insensitive uniqueness on user creation and reuses the existing error-checking pattern in this file.

Comment on lines +1000 to +1060
mocha.describe('IAM UpdateUser API', async function() {
mocha.before(async () => {
// create a user
const input = {
UserName: username
};
const command = new CreateUserCommand(input);
const response = await iam_account.send(command);
_check_status_code_ok(response);
});

mocha.after(async () => {
// delete a user
const input = {
UserName: username
};
const command = new DeleteUserCommand(input);
const response = await iam_account.send(command);
_check_status_code_ok(response);
});

mocha.it('update a user with same username', async function() {
const input = {
UserName: username,
NewUserName: username,
};
const command = new UpdateUserCommand(input);
const response = await iam_account.send(command);
_check_status_code_ok(response);
});

mocha.it('update a user with new username that already exists (lower case) should fail', async function() {
try {
const input = {
UserName: username,
NewUserName: username_lowercase,
};
const command = new UpdateUserCommand(input);
await iam_account.send(command);
assert.fail('update user with existing username (lower case) - should throw an error');
} catch (err) {
const err_code = err.Error.Code;
assert.equal(err_code, IamError.EntityAlreadyExists.code);
}
});

mocha.it('update a user with new username that already exists (upper case) should fail', async function() {
try {
const input = {
UserName: username,
NewUserName: username_uppercase,
};
const command = new UpdateUserCommand(input);
await iam_account.send(command);
assert.fail('update user with existing username (upper case) - should throw an error');
} catch (err) {
const err_code = err.Error.Code;
assert.equal(err_code, IamError.EntityAlreadyExists.code);
}
});
});
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

UpdateUser “duplicate username” tests don’t actually create a conflicting user

In the IAM UpdateUser API block you only ever create a single user (username). The two negative tests:

  • update a user with new username that already exists (lower case) should fail
  • update a user with new username that already exists (upper case) should fail

attempt to set NewUserName to username_lowercase / username_uppercase for that same user, but there is no other user with those names. As written, these tests will only fail if the backend incorrectly treats a rename of a user to a different casing of its own name as a conflict, and they do not validate “username already exists” behavior between distinct users.

To actually exercise case-insensitive uniqueness on update, you should create a second, conflicting user and then try to rename the first user to that name (in different casings). For example:

 mocha.describe('IAM UpdateUser API', async function() {
+                const conflicting_username = `${username}_conflict`;
+                const conflicting_username_lowercase = conflicting_username.toLowerCase();
+                const conflicting_username_uppercase = conflicting_username.toUpperCase();
+
                 mocha.before(async () => {
-                    // create a user
-                    const input = {
-                        UserName: username
-                    };
-                    const command = new CreateUserCommand(input);
-                    const response = await iam_account.send(command);
-                    _check_status_code_ok(response);
+                    // create two users so we can test collisions on update
+                    for (const name of [username, conflicting_username]) {
+                        const input = { UserName: name };
+                        const command = new CreateUserCommand(input);
+                        const response = await iam_account.send(command);
+                        _check_status_code_ok(response);
+                    }
                 });
 
                 mocha.after(async () => {
-                    // delete a user
-                    const input = {
-                        UserName: username
-                    };
-                    const command = new DeleteUserCommand(input);
-                    const response = await iam_account.send(command);
-                    _check_status_code_ok(response);
+                    // delete both users
+                    for (const name of [username, conflicting_username]) {
+                        const input = { UserName: name };
+                        const command = new DeleteUserCommand(input);
+                        const response = await iam_account.send(command);
+                        _check_status_code_ok(response);
+                    }
                 });
@@
                 mocha.it('update a user with new username that already exists (lower case) should fail', async function() {
                     try {
                         const input = {
                             UserName: username,
-                            NewUserName: username_lowercase,
+                            NewUserName: conflicting_username_lowercase,
                         };
@@
                 mocha.it('update a user with new username that already exists (upper case) should fail', async function() {
                     try {
                         const input = {
                             UserName: username,
-                            NewUserName: username_uppercase,
+                            NewUserName: conflicting_username_uppercase,
                         };

This way you test that updating one user to a name already used by another user (in any casing) correctly yields IamError.EntityAlreadyExists, while still allowing no-op updates with the same username.

🤖 Prompt for AI Agents
In src/test/integration_tests/api/iam/test_iam_basic_integration.js around lines
1000-1060, the two negative UpdateUser tests only create a single user
(username) so they never exercise a conflict with a distinct existing user;
create a second user with the conflicting name (username_lowercase /
username_uppercase) before attempting the UpdateUser call (either in the
mocha.before for this describe block or at the start of each negative test),
then attempt to rename the original user to that second user’s name (different
casing) and assert EntityAlreadyExists, and finally ensure the second user is
deleted in the mocha.after cleanup (or removed at test end) so both created
users are cleaned up.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant