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

Local check runner #51

Merged
merged 95 commits into from
Sep 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
95 commits
Select commit Hold shift + click to select a range
25cf982
Changes for local-check-runner utility.
dmichaels-harvard Jul 16, 2023
89e6973
typo
dmichaels-harvard Jul 16, 2023
61c6934
Merge branch 'master' into local-check-runner
dmichaels-harvard Jul 16, 2023
ed6e363
Adding support for local-check-runner utility.
dmichaels-harvard Jul 16, 2023
0ff3ceb
Adding support for local-check-runner utility.
dmichaels-harvard Jul 16, 2023
57720f7
Adding support for local-check-runner utility.
dmichaels-harvard Jul 16, 2023
a56d731
Adding support for local-check-runner utility.
dmichaels-harvard Jul 16, 2023
3c5659c
Adding support for local-check-runner utility.
dmichaels-harvard Jul 17, 2023
38f91d4
Adding support for local-check-runner utility.
dmichaels-harvard Jul 17, 2023
485bdf7
Adding support for local-check-runner utility.
dmichaels-harvard Jul 17, 2023
0fbbc50
Adding support for local-check-runner utility.
dmichaels-harvard Jul 17, 2023
be29cd1
Adding support for local-check-runner utility.
dmichaels-harvard Jul 17, 2023
dc89492
Adding support for local-check-runner utility.
dmichaels-harvard Jul 17, 2023
040a4a7
Adding support for local-check-runner utility.
dmichaels-harvard Jul 17, 2023
3c329ba
Adding support for local-check-runner utility.
dmichaels-harvard Jul 17, 2023
8f321cf
Adding support for local-check-runner utility.
dmichaels-harvard Jul 17, 2023
6479479
Adding support for local-check-runner utility.
dmichaels-harvard Jul 17, 2023
86e9a65
Adding support for local-check-execution utility.
dmichaels-harvard Jul 17, 2023
93c8890
Adding support for local-check-execution utility.
dmichaels-harvard Jul 18, 2023
4d65058
Fix to test_fs_connection
dmichaels-harvard Jul 19, 2023
2d6fa13
comments
dmichaels-harvard Jul 19, 2023
86cddd0
Version update
dmichaels-harvard Jul 28, 2023
2c7242f
Minor update to identity.py to respect REDIS_HOST_LOCAL.
dmichaels-harvard Aug 14, 2023
8aecbd3
Allow override of Auth0 client/secret via env var for local dev.
dmichaels-harvard Aug 15, 2023
47d3c44
Misc updates related to foursight-smaht.
dmichaels-harvard Aug 29, 2023
d5279bb
Misc updates related to foursight-smaht.
dmichaels-harvard Aug 29, 2023
a2d71d1
Minor test fix.
dmichaels-harvard Aug 29, 2023
70e8f55
SMaHT related UI updates.
dmichaels-harvard Aug 30, 2023
427863e
SMaHT related UI updates.
dmichaels-harvard Aug 30, 2023
425f170
Minor UI fix for Foufront
dmichaels-harvard Aug 30, 2023
1a3495f
Minor UI fix for Foufront
dmichaels-harvard Aug 30, 2023
e7f7e59
Minor SMaHT related updates.
dmichaels-harvard Aug 31, 2023
a28f07c
Minor SMaHT related updates.
dmichaels-harvard Aug 31, 2023
b8f0a46
Minor SMaHT related updates.
dmichaels-harvard Sep 1, 2023
6d8d509
Minor SMaHT related updates.
dmichaels-harvard Sep 1, 2023
d035521
Fixup users
dmichaels-harvard Sep 3, 2023
34a55e5
Fixup users
dmichaels-harvard Sep 4, 2023
49e9123
Fixup users
dmichaels-harvard Sep 4, 2023
2774547
Fixup users
dmichaels-harvard Sep 4, 2023
b72e045
Fixup users
dmichaels-harvard Sep 4, 2023
fce6e65
Fixup users
dmichaels-harvard Sep 4, 2023
b04015b
Fixup users
dmichaels-harvard Sep 4, 2023
d3bd79a
Fixup users
dmichaels-harvard Sep 4, 2023
bfb91db
Fixup users
dmichaels-harvard Sep 4, 2023
85006df
Fixup users
dmichaels-harvard Sep 4, 2023
8b6e76d
Fixup users
dmichaels-harvard Sep 5, 2023
2df1f54
Fixup users
dmichaels-harvard Sep 5, 2023
3624c96
Fixup users
dmichaels-harvard Sep 5, 2023
1fca246
Fixup users
dmichaels-harvard Sep 5, 2023
5231161
Fixup users
dmichaels-harvard Sep 5, 2023
5bac39a
Fixup users
dmichaels-harvard Sep 5, 2023
0872b7e
Fixup users
dmichaels-harvard Sep 5, 2023
e30f9e7
Fixup users
dmichaels-harvard Sep 5, 2023
68d4e0d
Fixup users
dmichaels-harvard Sep 5, 2023
42c7e18
Fixup users
dmichaels-harvard Sep 5, 2023
e7afba2
Minor updates to accounts component.
dmichaels-harvard Sep 6, 2023
e698a8e
Minor fix in accounts component.
dmichaels-harvard Sep 6, 2023
1c44926
Minor fix in accounts component.
dmichaels-harvard Sep 6, 2023
741367e
Minor fix in accounts component.
dmichaels-harvard Sep 7, 2023
237fc04
Minor fix in accounts component.
dmichaels-harvard Sep 7, 2023
521f8d1
Minor fix in accounts component.
dmichaels-harvard Sep 8, 2023
5db0045
Minor fix in accounts component.
dmichaels-harvard Sep 8, 2023
6f528d8
Minor fix in accounts component.
dmichaels-harvard Sep 8, 2023
bcaa9f0
Minor fix in accounts component.
dmichaels-harvard Sep 8, 2023
55fe023
Minor fix in accounts component.
dmichaels-harvard Sep 8, 2023
8e5471f
Minor fix in accounts component.
dmichaels-harvard Sep 8, 2023
ae1ef02
Minor fix in accounts component.
dmichaels-harvard Sep 8, 2023
a617f79
Minor fix in accounts component.
dmichaels-harvard Sep 8, 2023
698dd1f
Minor fix in accounts component.
dmichaels-harvard Sep 8, 2023
fa558e1
Minor fix in accounts component.
dmichaels-harvard Sep 8, 2023
2d5316d
Minor UI update.
dmichaels-harvard Sep 10, 2023
2dcf80f
Support for ingestion sumbission endpoints.
dmichaels-harvard Sep 17, 2023
8b0ec14
Support for ingestion sumbission endpoints.
dmichaels-harvard Sep 17, 2023
68d4718
Support for ingestion sumbission endpoints.
dmichaels-harvard Sep 17, 2023
efac358
Support for ingestion sumbission endpoints.
dmichaels-harvard Sep 17, 2023
bd11700
Support for ingestion sumbission endpoints.
dmichaels-harvard Sep 17, 2023
6727d36
Support for ingestion sumbission endpoints.
dmichaels-harvard Sep 17, 2023
8960b9d
Support for ingestion sumbission endpoints.
dmichaels-harvard Sep 17, 2023
aa5622e
Support for ingestion sumbission endpoints.
dmichaels-harvard Sep 17, 2023
8a367c0
Support for ingestion sumbission endpoints.
dmichaels-harvard Sep 17, 2023
c24eccb
Support for ingestion sumbission endpoints.
dmichaels-harvard Sep 17, 2023
69d91e1
Support for ingestion sumbission endpoints.
dmichaels-harvard Sep 17, 2023
1154ef4
Support for ingestion sumbission endpoints.
dmichaels-harvard Sep 17, 2023
ac11e6f
Support for ingestion sumbission endpoints.
dmichaels-harvard Sep 17, 2023
2622ac9
Support for ingestion sumbission endpoints.
dmichaels-harvard Sep 17, 2023
446e636
Support for ingestion sumbission endpoints.
dmichaels-harvard Sep 18, 2023
841b863
versions
dmichaels-harvard Sep 18, 2023
75c16ca
versions
dmichaels-harvard Sep 18, 2023
217d2ce
versions
dmichaels-harvard Sep 18, 2023
a6c7774
versions
dmichaels-harvard Sep 18, 2023
7fbaed7
Minor updates to ingestion submissions page.
dmichaels-harvard Sep 18, 2023
e999725
Minor updates to ingestion submissions page.
dmichaels-harvard Sep 18, 2023
0f59871
Minor updates to ingestion submissions page.
dmichaels-harvard Sep 18, 2023
dc0c2f5
Minor updates to ingestion submissions page.
dmichaels-harvard Sep 19, 2023
33fd703
Minor updates to ingestion submissions page.
dmichaels-harvard Sep 19, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,19 @@ foursight-core
Change Log
----------

