Skip to content

Commit

Permalink
Add active/inactive accoutn check for dbGaP collaborators
Browse files Browse the repository at this point in the history
Check collaborators' active or inactive status when auditing. Note
that we are not checking PI status, because if a PI leaves we'll know
about it through other channels, and need to decide what to do.
  • Loading branch information
amstilp committed Feb 14, 2025
1 parent 34c1778 commit a8a43d7
Show file tree
Hide file tree
Showing 2 changed files with 86 additions and 14 deletions.
52 changes: 38 additions & 14 deletions primed/dbgap/audit/collaborator_audit.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,9 @@ class dbGaPCollaboratorAudit(PRIMEDAudit):
NOT_COLLABORATOR = "Not a collaborator."
GROUP_WITHOUT_ACCESS = "Groups do not have access."

# Inactive account.
INACTIVE_ACCOUNT = "Account is inactive."

# # Unexpected.
# ERROR_HAS_ACCESS = "Has access for an unknown reason."
UNEXPECTED_GROUP_ACCESS = "Group should not have access."
Expand Down Expand Up @@ -267,6 +270,7 @@ def _audit_application_and_account(self, dbgap_application, account):

is_pi = user == dbgap_application.principal_investigator
is_collaborator = user in dbgap_application.collaborators.all()
is_active = account.status == account.ACTIVE_STATUS

if is_in_access_group:
if is_pi:
Expand All @@ -279,14 +283,24 @@ def _audit_application_and_account(self, dbgap_application, account):
)
)
elif is_collaborator:
self.verified.append(
VerifiedAccess(
dbgap_application=dbgap_application,
user=user,
member=account,
note=self.COLLABORATOR_IN_ACCESS_GROUP,
if is_active:
self.verified.append(
VerifiedAccess(
dbgap_application=dbgap_application,
user=user,
member=account,
note=self.COLLABORATOR_IN_ACCESS_GROUP,
)
)
else:
self.needs_action.append(
RemoveAccess(
dbgap_application=dbgap_application,
user=user,
member=account,
note=self.INACTIVE_ACCOUNT,
)
)
)
else:
self.needs_action.append(
RemoveAccess(
Expand All @@ -307,14 +321,24 @@ def _audit_application_and_account(self, dbgap_application, account):
)
)
elif is_collaborator:
self.needs_action.append(
GrantAccess(
dbgap_application=dbgap_application,
user=user,
member=account,
note=self.COLLABORATOR_LINKED_ACCOUNT,
if is_active:
self.needs_action.append(
GrantAccess(
dbgap_application=dbgap_application,
user=user,
member=account,
note=self.COLLABORATOR_LINKED_ACCOUNT,
)
)
else:
self.verified.append(
VerifiedNoAccess(
dbgap_application=dbgap_application,
user=user,
member=account,
note=self.INACTIVE_ACCOUNT,
)
)
)
else:
self.verified.append(
VerifiedNoAccess(
Expand Down
48 changes: 48 additions & 0 deletions primed/dbgap/tests/test_audit.py
Original file line number Diff line number Diff line change
Expand Up @@ -1190,6 +1190,54 @@ def test_collaborator_linked_account_not_in_access_group(self):
self.assertEqual(record.member, account)
self.assertEqual(record.note, collaborator_audit.dbGaPCollaboratorAudit.COLLABORATOR_LINKED_ACCOUNT)

def test_collaborator_linked_account_inactive_in_access_group(self):
# Create applications.
dbgap_application = factories.dbGaPApplicationFactory.create()
# Create accounts.
account = AccountFactory.create(verified=True)
# Set up collaborators.
dbgap_application.collaborators.add(account.user)
# Deactivate account.
account.deactivate()
# Access group membership.
GroupAccountMembershipFactory.create(group=dbgap_application.anvil_access_group, account=account)
# Set up audit
collab_audit = collaborator_audit.dbGaPCollaboratorAudit()
# Run audit
collab_audit.audit_application_and_object(dbgap_application, account.user)
self.assertEqual(len(collab_audit.verified), 0)
self.assertEqual(len(collab_audit.needs_action), 1)
self.assertEqual(len(collab_audit.errors), 0)
record = collab_audit.needs_action[0]
self.assertIsInstance(record, collaborator_audit.RemoveAccess)
self.assertEqual(record.dbgap_application, dbgap_application)
self.assertEqual(record.user, account.user)
self.assertEqual(record.member, account)
self.assertEqual(record.note, collaborator_audit.dbGaPCollaboratorAudit.INACTIVE_ACCOUNT)

def test_collaborator_linked_account_inactive_not_in_access_group(self):
# Create applications.
dbgap_application = factories.dbGaPApplicationFactory.create()
# Create accounts.
account = AccountFactory.create(verified=True)
# Set up collaborators.
dbgap_application.collaborators.add(account.user)
# Deactivate account.
account.deactivate()
# Set up audit
collab_audit = collaborator_audit.dbGaPCollaboratorAudit()
# Run audit
collab_audit.audit_application_and_object(dbgap_application, account.user)
self.assertEqual(len(collab_audit.verified), 1)
self.assertEqual(len(collab_audit.needs_action), 0)
self.assertEqual(len(collab_audit.errors), 0)
record = collab_audit.verified[0]
self.assertIsInstance(record, collaborator_audit.VerifiedNoAccess)
self.assertEqual(record.dbgap_application, dbgap_application)
self.assertEqual(record.user, account.user)
self.assertEqual(record.member, account)
self.assertEqual(record.note, collaborator_audit.dbGaPCollaboratorAudit.INACTIVE_ACCOUNT)

def test_collaborator_no_account(self):
# Create applications.
dbgap_application = factories.dbGaPApplicationFactory.create()
Expand Down

0 comments on commit a8a43d7

Please sign in to comment.