Skip to content

Commit

Permalink
Merge pull request #71 from AndrewSergienko/2.x/logging
Browse files Browse the repository at this point in the history
2.x/logging
  • Loading branch information
andiserg authored May 3, 2024
2 parents 5ce8c4d + 08b4bea commit e3c9a70
Show file tree
Hide file tree
Showing 80 changed files with 660 additions and 563 deletions.
4 changes: 3 additions & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,16 @@ repos:
- id: check-merge-conflict
- id: check-toml
- id: check-yaml
exclude: "kubeconf"
- id: debug-statements
- id: detect-private-key
- id: end-of-file-fixer
- id: trailing-whitespace
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.3.2
rev: v0.4.2
hooks:
- id: ruff
pass_filenames: false
- repo: https://github.com/pycqa/isort
rev: 5.13.2
hooks:
Expand Down
2 changes: 1 addition & 1 deletion kubeconf/sercets.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,4 @@ stringData:
db_host: "postgres.default.svc.cluster.local"
db_port: ""
auth0_client_id: ""
auth0_client_secret: ""
auth0_client_secret: ""
16 changes: 16 additions & 0 deletions kubeconf/service.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,19 @@ spec:
targetPort: 80
selector:
app: costy-app
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: costy-ingress
spec:
rules:
- http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: costy-service
port:
number: 80
81 changes: 72 additions & 9 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ requires = ["setuptools"]
build-backend = "setuptools.build_meta"

[project]
name="costy"
version="0.0.1"
name = "costy"
version = "0.0.1"
dependencies = [
'sqlalchemy',
'litestar',
Expand All @@ -13,7 +13,8 @@ dependencies = [
'alembic',
'adaptix',
'aiohttp',
'python-jose'
'python-jose',
'prometheus-client'
]

[project.optional-dependencies]
Expand All @@ -35,11 +36,73 @@ dev = [
]

[tool.isort]
profile = "black"
line_length = 79
multi_line_output = 3
line_length = 120
include_trailing_comma = true
combine_as_imports = true
remove_redundant_aliases = true

[tool.black]
line-length = 79
target-version = ['py310']

[tool.pytest_env]
[tool.ruff]
include = ['src']
exclude = ['migrations']
line-length = 120

[tool.ruff.lint]
select = ['ALL']
fixable = [
'Q000',
'Q001',
'COM812',
'D400',
'PT001',
]
ignore = [
# Rules that should be turned on in the near future
'D',
'N818',
'B904',
'FIX002',
'RUF012',
'S311',
'DTZ005',
'DTZ006',
# Rules emitting false alerts
'N804',
'B008',
'BLE001',
'RUF009',
'I001',
# Rules that are not applicable in the project for now
'TID252',
'D104',
'ANN',
'SLF001',
'ARG',
'D100',
'PLR0913',
'TCH002',
# Strange and obscure rules that will never be turned on
'ANN101',
'FA100',
'TRY003',
'TRY201',
'EM',
'PERF203',
'TCH001',
'TD002',
'PTH201',
'RSE102',
'FA102',
'TD003',
'PTH123'
]

[tool.ruff.lint.per-file-ignores]
"__init__.py" = ['F401']

[tool.ruff.lint.pyupgrade]
keep-runtime-typing = true

[tool.ruff.lint.flake8-pytest-style]
parametrize-names-type = "list"
18 changes: 13 additions & 5 deletions src/costy/adapters/auth/auth_gateway.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import logging

from httpx import AsyncClient
from sqlalchemy import Table
from sqlalchemy.ext.asyncio import AsyncSession
Expand All @@ -6,15 +8,19 @@
from costy.domain.exceptions.access import AuthenticationError, RegisterError
from costy.infrastructure.config import AuthSettings

logger = logging.getLogger(__name__)


class AuthGateway(AuthLoger, AuthRegister):
AUTH_SUCCESS_CODE = 200
REGISTER_SUCCESS_CODE = 200

def __init__(
self,
db_session: AsyncSession,
web_session: AsyncClient,
table: Table,
settings: AuthSettings
settings: AuthSettings,
) -> None:
self.db_session = db_session
self.web_session = web_session
Expand All @@ -29,14 +35,15 @@ async def authenticate(self, email: str, password: str) -> str:
"client_id": self.settings.client_id,
"client_secret": self.settings.client_secret,
"audience": self.settings.audience,
"grant_type": self.settings.grant_type
"grant_type": self.settings.grant_type,
}
response = await self.web_session.post(url, data=data)
response_data = response.json()
if response.status_code == 200:
if response.status_code == self.AUTH_SUCCESS_CODE:
token: str | None = response_data.get("access_token")
if token:
return token
logger.info("Authentication failed: %s", response_data)
raise AuthenticationError(response_data)

async def register(self, email: str, password: str) -> str:
Expand All @@ -46,10 +53,11 @@ async def register(self, email: str, password: str) -> str:
"password": password,
"client_id": self.settings.client_id,
"client_secret": self.settings.client_secret,
"connection": self.settings.connection
"connection": self.settings.connection,
}
response = await self.web_session.post(url, data=data)
response_data = response.json()
if response.status_code == 200:
if response.status_code == self.REGISTER_SUCCESS_CODE:
return response_data["_id"]
logger.info("Register failed: %s", response_data)
raise RegisterError(response_data)
38 changes: 22 additions & 16 deletions src/costy/adapters/auth/token.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import logging
from datetime import datetime, timedelta
from typing import Any, Literal

