fix(ci): fix black/ruff failures, add CoC and PR template

- Fix Python formatting (sync no longer strips blank lines from .py files)
- Remove test_community_build.py (tests private sync module)
- Fix ruff warnings in test files
- Add CODE_OF_CONDUCT.md
- Add .github/PULL_REQUEST_TEMPLATE.md

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
airano
2026-02-17 18:19:39 +03:30
parent c9083d86b1
commit c73e39f6e4
135 changed files with 1185 additions and 317 deletions

View File

@@ -13,6 +13,7 @@ from .schemas import OAuthClient
logger = logging.getLogger(__name__)
class ClientRegistry:
"""
OAuth Client Registry with JSON storage.
@@ -143,9 +144,11 @@ class ClientRegistry:
return True
return False
# Singleton instance
_client_registry: ClientRegistry | None = None
def get_client_registry() -> ClientRegistry:
"""Get singleton ClientRegistry instance"""
global _client_registry

View File

@@ -10,6 +10,7 @@ Part of Phase E: Custom OAuth Authorization Page
import secrets
import time
class CSRFTokenManager:
"""
Manages CSRF tokens for OAuth authorization requests.
@@ -107,9 +108,11 @@ class CSRFTokenManager:
"token_lifetime_seconds": self._token_lifetime,
}
# Global CSRF token manager instance
_csrf_manager: CSRFTokenManager | None = None
def get_csrf_manager() -> CSRFTokenManager:
"""
Get the global CSRF token manager instance.

View File

@@ -8,6 +8,7 @@ import hashlib
import secrets
from typing import Literal
def generate_code_verifier(length: int = 64) -> str:
"""
Generate PKCE code verifier.
@@ -34,6 +35,7 @@ def generate_code_verifier(length: int = 64) -> str:
return verifier
def generate_code_challenge(code_verifier: str, method: Literal["S256"] = "S256") -> str:
"""
Generate PKCE code challenge from verifier.
@@ -63,6 +65,7 @@ def generate_code_challenge(code_verifier: str, method: Literal["S256"] = "S256"
return challenge
def validate_code_challenge(
code_verifier: str, code_challenge: str, method: Literal["S256"] = "S256"
) -> bool:

View File

@@ -6,6 +6,7 @@ from datetime import UTC, datetime
from pydantic import BaseModel, Field, field_validator
class OAuthClient(BaseModel):
"""OAuth 2.1 Client Model"""
@@ -44,6 +45,7 @@ class OAuthClient(BaseModel):
raise ValueError(f"Invalid grant type: {grant}")
return v
class AuthorizationCode(BaseModel):
"""Authorization Code Model"""
@@ -77,6 +79,7 @@ class AuthorizationCode(BaseModel):
raise ValueError("Only S256 code_challenge_method is supported (OAuth 2.1)")
return v
class AccessToken(BaseModel):
"""Access Token Model"""
@@ -96,6 +99,7 @@ class AccessToken(BaseModel):
expires = expires.replace(tzinfo=UTC)
return now > expires
class RefreshToken(BaseModel):
"""Refresh Token Model"""
@@ -115,6 +119,7 @@ class RefreshToken(BaseModel):
expires = expires.replace(tzinfo=UTC)
return now > expires
class TokenRequest(BaseModel):
"""Token Request Model"""
@@ -135,6 +140,7 @@ class TokenRequest(BaseModel):
client_secret: str | None = None
scope: str | None = None
class TokenResponse(BaseModel):
"""Token Response Model"""

View File

@@ -16,6 +16,7 @@ from .token_manager import get_token_manager
logger = logging.getLogger(__name__)
class OAuthError(Exception):
"""OAuth error with error code and description"""
@@ -25,6 +26,7 @@ class OAuthError(Exception):
self.status_code = status_code
super().__init__(error_description)
class OAuthServer:
"""
OAuth 2.1 Authorization Server
@@ -385,9 +387,11 @@ class OAuthServer:
scope=" ".join(requested_scopes),
)
# Singleton
_oauth_server: OAuthServer | None = None
def get_oauth_server() -> OAuthServer:
"""Get singleton OAuthServer instance"""
global _oauth_server

View File

@@ -13,6 +13,7 @@ from .schemas import AccessToken, AuthorizationCode, RefreshToken
logger = logging.getLogger(__name__)
class BaseStorage:
"""Base storage interface"""
@@ -43,6 +44,7 @@ class BaseStorage:
def revoke_refresh_token(self, token: str) -> bool:
raise NotImplementedError
class JSONStorage(BaseStorage):
"""
JSON file storage for OAuth tokens.
@@ -199,6 +201,7 @@ class JSONStorage(BaseStorage):
logger.info(f"Cleaned up {len(codes) - len(cleaned_codes)} expired authorization codes")
logger.info(f"Cleaned up {len(tokens) - len(cleaned_tokens)} expired access tokens")
def get_storage() -> BaseStorage:
"""
Get storage instance based on environment.

View File

@@ -17,11 +17,13 @@ from .storage import get_storage
logger = logging.getLogger(__name__)
class SecurityError(Exception):
"""Security-related error (e.g., token reuse)"""
pass
class TokenManager:
"""
OAuth 2.1 Token Manager.
@@ -302,9 +304,11 @@ class TokenManager:
# Access tokens cannot be revoked (JWT stateless)
# They expire naturally after TTL
# Singleton
_token_manager: TokenManager | None = None
def get_token_manager() -> TokenManager:
"""Get singleton TokenManager instance"""
global _token_manager