Skip to content

Conversation

@aayushchouhan09
Copy link
Member

@aayushchouhan09 aayushchouhan09 commented Nov 21, 2025

Describe the Problem

Currently, bucket policy interfere with the list buckets which is not aws complaint.

Explain the Changes

  1. Handled list_buckets() with proper permissions and make it aws complaint.

Issues: Fixed #xxx / Gap #xxx

  1. Issue: https://issues.redhat.com/browse/DFBUGS-4449
  2. Related PR: Fix - list_buckets allowing unauthorized bucket access #9272

Testing Instructions:

  • Doc added/updated
  • Tests added

Summary by CodeRabbit

  • Bug Fixes

    • Bucket listing and access now respect ownership and IAM-root inheritance, so accounts only see or manage buckets they own or inherit.
  • New Features

    • Account and bucket metadata now include owner identifiers exposed via the SDK/API.
  • Refactor

    • Permission logic consolidated into reusable ownership-based checks with clearer decision flow between ownership and policy evaluation.
  • Tests

    • Removed two bucket-listing policy tests; added and updated bucket-tagging tests including cross-account scenarios with setup/cleanup.

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

@coderabbitai
Copy link

coderabbitai bot commented Nov 21, 2025

Walkthrough

List-buckets gating changed to ownership-based checks in src/sdk/bucketspace_fs.js. New public helpers (is_bucket_owner, is_iam_and_same_root_account_owner, has_bucket_ownership_permission) and NSFS access validators were added. has_bucket_action_permission and list_buckets were refactored. Tests updated: removed two ListBuckets policy tests and added/updated bucket-tagging tests.

Changes

Cohort / File(s) Summary
Ownership & permission logic
src/sdk/bucketspace_fs.js
Added public helpers: is_bucket_owner(bucket, account), is_iam_and_same_root_account_owner(account, bucket), has_bucket_ownership_permission(bucket, account). Refactored has_bucket_action_permission(...) to prefer ownership checks when no policy exists; added validate_fs_bucket_access(bucket, object_sdk) and _has_access_to_nsfs_dir(...). Updated list_buckets() gating to use ownership-based checks; minor docs/style tweaks.
Type definitions
src/sdk/nb.d.ts
Added owner: ID to Account and owner_account: ID to Bucket interfaces.
Unit tests — tagging & removed ListBuckets tests
src/test/unit_tests/nsfs/test_bucketspace_fs.js
Removed two ListBuckets policy-by-principal tests and imports. Added test_bucket_tagging fixture with setup/teardown; updated put/delete bucket tagging tests to use the fixture; added two cross-account put_bucket_tagging tests (principal by name and by id).

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant BucketSpaceFS
    participant Ownership as OwnershipChecker
    participant Policy as PolicyEvaluation
    participant NSFS as NSFSValidator

    rect rgb(245,250,255)
    note right of BucketSpaceFS: Ownership-first list_buckets flow
    Client->>BucketSpaceFS: list_buckets(request, account)
    BucketSpaceFS->>Ownership: has_bucket_ownership_permission(bucket, account)
    alt ownership true
        Ownership-->>BucketSpaceFS: true
        BucketSpaceFS->>NSFS: validate_fs_bucket_access(bucket, object_sdk)
        alt nsfs access ok
            NSFS-->>BucketSpaceFS: access OK
            BucketSpaceFS-->>Client: include bucket
        else nsfs denied
            NSFS-->>BucketSpaceFS: denied
            BucketSpaceFS-->>Client: omit bucket
        end
    else ownership false
        Ownership-->>BucketSpaceFS: false
        BucketSpaceFS->>Policy: get_bucket_policy(bucket)
        alt policy exists
            Policy-->>BucketSpaceFS: policy
            BucketSpaceFS->>Policy: evaluate s3:ListBucket principal
            alt allowed
                BucketSpaceFS-->>Client: include bucket
            else denied
                BucketSpaceFS-->>Client: omit bucket
            end
        else no policy
            BucketSpaceFS-->>Client: omit bucket
        end
    end
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Focus areas:
    • Correctness of ownership helpers (direct owner vs IAM-inherited owner) and interactions with new owner / owner_account fields.
    • Proper fallback between ownership checks and existing policy evaluation in has_bucket_action_permission.
    • NSFS access validation logic (validate_fs_bucket_access / _has_access_to_nsfs_dir) and its effect on list gating.
    • Test changes: ensure removed ListBuckets coverage is intentionally replaced and tagging test setup/teardown is correct.

