[project] name = "flaskpaste" version = "1.4.0" description = "Secure pastebin with mTLS authentication and E2E encryption" readme = "README.md" requires-python = ">=3.11" dependencies = [ "flask>=3.0", "cryptography>=42.0", ] [project.optional-dependencies] dev = [ "pytest>=8.0", "pytest-cov>=4.1", "ruff>=0.8", "mypy>=1.8", "bandit>=1.7", "pip-audit>=2.6", ] # ───────────────────────────────────────────────────────────────────────────── # Ruff - Fast Python linter and formatter # ───────────────────────────────────────────────────────────────────────────── [tool.ruff] target-version = "py311" line-length = 100 exclude = [ ".git", ".venv", "venv", "__pycache__", "*.egg-info", ] [tool.ruff.lint] select = [ "E", # pycodestyle errors "W", # pycodestyle warnings "F", # pyflakes "I", # isort "B", # flake8-bugbear "S", # flake8-bandit (security) "UP", # pyupgrade "SIM", # flake8-simplify "TCH", # type-checking imports "RUF", # ruff-specific ] ignore = [ "S101", # assert allowed in tests "S311", # pseudo-random ok for non-crypto "B008", # function call in default arg (Flask patterns) ] [tool.ruff.lint.per-file-ignores] "tests/*" = ["S101", "S105", "S106"] # Allow asserts and hardcoded passwords in tests "fpaste" = ["S603", "S607"] # Subprocess calls ok in CLI "app/config.py" = ["S105"] # Test config has hardcoded passwords [tool.ruff.lint.isort] known-first-party = ["app"] # ───────────────────────────────────────────────────────────────────────────── # Mypy - Static type checking # ───────────────────────────────────────────────────────────────────────────── [tool.mypy] python_version = "3.11" warn_return_any = true warn_unused_ignores = true warn_redundant_casts = true warn_unused_configs = true show_error_codes = true pretty = true # Strict mode components (enable incrementally) check_untyped_defs = true disallow_untyped_defs = false # Enable later for stricter checking disallow_incomplete_defs = true [[tool.mypy.overrides]] module = [ "flask.*", "cryptography.*", "werkzeug.*", ] ignore_missing_imports = true # ───────────────────────────────────────────────────────────────────────────── # Bandit - Security linter # ───────────────────────────────────────────────────────────────────────────── [tool.bandit] exclude_dirs = ["tests", "venv", ".venv"] skips = ["B101"] # assert_used - ok in production for invariants # ───────────────────────────────────────────────────────────────────────────── # Pytest # ───────────────────────────────────────────────────────────────────────────── [tool.pytest.ini_options] testpaths = ["tests"] python_files = "test_*.py" python_functions = "test_*" addopts = "-v --tb=short" # ───────────────────────────────────────────────────────────────────────────── # Coverage # ───────────────────────────────────────────────────────────────────────────── [tool.coverage.run] source = ["app"] branch = true omit = ["tests/*"] [tool.coverage.report] exclude_lines = [ "pragma: no cover", "if TYPE_CHECKING:", "raise NotImplementedError", ]