diff options
| author | 2020-12-27 19:58:14 +0000 | |
|---|---|---|
| committer | 2020-12-27 19:58:14 +0000 | |
| commit | 41ee41ebdc2f2a52015f53fabd47ef017d7461ee (patch) | |
| tree | 6d332d3220613dcae0d2c86093cefee39f360007 | |
| parent | Merge pull request #46 from python-discord/ks123/responses-bulk-delete (diff) | |
| parent | Create workflow for creating Sentry releases (diff) | |
Merge pull request #47 from python-discord/ks123/sentry
| -rw-r--r-- | .github/workflows/forms-backend.yml | 2 | ||||
| -rw-r--r-- | .github/workflows/sentry-release.yml | 24 | ||||
| -rw-r--r-- | Dockerfile | 6 | ||||
| -rw-r--r-- | backend/__init__.py | 12 | ||||
| -rw-r--r-- | backend/constants.py | 3 | ||||
| -rw-r--r-- | backend/routes/index.py | 7 | ||||
| -rw-r--r-- | deployment.yaml | 2 | ||||
| -rw-r--r-- | poetry.lock | 286 | ||||
| -rw-r--r-- | pyproject.toml | 1 | 
9 files changed, 238 insertions, 105 deletions
| diff --git a/.github/workflows/forms-backend.yml b/.github/workflows/forms-backend.yml index 1d7502b..80c53d6 100644 --- a/.github/workflows/forms-backend.yml +++ b/.github/workflows/forms-backend.yml @@ -105,6 +105,8 @@ jobs:            tags: |              ghcr.io/python-discord/forms-backend:latest              ghcr.io/python-discord/forms-backend:${{ steps.sha_tag.outputs.tag }} +          build-args: | +            git_sha=${{ github.sha }}    deploy:      name: Deployment diff --git a/.github/workflows/sentry-release.yml b/.github/workflows/sentry-release.yml new file mode 100644 index 0000000..243f170 --- /dev/null +++ b/.github/workflows/sentry-release.yml @@ -0,0 +1,24 @@ +name: Create Sentry release + +on: +  push: +    branches: +      - main + +jobs: +  create_sentry_release: +    runs-on: ubuntu-latest +    steps: +      - name: Checkout code +        uses: actions/checkout@master + +      - name: Create a Sentry.io release +        uses: tclindner/[email protected] +        env: +          SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} +          SENTRY_ORG: python-discord +          SENTRY_PROJECT: forms-backend +        with: +          tagName: ${{ github.sha }} +          environment: production +          releaseNamePrefix: forms-backend@ @@ -3,6 +3,12 @@ FROM python:3.9-slim  # Allow service to handle stops gracefully  STOPSIGNAL SIGQUIT +# Set Git SHA build argument +ARG git_sha="development" + +# Set Git SHA environment variable +ENV GIT_SHA=$git_sha +  # Install C compiler and make  RUN apt-get update && \      apt-get install -y gcc make && \ diff --git a/backend/__init__.py b/backend/__init__.py index 5c6328b..a3704a0 100644 --- a/backend/__init__.py +++ b/backend/__init__.py @@ -1,13 +1,22 @@ +import sentry_sdk +from sentry_sdk.integrations.asgi import SentryAsgiMiddleware  from starlette.applications import Starlette  from starlette.middleware import Middleware  from starlette.middleware.authentication import AuthenticationMiddleware  from starlette.middleware.cors import CORSMiddleware +from backend import constants  from backend.authentication import JWTAuthenticationBackend  from backend.route_manager import create_route_map  from backend.middleware import DatabaseMiddleware, ProtectedDocsMiddleware  from backend.validation import api +sentry_sdk.init( +    dsn=constants.FORMS_BACKEND_DSN, +    send_default_pii=True, +    release=f"forms-backend@{constants.GIT_SHA}" +) +  middleware = [      Middleware(          CORSMiddleware, @@ -21,7 +30,8 @@ middleware = [      ),      Middleware(DatabaseMiddleware),      Middleware(AuthenticationMiddleware, backend=JWTAuthenticationBackend()), -    Middleware(ProtectedDocsMiddleware) +    Middleware(SentryAsgiMiddleware), +    Middleware(ProtectedDocsMiddleware),  ]  app = Starlette(routes=create_route_map(), middleware=middleware) diff --git a/backend/constants.py b/backend/constants.py index bf0c33c..fedab64 100644 --- a/backend/constants.py +++ b/backend/constants.py @@ -17,6 +17,9 @@ OAUTH2_REDIRECT_URI = os.getenv(      "https://forms.pythondiscord.com/callback"  ) +GIT_SHA = os.getenv("GIT_SHA", "dev") +FORMS_BACKEND_DSN = os.getenv("FORMS_BACKEND_DSN") +  DOCS_PASSWORD = os.getenv("DOCS_PASSWORD")  SECRET_KEY = os.getenv("SECRET_KEY", binascii.hexlify(os.urandom(30)).decode()) diff --git a/backend/routes/index.py b/backend/routes/index.py index dd40d01..2551c58 100644 --- a/backend/routes/index.py +++ b/backend/routes/index.py @@ -7,6 +7,7 @@ from spectree import Response  from starlette.requests import Request  from starlette.responses import JSONResponse +from backend.constants import GIT_SHA  from backend.route import Route  from backend.validation import api @@ -19,6 +20,9 @@ class IndexResponse(BaseModel):              " be an IP of our internal load balancer"          )      ) +    sha: str = Field( +        description="Current release Git SHA in production." +    )  class IndexRoute(Route): @@ -41,7 +45,8 @@ class IndexRoute(Route):              "client": request.client.host,              "user": {                  "authenticated": False -            } +            }, +            "sha": GIT_SHA          }          if request.user.is_authenticated: diff --git a/deployment.yaml b/deployment.yaml index 56134a2..20b663a 100644 --- a/deployment.yaml +++ b/deployment.yaml @@ -21,3 +21,5 @@ spec:            envFrom:              - secretRef:                  name: forms-backend-env +            - sentryEnv: +                name: sentry-env diff --git a/poetry.lock b/poetry.lock index cf19c08..1fbfc18 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,42 +1,43 @@  [[package]] -name = "certifi" -version = "2020.12.5" -description = "Python package for providing Mozilla's CA Bundle."  category = "main" +description = "Python package for providing Mozilla's CA Bundle." +name = "certifi"  optional = false  python-versions = "*" +version = "2020.12.5"  [[package]] -name = "click" -version = "7.1.2" -description = "Composable command line interface toolkit"  category = "main" +description = "Composable command line interface toolkit" +name = "click"  optional = false  python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +version = "7.1.2"  [[package]] -name = "colorama" -version = "0.4.4" -description = "Cross-platform colored terminal text."  category = "main" +description = "Cross-platform colored terminal text." +marker = "sys_platform == \"win32\"" +name = "colorama"  optional = false  python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +version = "0.4.4"  [[package]] -name = "deepmerge" -version = "0.1.1" -description = "a toolset to deeply merge python dictionaries."  category = "main" +description = "a toolset to deeply merge python dictionaries." +name = "deepmerge"  optional = false  python-versions = "*" +version = "0.1.1"  [[package]] -name = "flake8" -version = "3.8.4" -description = "the modular source code checker: pep8 pyflakes and co"  category = "dev" +description = "the modular source code checker: pep8 pyflakes and co" +name = "flake8"  optional = false  python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7" +version = "3.8.4"  [package.dependencies]  mccabe = ">=0.6.0,<0.7.0" @@ -44,23 +45,26 @@ pycodestyle = ">=2.6.0a1,<2.7.0"  pyflakes = ">=2.2.0,<2.3.0"  [[package]] -name = "flake8-annotations" -version = "2.4.1" -description = "Flake8 Type Annotation Checks"  category = "dev" +description = "Flake8 Type Annotation Checks" +name = "flake8-annotations"  optional = false  python-versions = ">=3.6.1,<4.0.0" +version = "2.4.1"  [package.dependencies]  flake8 = ">=3.7,<3.9"  [[package]] -name = "gunicorn" -version = "20.0.4" -description = "WSGI HTTP Server for UNIX"  category = "main" +description = "WSGI HTTP Server for UNIX" +name = "gunicorn"  optional = false  python-versions = ">=3.4" +version = "20.0.4" + +[package.dependencies] +setuptools = ">=3.0"  [package.extras]  eventlet = ["eventlet (>=0.9.7)"] @@ -69,20 +73,20 @@ setproctitle = ["setproctitle"]  tornado = ["tornado (>=0.2)"]  [[package]] -name = "h11" -version = "0.11.0" -description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1"  category = "main" +description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" +name = "h11"  optional = false  python-versions = "*" +version = "0.11.0"  [[package]] -name = "httpcore" -version = "0.12.2" -description = "A minimal low-level HTTP client."  category = "main" +description = "A minimal low-level HTTP client." +name = "httpcore"  optional = false  python-versions = ">=3.6" +version = "0.12.2"  [package.dependencies]  h11 = "<1.0.0" @@ -92,84 +96,88 @@ sniffio = ">=1.0.0,<2.0.0"  http2 = ["h2 (>=3,<5)"]  [[package]] -name = "httptools" -version = "0.1.1" -description = "A collection of framework independent HTTP protocol utils."  category = "main" +description = "A collection of framework independent HTTP protocol utils." +marker = "sys_platform != \"win32\" and sys_platform != \"cygwin\" and platform_python_implementation != \"PyPy\"" +name = "httptools"  optional = false  python-versions = "*" +version = "0.1.1"  [package.extras] -test = ["Cython (==0.29.14)"] +test = ["Cython (0.29.14)"]  [[package]] -name = "httpx" -version = "0.16.1" -description = "The next generation HTTP client."  category = "main" +description = "The next generation HTTP client." +name = "httpx"  optional = false  python-versions = ">=3.6" +version = "0.16.1"  [package.dependencies]  certifi = "*"  httpcore = ">=0.12.0,<0.13.0" -rfc3986 = {version = ">=1.3,<2", extras = ["idna2008"]}  sniffio = "*" +[package.dependencies.rfc3986] +extras = ["idna2008"] +version = ">=1.3,<2" +  [package.extras]  brotli = ["brotlipy (>=0.7.0,<0.8.0)"]  http2 = ["h2 (>=3.0.0,<4.0.0)"]  [[package]] -name = "idna" -version = "2.10" -description = "Internationalized Domain Names in Applications (IDNA)"  category = "main" +description = "Internationalized Domain Names in Applications (IDNA)" +name = "idna"  optional = false  python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "2.10"  [[package]] -name = "mccabe" -version = "0.6.1" -description = "McCabe checker, plugin for flake8"  category = "dev" +description = "McCabe checker, plugin for flake8" +name = "mccabe"  optional = false  python-versions = "*" +version = "0.6.1"  [[package]] -name = "motor" -version = "2.3.0" -description = "Non-blocking MongoDB driver for Tornado or asyncio"  category = "main" +description = "Non-blocking MongoDB driver for Tornado or asyncio" +name = "motor"  optional = false  python-versions = ">=3.5.2" +version = "2.3.0"  [package.dependencies]  pymongo = ">=3.11,<4"  [[package]] -name = "nested-dict" -version = "1.61" -description = "Python dictionary with automatic and arbitrary levels of nestedness"  category = "main" +description = "Python dictionary with automatic and arbitrary levels of nestedness" +name = "nested-dict"  optional = false  python-versions = "*" +version = "1.61"  [[package]] -name = "pycodestyle" -version = "2.6.0" -description = "Python style guide checker"  category = "dev" +description = "Python style guide checker" +name = "pycodestyle"  optional = false  python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "2.6.0"  [[package]] -name = "pydantic" -version = "1.7.3" -description = "Data validation and settings management using python 3.6 type hinting"  category = "main" +description = "Data validation and settings management using python 3.6 type hinting" +name = "pydantic"  optional = false  python-versions = ">=3.6" +version = "1.7.3"  [package.extras]  dotenv = ["python-dotenv (>=0.10.4)"] @@ -177,34 +185,34 @@ email = ["email-validator (>=1.0.3)"]  typing_extensions = ["typing-extensions (>=3.7.2)"]  [[package]] -name = "pyflakes" -version = "2.2.0" -description = "passive checker of Python programs"  category = "dev" +description = "passive checker of Python programs" +name = "pyflakes"  optional = false  python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "2.2.0"  [[package]] -name = "pyjwt" -version = "2.0.0" -description = "JSON Web Token implementation in Python"  category = "main" +description = "JSON Web Token implementation in Python" +name = "pyjwt"  optional = false  python-versions = ">=3.6" +version = "2.0.0"  [package.extras]  crypto = ["cryptography (>=3.3.1,<4.0.0)"] -dev = ["sphinx", "sphinx-rtd-theme", "zope.interface", "cryptography (>=3.3.1,<4.0.0)", "pytest (>=6.0.0,<7.0.0)", "coverage[toml] (==5.0.4)", "mypy", "pre-commit"] +dev = ["sphinx", "sphinx-rtd-theme", "zope.interface", "cryptography (>=3.3.1,<4.0.0)", "pytest (>=6.0.0,<7.0.0)", "coverage (5.0.4)", "mypy", "pre-commit"]  docs = ["sphinx", "sphinx-rtd-theme", "zope.interface"] -tests = ["pytest (>=6.0.0,<7.0.0)", "coverage[toml] (==5.0.4)"] +tests = ["pytest (>=6.0.0,<7.0.0)", "coverage (5.0.4)"]  [[package]] -name = "pymongo" -version = "3.11.2" -description = "Python driver for MongoDB <http://www.mongodb.org>"  category = "main" +description = "Python driver for MongoDB <http://www.mongodb.org>" +name = "pymongo"  optional = false  python-versions = "*" +version = "3.11.2"  [package.extras]  aws = ["pymongo-auth-aws (<2.0.0)"] @@ -217,53 +225,83 @@ tls = ["ipaddress"]  zstd = ["zstandard"]  [[package]] -name = "python-dotenv" -version = "0.15.0" -description = "Add .env support to your django/flask apps in development and deployments"  category = "main" +description = "Add .env support to your django/flask apps in development and deployments" +name = "python-dotenv"  optional = false  python-versions = "*" +version = "0.15.0"  [package.extras]  cli = ["click (>=5.0)"]  [[package]] -name = "pyyaml" -version = "5.3.1" -description = "YAML parser and emitter for Python"  category = "main" +description = "YAML parser and emitter for Python" +name = "pyyaml"  optional = false  python-versions = "*" +version = "5.3.1"  [[package]] +category = "main" +description = "Validating URI References per RFC 3986"  name = "rfc3986" +optional = false +python-versions = "*"  version = "1.4.0" -description = "Validating URI References per RFC 3986" + +[package.dependencies] +[package.dependencies.idna] +optional = true +version = "*" + +[package.extras] +idna2008 = ["idna"] + +[[package]]  category = "main" +description = "Python client for Sentry (https://sentry.io)" +name = "sentry-sdk"  optional = false  python-versions = "*" +version = "0.19.5"  [package.dependencies] -idna = {version = "*", optional = true, markers = "extra == \"idna2008\""} +certifi = "*" +urllib3 = ">=1.10.0"  [package.extras] -idna2008 = ["idna"] +aiohttp = ["aiohttp (>=3.5)"] +beam = ["apache-beam (>=2.12)"] +bottle = ["bottle (>=0.12.13)"] +celery = ["celery (>=3)"] +chalice = ["chalice (>=1.16.0)"] +django = ["django (>=1.8)"] +falcon = ["falcon (>=1.4)"] +flask = ["flask (>=0.11)", "blinker (>=1.1)"] +pure_eval = ["pure-eval", "executing", "asttokens"] +pyspark = ["pyspark (>=2.4.4)"] +rq = ["rq (>=0.6)"] +sanic = ["sanic (>=0.8)"] +sqlalchemy = ["sqlalchemy (>=1.2)"] +tornado = ["tornado (>=5)"]  [[package]] -name = "sniffio" -version = "1.2.0" -description = "Sniff out which async library your code is running under"  category = "main" +description = "Sniff out which async library your code is running under" +name = "sniffio"  optional = false  python-versions = ">=3.5" +version = "1.2.0"  [[package]] -name = "spectree" -version = "0.3.16" -description = "generate OpenAPI document and validate request&response with Python annotations."  category = "main" +description = "generate OpenAPI document and validate request&response with Python annotations." +name = "spectree"  optional = false  python-versions = ">=3.6" +version = "0.3.16"  [package.dependencies]  pydantic = ">=1.2" @@ -275,66 +313,100 @@ flask = ["flask"]  starlette = ["starlette"]  [[package]] -name = "starlette" -version = "0.14.1" -description = "The little ASGI library that shines."  category = "main" +description = "The little ASGI library that shines." +name = "starlette"  optional = false  python-versions = ">=3.6" +version = "0.14.1"  [package.extras]  full = ["aiofiles", "graphene", "itsdangerous", "jinja2", "python-multipart", "pyyaml", "requests"]  [[package]] -name = "uvicorn" -version = "0.13.2" -description = "The lightning-fast ASGI server."  category = "main" +description = "HTTP library with thread-safe connection pooling, file post, and more." +name = "urllib3" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" +version = "1.26.2" + +[package.extras] +brotli = ["brotlipy (>=0.6.0)"] +secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "ipaddress"] +socks = ["PySocks (>=1.5.6,<1.5.7 || >1.5.7,<2.0)"] + +[[package]] +category = "main" +description = "The lightning-fast ASGI server." +name = "uvicorn"  optional = false  python-versions = "*" +version = "0.13.2"  [package.dependencies]  click = ">=7.0.0,<8.0.0" -colorama = {version = ">=0.4", optional = true, markers = "sys_platform == \"win32\" and extra == \"standard\""}  h11 = ">=0.8" -httptools = {version = ">=0.1.0,<0.2.0", optional = true, markers = "sys_platform != \"win32\" and sys_platform != \"cygwin\" and platform_python_implementation != \"PyPy\" and extra == \"standard\""} -python-dotenv = {version = ">=0.13", optional = true, markers = "extra == \"standard\""} -PyYAML = {version = ">=5.1", optional = true, markers = "extra == \"standard\""} -uvloop = {version = ">=0.14.0", optional = true, markers = "sys_platform != \"win32\" and sys_platform != \"cygwin\" and platform_python_implementation != \"PyPy\" and extra == \"standard\""} -watchgod = {version = ">=0.6,<0.7", optional = true, markers = "extra == \"standard\""} -websockets = {version = ">=8.0.0,<9.0.0", optional = true, markers = "extra == \"standard\""} + +[package.dependencies.PyYAML] +optional = true +version = ">=5.1" + +[package.dependencies.colorama] +optional = true +version = ">=0.4" + +[package.dependencies.httptools] +optional = true +version = ">=0.1.0,<0.2.0" + +[package.dependencies.python-dotenv] +optional = true +version = ">=0.13" + +[package.dependencies.uvloop] +optional = true +version = ">=0.14.0" + +[package.dependencies.watchgod] +optional = true +version = ">=0.6,<0.7" + +[package.dependencies.websockets] +optional = true +version = ">=8.0.0,<9.0.0"  [package.extras]  standard = ["websockets (>=8.0.0,<9.0.0)", "watchgod (>=0.6,<0.7)", "python-dotenv (>=0.13)", "PyYAML (>=5.1)", "httptools (>=0.1.0,<0.2.0)", "uvloop (>=0.14.0)", "colorama (>=0.4)"]  [[package]] -name = "uvloop" -version = "0.14.0" -description = "Fast implementation of asyncio event loop on top of libuv"  category = "main" +description = "Fast implementation of asyncio event loop on top of libuv" +marker = "sys_platform != \"win32\" and sys_platform != \"cygwin\" and platform_python_implementation != \"PyPy\"" +name = "uvloop"  optional = false  python-versions = "*" +version = "0.14.0"  [[package]] -name = "watchgod" -version = "0.6" -description = "Simple, modern file watching and code reload in python."  category = "main" +description = "Simple, modern file watching and code reload in python." +name = "watchgod"  optional = false  python-versions = ">=3.5" +version = "0.6"  [[package]] -name = "websockets" -version = "8.1" -description = "An implementation of the WebSocket Protocol (RFC 6455 & 7692)"  category = "main" +description = "An implementation of the WebSocket Protocol (RFC 6455 & 7692)" +name = "websockets"  optional = false  python-versions = ">=3.6.1" +version = "8.1"  [metadata] -lock-version = "1.1" +content-hash = "359efdcf2f8aa3bbfa8978c8cc7a5dab940c2fa2e53f922888e604b674e53e65"  python-versions = "^3.9" -content-hash = "d863036c29d41783f127e3ebd0dce61349c5c071d5de438ab208863505d00c2d"  [metadata.files]  certifi = [ @@ -531,6 +603,10 @@ rfc3986 = [      {file = "rfc3986-1.4.0-py2.py3-none-any.whl", hash = "sha256:af9147e9aceda37c91a05f4deb128d4b4b49d6b199775fd2d2927768abdc8f50"},      {file = "rfc3986-1.4.0.tar.gz", hash = "sha256:112398da31a3344dc25dbf477d8df6cb34f9278a94fee2625d89e4514be8bb9d"},  ] +sentry-sdk = [ +    {file = "sentry-sdk-0.19.5.tar.gz", hash = "sha256:737a094e49a529dd0fdcaafa9e97cf7c3d5eb964bd229821d640bc77f3502b3f"}, +    {file = "sentry_sdk-0.19.5-py2.py3-none-any.whl", hash = "sha256:0a711ec952441c2ec89b8f5d226c33bc697914f46e876b44a4edd3e7864cf4d0"}, +]  sniffio = [      {file = "sniffio-1.2.0-py3-none-any.whl", hash = "sha256:471b71698eac1c2112a40ce2752bb2f4a4814c22a54a3eed3676bc0f5ca9f663"},      {file = "sniffio-1.2.0.tar.gz", hash = "sha256:c4666eecec1d3f50960c6bdf61ab7bc350648da6c126e3cf6898d8cd4ddcd3de"}, @@ -543,6 +619,10 @@ starlette = [      {file = "starlette-0.14.1-py3-none-any.whl", hash = "sha256:d2f55fb835378442b812637ed3e3fcef3d3e22d292fcb8400fa48d2473202411"},      {file = "starlette-0.14.1.tar.gz", hash = "sha256:5268ef5d4904ec69582d5fd207b869a5aa0cd59529848ba4cf429b06e3ced99a"},  ] +urllib3 = [ +    {file = "urllib3-1.26.2-py2.py3-none-any.whl", hash = "sha256:d8ff90d979214d7b4f8ce956e80f4028fc6860e4431f731ea4a8c08f23f99473"}, +    {file = "urllib3-1.26.2.tar.gz", hash = "sha256:19188f96923873c92ccb987120ec4acaa12f0461fa9ce5d3d0772bc965a39e08"}, +]  uvicorn = [      {file = "uvicorn-0.13.2-py3-none-any.whl", hash = "sha256:6707fa7f4dbd86fd6982a2d4ecdaad2704e4514d23a1e4278104311288b04691"},      {file = "uvicorn-0.13.2.tar.gz", hash = "sha256:d19ca083bebd212843e01f689900e5c637a292c63bb336c7f0735a99300a5f38"}, diff --git a/pyproject.toml b/pyproject.toml index 8dd723d..4ea563d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -18,6 +18,7 @@ gunicorn = "^20.0.4"  pydantic = "^1.7.2"  spectree = "^0.3.16"  deepmerge = "^0.1.1" +sentry-sdk = "^0.19.5"  [tool.poetry.dev-dependencies]  flake8 = "^3.8.4" | 