4.5.0
=====
* 2023-08
* Support local-check-runner utility.
* Minor change to respect REDIS_HOST_LOCAL environment variable (for local dev/testing),
as well as allowing override of Auth0 client/secret (AUTH0_CLIENT_LOCAL, AUTH0_SECRET_LOCAL).
* Miscellaneous changes to get foursight-smaht working properly.
* Support to get consorita/submission_centers, as well as for
awards/labs for foursight-fourfront (previous oversight).
* Fixed up users pages.
* Added UI warning bar about inability to connect to ElasticSearch.


4.4.0
=====
* 2023-06-20
Expand Down
4 changes: 4 additions & 0 deletions foursight_core/app.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,6 @@
from typing import Optional
from chalice import Chalice
app = Chalice(app_name='foursight-core')
app.request_args = lambda: app.current_request.to_dict().get("query_params", {})
app.request_arg = lambda name, default = None: app.current_request.to_dict().get("query_params", {}).get(name, default)
app.request = lambda: app.current_request
70 changes: 70 additions & 0 deletions foursight_core/captured_output.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# TODO: Move to dcicutils.
from collections import namedtuple
from contextlib import contextmanager
import io
import sys
from typing import Optional

_real_stdout = sys.stdout
_real_stderr = sys.stderr

@contextmanager
def captured_output(capture: bool = True):
Copy link
Member

