Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(staff): Create initial staff class for _admin mode #61653

Merged
merged 11 commits into from
Dec 18, 2023

Conversation

schew2381
Copy link
Contributor

@schew2381 schew2381 commented Dec 13, 2023

In future PRs, I will create + test the staff middleware and index endpoint

Summary

This PR creates a new staff class that is modeled off of the existing Superuser class. I removed all the code that was added to support the superuser modal because _admin will not require that, only 2FA.

Similarities

  1. is_active_staff is not a class method but a helper function, that checks for staff the same way as is_active_superuser checks for superuser
  2. get_session_data is identical
  3. set_logged_out and _set_logged_out are identical
  4. on_response is identical

Differences

  1. set_logged_in for Staff vs Superuser
    • Staff does not exist for self-hosted, is not enabled automatically upon login, and does not require a form to enable (only SSO/2FA)
    • Therefore Staff does not have a _needs_validation function
    • Staff also does not have form checks
  2. is_active class property does not check for an expiry time depending on in you switched orgs b/c staff mode is not tied to any org
    • Thus we don't need _check_expired_on_org_change
  3. STAFF_ORG_ID, instead of setting this is init, we know keep it as a file constant because it should never change

Closes https://github.com/getsentry/team-enterprise/issues/5

@schew2381 schew2381 self-assigned this Dec 13, 2023
@github-actions github-actions bot added the Scope: Backend Automatically applied to PRs that change backend components label Dec 13, 2023
Copy link

codecov bot commented Dec 13, 2023

Codecov Report

Merging #61653 (008b4e6) into master (e331269) will increase coverage by 0.86%.
Report is 3 commits behind head on master.
The diff coverage is 82.05%.

Additional details and impacted files
@@            Coverage Diff             @@
##           master   #61653      +/-   ##
==========================================
+ Coverage   80.35%   81.22%   +0.86%     
==========================================
  Files        5187     5188       +1     
  Lines      228691   228847     +156     
  Branches    38396    38428      +32     
==========================================
+ Hits       183770   185885    +2115     
+ Misses      39050    37294    -1756     
+ Partials     5871     5668     -203     
Files Coverage Δ
src/sentry/auth/staff.py 82.05% <82.05%> (ø)

... and 218 files with indirect coverage changes

Copy link
Member

@cathteng cathteng left a comment

Choose a reason for hiding this comment

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

i still need to look at tests

src/sentry/auth/staff.py Show resolved Hide resolved
src/sentry/auth/superuser.py Outdated Show resolved Hide resolved
src/sentry/auth/staff.py Outdated Show resolved Hide resolved
src/sentry/auth/staff.py Show resolved Hide resolved
Copy link
Member

@cathteng cathteng left a comment

Choose a reason for hiding this comment

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

lgtm but this is also an ever evolving project

@schew2381 schew2381 merged commit aa13083 into master Dec 18, 2023
49 of 50 checks passed
@schew2381 schew2381 deleted the seiji/feat/create-staff-class branch December 18, 2023 23:51
Copy link
Contributor

@ykamo001 ykamo001 left a comment

Choose a reason for hiding this comment

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

I know I'm a little late to this PR, sorry! But happy to go over the comments more if you want. Let me know if I've misunderstood something, or don't have the right context.

src/sentry/auth/staff.py Show resolved Hide resolved
src/sentry/auth/staff.py Show resolved Hide resolved
def is_active_staff(request: Request) -> bool:
if is_system_auth(getattr(request, "auth", None)):
return True
stf = getattr(request, "staff", None) or Staff(request)
Copy link
Contributor

Choose a reason for hiding this comment

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

considering that Staff initializer can throw errors, would it be more prudent to have this around a try/except so that we don't have unintended behaviors or errors? Something along the lines of:

try:
   stf = getattr(request, "staff", None) or Staff(request)
except Exception as err:
    logger.error(f"unexpected error trying to determine active staff user, defaulting to False", exc_info=err)
    return False

return stf.is_active

# if the user has changed
if str(self.request.user.id) != self.uid:
return False
return self._is_active
Copy link
Contributor

Choose a reason for hiding this comment

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

After reading the code all the way, I now know _populate is at the end supposed to help establish this value before being referenced, but if that's the case, it would be better in the __init__ to establish this value first as a default for safer code. Reading this code from top to bottom, it's not clear that the value gets dynamically added to the instance; I thought "Oh no, we're referencing a value that doesn't exist!" haha

We have to go 2 levels deep (from populate -> set_logged_in/out) to know this is a class variable we can use in this class, and if something happens in that chain, we could be blowing up here/throwing an error.

src/sentry/auth/staff.py Show resolved Hide resolved
)
return

session_token = data.get("tok")
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: do we have constants for these keys/references?

src/sentry/auth/staff.py Show resolved Hide resolved
return False, "invalid-ip"
return True, None

def get_session_data(self, current_datetime=None):
Copy link
Contributor

Choose a reason for hiding this comment

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

There is a lot of checks and calculations happening in this function. Can we break those apart? I think the code would be much easier to read, and the flow/logic much more feasible to follow in the mind!

We also seem to be populating some keys and not others if a condition fails. For example, if idl is less than current, we will return early and not populate the rest of the keys (exp). Is that what we expect? Should the rest of the keys still be defaulted so they exist? Could we pull the populating/checking of those keys out to another function so that we could handle that decision more easily?


return data

def _populate(self, current_datetime=None):
Copy link
Contributor

Choose a reason for hiding this comment

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

Could we name this function to something else? Populate is very generic, I'm not sure what it's supposed to be populating, and if it's okay to rerun this function or add to another private function.

If this is only meant to be run once, could we add some guard rails/checks for that? Or restructure this function so that it returns the values we want to populate and the __init__ can be responsible for adding them to the class?

Comment on lines +220 to +237
if not self.is_active:
if self._inactive_reason:
logger.warning(
"staff.%s",
self._inactive_reason,
extra={
"ip_address": request.META["REMOTE_ADDR"],
"user_id": request.user.id,
},
)
else:
logger.warning(
"staff.inactive-unknown-reason",
extra={
"ip_address": request.META["REMOTE_ADDR"],
"user_id": request.user.id,
},
)
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we need to do this logic in this function at this level? Right now, is_activate property needs _populate to finish first so that _is_active gets added to the class, now _populate needs is_active to function correctly. It's creating this cyclic dependency effect, and it would be best to pull that out.

@ykamo001
Copy link
Contributor

Super exciting work here Seiji!!

schew2381 added a commit that referenced this pull request Dec 20, 2023
Create staff middleware and tests.
The code has been copied and adjusted over from the superuser
middleware.

Requires #61653
Closes https://github.com/getsentry/team-enterprise/issues/6
@github-actions github-actions bot locked and limited conversation to collaborators Jan 5, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Scope: Backend Automatically applied to PRs that change backend components
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants