diff --git a/data_safe_haven/external/api/graph_api.py b/data_safe_haven/external/api/graph_api.py index ab0a68d7c9..d099fa51eb 100644 --- a/data_safe_haven/external/api/graph_api.py +++ b/data_safe_haven/external/api/graph_api.py @@ -20,7 +20,7 @@ DataSafeHavenInternalError, DataSafeHavenMicrosoftGraphError, ) -from data_safe_haven.utility import LoggingSingleton +from data_safe_haven.utility import LoggingSingleton, NonLoggingSingleton class LocalTokenCache(SerializableTokenCache): @@ -62,21 +62,20 @@ class GraphApi: def __init__( self, - *args: Any, + *, tenant_id: str | None = None, auth_token: str | None = None, application_id: str | None = None, application_secret: str | None = None, base_endpoint: str = "", default_scopes: Sequence[str] = [], - **kwargs: Any, + disable_logging: bool = False, ): - super().__init__(*args, **kwargs) self.base_endpoint = ( base_endpoint if base_endpoint else "https://graph.microsoft.com/v1.0" ) self.default_scopes = list(default_scopes) - self.logger = LoggingSingleton() + self.logger = NonLoggingSingleton() if disable_logging else LoggingSingleton() self.tenant_id = tenant_id if auth_token: self.token = auth_token @@ -875,10 +874,14 @@ def verify_custom_domain( "You will need to delegate to the following nameservers:" f" {', '.join([f'[green]{n}[/]' for n in expected_nameservers])}" ) - self.logger.confirm( - f"Have you delegated {domain_name} to the Azure nameservers above?", - default_to_yes=True, - ) + if isinstance(self.logger, LoggingSingleton): + self.logger.confirm( + f"Have you delegated {domain_name} to the Azure nameservers above?", + default_to_yes=True, + ) + else: + msg = "Unable to confirm Azure nameserver delegation." + raise NotImplementedError(msg) # Send verification request if needed if not any((d["id"] == domain_name and d["isVerified"]) for d in domains): response = self.http_post( diff --git a/data_safe_haven/pulumi/dynamic/azuread_application.py b/data_safe_haven/pulumi/dynamic/azuread_application.py index 7f1c52924e..34618c34f7 100644 --- a/data_safe_haven/pulumi/dynamic/azuread_application.py +++ b/data_safe_haven/pulumi/dynamic/azuread_application.py @@ -30,7 +30,7 @@ class AzureADApplicationProvider(DshResourceProvider): def refresh(props: dict[str, Any]) -> dict[str, Any]: outs = dict(**props) with suppress(Exception): - graph_api = GraphApi(auth_token=outs["auth_token"]) + graph_api = GraphApi(auth_token=outs["auth_token"], disable_logging=True) if json_response := graph_api.get_application_by_name( outs["application_name"] ): @@ -42,9 +42,7 @@ def create(self, props: dict[str, Any]) -> CreateResult: """Create new AzureAD application.""" outs = dict(**props) try: - graph_api = GraphApi( - auth_token=props["auth_token"], - ) + graph_api = GraphApi(auth_token=props["auth_token"], disable_logging=True) json_response = graph_api.create_application( props["application_name"], request_json={ @@ -71,9 +69,7 @@ def delete(self, id_: str, props: dict[str, Any]) -> None: # Use `id` as a no-op to avoid ARG002 while maintaining function signature id(id_) try: - graph_api = GraphApi( - auth_token=props["auth_token"], - ) + graph_api = GraphApi(auth_token=props["auth_token"], disable_logging=True) graph_api.delete_application(props["application_name"]) except Exception as exc: msg = f"Failed to delete application [green]{props['application_name']}[/] from AzureAD.\n{exc}"