Choose a reason for hiding this comment

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

Seems like a good candidate for utils

"""
Context manager to capture any/all output to stdout or stderr, and not actually output it to stdout
or stderr. Yields and object with a get_captured_output() method to get the output captured thus far,
and another uncaptured_print() method to actually print the given output to stdout, even though output
to stdout is being captured. Can be useful, for example, in creating command-line scripts which invoke
code which outputs a lot of info, warning, error, etc to stdout or stderr, and we want to suprress that
output; but with the yielded uncaptured_print() method output specific to the script can actually be
output (to stdout); and/or can also optionally output any/all captured output, e.g. for debugging or
troubleshooting purposes. Disable this capture, without having to restructure your code WRT the usage
of the with-clause with this context manager, pass False as an argument to this context manager.
"""

original_stdout = _real_stdout
original_stderr = _real_stderr
captured_output = io.StringIO()

def set_original_output() -> None:
sys.stdout = original_stdout
sys.stderr = original_stderr

def set_captured_output() -> None:
if capture:
sys.stdout = captured_output
sys.stderr = captured_output

def uncaptured_print(*args, **kwargs) -> None:
set_original_output()
print(*args, **kwargs)
set_captured_output()

def uncaptured_input(message: str) -> str:
set_original_output()
value = input(message)
set_captured_output()
return value

def get_captured_output() -> Optional[str]:
return captured_output.getvalue() if capture else None

try:
set_captured_output()
Result = namedtuple("Result", ["get_captured_output", "uncaptured_print", "uncaptured_input"])
yield Result(get_captured_output, uncaptured_print, uncaptured_input)
finally:
set_original_output()