from httpx import AsyncClient
from jose import exceptions as jwt_exc
from jose import jwt
from jose import exceptions as jwt_exc, jwt

from costy.application.common.id_provider import IdProvider
from costy.application.common.user.user_gateway import UserReader
Expand All @@ -15,13 +15,15 @@
"RS256", "RS384", "RS512",
]

logger = logging.getLogger(__name__)


class JwtTokenProcessor:
def __init__(
self,
algorithm: Algorithm,
audience: str,
issuer: str,
self,
algorithm: Algorithm,
audience: str,
issuer: str,
):
self.algorithm = algorithm
self.audience = audience
Expand All @@ -36,19 +38,20 @@ def _fetch_rsa_key(self, jwks: dict[Any, Any], unverified_header: dict[str, str]
"kid": key["kid"],
"use": key["use"],
"n": key["n"],
"e": key["e"]
"e": key["e"],
}
return rsa_key

def validate_token(self, token: str, jwks: dict[Any, Any]) -> str:
invalid_header_error = AuthenticationError(
{"detail": "Invalid header. Use an RS256 signed JWT Access Token"}
{"detail": "Invalid header. Use an RS256 signed JWT Access Token"},
)
try:
unverified_header = jwt.get_unverified_header(token)
except jwt_exc.JWTError:
raise invalid_header_error
if unverified_header["alg"] == "HS256":
logger.info("Token decode error. Invalid encode algorithm: %s", unverified_header["alg"])
raise invalid_header_error
rsa_key = self._fetch_rsa_key(jwks, unverified_header)
try:
Expand All @@ -57,18 +60,21 @@ def validate_token(self, token: str, jwks: dict[Any, Any]) -> str:
rsa_key,
algorithms=[self.algorithm],
audience=self.audience,
issuer=self.issuer
issuer=self.issuer,
)
return payload["sub"].replace("auth0|", "")
except jwt_exc.ExpiredSignatureError:
raise AuthenticationError({"detail": "token is expired"})
except jwt_exc.JWTClaimsError:
message = "incorrect claims (check audience and issuer)"
logger.exception("Auth token resolving fail. Message: %s", message)
raise AuthenticationError(
{"detail": "incorrect claims (check audience and issuer)"}
{"detail": "incorrect claims (check audience and issuer)"},
)
except Exception:
except Exception as e:
logger.warning("Auth token resolving unknown error. Message: %s", e.args)
raise AuthenticationError(
{"detail": "Unable to parse authentication token."}
{"detail": "Unable to parse authentication token."},
)


Expand Down Expand Up @@ -96,10 +102,10 @@ async def _request_new_key_set(self) -> None:

class TokenIdProvider(IdProvider):
def __init__(
self,
token_processor: JwtTokenProcessor,
key_set_provider: KeySetProvider,
token: str | None = None
self,
token_processor: JwtTokenProcessor,
key_set_provider: KeySetProvider,
token: str | None = None,
):
self.token_processor = token_processor
self.key_set_provider = key_set_provider
Expand Down
10 changes: 5 additions & 5 deletions src/costy/adapters/bankapi/bank_gateway.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@
class BankGateway(Protocol):
@abstractmethod
async def fetch_operations(
self,
access_data: dict,
user_id: UserId,
from_time: datetime | None = None
) -> list[BankOperationDTO]:
self,
access_data: dict,
user_id: UserId,
from_time: datetime | None = None,
) -> list[BankOperationDTO] | None:
raise NotImplementedError
8 changes: 4 additions & 4 deletions src/costy/adapters/bankapi/bankapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ class BankAPIGateway(
BankAPIReader,
BanksAPIReader,
BankAPIBulkUpdater,
BankAPIOperationsReader
BankAPIOperationsReader,
):
def __init__(
self,
Expand All @@ -37,7 +37,7 @@ def __init__(
table: Table,
retort: Retort,
bank_gateways: dict[str, BankGateway],
banks_info: dict[str, dict]
banks_info: dict[str, dict],
) -> None:
self._db_session = db_session
self._web_session = web_session
Expand All @@ -52,7 +52,7 @@ async def get_bankapi(self, bankapi_id: BankApiId) -> BankAPI | None:
return self._retort.load(result, BankAPI) if result else None

async def save_bankapi(self, bankapi: BankAPI) -> None:
retort = self._retort.extend(recipe=[name_mapping(BankAPI, skip=['id'])])
retort = self._retort.extend(recipe=[name_mapping(BankAPI, skip=["id"])])
values = retort.dump(bankapi)
query = insert(self._table).values(**values)
result = await self._db_session.execute(query)
Expand Down Expand Up @@ -85,7 +85,7 @@ async def update_bankapis(self, bankapis: list[BankAPI]) -> None:
for stmt in stmts:
await self._db_session.execute(stmt)

async def read_bank_operations(self, bankapi: BankAPI) -> list[BankOperationDTO]:
async def read_bank_operations(self, bankapi: BankAPI) -> list[BankOperationDTO] | None:
bank_gateway = self._bank_gateways[bankapi.name]
from_time = datetime.fromtimestamp(bankapi.updated_at) if bankapi.updated_at else None
return await bank_gateway.fetch_operations(bankapi.access_data, bankapi.user_id, from_time)
Loading

0 comments on commit e3c9a70

Please sign in to comment.