Possibly related PRs

Suggested reviewers

  • nimrod-becker
  • liranmauda
  • naveenpaul1

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: fixing list_buckets to prevent unauthorized bucket access by implementing ownership-based gating instead of bucket policy-based gating, making it AWS-compliant.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ 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: 0

🧹 Nitpick comments (3)
src/sdk/bucketspace_fs.js (3)

263-281: Ownership-only filtering in list_buckets looks right; please verify IAM & no‑DB flows and add tests

Using has_bucket_ownership_permission(bucket, account) here is a good move to decouple ListBuckets from bucket policy and avoid non‑AWS cross‑account listing via s3:ListBucket.

Two edge cases are worth double‑checking:

  • For IAM users (account.owner set, _id != bucket.owner_account.id), has_bucket_ownership_permission() currently returns false (TODO not implemented), so ListBuckets will not show buckets owned by their root account at all. If IAM listing should be supported now, this is a behavior change from previous policy‑based listing.
  • For NSFS no‑DB / anonymous‑style flows where object_sdk.requesting_account may be missing _id, this filter will silently drop all buckets even if FS ACLs would allow access.

I recommend:

  • Clarifying whether IAM and no‑DB callers are expected to see buckets now, and adjusting has_bucket_ownership_permission() accordingly (see below), or explicitly documenting this limitation.
  • Adding tests around ListBuckets for: root owner, IAM user of same root, another account with bucket policy, and an account with no buckets.

924-959: Align has_bucket_ownership_permission with documented IAM behavior and reuse it consistently

The helper extraction is good, but there are a couple of mismatches and duplication spots:

  1. The JSDoc says:

    • “Root accounts can list buckets they own”
    • “IAM users can list their owner buckets”

    but the implementation only checks direct ownership via _id and always returns false for IAM users.

  2. You already implement “IAM user + same root account owner” logic in has_bucket_action_permission via:

    const is_iam_and_same_root_account_owner = account.owner !== undefined &&
        account.owner === bucket.owner_account.id;

    has_bucket_ownership_permission should likely use the same rule so that ListBuckets and per‑bucket actions share ownership semantics instead of duplicating them.

Given the existing pattern and the prior learning that account.owner is already a string owner ID in S3 REST flows, no extra .toString()/._id work is needed when comparing it to bucket.owner_account.id. Based on learnings, …

You could tighten this helper as:

 async has_bucket_ownership_permission(bucket, account) {
-    // check direct ownership (root accounts only)
-    if (this.is_bucket_owner(bucket, account)) return true;
-
-    // special case: iam user can list the buckets of their owner
-    // TODO: handle iam user
-
-    return false;
+    // direct ownership (root account owns the bucket)
+    if (this.is_bucket_owner(bucket, account)) return true;
+
+    // IAM user can list buckets owned by its root account
+    if (account?.owner && account.owner === bucket?.owner_account?.id) return true;
+
+    return false;
 }

Optionally, you could also have has_bucket_action_permission call this helper for its “no policy” branch to avoid repeating the IAM/root ownership check in two places.

Also, the TODO comment above mentions “4 functions” but currently lists 5; might be worth correcting to avoid confusion.


963-1005: has_bucket_action_permission refactor to use is_bucket_owner looks good; consider reusing ownership helper

Refactoring the ownership check into is_bucket_owner() and dropping the deprecated system_owner handling is a nice cleanup and keeps the method focused on bucket owner + policy evaluation.

To keep ownership semantics consistent across APIs, you may want to:

  • Reuse has_bucket_ownership_permission() here for the “no bucket policy” case instead of duplicating the ownership vs IAM logic (is_owner || is_iam_and_same_root_account_owner), so any future change to ownership rules is centralized in one place.

Functionally, though, the current change maintains the previous behavior (modulo the system_owner deprecation), so it looks safe.

📜 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 0d80b71 and d895b76.