@contextmanager
def uncaptured_output():
original_stdout = sys.stdout
original_stderr = sys.stderr
sys.stdout = _real_stdout
sys.stderr = _real_stderr
try:
yield
finally:
sys.stdout = original_stdout
sys.stderr = original_stderr
151 changes: 130 additions & 21 deletions foursight_core/check_utils.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import os
import importlib
from collections import namedtuple
import copy
import importlib
import json
import logging
import os
from typing import Callable, Optional
from dcicutils.env_base import EnvBase
from dcicutils.env_utils import infer_foursight_from_env
from dcicutils.misc_utils import json_leaf_subst
Expand Down Expand Up @@ -39,7 +41,7 @@ def __init__(self, foursight_prefix, check_package_name='foursight_core', check_
# which calls back to the locate_check_setup_file function AppUtilsCore here in foursight-core).
if not os.path.exists(check_setup_file):
raise BadCheckSetup(f"Did not locate the specified check setup file: {check_setup_file}")
self.CHECK_SETUP_FILE = check_setup_file # for display/troubleshooting
self.CHECK_SETUP_FILE = check_setup_file # for display/troubleshooting
with open(check_setup_file, 'r') as jfile:
self.CHECK_SETUP = json.load(jfile)
logger.debug(f"foursight_core/CheckHandler: Loaded check_setup.json file: {check_setup_file} ...")
Expand Down Expand Up @@ -374,31 +376,138 @@ def run_check_or_action(self, connection, check_str, check_kwargs):
Fetches the check function and runs it (returning whatever it returns)
Return a string for failed results, CheckResult/ActionResult object otherwise.
"""
# make sure parameters are good
error_str = ' '.join(['Info: CHECK:', str(check_str), 'KWARGS:', str(check_kwargs)])
if len(check_str.strip().split('/')) != 2:
return ' '.join(['ERROR. Check string must be of form module/check_name.', error_str])
mod_name = check_str.strip().split('/')[0]
check_name = check_str.strip().split('/')[1]
check_method = None
try:
check_method = self._get_check_or_action_function(check_str)
except Exception as e:
return f"ERROR: {str(e)}"
if not isinstance(check_kwargs, dict):
return ' '.join(['ERROR. Check kwargs must be a dict.', error_str])
check_mod = None
return "ERROR: Check kwargs must be a dictionary: {check_str}"
return check_method(connection, **check_kwargs)

def _get_check_or_action_function(self, check_or_action_string: str, check_or_action: str = "check") -> Callable:
if len(check_or_action_string.strip().split('/')) != 2:
raise Exception(f"{check_or_action.title()} string must be of form"
"module_name/{check_or_action}_function_name: {check_or_action_string}")
module_name = check_or_action_string.strip().split('/')[0]
function_name = check_or_action_string.strip().split('/')[1]
module = None
for package_name in [self.check_package_name, 'foursight_core']:
try:
check_mod = self.import_check_module(package_name, mod_name)
module = self.import_check_module(package_name, module_name)
except ModuleNotFoundError:
continue
except Exception as e:
raise e
if not check_mod:
return ' '.join(['ERROR. Check module is not valid.', error_str])
check_method = check_mod.__dict__.get(check_name)
if not check_method:
return ' '.join(['ERROR. Check name is not valid.', error_str])
if not self.check_method_deco(check_method, self.CHECK_DECO) and \
not self.check_method_deco(check_method, self.ACTION_DECO):
return ' '.join(['ERROR. Check or action must use a decorator.', error_str])
return check_method(connection, **check_kwargs)
if not module:
raise Exception(f"Cannot find check module: {module_name}")
function = module.__dict__.get(function_name)
if not function:
raise Exception(f"Cannot find check function: {module_name}/{function_name}")
if not self.check_method_deco(function, self.CHECK_DECO) and \
not self.check_method_deco(function, self.ACTION_DECO):
raise Exception(f"{check_or_action.title()} function must use"
"@{check_or_action}_function decorator: {module_name}/{function_name}")
return function

@staticmethod
def get_checks_info(search: str = None) -> list:
checks = []
registry = Decorators.get_registry()
for item in registry:
info = CheckHandler._create_check_or_action_info(registry[item])
if search and search not in info.qualified_name.lower():
continue
if info.is_check:
checks.append(info)
return sorted(checks, key=lambda item: item.qualified_name)

@staticmethod
def get_actions_info(search: str = None) -> list:
actions = []
registry = Decorators.get_registry()
for item in registry:
info = CheckHandler._create_check_or_action_info(registry[item])
if search and search not in info.qualified_name.lower():
continue
if info.is_action:
actions.append(info)
return sorted(actions, key=lambda item: item.qualified_name)

@staticmethod
def get_check_info(check_function_name: str, check_module_name: str = None) -> Optional[namedtuple]:
return CheckHandler._get_check_or_action_info(check_function_name, check_module_name, "check")

@staticmethod
def get_action_info(action_function_name: str, action_module_name: str = None) -> Optional[namedtuple]:
return CheckHandler._get_check_or_action_info(action_function_name, action_module_name, "action")

@staticmethod
def _get_check_or_action_info(function_name: str,
module_name: str = None, kind: str = None) -> Optional[namedtuple]:

function_name = function_name.strip();
if module_name:
module_name = module_name.strip();
if not module_name:
if len(function_name.split("/")) == 2:
module_name = function_name.split("/")[0].strip()
function_name = function_name.split("/")[1].strip()
elif len(function_name.split(".")) == 2:
module_name = function_name.split(".")[0].strip()
function_name = function_name.split(".")[1].strip()
registry = Decorators.get_registry()
for name in registry:
if not kind or registry[name]["kind"] == kind:
item = registry[name]
if item["name"] == function_name:
if not module_name:
return CheckHandler._create_check_or_action_info(item)
if item["module"].endswith("." + module_name):
return CheckHandler._create_check_or_action_info(item)

@staticmethod
def _create_check_or_action_info(info: dict) -> Optional[namedtuple]:

def unqualified_module_name(module_name: str) -> str:
return module_name.rsplit(".", 1)[-1] if "." in module_name else module_name

def qualified_check_or_action_name(check_or_action_name: str, module_name: str) -> str:
unqualified_module = unqualified_module_name(module_name)
return f"{unqualified_module}/{check_or_action_name}" if unqualified_module else check_or_action_name

Info = namedtuple("CheckInfo", ["kind",
"is_check",
"is_action",
"name",
"qualified_name",
"file",
"line",
"module",
"unqualified_module",
"package",
"github_url",
"args",
"kwargs",
"function",
"associated_action",
"associated_check"])
return Info(info["kind"],
info["kind"] == "check",
info["kind"] == "action",
info["name"],
qualified_check_or_action_name(info["name"], info["module"]),
info["file"],
info["line"],
info["module"],
unqualified_module_name(info["module"]),
info["package"],
info["github_url"],
info["args"],
info["kwargs"],
info["function"],
info.get("action"),
info.get("check"))

Comment on lines +479 to +510
Copy link
Member

Choose a reason for hiding this comment

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

Does this really serve any purpose if you're not going to use outside of this function? You might consider moving this somewhere it can be used more widely ie: helper function that builds.

def init_check_or_action_res(self, connection, check):
"""
Expand Down
8 changes: 7 additions & 1 deletion foursight_core/decorators.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,10 +87,16 @@ def create_registry_record(self, kind, func, default_args, default_kwargs) -> No
"package": func_package,
"github_url": get_github_url(func_package, func_file, func_line),
"args": default_args,
"kwargs": default_kwargs
"kwargs": default_kwargs,
"function": func
}
if associated_action:
registry_record["action"] = associated_action
elif kind == "action":
for name in _decorator_registry:
item = _decorator_registry[name]
if item.get("action") == func_name:
registry_record["check"] = item["name"]
_decorator_registry[func_name] = registry_record

