Skip to content

KC-1361: Reject share commands that target a record or folder owner#2235

Merged
sshrushanth-ks merged 3 commits into
share-commands-fixfrom
share-commands-fix-int
Jul 23, 2026
Merged

KC-1361: Reject share commands that target a record or folder owner#2235
sshrushanth-ks merged 3 commits into
share-commands-fixfrom
share-commands-fix-int

Conversation

@sshrushanth-ks

Copy link
Copy Markdown
Contributor

Summary

Sharing a record or folder to its owner via share-record, share-folder, nsf-share-record, or nsf-share-folder treated the owner like a normal share recipient. Grant, update, and revoke against the owner are invalid because the owner already has full access. These commands now detect that case early and fail with a clear message instead of sending a confusing or no-op share request. Ownership transfer (share-record -a owner) still works, but transferring to someone who already owns the record is rejected as a no-op.

Changes

  • register.py — added owner lookup helpers; share-record and share-folder now reject grant/revoke (and grant on folders) when the target is the owner; bulk user updates also skip the folder owner
  • helpers.py — added shared NSF owner checks and raise_if_record_share_target_is_owner
  • sharing_commands.py / folder_commands.py — wired the same owner rejection into nsf-share-record and nsf-share-folder
  • record_api.py — added find_record_owner_username for NSF record owner resolution
  • test_command_register.py / test_nested_share_folder.py — added tests covering grant-to-owner rejection and self ownership-transfer rejection

Fail early with a clear message for share-record, share-folder,
nsf-share-record, and nsf-share-folder so owners are not granted,
updated, or revoked as if they were share recipients.
@sshrushanth-ks sshrushanth-ks self-assigned this Jul 21, 2026
@sshrushanth-ks
sshrushanth-ks marked this pull request as ready for review July 21, 2026 05:19
@sali-ks
sali-ks requested a review from adeshmukh-ks July 22, 2026 04:39
owner_username = shared_folder.get('owner_username') or ''
if owner_username and owner_username.casefold() == email_cf:
return True
# Some sync payloads also put an owner flag on the user row.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Avoid the explicit for loop and continue.
Short-circuit as soon as a matching owner is found. Return False automatically if no matching user exists.

You can refactor with any()

users = shared_folder.get("users", [])

return any(
    user.get("owner") is True
    and (user.get("username") or "").casefold() == email_cf
    for user in users
)

continue
if access.get('owner'):
return access.get('accessor_name') or ''
return ''

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

You can use next() with a generator expression to make this more concise while preserving the behavior

return next(
    (
        access.get("accessor_name") or ""
        for access in access_result.get("record_accesses", [])
        if access.get("record_uid") == record_uid and access.get("owner")
    ),
    "",
)

username = accessor.get('username')
if username and username != params.user:
if is_nested_share_folder_owner_email(params, folder_uid, username):
continue

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

wouldn't logging a info or warning that owner is skipped from sharing be better

username = a.get('username')
if username and username != params.user:
if is_nested_share_folder_owner_email(params, folder_uid, username):
continue

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

wouldn't logging a info or warning that owner is skipped from sharing be better

owner = find_record_owner_username(access_result, record_uid)
if not owner or owner.casefold() != email.casefold():
return
if allow_owner_transfer:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

please change this variable name for better readibility, this is confusing

@sshrushanth-ks
sshrushanth-ks merged commit 1d2159d into share-commands-fix Jul 23, 2026
4 checks passed
sshrushanth-ks added a commit that referenced this pull request Jul 23, 2026
…2235)

* Reject share commands that target a record or folder owner.

Fail early with a clear message for share-record, share-folder,
nsf-share-record, and nsf-share-folder so owners are not granted,
updated, or revoked as if they were share recipients.

* resolved review comments

* addressed logging and variable naming comments
sk-keeper pushed a commit that referenced this pull request Jul 23, 2026
…2235)

* Reject share commands that target a record or folder owner.

Fail early with a clear message for share-record, share-folder,
nsf-share-record, and nsf-share-folder so owners are not granted,
updated, or revoked as if they were share recipients.

* resolved review comments

* addressed logging and variable naming comments
@sshrushanth-ks
sshrushanth-ks deleted the share-commands-fix-int branch July 24, 2026 05:29
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.

4 participants