Source code for app.settings

# https://fastapi.tiangolo.com/advanced/settings/#pydantic-settings

import logging.config
import re
from typing import TYPE_CHECKING, Any

import sentry_sdk
from pydantic_settings import BaseSettings, SettingsConfigDict
from sentry_sdk.integrations.fastapi import FastApiIntegration
from sentry_sdk.integrations.starlette import StarletteIntegration

if TYPE_CHECKING:
    from sentry_sdk._types import Event, Hint
else:
    Event = dict[str, Any]
    Hint = dict[str, Any]


def sentry_filter_transactions(event: Event, hint: Hint) -> Event | None:
    """
    Filter transactions to be sent to Sentry.

    This function prevents transactions that interact with Cognito from being sent to Sentry.

    :param event: The event data.
    :param hint: A dictionary of extra data passed to the function.
    :return: The event data if it should be sent to Sentry, otherwise None.
    """
    # The "values" type is under-specified, so we need to use type: ignore.
    # https://github.com/getsentry/sentry-python/blob/65d31af4ff9b93cddf12d043fe9d631e3c6c85a4/sentry_sdk/_types.py#L166-L168
    data_url = event["breadcrumbs"]["values"][0]["data"]["url"] or None  # type: ignore[index]
    if data_url and re.search(r"https://cognito-idp.*\.amazonaws\.com", data_url):
        return None
    return event


