Skip to content

Exclude tool provider admins from the last-user check - #93

Merged
arobson-ods merged 4 commits into
developfrom
ar/fix-last-user-check
Oct 6, 2026
Merged

arobson-ods merged 4 commits into
developfrom
ar/fix-last-user-check

Conversation

@arobson-ods

Copy link
Copy Markdown
Contributor

Addresses issue #85 - provider admins incorrectly counted in last-user check

What changed

DELETE /users/{user_id}/reporting-org/{org_id} guards against emptying an organisation with a "is this the last user?" check. It counted the result of get_user_associations_for_org, which returns tool-derived PROVIDER_ADMIN associations as well as direct reporting-org roles so a tool's provider admin counted as a member of the organisation, and contributed one association per authorised tool. The last real member of an org authorised for a tool could be removed, leaving the org with nobody in it.

FineGrainedAuthorisationProvider gains get_direct_user_associations_for_org, and the check calls that instead. It's a concrete method defined in terms of the existing abstract get_user_associations_for_org, so it inherits all integrity checks and obliges no implementation to supply anything.

Two commits:

  • test: adds the fixture and repoints the test - fails at this commit
  • fix: adds the provider method and switches the function call - green

Scope decisions

  • A long function with numbered sections is a candidate for refactor. Underlying cause of the bug was the awkwardness of testing the function as it stands. test_delete_user_role_cannot_delete_last_user was passing because of the '5b' last-admin check. The '5a - check that the user isn't the last user in the organisation' check was never exercised. Refactoring for testability considered out of scope.

Testing

  • Full suite: 342 passed, 1 skipped (pre-existing) - flake8, black, isort, mypy clean; bandit zero issues.
  • Bug reproduced before fixing: at the test: commit the new test fails with 200 == 400 and the SQL log shows the DELETE executing.
  • New provider-level assertions in test_provider_roles_are_correctly_applied cover an org with one direct user among four provider-admin associations, and an org with none at all despite two provider admins reaching it.

Notes for reviewer

  • New fixture org ("Sole Contributor Agency 04"): one non-admin direct user plus an authorised tool. No existing org could exercise the check. Every one had two or more direct users, or none.

Fixes the tests to replicate bug in issue #85

No fixture org had a single direct user, so check 5a had no coverage at
all, and test_delete_user_role_cannot_delete_last_user pointed at an org
with two so it passed via the last-admin check below it.

Adds an org with one non-admin direct user and an authorised tool, and
repoints that test at it.  The test fails at this commit. The tool-derived
PROVIDER_ADMIN rows inflate the count, 5a passes, and the organisation's
last member is removed.  Also pins the sibling last-admin test to its own
error message, since both checks return 400.
The last-user check on removing a user from a reporting org counted the
result of get_user_associations_for_org, which returns tool-derived
PROVIDER_ADMIN associations as well as direct reporting-org roles.  A
tool's provider admin therefore counted as a member of the organisation,
and contributed one association per authorised tool, so the last direct
member of an org authorised for a tool could be removed and the org left
with no members.

This commit adds get_direct_user_associations_for_org to the provider
interface and uses it to fix the last user check.
@arobson-ods
arobson-ods requested a review from simon-20 October 1, 2026 14:44

@simon-20 simon-20 left a comment •

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.

This is good, the only thing I'd request is that you bump the version and amend the CHANGELOG to refer to the new version. Approving as that's straightforward enough.

  • Update version in pyproject.toml
  • Update CHANGELOG to reflect new version

@arobson-ods
arobson-ods merged commit 8a54831 into develop Oct 6, 2026
5 checks passed
@arobson-ods
arobson-ods deleted the ar/fix-last-user-check branch October 6, 2026 09:21
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.

2 participants