📒 Files selected for processing (1)
  • src/sdk/bucketspace_fs.js (2 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 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/sdk/bucketspace_fs.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: Build Noobaa Image
  • GitHub Check: run-jest-unit-tests
  • GitHub Check: run-package-lock-validation

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 (3)
src/sdk/bucketspace_fs.js (2)

938-947: Inconsistent parameter order with is_bucket_owner.

This method uses (account, bucket) order while is_bucket_owner uses (bucket, account). This inconsistency makes the API confusing and error-prone, especially when both methods are used together (as in has_bucket_ownership_permission and has_bucket_action_permission).

Consider aligning the parameter order:

-    is_iam_and_same_root_account_owner(account, bucket) {
-        if (!account?.owner || !bucket?.owner_account?.id) return false;
-        return account.owner === bucket.owner_account.id;
+    is_iam_and_same_root_account_owner(bucket, account) {
+        if (!account?.owner || !bucket?.owner_account?.id) return false;
+        return account.owner === bucket.owner_account.id;
     }

Then update the call sites at lines 965 and 983:

-        if (this.is_iam_and_same_root_account_owner(account, bucket)) return true;
+        if (this.is_iam_and_same_root_account_owner(bucket, account)) return true;

949-968: Unnecessary async keyword.

This method is marked async but contains no await expressions. The function executes synchronously and wraps the result in a Promise unnecessarily.

Consider making this synchronous:

-    async has_bucket_ownership_permission(bucket, account) {
+    has_bucket_ownership_permission(bucket, account) {

Note: If you anticipate future async operations (e.g., database lookups for ownership), keeping it async is acceptable for forward compatibility. Update the caller at line 275 accordingly if changed to sync.

src/test/unit_tests/nsfs/test_bucketspace_fs.js (1)

25-25: Consider adding unit tests for new ownership helper methods.

The PR adds three new methods (is_bucket_owner, is_iam_and_same_root_account_owner, has_bucket_ownership_permission) but no direct unit tests for them. While the existing integration tests at lines 502-521 cover the behavior through list_buckets, dedicated unit tests for these methods would:

  1. Ensure edge cases are covered (e.g., missing owner_account.id, missing account._id, missing account.owner)
  2. Provide clearer regression detection if these methods are modified
  3. Document the expected behavior more explicitly

Based on coding guidelines, ensure tests are added for the changes.

📜 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 d895b76 and a15ab26.

📒 Files selected for processing (2)
  • src/sdk/bucketspace_fs.js (3 hunks)
  • src/test/unit_tests/nsfs/test_bucketspace_fs.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/unit_tests/nsfs/test_bucketspace_fs.js
🧠 Learnings (1)
📚 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/sdk/bucketspace_fs.js
🧬 Code graph analysis (1)
src/test/unit_tests/nsfs/test_bucketspace_fs.js (1)
src/sdk/bucketspace_fs.js (5)
  • require (15-23)
  • require (24-24)
  • require (25-25)
  • require (27-27)
  • require (30-30)
⏰ 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-jest-unit-tests
  • GitHub Check: Build Noobaa Image
  • GitHub Check: run-package-lock-validation
🔇 Additional comments (4)
src/sdk/bucketspace_fs.js (3)

927-936: LGTM!

The ownership check is well-implemented with proper null safety using optional chaining.


970-983: LGTM!

The refactored ownership logic properly replaces the deprecated system_owner check with the new is_bucket_owner method. The no-policy case correctly allows access for both direct owners and IAM users of the owner.


274-278: LGTM!

The ownership-based gating for list_buckets correctly implements AWS-compliant behavior where only bucket owners (and their IAM users) can see buckets in the listing.

src/test/unit_tests/nsfs/test_bucketspace_fs.js (1)

488-536: Existing test coverage for ownership-based listing looks adequate.

The tests correctly verify:

  • IAM accounts can list buckets owned by their root account (lines 502-515)
  • Different accounts cannot see each other's buckets (lines 516-521)

These tests align well with the new ownership-based gating logic.

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 (2)
src/sdk/bucketspace_fs.js (2)

933-947: Consider consistent parameter ordering across helper methods.

The parameter order differs between is_bucket_owner(bucket, account) and is_iam_and_same_root_account_owner(account, bucket). For better code maintainability, consider using a consistent order (e.g., always bucket, account or always account, bucket).

Example with consistent ordering:

-    is_iam_and_same_root_account_owner(account, bucket) {
+    is_iam_and_same_root_account_owner(bucket, account) {
         if (!account?.owner || !bucket?.owner_account?.id) return false;
         return account.owner === bucket.owner_account.id;
     }

Then update the caller at line 965:

-        if (this.is_iam_and_same_root_account_owner(account, bucket)) return true;
+        if (this.is_iam_and_same_root_account_owner(bucket, account)) return true;

960-968: Remove unnecessary async keyword.

The has_bucket_ownership_permission method is marked async but doesn't perform any asynchronous operations. This can be simplified to a synchronous method for a minor performance improvement.

Apply this diff:

-    async has_bucket_ownership_permission(bucket, account) {
+    has_bucket_ownership_permission(bucket, account) {
         // check direct ownership
         if (this.is_bucket_owner(bucket, account)) return true;
 
         // special case: iam user can list the buckets of their owner
         if (this.is_iam_and_same_root_account_owner(account, bucket)) return true;
 
         return false;
     }

Then update the caller at line 275:

-            if (!await this.has_bucket_ownership_permission(bucket, account)) return;
+            if (!this.has_bucket_ownership_permission(bucket, account)) return;
📜 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 a15ab26 and 0e22c56.

📒 Files selected for processing (2)
  • src/sdk/bucketspace_fs.js (3 hunks)
  • src/test/unit_tests/nsfs/test_bucketspace_fs.js (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • src/test/unit_tests/nsfs/test_bucketspace_fs.js
🧰 Additional context used
🧠 Learnings (1)
📚 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/sdk/bucketspace_fs.js
🔇 Additional comments (3)
src/sdk/bucketspace_fs.js (3)

244-244: LGTM: Comment accurately reflects ownership-based filtering.

The updated comment correctly describes the new AWS-compliant behavior where list_buckets filters by ownership rather than bucket policy.


274-275: LGTM: Ownership-based filtering makes list_buckets AWS-compliant.

This change correctly implements AWS-compliant behavior where the ListBuckets operation is based on ownership rather than bucket policies. Root accounts can list their own buckets, and IAM users can list their root account's buckets, which matches AWS S3 behavior.


970-1013: LGTM: Refactoring improves code clarity while preserving functionality.

The refactoring to use is_bucket_owner and is_iam_and_same_root_account_owner helper methods improves code maintainability. The removal of the deprecated system_owner check is appropriate, and the logic correctly handles both ownership-based access and bucket policy-based access.

/////////////////

// TODO: move the following 3 functions - has_bucket_action_permission(), validate_fs_bucket_access(), _has_access_to_nsfs_dir()
// TODO: move the following 5 functions - is_bucket_owner(), is_iam_and_same_root_account_owner(), has_bucket_ownership_permission(), has_bucket_action_permission(), validate_fs_bucket_access(), _has_access_to_nsfs_dir()
Copy link
Contributor

Choose a reason for hiding this comment

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

If the functions are not used anymore, you can remove them.

Copy link
Member Author

Choose a reason for hiding this comment

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

These are util functions and all are used, comment is about to move them in future for code reusability

const res = await bucketspace_fs.list_buckets({}, dummy_object_sdk_for_iam_account);
assert.equal(res.buckets.length, 0);
});
mocha.it('list buckets - different account with bucket policy (principal by name)', async function() {
Copy link
Contributor

@shirady shirady Nov 26, 2025

Choose a reason for hiding this comment

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

I suggest changing the test instead of removing it.
Change to another action (not list buckets).
I think it was mainly for checking different principals in bucket policy.

Copy link
Member Author

Choose a reason for hiding this comment

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

Sure I will edit them to work for different action.

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/sdk/bucketspace_fs.js (1)

924-969: Ownership helpers correctly encode root/IAM semantics; only minor nits

The split into is_bucket_owner, is_iam_and_same_root_account_owner, and has_bucket_ownership_permission captures the intended model:

  • Root: bucket.owner_account.id === account._id.
  • IAM: account.owner === bucket.owner_account.id (same root account).

This is consistent with how owner_account is written in new_bucket_defaults and with prior context that account.owner is already a serialized account ID string, so no extra .toString() is needed. Based on learnings, this comparison style is appropriate.

Two small, optional tweaks you might consider later:

  • has_bucket_ownership_permission is purely synchronous; you could drop async/await to simplify the call chain if you don’t plan async checks here.
  • In has_bucket_action_permission, you could call await this.has_bucket_ownership_permission(bucket, account) instead of re-implementing the same logic, to keep ownership semantics centralized.
📜 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 0e22c56 and 85fe071.

📒 Files selected for processing (2)
  • src/sdk/bucketspace_fs.js (3 hunks)
  • src/test/unit_tests/nsfs/test_bucketspace_fs.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/unit_tests/nsfs/test_bucketspace_fs.js
🧠 Learnings (1)
📚 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/sdk/bucketspace_fs.js
🧬 Code graph analysis (1)
src/test/unit_tests/nsfs/test_bucketspace_fs.js (2)
src/test/integration_tests/api/s3/test_s3_list_buckets.js (1)
  • create_bucket (66-66)
src/sdk/config_fs.js (1)
  • CONFIG_SUBDIRS (42-50)
⏰ 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). (2)
  • GitHub Check: Build Noobaa Image
  • GitHub Check: run-jest-unit-tests
🔇 Additional comments (3)
src/sdk/bucketspace_fs.js (2)

239-282: Ownership-based ListBuckets filtering looks correct and AWS-aligned

Filtering buckets in list_buckets via has_bucket_ownership_permission() (direct owner or IAM user whose owner matches the bucket’s root account) matches AWS behavior where ListBuckets only returns buckets owned by the caller’s account, regardless of bucket policy. The updated doc comment at Line 244 correctly reflects this behavior, and the early ownership filter precedes the existing FS-access check without altering error handling.


970-1013: I'm experiencing persistent repository cloning issues that prevent me from accessing the codebase. However, I can use the retrieved learnings to inform my analysis.

Cannot verify bucket object normalization—repository access unavailable

The repository cloning infrastructure is currently unavailable, preventing me from:

  • Inspecting the is_bucket_owner implementation to confirm what shape it expects from bucket.owner_account
  • Scanning all call sites of has_bucket_action_permission to verify whether normalized bucket objects are consistently passed
  • Confirming whether any code paths could pass raw config buckets (with string owner_account) to this method

The review comment raises a valid concern about implicit assumptions on bucket shape. The fix depends on verifying:

  1. Whether is_bucket_owner actually validates/requires the { id: ... } structure for owner_account
  2. Whether all callers (especially in S3 REST handlers, bucket operations, etc.) consistently normalize buckets before calling has_bucket_action_permission

Without codebase access, I cannot confirm if the concern is theoretical or represents a real bug path.

src/test/unit_tests/nsfs/test_bucketspace_fs.js (1)

909-956: Dedicated tagging bucket and policy-principal tests look good

The tagging suite now:

  • Uses a dedicated test_bucket_tagging bucket with explicit before/after setup and cleanup, reducing coupling with other tests.
  • Re-points the basic put/delete tagging tests at this bucket.
  • Adds two focused tests that create bucket policies with principals specified by name and by id and then perform PutBucketTagging via a different account’s SDK wrapper, confirming that such policies are accepted and that tagging state round-trips correctly.

This gives you test coverage for the principal encodings after the list_buckets behavior change and satisfies the requirement to include tests alongside the permission/ownership changes.

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

♻️ Duplicate comments (1)
src/sdk/bucketspace_fs.js (1)

924-926: Future refactoring noted.

The TODO to extract these utility functions for reuse is reasonable. Consider prioritizing this refactoring if these functions will be needed in other modules.

🧹 Nitpick comments (1)
src/sdk/bucketspace_fs.js (1)

938-947: Consider standardizing parameter order across helper functions.

The function logic is correct, but the parameter order (account, bucket) differs from is_bucket_owner(bucket, account). Standardizing to a consistent order (e.g., always bucket, account) would improve code maintainability and reduce the chance of bugs when calling these functions.

Apply this diff if you choose to align the parameter order:

-    is_iam_and_same_root_account_owner(account, bucket) {
-        if (!account?.owner || !bucket?.owner_account?.id) return false;
-        return account.owner === bucket.owner_account.id;
+    is_iam_and_same_root_account_owner(bucket, account) {
+        if (!account?.owner || !bucket?.owner_account?.id) return false;
+        return account.owner === bucket.owner_account.id;
     }

And update the call sites at lines 965 and 983 accordingly.

📜 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 85fe071 and f36aadc.

📒 Files selected for processing (1)
  • src/sdk/bucketspace_fs.js (3 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 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/sdk/bucketspace_fs.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: Build Noobaa Image
  • GitHub Check: run-jest-unit-tests
  • GitHub Check: run-package-lock-validation
🔇 Additional comments (5)
src/sdk/bucketspace_fs.js (5)

244-244: LGTM: Comment accurately reflects the new ownership-based filtering.

The updated comment correctly describes that buckets are now filtered based on ownership (direct or IAM user's root account ownership) rather than bucket policy access.


274-276: LGTM: Ownership-based filtering is correct and AWS-compliant.

The switch from policy-based permission checks to has_bucket_ownership_permission() aligns with AWS behavior where bucket policies do not affect the ListBuckets operation. Only buckets owned by the requesting account (or their root account for IAM users) are returned.


927-936: LGTM: Direct ownership check is correct.

The function properly validates direct bucket ownership with appropriate null safety guards.


949-968: LGTM: Ownership permission logic correctly implements AWS-compliant behavior.

The function properly combines direct ownership and IAM user inheritance checks to determine if a bucket should appear in ListBuckets results. The implementation aligns with AWS behavior where:

  • Root accounts see buckets they own
  • IAM users see buckets owned by their root account

970-1013: LGTM: Refactored permission logic maintains correct behavior.

The updates properly:

  • Use the new ownership helper functions for consistency
  • Remove deprecated system_owner checks
  • Maintain correct fallback behavior: ownership grants access when no policy exists, and policy can grant additional access beyond ownership

The logic at line 1012 correctly allows access if the account is the owner OR if the bucket policy explicitly allows the action.

/////////////////

// TODO: move the following 3 functions - has_bucket_action_permission(), validate_fs_bucket_access(), _has_access_to_nsfs_dir()
// TODO: move the following 6 functions - is_bucket_owner(), is_iam_and_same_root_account_owner(), has_bucket_ownership_permission(), has_bucket_action_permission(), validate_fs_bucket_access(), _has_access_to_nsfs_dir()
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't like keeping this updated after each PR, if we don't want to move it right now, let's create a new section // SHARED UTILS - with the original explanation - and keep everything that we think we want to move from this file there

Copy link
Member Author

Choose a reason for hiding this comment

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

Moved, Thanks

Signed-off-by: Aayush Chouhan <[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: 0

🧹 Nitpick comments (2)
src/sdk/bucketspace_fs.js (1)

1032-1037: Consider extracting shared utilities in a future refactor.

The TODO comment indicates these functions could be extracted to a shared utility file for reuse across the codebase. While this would improve maintainability, it's reasonable to defer this refactor given the PR's current scope.

src/test/unit_tests/nsfs/test_bucketspace_fs.js (1)

908-957: Consider adding explicit tests for new ownership helper functions.

The PR introduces several new access control functions (is_bucket_owner, is_iam_and_same_root_account_owner, has_bucket_ownership_permission) but doesn't include explicit unit tests for them. While existing tests like list_buckets - iam accounts (lines 502-515) exercise these functions implicitly, dedicated tests would improve coverage and make the behavior more explicit.

Consider adding tests such as:

  • is_bucket_owner - returns true for direct owner
  • is_bucket_owner - returns false for non-owner
  • is_iam_and_same_root_account_owner - returns true for IAM user of root owner
  • has_bucket_ownership_permission - various ownership scenarios

As per coding guidelines: "Ensure that the PR includes tests for the changes."

📜 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 f36aadc and 5a6620d.

📒 Files selected for processing (3)
  • src/sdk/bucketspace_fs.js (7 hunks)
  • src/sdk/nb.d.ts (2 hunks)
  • src/test/unit_tests/nsfs/test_bucketspace_fs.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/unit_tests/nsfs/test_bucketspace_fs.js
🧠 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/sdk/nb.d.ts
📚 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/sdk/nb.d.ts
📚 Learning: 2025-11-18T07:00:17.653Z
Learnt from: naveenpaul1
Repo: noobaa/noobaa-core PR: 9277
File: src/endpoint/s3/s3_bucket_policy_utils.js:357-368
Timestamp: 2025-11-18T07:00:17.653Z
Learning: In NooBaa codebase, account.name is always a SensitiveString instance, so calling account.name.unwrap() is safe without defensive type checks in functions like get_bucket_policy_principal_arn in src/endpoint/s3/s3_bucket_policy_utils.js.

Applied to files:

  • src/sdk/bucketspace_fs.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/bucketspace_fs.js
🧬 Code graph analysis (2)
src/test/unit_tests/nsfs/test_bucketspace_fs.js (1)
src/sdk/config_fs.js (1)
  • CONFIG_SUBDIRS (42-50)
src/sdk/bucketspace_fs.js (2)
src/endpoint/s3/s3_bucket_policy_utils.js (1)
  • account (303-303)
src/server/common_services/auth_server.js (2)
  • bucket_policy (619-619)
  • bucket_policy (673-673)
⏰ 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-jest-unit-tests
  • GitHub Check: Build Noobaa Image
  • GitHub Check: run-package-lock-validation
🔇 Additional comments (6)
src/sdk/nb.d.ts (1)

66-66: LGTM! Type declarations support ownership-based access control.

The new owner field on Account and owner_account on Bucket properly support the ownership-based access control logic introduced in this PR.

Also applies to: 183-183

src/sdk/bucketspace_fs.js (4)

244-282: LGTM! List_buckets correctly implements ownership-based gating.

The refactored flow properly checks ownership permissions (line 275) instead of bucket policy permissions, making the behavior AWS-compliant. The additional filesystem access validation (line 277) ensures the account can actually access the underlying storage.


1113-1122: Clarify the conditional check by account name.

The condition if (account.owner === undefined) restricts name-based permission checks to root accounts only, but the comment suggests all accounts should support both ID and name identification.

Is this intentional? If IAM users should also be checkable by name, the condition should be removed:

-        if (account.owner === undefined) {
-            permission_by_name = await bucket_policy_utils.has_bucket_policy_permission(
-                bucket_policy,
-                account.name.unwrap(),
-                action,
-                `arn:aws:s3:::${bucket.name.unwrap()}${bucket_path}`,
-                undefined,
-                { disallow_public_access: bucket.public_access_block?.restrict_public_buckets }
-            );
-        }
+        permission_by_name = await bucket_policy_utils.has_bucket_policy_permission(
+            bucket_policy,
+            account.name.unwrap(),
+            action,
+            `arn:aws:s3:::${bucket.name.unwrap()}${bucket_path}`,
+            undefined,
+            { disallow_public_access: bucket.public_access_block?.restrict_public_buckets }
+        );

1127-1153: LGTM! Filesystem access validation is properly implemented.

The functions correctly validate that:

  1. The bucket is an NSFS bucket (line 1130)
  2. The account has valid nsfs_account_config with uid/gid (lines 1140-1141)
  3. The account can access the bucket's underlying storage path (line 1146)
  4. Expected access errors are handled gracefully (line 1150)

1056-1059: Based on the learnings provided and the repository access limitations, I can analyze this review comment:

Key Evidence from Learnings:

  1. Learning 1 (PR 9291, auth_server.js): account.owner from system_store is an ObjectID reference with ._id property
  2. Learning 2 (PR 9277, s3_rest.js): account.owner is a string due to RPC serialization
  3. The type of account.owner varies depending on how the account object is loaded

Analysis:
The review comment raises a valid concern about type consistency. The learnings demonstrate that account.owner has different types across different contexts in the codebase:

  • When loaded from system_store (auth_server): ObjectID object
  • When received via RPC (s3_rest): string

In bucketspace_fs, which is NSFS (filesystem-backed), accounts are loaded from config files. The review suggests both account.owner and bucket.owner_account.id should be strings from JSON config, but the comparison lacks explicit type validation.

However, without direct access to the codebase, I cannot definitively verify:

  • Where exactly accounts are loaded in bucketspace_fs
  • Whether account objects are reused across contexts (potentially mixing types)
  • If the current code actually fails due to type mismatch

The suggested defensive String() coercion is valid practice for ensuring safety when type consistency cannot be guaranteed.


The comparison account.owner === bucket.owner_account.id may have type consistency issues. Given that account.owner can be an ObjectID or string depending on loading context (per learnings from other parts of the codebase), add defensive type coercion to ensure safe comparison:

 is_iam_and_same_root_account_owner(account, bucket) {
     if (!account?.owner || !bucket?.owner_account?.id) return false;
-    return account.owner === bucket.owner_account.id;
+    return String(account.owner) === String(bucket.owner_account.id);
 }

Verify that both account.owner and bucket.owner_account.id originate from the same source (JSON config) and confirm types are consistently strings in this NSFS context.

src/test/unit_tests/nsfs/test_bucketspace_fs.js (1)

928-950: LGTM! Tests validate policy-based tagging access.

The new tests properly verify that bucket policy permissions enable cross-account tagging operations for both principal formats (by name and by ID). The tests correctly:

  1. Set up bucket policy granting s3:PutBucketTagging permission
  2. Execute the operation with a different account
  3. Verify the tagging was applied

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.

3 participants