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

Make code changes to address all test warnings #950

Merged
merged 15 commits into from
Aug 7, 2024
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
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
40 changes: 24 additions & 16 deletions ctms/app.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import sys
import time
from contextlib import asynccontextmanager

import sentry_sdk
import structlog
import uvicorn
from dockerflow.fastapi import router as dockerflow_router
from dockerflow.fastapi.middleware import RequestIdMiddleware
from fastapi import FastAPI, Request
from sentry_sdk.integrations.asgi import SentryAsgiMiddleware
from sentry_sdk.integrations.logging import ignore_logger

from .config import get_version
from .config import Settings, get_version
from .database import SessionLocal
from .exception_capture import init_sentry
from .log import context_from_request, get_log_line
from .metrics import (
METRICS_REGISTRY,
Expand All @@ -22,28 +22,36 @@
)
from .routers import contacts, platform

settings = Settings()

sentry_sdk.init(
dsn=settings.sentry_dsn,
release=get_version()["version"],
debug=settings.sentry_debug,
send_default_pii=False,
)
ignore_logger("uvicorn.error")
ignore_logger("ctms.web")


@asynccontextmanager
async def lifespan(app: FastAPI):
set_metrics(init_metrics(METRICS_REGISTRY))
init_metrics_labels(SessionLocal(), app, get_metrics())
yield


app = FastAPI(
title="ConTact Management System (CTMS)",
description="CTMS API (work in progress)",
version=get_version()["version"],
lifespan=lifespan,
)
app.include_router(dockerflow_router)
app.include_router(platform.router)
app.include_router(contacts.router)


# Initialize Sentry for each thread, unless we're in tests
if "pytest" not in sys.argv[0]: # pragma: no cover
init_sentry()
app.add_middleware(SentryAsgiMiddleware)


@app.on_event("startup")
def startup_event(): # pragma: no cover
set_metrics(init_metrics(METRICS_REGISTRY))
init_metrics_labels(SessionLocal(), app, get_metrics())


@app.middleware("http")
async def log_request_middleware(request: Request, call_next):
"""Add timing and per-request logging context."""
Expand Down
25 changes: 10 additions & 15 deletions ctms/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,31 +11,26 @@
from datetime import datetime, timedelta, timezone
from typing import Dict, Optional

import argon2
import jwt
from fastapi.exceptions import HTTPException
from fastapi.param_functions import Form
from fastapi.security.oauth2 import OAuth2, OAuthFlowsModel
from fastapi.security.utils import get_authorization_scheme_param
from passlib.context import CryptContext
from starlette.requests import Request
from starlette.status import HTTP_401_UNAUTHORIZED

with warnings.catch_warnings():
# TODO: remove when fixed: https://github.com/mpdavis/python-jose/issues/208
warnings.filterwarnings("ignore", message="int_from_bytes is deprecated")
from jose import JWTError, jwt
pwd_context = argon2.PasswordHasher()

# Argon2 is the winner of the 2015 password hashing competion.
# It is supported by passlib with the recommended argon2_cffi library.
pwd_context = CryptContext(schemes=["argon2"], deprecated=["auto"])


def verify_password(plain_password, hashed_password):
"""Verify the password, using a constant time equality check."""
return pwd_context.verify(plain_password, hashed_password)
def verify_password(plain_password, hashed_password) -> bool:
try:
return pwd_context.verify(hashed_password, plain_password)
except argon2.exceptions.VerifyMismatchError:
return False


def hash_password(plain_password):
"""Hash the password, using the pre-configured CryptContext."""
return pwd_context.hash(plain_password)


Expand All @@ -61,7 +56,7 @@ def get_subject_from_token(token: str, secret_key: str):
"""
try:
payload = jwt.decode(token, secret_key, algorithms=["HS256"])
except JWTError:
except jwt.InvalidTokenError:
return None, None
sub = payload["sub"]
if ":" not in sub:
Expand Down Expand Up @@ -96,7 +91,7 @@ def login(form_data: OAuth2ClientCredentialsRequestForm = Depends()):

def __init__(
self,
grant_type: str = Form(None, regex="^(client_credentials|refresh_token)$"),
grant_type: str = Form(None, pattern="^(client_credentials|refresh_token)$"),
scope: str = Form(""),
client_id: Optional[str] = Form(None),
client_secret: Optional[str] = Form(None),
Expand Down
3 changes: 3 additions & 0 deletions ctms/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
from pydantic import AfterValidator, Field, PostgresDsn
from pydantic_settings import BaseSettings, SettingsConfigDict

from ctms.schemas.common import AnyUrlString

PostgresDsnStr = Annotated[PostgresDsn, AfterValidator(str)]


Expand Down Expand Up @@ -48,6 +50,7 @@ class Settings(BaseSettings):
sentry_debug: bool = False

fastapi_env: Optional[str] = Field(default=None, alias="FASTAPI_ENV")
sentry_dsn: Optional[AnyUrlString] = Field(default=None, alias="SENTRY_DSN")
host: str = Field(default="0.0.0.0", alias="HOST")
port: int = Field(default=8000, alias="PORT")

Expand Down
34 changes: 0 additions & 34 deletions ctms/exception_capture.py

This file was deleted.

Loading