diff --git a/diracx-routers/src/diracx/routers/auth/authorize_code_flow.py b/diracx-routers/src/diracx/routers/auth/authorize_code_flow.py index d7da44fd3..cea354df7 100644 --- a/diracx-routers/src/diracx/routers/auth/authorize_code_flow.py +++ b/diracx-routers/src/diracx/routers/auth/authorize_code_flow.py @@ -6,14 +6,14 @@ from __future__ import annotations import logging +from http import HTTPStatus from typing import Literal from fastapi import ( HTTPException, Request, - responses, - status, ) +from fastapi.responses import RedirectResponse from diracx.core.exceptions import AuthorizationError, IAMClientError, IAMServerError from diracx.core.settings import AuthSettings @@ -48,7 +48,7 @@ async def initiate_authorization_flow( config: Config, available_properties: AvailableSecurityProperties, settings: AuthSettings, -) -> responses.RedirectResponse: +) -> RedirectResponse: """Initiate the authorization flow. It will redirect to the actual OpenID server (IAM, CheckIn) to @@ -85,11 +85,11 @@ async def initiate_authorization_flow( ) except ValueError as e: raise HTTPException( - status_code=status.HTTP_400_BAD_REQUEST, + status_code=HTTPStatus.BAD_REQUEST, detail=str(e), ) from e - return responses.RedirectResponse(redirect_uri) + return RedirectResponse(redirect_uri) @router.get("/authorize/complete") @@ -100,7 +100,7 @@ async def complete_authorization_flow( auth_db: AuthDB, config: Config, settings: AuthSettings, -) -> responses.RedirectResponse: +) -> RedirectResponse: """Complete the authorization flow. The user is redirected back to the DIRAC auth service after completing the IAM's authorization flow. @@ -119,17 +119,17 @@ async def complete_authorization_flow( except AuthorizationError as e: logger.warning("Authorization flow failed with invalid state: %s", e) raise HTTPException( - status_code=status.HTTP_400_BAD_REQUEST, detail="Invalid state" + status_code=HTTPStatus.BAD_REQUEST, detail="Invalid state" ) from e except IAMServerError as e: logger.warning("IAM server error during authorization flow: %s", e) raise HTTPException( - status_code=status.HTTP_502_BAD_GATEWAY, + status_code=HTTPStatus.BAD_GATEWAY, detail="Failed to contact IAM server", ) from e except IAMClientError as e: logger.warning("IAM client error during authorization flow: %s", e) raise HTTPException( - status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid code" + status_code=HTTPStatus.UNAUTHORIZED, detail="Invalid code" ) from e - return responses.RedirectResponse(redirect_uri) + return RedirectResponse(redirect_uri) diff --git a/diracx-routers/src/diracx/routers/auth/device_flow.py b/diracx-routers/src/diracx/routers/auth/device_flow.py index 53c3606e7..bfcf3bb8f 100644 --- a/diracx-routers/src/diracx/routers/auth/device_flow.py +++ b/diracx-routers/src/diracx/routers/auth/device_flow.py @@ -6,13 +6,12 @@ from __future__ import annotations import logging +from http import HTTPStatus from fastapi import ( HTTPException, Request, Response, - responses, - status, ) from fastapi.responses import RedirectResponse from sqlalchemy.exc import NoResultFound @@ -78,7 +77,7 @@ async def initiate_device_flow( ) except ValueError as e: raise HTTPException( - status_code=status.HTTP_400_BAD_REQUEST, + status_code=HTTPStatus.BAD_REQUEST, detail=e.args[0], ) from e @@ -116,19 +115,19 @@ async def do_device_flow( except NoResultFound as e: logger.warning("Invalid or expired user_code: %s", e) raise HTTPException( - status_code=status.HTTP_400_BAD_REQUEST, + status_code=HTTPStatus.BAD_REQUEST, detail=e.args[0], ) from e except ValueError as e: logger.warning("Invalid scope during device flow: %s", e) raise HTTPException( - status_code=status.HTTP_400_BAD_REQUEST, + status_code=HTTPStatus.BAD_REQUEST, detail=e.args[0], ) from e except IAMServerError as e: logger.warning("IAM server error during device flow: %s", e) raise HTTPException( - status_code=status.HTTP_502_BAD_GATEWAY, + status_code=HTTPStatus.BAD_GATEWAY, detail=e.args[0], ) from e return RedirectResponse(authorization_flow_url) @@ -163,17 +162,17 @@ async def finish_device_flow( except IAMServerError as e: logger.warning("IAM server error during device flow completion: %s", e) raise HTTPException( - status_code=status.HTTP_502_BAD_GATEWAY, + status_code=HTTPStatus.BAD_GATEWAY, detail=e.args[0], ) from e except IAMClientError as e: logger.warning("IAM client error during device flow completion: %s", e) raise HTTPException( - status_code=status.HTTP_401_UNAUTHORIZED, + status_code=HTTPStatus.UNAUTHORIZED, detail=e.args[0], ) from e - return responses.RedirectResponse(f"{request_url}/finished") + return RedirectResponse(f"{request_url}/finished") @router.get("/device/complete/finished") diff --git a/diracx-routers/src/diracx/routers/auth/management.py b/diracx-routers/src/diracx/routers/auth/management.py index a054ff72b..bd63be22d 100644 --- a/diracx-routers/src/diracx/routers/auth/management.py +++ b/diracx-routers/src/diracx/routers/auth/management.py @@ -7,9 +7,10 @@ from __future__ import annotations import logging +from http import HTTPStatus from typing import Annotated, Any -from fastapi import Depends, Form, HTTPException, status +from fastapi import Depends, Form, HTTPException from joserfc.errors import DecodeError from typing_extensions import TypedDict from uuid_utils import UUID @@ -92,12 +93,12 @@ async def revoke_refresh_token_by_refresh_token( ) except ValueError as e: raise HTTPException( - status_code=status.HTTP_400_BAD_REQUEST, + status_code=HTTPStatus.BAD_REQUEST, detail=str(e), ) from e except InvalidCredentialsError as e: raise HTTPException( - status_code=status.HTTP_401_UNAUTHORIZED, + status_code=HTTPStatus.UNAUTHORIZED, detail=str(e), headers={"WWW-Authenticate": "Bearer"}, ) from e @@ -124,17 +125,17 @@ async def revoke_refresh_token_by_jti( await revoke_refresh_token_by_jti_bl(auth_db, subject, UUID(jti)) except ValueError as e: raise HTTPException( - status_code=status.HTTP_400_BAD_REQUEST, + status_code=HTTPStatus.BAD_REQUEST, detail=str(e), ) from e except PermissionError as e: raise HTTPException( - status_code=status.HTTP_403_FORBIDDEN, + status_code=HTTPStatus.FORBIDDEN, detail=str(e), ) from e except TokenNotFoundError as e: raise HTTPException( - status_code=status.HTTP_404_NOT_FOUND, + status_code=HTTPStatus.NOT_FOUND, detail=str(e), ) from e return "Refresh token revoked" diff --git a/diracx-routers/src/diracx/routers/auth/token.py b/diracx-routers/src/diracx/routers/auth/token.py index 55e17bece..b61222fa0 100644 --- a/diracx-routers/src/diracx/routers/auth/token.py +++ b/diracx-routers/src/diracx/routers/auth/token.py @@ -4,9 +4,10 @@ import logging import os +from http import HTTPStatus from typing import Annotated, Literal -from fastapi import Depends, Form, Header, HTTPException, status +from fastapi import Depends, Form, Header, HTTPException from joserfc.errors import JoseError from diracx.core.exceptions import ( @@ -47,7 +48,7 @@ async def mint_token( """Enrich the token with policy specific content and mint it.""" if not refresh_payload and not existing_refresh_token: raise HTTPException( - status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + status_code=HTTPStatus.INTERNAL_SERVER_ERROR, detail="Refresh token is not set and no refresh token was provided", ) @@ -140,12 +141,12 @@ async def get_oidc_token( ) except PendingAuthorizationError as e: raise DiracHttpResponseError( - status_code=status.HTTP_400_BAD_REQUEST, + status_code=HTTPStatus.BAD_REQUEST, data={"error": "authorization_pending"}, ) from e except ValueError as e: raise HTTPException( - status_code=status.HTTP_400_BAD_REQUEST, + status_code=HTTPStatus.BAD_REQUEST, detail=str(e), ) from e except ( @@ -153,13 +154,13 @@ async def get_oidc_token( JoseError, ) as e: raise HTTPException( - status_code=status.HTTP_401_UNAUTHORIZED, + status_code=HTTPStatus.UNAUTHORIZED, detail=str(e), headers={"WWW-Authenticate": "Bearer"}, ) from e except PermissionError as e: raise HTTPException( - status_code=status.HTTP_403_FORBIDDEN, + status_code=HTTPStatus.FORBIDDEN, detail=str(e), ) from e return await mint_token( @@ -196,7 +197,7 @@ async def perform_legacy_exchange( expected_api_key := os.environ.get("DIRACX_LEGACY_EXCHANGE_HASHED_API_KEY") ): raise HTTPException( - status_code=status.HTTP_503_SERVICE_UNAVAILABLE, + status_code=HTTPStatus.SERVICE_UNAVAILABLE, detail="Legacy exchange is not enabled", ) @@ -214,18 +215,18 @@ async def perform_legacy_exchange( ) except ValueError as e: raise HTTPException( - status_code=status.HTTP_400_BAD_REQUEST, + status_code=HTTPStatus.BAD_REQUEST, detail=str(e), ) from e except InvalidCredentialsError as e: raise HTTPException( - status_code=status.HTTP_401_UNAUTHORIZED, + status_code=HTTPStatus.UNAUTHORIZED, detail=str(e), headers={"WWW-Authenticate": "Bearer"}, ) from e except PermissionError as e: raise HTTPException( - status_code=status.HTTP_403_FORBIDDEN, + status_code=HTTPStatus.FORBIDDEN, detail=str(e), ) from e return await mint_token( diff --git a/diracx-routers/src/diracx/routers/configuration.py b/diracx-routers/src/diracx/routers/configuration.py index 4698cb047..63d4ea199 100644 --- a/diracx-routers/src/diracx/routers/configuration.py +++ b/diracx-routers/src/diracx/routers/configuration.py @@ -4,13 +4,13 @@ import logging from datetime import datetime, timezone +from http import HTTPStatus from typing import Annotated from fastapi import ( Header, HTTPException, Response, - status, ) from diracx.routers.dependencies import Config @@ -48,7 +48,7 @@ async def serve_config( } if if_none_match == config._hexsha: - raise HTTPException(status_code=status.HTTP_304_NOT_MODIFIED, headers=headers) + raise HTTPException(status_code=HTTPStatus.NOT_MODIFIED, headers=headers) # This is to prevent flip/flopping in case # a server gets out of sync with disk @@ -64,7 +64,7 @@ async def serve_config( else: if not_before > config._modified: raise HTTPException( - status_code=status.HTTP_304_NOT_MODIFIED, headers=headers + status_code=HTTPStatus.NOT_MODIFIED, headers=headers ) response.headers.update(headers) diff --git a/diracx-routers/src/diracx/routers/factory.py b/diracx-routers/src/diracx/routers/factory.py index 342e6d5cd..4c26f4c58 100644 --- a/diracx-routers/src/diracx/routers/factory.py +++ b/diracx-routers/src/diracx/routers/factory.py @@ -16,7 +16,7 @@ import dotenv from cachetools import TTLCache -from fastapi import APIRouter, Depends, FastAPI, HTTPException, Request, status +from fastapi import APIRouter, Depends, FastAPI, HTTPException, Request from fastapi.dependencies.models import Dependant from fastapi.exception_handlers import request_validation_exception_handler from fastapi.exceptions import RequestValidationError @@ -414,7 +414,7 @@ def route_unavailable_error_hander(request: Request, exc: DBUnavailableError): exc_info=True, ) return JSONResponse( - status_code=status.HTTP_503_SERVICE_UNAVAILABLE, + status_code=HTTPStatus.SERVICE_UNAVAILABLE, headers={"Retry-After": "10"}, content={"detail": str(exc)}, ) diff --git a/diracx-routers/src/diracx/routers/jobs/access_policies.py b/diracx-routers/src/diracx/routers/jobs/access_policies.py index bd0b29101..082e87e51 100644 --- a/diracx-routers/src/diracx/routers/jobs/access_policies.py +++ b/diracx-routers/src/diracx/routers/jobs/access_policies.py @@ -2,9 +2,10 @@ from collections.abc import Callable from enum import StrEnum, auto +from http import HTTPStatus from typing import Annotated -from fastapi import Depends, HTTPException, status +from fastapi import Depends, HTTPException from diracx.core.models import VectorSearchOperator from diracx.core.properties import GENERIC_PILOT, JOB_ADMINISTRATOR, NORMAL_USER @@ -60,7 +61,7 @@ async def policy( "job_ids is not None with ActionType.CREATE. This shouldn't happen" ) if NORMAL_USER not in user_info.properties: - raise HTTPException(status.HTTP_403_FORBIDDEN) + raise HTTPException(HTTPStatus.FORBIDDEN) return if GENERIC_PILOT in user_info.properties and action == ActionType.MANAGE: @@ -71,7 +72,7 @@ async def policy( return if NORMAL_USER not in user_info.properties: - raise HTTPException(status.HTTP_403_FORBIDDEN) + raise HTTPException(HTTPStatus.FORBIDDEN) if action == ActionType.QUERY: if job_ids is not None: @@ -109,7 +110,7 @@ async def policy( if job_owners == [expected_owner]: return - raise HTTPException(status.HTTP_403_FORBIDDEN) + raise HTTPException(HTTPStatus.FORBIDDEN) CheckWMSPolicyCallable = Annotated[Callable, Depends(WMSAccessPolicy.check)] @@ -138,14 +139,14 @@ async def policy( if action == ActionType.CREATE: if NORMAL_USER not in user_info.properties: - raise HTTPException(status.HTTP_403_FORBIDDEN) + raise HTTPException(HTTPStatus.FORBIDDEN) return if JOB_ADMINISTRATOR in user_info.properties: return if NORMAL_USER not in user_info.properties: - raise HTTPException(status.HTTP_403_FORBIDDEN) + raise HTTPException(HTTPStatus.FORBIDDEN) # Getting a sandbox or modifying it if pfns: @@ -158,7 +159,7 @@ async def policy( for pfn in pfns: if not pfn.startswith(required_prefix): raise HTTPException( - status_code=status.HTTP_403_FORBIDDEN, + status_code=HTTPStatus.FORBIDDEN, detail=f"Invalid PFN. PFN must start with {required_prefix}", ) # Checking if the user owns the sandbox @@ -168,7 +169,7 @@ async def policy( ) if not owner_id or owner_id != sandbox_owner_id: raise HTTPException( - status_code=status.HTTP_403_FORBIDDEN, + status_code=HTTPStatus.FORBIDDEN, detail=f"{user_info.preferred_username} is not the owner of the sandbox", ) diff --git a/diracx-routers/src/diracx/routers/utils/users.py b/diracx-routers/src/diracx/routers/utils/users.py index 8228a9ba8..97ab39d27 100644 --- a/diracx-routers/src/diracx/routers/utils/users.py +++ b/diracx-routers/src/diracx/routers/utils/users.py @@ -3,9 +3,10 @@ import logging import re import uuid as std_uuid +from http import HTTPStatus from typing import Annotated, Any -from fastapi import Depends, HTTPException, status +from fastapi import Depends, HTTPException from fastapi.security import OpenIdConnect from joserfc.errors import JoseError from joserfc.jwt import JWTClaimsRegistry @@ -83,7 +84,7 @@ async def verify_dirac_access_token( """ if not authorization: raise HTTPException( - status_code=status.HTTP_401_UNAUTHORIZED, + status_code=HTTPStatus.UNAUTHORIZED, detail="Authorization header is missing", headers={"WWW-Authenticate": "Bearer"}, ) @@ -91,7 +92,7 @@ async def verify_dirac_access_token( raw_token = match.group(1) else: raise HTTPException( - status_code=status.HTTP_400_BAD_REQUEST, + status_code=HTTPStatus.BAD_REQUEST, detail="Invalid authorization header", ) @@ -107,7 +108,7 @@ async def verify_dirac_access_token( except JoseError as e: logger.warning("Token validation failed: %s", e) raise HTTPException( - status_code=status.HTTP_401_UNAUTHORIZED, + status_code=HTTPStatus.UNAUTHORIZED, detail="Invalid JWT", ) from e diff --git a/diracx-routers/tests/jobs/test_wms_access_policy.py b/diracx-routers/tests/jobs/test_wms_access_policy.py index 83484b8d1..6f2227fa8 100644 --- a/diracx-routers/tests/jobs/test_wms_access_policy.py +++ b/diracx-routers/tests/jobs/test_wms_access_policy.py @@ -1,7 +1,9 @@ from __future__ import annotations +from http import HTTPStatus + import pytest -from fastapi import HTTPException, status +from fastapi import HTTPException from uuid_utils import uuid7 from diracx.core.properties import JOB_ADMINISTRATOR, NORMAL_USER @@ -48,17 +50,17 @@ def sandbox_metadata_db(): async def test_wms_access_policy_weird_user(job_db): """USer without NORMAL_USER or JOB_ADMINISTRATION can't do anything.""" weird_user = AuthorizedUserInfo(properties=[], **base_payload) - with pytest.raises(HTTPException, match=f"{status.HTTP_403_FORBIDDEN}"): + with pytest.raises(HTTPException, match=f"{HTTPStatus.FORBIDDEN}"): await WMSAccessPolicy.policy( WMS_POLICY_NAME, weird_user, action=ActionType.CREATE, job_db=job_db ) - with pytest.raises(HTTPException, match=f"{status.HTTP_403_FORBIDDEN}"): + with pytest.raises(HTTPException, match=f"{HTTPStatus.FORBIDDEN}"): await WMSAccessPolicy.policy( WMS_POLICY_NAME, weird_user, action=ActionType.QUERY, job_db=job_db ) - with pytest.raises(HTTPException, match=f"{status.HTTP_403_FORBIDDEN}"): + with pytest.raises(HTTPException, match=f"{HTTPStatus.FORBIDDEN}"): await WMSAccessPolicy.policy( WMS_POLICY_NAME, weird_user, @@ -91,7 +93,7 @@ async def test_wms_access_policy_create(job_db): ) # An admin cannot create any resource - with pytest.raises(HTTPException, match=f"{status.HTTP_403_FORBIDDEN}"): + with pytest.raises(HTTPException, match=f"{HTTPStatus.FORBIDDEN}"): await WMSAccessPolicy.policy( WMS_POLICY_NAME, admin_user, action=ActionType.CREATE, job_db=job_db ) @@ -183,7 +185,7 @@ async def summary_other_owner(*args): return [{"Owner": "other_owner", "VO": "lhcb", "count": 3}] monkeypatch.setattr(job_db, "summary", summary_other_owner) - with pytest.raises(HTTPException, match=f"{status.HTTP_403_FORBIDDEN}"): + with pytest.raises(HTTPException, match=f"{HTTPStatus.FORBIDDEN}"): await WMSAccessPolicy.policy( WMS_POLICY_NAME, normal_user, @@ -197,7 +199,7 @@ async def summary_other_vo(*args): return [{"Owner": "preferred_username", "VO": "gridpp", "count": 3}] monkeypatch.setattr(job_db, "summary", summary_other_vo) - with pytest.raises(HTTPException, match=f"{status.HTTP_403_FORBIDDEN}"): + with pytest.raises(HTTPException, match=f"{HTTPStatus.FORBIDDEN}"): await WMSAccessPolicy.policy( WMS_POLICY_NAME, normal_user, @@ -211,7 +213,7 @@ async def summary_other_vo(*args): return [{"Owner": "preferred_username", "VO": "lhcb", "count": 2}] monkeypatch.setattr(job_db, "summary", summary_other_vo) - with pytest.raises(HTTPException, match=f"{status.HTTP_403_FORBIDDEN}"): + with pytest.raises(HTTPException, match=f"{HTTPStatus.FORBIDDEN}"): await WMSAccessPolicy.policy( WMS_POLICY_NAME, normal_user, @@ -242,7 +244,7 @@ async def test_sandbox_access_policy_create(sandbox_metadata_db): ) # An admin cannot create any resource - with pytest.raises(HTTPException, match=f"{status.HTTP_403_FORBIDDEN}"): + with pytest.raises(HTTPException, match=f"{HTTPStatus.FORBIDDEN}"): await SandboxAccessPolicy.policy( SANDBOX_POLICY_NAME, admin_user, diff --git a/diracx-routers/tests/test_config_manager.py b/diracx-routers/tests/test_config_manager.py index 6175b22cd..2b17ae9f0 100644 --- a/diracx-routers/tests/test_config_manager.py +++ b/diracx-routers/tests/test_config_manager.py @@ -1,7 +1,8 @@ from __future__ import annotations +from http import HTTPStatus + import pytest -from fastapi import status pytestmark = pytest.mark.enabled_dependencies( ["AuthSettings", "ConfigSource", "OpenAccessPolicy"] @@ -17,12 +18,12 @@ def normal_user_client(client_factory): def test_unauthenticated(client_factory): with client_factory.unauthenticated() as client: response = client.get("/api/config/") - assert response.status_code == status.HTTP_401_UNAUTHORIZED + assert response.status_code == HTTPStatus.UNAUTHORIZED def test_get_config(normal_user_client): r = normal_user_client.get("/api/config/") - assert r.status_code == status.HTTP_200_OK, r.json() + assert r.status_code == HTTPStatus.OK, r.json() assert r.json(), r.text last_modified = r.headers["Last-Modified"] @@ -36,7 +37,7 @@ def test_get_config(normal_user_client): }, ) - assert r.status_code == status.HTTP_304_NOT_MODIFIED, r.text + assert r.status_code == HTTPStatus.NOT_MODIFIED, r.text assert not r.text # If only an invalid ETAG is passed, we expect a response @@ -46,7 +47,7 @@ def test_get_config(normal_user_client): "If-None-Match": "wrongEtag", }, ) - assert r.status_code == status.HTTP_200_OK, r.json() + assert r.status_code == HTTPStatus.OK, r.json() assert r.json(), r.text # If an past ETAG and an past timestamp as give, we expect an response @@ -57,7 +58,7 @@ def test_get_config(normal_user_client): "If-Modified-Since": "Mon, 1 Apr 2000 00:42:42 GMT", }, ) - assert r.status_code == status.HTTP_200_OK, r.json() + assert r.status_code == HTTPStatus.OK, r.json() assert r.json(), r.text # If an future ETAG and an new timestamp as give, we expect 304 @@ -68,7 +69,7 @@ def test_get_config(normal_user_client): "If-Modified-Since": "Mon, 1 Apr 9999 00:42:42 GMT", }, ) - assert r.status_code == status.HTTP_304_NOT_MODIFIED, r.text + assert r.status_code == HTTPStatus.NOT_MODIFIED, r.text assert not r.text # If an invalid ETAG and an invalid modified time, we expect a response @@ -79,7 +80,7 @@ def test_get_config(normal_user_client): "If-Modified-Since": "wrong format", }, ) - assert r.status_code == status.HTTP_200_OK, r.json() + assert r.status_code == HTTPStatus.OK, r.json() assert r.json(), r.text # If the correct ETAG and a past timestamp as give, we expect 304 @@ -90,7 +91,7 @@ def test_get_config(normal_user_client): "If-Modified-Since": "Mon, 1 Apr 2000 00:42:42 GMT", }, ) - assert r.status_code == status.HTTP_304_NOT_MODIFIED, r.text + assert r.status_code == HTTPStatus.NOT_MODIFIED, r.text assert not r.text # If the correct ETAG and a new timestamp as give, we expect 304 @@ -101,7 +102,7 @@ def test_get_config(normal_user_client): "If-Modified-Since": "Mon, 1 Apr 9999 00:42:42 GMT", }, ) - assert r.status_code == status.HTTP_304_NOT_MODIFIED, r.text + assert r.status_code == HTTPStatus.NOT_MODIFIED, r.text assert not r.text # If the correct ETAG and an invalid modified time, we expect 304 @@ -112,5 +113,5 @@ def test_get_config(normal_user_client): "If-Modified-Since": "wrong format", }, ) - assert r.status_code == status.HTTP_304_NOT_MODIFIED, r.text + assert r.status_code == HTTPStatus.NOT_MODIFIED, r.text assert not r.text diff --git a/extensions/gubbins/gubbins-routers/src/gubbins/routers/lollygag/access_policy.py b/extensions/gubbins/gubbins-routers/src/gubbins/routers/lollygag/access_policy.py index 36b6551f5..85813c5a7 100644 --- a/extensions/gubbins/gubbins-routers/src/gubbins/routers/lollygag/access_policy.py +++ b/extensions/gubbins/gubbins-routers/src/gubbins/routers/lollygag/access_policy.py @@ -8,11 +8,12 @@ from collections.abc import Callable from enum import StrEnum, auto +from http import HTTPStatus from typing import Annotated from diracx.routers.access_policies import BaseAccessPolicy from diracx.routers.utils import AuthorizedUserInfo -from fastapi import Depends, HTTPException, status +from fastapi import Depends, HTTPException from gubbins.core.properties import GUBBINS_SENSEI @@ -37,7 +38,7 @@ async def policy( assert action, "action is a mandatory parameter" if action == ActionType.MANAGE and GUBBINS_SENSEI not in user_info.properties: - raise HTTPException(status.HTTP_403_FORBIDDEN, detail="Streng verboten !!") + raise HTTPException(HTTPStatus.FORBIDDEN, detail="Streng verboten !!") CheckLollygagPolicyCallable = Annotated[Callable, Depends(LollygagAccessPolicy.check)] diff --git a/extensions/gubbins/gubbins-routers/tests/test_wellknown.py b/extensions/gubbins/gubbins-routers/tests/test_wellknown.py index 850a86147..40c642437 100644 --- a/extensions/gubbins/gubbins-routers/tests/test_wellknown.py +++ b/extensions/gubbins/gubbins-routers/tests/test_wellknown.py @@ -2,8 +2,9 @@ Test the extended well_known endpoint """ +from http import HTTPStatus + import pytest -from fastapi import status pytestmark = pytest.mark.enabled_dependencies( ["AuthSettings", "ConfigSource", "BaseAccessPolicy", "DevelopmentSettings"] @@ -23,7 +24,7 @@ async def test_dirac_metadata_is_overwriten(test_client): r = test_client.get( "/.well-known/dirac-metadata", ) - assert r.status_code == 200, r.json() + assert r.status_code == HTTPStatus.OK, r.json() assert "gubbins_secrets" in r.json(), r.json() @@ -33,5 +34,5 @@ async def test_openid_configuration_is_not_changed(test_client): r = test_client.get( "/.well-known/openid-configuration", ) - assert r.status_code == status.HTTP_200_OK, r.json() + assert r.status_code == HTTPStatus.OK, r.json() assert "authorization_endpoint" in r.json(), r.json() diff --git a/extensions/gubbins/pyproject.toml b/extensions/gubbins/pyproject.toml index 287902ca4..51434fe19 100644 --- a/extensions/gubbins/pyproject.toml +++ b/extensions/gubbins/pyproject.toml @@ -58,6 +58,7 @@ select = [ "DTZ", # flake8-datetimez "S", # flake8-bandit "N", # pep8-naming + "TID251", # flake8-tidy-imports.banned-api ] ignore = [ @@ -68,7 +69,8 @@ ignore = [ "S311", # bandit: pseudo-random generators — gubbins uses them for simulation, not crypto ] - +[tool.ruff.lint.flake8-tidy-imports.banned-api] +"fastapi.status".msg = "Use http.HTTPStatus instead" [tool.ruff.lint.flake8-bugbear] # Allow default arguments like, e.g., `data: List[str] = fastapi.Query(None)`. diff --git a/pyproject.toml b/pyproject.toml index a65d34e07..c07896344 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -47,6 +47,7 @@ select = [ "N", # pep8-naming "INP", # flake8-no-implicit-namespace-packages "RUF022", + "TID251", # flake8-tidy-imports.banned-api ] ignore = [ "B905", @@ -86,6 +87,9 @@ extend-immutable-calls = [ "fastapi.Header", ] +[tool.ruff.lint.flake8-tidy-imports.banned-api] +"fastapi.status".msg = "Use http.HTTPStatus instead" + [tool.ruff.lint.pycodestyle] max-line-length = 120