Workflow moved to .gitea/workflows/ci.yml (Gitea is the CI host). Every gate now passes locally, step-for-step; green on main is pending an act_runner on gitea.doesworks.net (runs #1-#5 are queued "Waiting"). Gate fixes found by actually running them: - pip-audit: `--disable-pip` without `-r` was a usage error, so the old step could never pass. Now `pip-audit --strict .` audits the runtime dependency set from pyproject. - pip-audit then flagged ecdsa (PYSEC-2026-1325, no fix), a hard dep of python-jose. Swapped to PyJWT (HS256 only; 3-line change in auth/security.py). Flag to OWC. - PyJWT warned the test JWT secret was 11 bytes. JWT_SECRET now requires >= 32 bytes (RFC 7518 s3.2) at settings load; dev/compose/test defaults updated. Test-only value carries an inline gitleaks:allow. - bandit B101: assert in retention._count_past replaced with a raise. - gitleaks: gitleaks-action needs a GitHub token/license; replaced with the pinned 8.30.1 binary, sha256-verified, scanning full history. Added: - SBOM: CycloneDX 1.6 from a clean runtime-only venv (39 components), uploaded as a CI artifact. YPMS-POAM-042. - cyclonedx-bom in dev extras; CI outputs gitignored. 158 tests passing, 95.83% coverage; ruff, mypy, bandit, pip-audit, gitleaks clean. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
92 lines
2.3 KiB
TOML
92 lines
2.3 KiB
TOML
[project]
|
|
name = "ypms"
|
|
version = "0.1.0"
|
|
description = "DC Youth Program Management System"
|
|
requires-python = ">=3.12"
|
|
dependencies = [
|
|
"fastapi>=0.115",
|
|
"uvicorn[standard]>=0.30",
|
|
"sqlalchemy>=2.0",
|
|
"alembic>=1.13",
|
|
"psycopg[binary]>=3.2",
|
|
"pydantic[email]>=2.8",
|
|
"pydantic-settings>=2.4",
|
|
"passlib>=1.7",
|
|
"pyjwt>=2.9",
|
|
"python-multipart>=0.0.9",
|
|
"structlog>=24.4",
|
|
"cryptography>=43",
|
|
"jinja2>=3.1",
|
|
]
|
|
|
|
[project.optional-dependencies]
|
|
dev = [
|
|
"pytest>=8.3",
|
|
"pytest-asyncio>=0.24",
|
|
"pytest-cov>=5.0",
|
|
"httpx>=0.27",
|
|
"ruff>=0.6",
|
|
"mypy>=1.11",
|
|
"bandit>=1.7",
|
|
"pip-audit>=2.7",
|
|
"cyclonedx-bom>=4",
|
|
]
|
|
|
|
[build-system]
|
|
requires = ["setuptools>=68"]
|
|
build-backend = "setuptools.build_meta"
|
|
|
|
[tool.setuptools.packages.find]
|
|
where = ["src"]
|
|
|
|
[tool.pytest.ini_options]
|
|
testpaths = ["tests"]
|
|
asyncio_mode = "auto"
|
|
addopts = "-ra --strict-markers"
|
|
|
|
[tool.coverage.run]
|
|
source = ["src/ypms"]
|
|
omit = [
|
|
"tests/*",
|
|
# router.py is testable end-to-end only once the auth stack lands in
|
|
# milestone 0.3. The framework tests exercise its underlying CRUDService
|
|
# + BulkOps directly, which is where the real logic lives.
|
|
"src/ypms/framework/router.py",
|
|
]
|
|
|
|
[tool.coverage.report]
|
|
show_missing = true
|
|
skip_covered = false
|
|
|
|
[tool.ruff]
|
|
line-length = 100
|
|
target-version = "py312"
|
|
|
|
[tool.ruff.lint]
|
|
select = ["E", "F", "I", "UP", "B", "SIM"]
|
|
# E501: handled by formatter; B008: FastAPI's Depends() in defaults is canonical
|
|
ignore = ["E501", "B008"]
|
|
|
|
[tool.mypy]
|
|
python_version = "3.12"
|
|
strict = true
|
|
ignore_missing_imports = true
|
|
|
|
# The generic router factory has to work with runtime-bound type variables
|
|
# that FastAPI introspects via typing.get_type_hints. That means the closure
|
|
# uses `create_t: type[BaseModel]` bindings which mypy can't model precisely.
|
|
# See ARCHITECTURE.md §4.1. Same suppression pattern as OWC's framework.
|
|
[[tool.mypy.overrides]]
|
|
module = "ypms.framework.router"
|
|
disable_error_code = ["valid-type", "type-arg", "attr-defined", "unused-ignore"]
|
|
|
|
# Generic CRUD uses TypeVars mypy can't fully model — the ModelT.id and
|
|
# ModelT.deleted_at accesses require a Protocol bound we don't ship for
|
|
# ergonomics. Same suppression pattern OWC uses in practice.
|
|
[[tool.mypy.overrides]]
|
|
module = "ypms.framework.crud"
|
|
disable_error_code = ["attr-defined", "valid-type", "unused-ignore"]
|
|
|
|
[tool.bandit]
|
|
exclude_dirs = ["tests", "migrations"]
|