def check_function(self, *default_args, **default_kwargs):
Expand Down
2 changes: 1 addition & 1 deletion foursight_core/fs_connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ def __init__(self, fs_environ, fs_environ_info, test=False, use_es=True, host=No
# FOURFRONT information
self.ff_server = fs_environ_info['fourfront']
self.ff_env = fs_environ_info['ff_env']
self.ff_es = fs_environ_info['es']
self.ff_es = fs_environ_info['es'] if not host else host
self.ff_bucket = fs_environ_info['bucket']
self.redis = None
self.redis_url = None
Expand Down
30 changes: 30 additions & 0 deletions foursight_core/identity.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,30 @@ def set_elasticsearch_host_environment_variable() -> None:
logger.info(f"Foursight ES_HOST environment variable value is: {os.environ.get('ES_HOST')}")


def set_redis_host_environment_variable() -> None:
redis_host_local = os.environ.get("REDIS_HOST_LOCAL")
if redis_host_local:
os.environ["REDIS_HOST"] = redis_host_local
logger.info(f"Foursight REDIS_HOST local environment variable value is: {os.environ.get('REDIS_HOST')}")
else:
logger.info(f"Foursight REDIS_HOST environment variable value is: {os.environ.get('REDIS_HOST')}")


def set_auth0_environment_variable() -> None:
auth0_client_local = os.environ.get("AUTH0_CLIENT_LOCAL")
if auth0_client_local:
os.environ["CLIENT_ID"] = auth0_client_local
logger.info(f"Foursight Auth0 CLIENT_ID local environment variable value is: {os.environ.get('CLIENT_ID')}")
else:
logger.info(f"Foursight Auth0 CLIENT_ID environment variable value is: {os.environ.get('CLIENT_ID')}")
auth0_secret_local = os.environ.get("AUTH0_SECRET_LOCAL")
if auth0_secret_local:
os.environ["CLIENT_SECRET"] = auth0_secret_local
logger.info("Foursight Auth0 CLIENT_SECRET local environment variable value is: REDACTED")
else:
logger.info("Foursight Auth0 CLIENT_SECRET environment variable value is: REDACTED")


def apply_identity_globally():

# Make sure the IDENTITY (environment variable) is set (via Foursight CloudFormation template);
Expand Down Expand Up @@ -173,3 +197,9 @@ def apply_identity_globally():

# Set ES_HOST to proxy for local testing (e.g. http://localhost:9200) via ES_HOST_LOCAL environment variable.
set_elasticsearch_host_environment_variable()

# Set REDIS_HOST to proxy for local testing (e.g. redis://localhost:6379) via REDIS_HOST_LOCAL environment variable.
set_redis_host_environment_variable()

# Set AUTH0_CLIENT_LOCAL/AUTH0_SECRET_LOCAL for local testing.
set_auth0_environment_variable()
2 changes: 1 addition & 1 deletion foursight_core/react/api/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ def create_authtoken(self, jwt: str, jwt_expires_at: int, domain: str, request:
# For testing only, we simulate a portal access key error (e.g. due to expiration),
# which would manifest itself, primarily and most importantly, here, on login.
raise Exception("test_mode_access_key_simulate_error")
allowed_envs, first_name, last_name = self._envs.get_user_auth_info(email, raise_exception=True)
allowed_envs, first_name, last_name = self._envs.get_user_auth_info(email)
user_exception = False
except Exception as e:
#
Expand Down
9 changes: 7 additions & 2 deletions foursight_core/react/api/envs.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from dcicutils.env_utils import foursight_env_name
from dcicutils.function_cache_decorator import function_cache
from dcicutils.misc_utils import find_association
from ...app import app
from .gac import Gac

logging.basicConfig()
Expand Down Expand Up @@ -81,15 +82,19 @@ def get_user_auth_info(self, email: str, raise_exception: bool = False) -> Tuple
try:
# Note we must lower case the email to find the user. This is because all emails
# in the database are lowercased; it causes issues with OAuth if we don't do this.
known_env_name = known_env["full_name"]
envs = app.core.init_environments(known_env_name)
connection = app.core.init_connection(known_env_name, envs)
user = ff_utils.get_metadata('users/' + email.lower(),
ff_env=known_env["full_name"], add_on="frame=object&datastore=database")
key=connection.ff_keys,
add_on="frame=object&datastore=database")
if self._is_user_allowed_access(user):
# Since this is in a loop, for each env, this setup here will end up getting first/last name
# from the last env in the loop; doesn't really matter, just pick one set; this is just for
# informational/display purposes in the UI.
first_name = user.get("first_name")
last_name = user.get("last_name")
allowed_envs.append(known_env["full_name"])
allowed_envs.append(known_env_name)
except Exception as e:
if raise_exception:
raise
Expand Down
Loading
Loading