[docs] class Settings(BaseSettings): """ Each setting has a corresponding uppercase environment variable. .. seealso:: `Settings Management <https://docs.pydantic.dev/latest/concepts/pydantic_settings/#usage>`__ """ #: If "production", emails all recipients. Otherwise, emails lenders and #: :attr:`~app.settings.Settings.ocp_email_group` only, replacing borrower email addresses with #: :attr:`~app.settings.Settings.test_mail_receiver`. environment: str = "development" #: The `logging level <https://docs.python.org/3/library/logging.html#levels>`__ of the root logger. log_level: int | str = logging.INFO #: PostgreSQL connection string. database_url: str = "postgresql:///credere_backend?application_name=credere_backend" #: PostgreSQL connection string that overrides ``DATABASE_URL`` (:ref:`tests<dev-tests>` drops the database). test_database_url: str = "" # Security #: The secret key with which to hash borrower identifiers (to allow for deduplication even after the borrower's #: information has been removed). #: #: .. seealso:: :func:`app.util.get_secret_hash` hash_key: str = "" #: The maximum file size of uploaded documents or uploaded contracts (sync with ``VITE_MAX_FILE_SIZE_MB`` in #: Credere frontend). #: #: .. seealso:: :func:`app.util.validate_file` max_file_size_mb: int = 20 # Timeline #: The number of days after the application is created, after which a PENDING or DECLINED application becomes #: inaccessible to the borrower. #: #: .. seealso:: #: #: - :attr:`~app.settings.Settings.reminder_days_before_expiration` #: - :typer:`python-m-app-fetch-awards` application_expiration_days: int = 7 #: The number of days before a PENDING application's expiration date, past which the borrower is sent a reminder. #: #: .. seealso:: #: #: - :attr:`~app.settings.Settings.application_expiration_days` #: - :meth:`app.models.Application.pending_introduction_reminder` reminder_days_before_expiration: int = 3 #: The number of days before an ACCEPTED application's lapsed date, past which the borrower is sent a reminder. #: #: .. seealso:: #: #: - :attr:`~app.settings.Settings.days_to_change_to_lapsed` #: - :meth:`app.models.Application.pending_submission_reminder` reminder_days_before_lapsed: int = 3 #: The number of days before a SUBMITTED application's lapsed date, past which the borrower is sent a reminder, # if the lender uses external onboarding. #: #: .. seealso:: #: #: - :attr:`~app.settings.Settings.days_to_change_to_lapsed` #: - :meth:`app.models.Application.pending_external_onboarding_reminder` reminder_days_before_lapsed_for_external_onboarding: int = 13 #: Lenders agree to respond to application changes (STARTED, CONTRACT_UPLOADED) within a number of days, known as #: Service Level Agreement (SLA) days (:attr:`app.models.Lender.sla_days`). #: #: This is the ratio of SLA days for which to wait for the lender to respond, after which an application is #: overdue, and the lender is sent a reminder. #: #: For example, if set to 0.7, a lender with 10 SLA days receives the first reminder after an application has been #: waiting for the lender to respond for 7 days. #: #: .. seealso:: #: #: - :typer:`python-m-app-sla-overdue-applications` #: - :meth:`app.models.Application.days_waiting_for_lender` progress_to_remind_started_applications: float = 0.7 #: The number of days for which to wait for the borrower to respond, after which an application becomes LAPSED. #: #: .. seealso:: :meth:`app.models.Application.lapseable` days_to_change_to_lapsed: int = 14 #: The number of days after the application reaches a final state, after which the application is archived. #: #: .. seealso:: :meth:`app.models.Application.archivable` days_to_erase_borrowers_data: int = 7 # Data sources #: The application token to the `SECOP API <https://datos.gov.co/profile/edit/developer_settings>`__. colombia_secop_app_token: str = "" #: The number of items to retrieve at once in :typer:`python-m-app-fetch-awards`. secop_pagination_limit: int = 5 #: The number of days of past items to retrieve the first time :typer:`python-m-app-fetch-awards` runs. secop_default_days_from_ultima_actualizacion: int = 365 # Email addresses #: The verified email address in :doc:`Amazon SES</aws/ses>` to use as the FROM email address. email_sender_address: str = "credere@noreply.open-contracting.org" #: The email address of Credere administrators, to notify about new and overdue applications. #: #: .. seealso:: :attr:`~app.settings.Settings.progress_to_remind_started_applications` ocp_email_group: str = "credere@noreply.open-contracting.org" # should not be a noreply in production #: The email address with which to replace borrower email addresses in a non-production #: :attr:`~app.settings.Settings.environment` (for example, your own email address). test_mail_receiver: str = "credere@noreply.open-contracting.org" # Email templates #: The base URL of Credere. frontend_url: str = "http://localhost:3000" # also for CORS backend_url: str = "http://localhost:8000" #: The language of the email templates to use. email_template_lang: str = "es" #: The base URL of Credere's images directory (can be a CDN URL). images_base_url: str = "https://credere.open-contracting.org/images" # Third-party services #: Amazon Web Services region. aws_region: str = "us-west-2" #: :doc:`Operational user</aws/iam>` access key. aws_access_key: str = "" #: :doc:`Operational user</aws/iam>` client secret. aws_client_secret: str = "" #: :doc:`Cognito</aws/cognito>` user pool ID. cognito_pool_id: str = "" #: :doc:`Cognito</aws/cognito>` app client ID. cognito_client_id: str = "" #: :doc:`Cognito</aws/cognito>` app client secret. cognito_client_secret: str = "" #: Sentry DSN. sentry_dsn: str = "" model_config = SettingsConfigDict(env_file=".env")
app_settings = Settings() logging.config.dictConfig( { "version": 1, "disable_existing_loggers": False, "formatters": { "console": { "format": "%(asctime)s %(levelname)s [%(name)s:%(lineno)s] %(message)s", }, }, "handlers": { "console": { "class": "logging.StreamHandler", "formatter": "console", }, }, "loggers": { "": { "handlers": ["console"], "level": app_settings.log_level, }, }, } ) if app_settings.sentry_dsn: # https://docs.sentry.io/platforms/python/integrations/fastapi/ sentry_sdk.init( dsn=app_settings.sentry_dsn, before_send=sentry_filter_transactions, traces_sample_rate=1.0, # FastAPI uses 400 for request validation errors, which shouldn't occur unless the frontend is misimplemented. integrations=[ StarletteIntegration( failed_request_status_codes=[400, 413, range(500, 599)], ), FastApiIntegration( failed_request_status_codes=[400, 413, range(500, 599)], ), ], )