Add pal-e-auth integration to gate roster endpoints #5

Merged
forgejo_admin merged 11 commits from 4-add-auth into main 2026-02-24 04:55:03 +00:00

Closes #4

Summary

  • Add pal-e-auth-ldraney>=0.1.0 dependency
  • Add jwt_secret_key, google_client_id, google_client_secret to Settings (BASKETBALL_ prefix)
  • Wire AuthConfig + auth_router in main.py — single config instance for both router and app.state
  • Gate get_roster and roster_page with require_role("admin", "coach")
  • Add pal-e-auth-secrets env vars to k8s/deployment.yaml

Prerequisites

  • pal-e-auth-ldraney published to PyPI (add pypi_token Woodpecker secret first)
  • tofu apply for basketball-api namespaces
  • Create pal-e-auth-secrets K8s secret in both namespaces

Test plan

  • pytest passes (health tests, auth imports resolve)
  • ruff check clean on changed files
  • Integration test: OAuth flow → cookie → roster access on dev

🤖 Generated with Claude Code

Closes #4 ## Summary - Add `pal-e-auth-ldraney>=0.1.0` dependency - Add `jwt_secret_key`, `google_client_id`, `google_client_secret` to Settings (BASKETBALL_ prefix) - Wire `AuthConfig` + `auth_router` in `main.py` — single config instance for both router and `app.state` - Gate `get_roster` and `roster_page` with `require_role("admin", "coach")` - Add `pal-e-auth-secrets` env vars to `k8s/deployment.yaml` ## Prerequisites - [ ] `pal-e-auth-ldraney` published to PyPI (add `pypi_token` Woodpecker secret first) - [ ] `tofu apply` for basketball-api namespaces - [ ] Create `pal-e-auth-secrets` K8s secret in both namespaces ## Test plan - [x] `pytest` passes (health tests, auth imports resolve) - [x] `ruff check` clean on changed files - [ ] Integration test: OAuth flow → cookie → roster access on dev 🤖 Generated with [Claude Code](https://claude.com/claude-code)
FastAPI app with Stripe webhooks, gmail-sdk email, Postgres via SQLAlchemy/Alembic.
Includes k8s manifests (deployment, service, postgres), Woodpecker CI, and Dockerfile
for deployment to pal-e cluster.

Closes #1

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Escape all user-controlled values in HTML roster and email templates
- Remove hardcoded credentials from alembic.ini
- Set stripe.api_key on app startup
- Return 400 (not 422) for missing stripe-signature header
- Add postgres subPath for k3s compatibility
- Document single-replica constraint for migrations

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add src/ copy to Dockerfile builder stage
- Add idempotency check on stripe_checkout_session_id in webhook handler
- Use stripe.SignatureVerificationError (stable import path)
- Migrate from deprecated on_event to lifespan pattern
- Fix seed script session cleanup

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add unique constraint on Registration.stripe_checkout_session_id
- Add IntegrityError catch as secondary idempotency defense
- Return 200 for permanent webhook failures (ValueError), 500 only for transient
- Add initial Alembic migration for all tables

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- .woodpecker.yaml: switch to kaniko plugin, full SHA tags, proper path
  exclude, add pytest test step
- k8s manifests: add namespace to all resources, add resource
  requests/limits, fix Service port to 8000 with name: http
- k8s/postgres.yaml: add subPath for k3s, PGDATA env, strategy: Recreate,
  resource limits
- k8s/servicemonitor.yaml: new file for Prometheus scraping
- /metrics endpoint: stub returning basketball_api_up gauge

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
ArgoCD destination.namespace controls placement, making manifests
environment-agnostic. This enables branch-based dev/prod promotion.

Refs: forgejo_admin/basketball-api#1

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Wire Google OAuth + JWT auth via pal-e-auth-ldraney. Roster endpoints
now require admin or coach role. Auth secrets mounted from separate
pal-e-auth-secrets K8s secret.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Crash at startup if BASKETBALL_JWT_SECRET_KEY is unset to prevent
silently signing JWTs with an empty key. Add test conftest with
auth env defaults. Set login_redirect_url to /docs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Author
Owner

Review Fix (Round 1)

BLOCKER fixed: Empty jwt_secret_key no longer silently accepted. _build_auth_config() now raises RuntimeError at startup if BASKETBALL_JWT_SECRET_KEY is unset, preventing JWT forgery with empty key.

NIT fixed: Set login_redirect_url="/docs" instead of default / (which would 404).

Added: tests/conftest.py with auth env defaults so tests can import main.py without crashing.

Other NITs (memory limits, static metrics) are pre-existing and out of scope for this PR.

## Review Fix (Round 1) **BLOCKER fixed:** Empty `jwt_secret_key` no longer silently accepted. `_build_auth_config()` now raises `RuntimeError` at startup if `BASKETBALL_JWT_SECRET_KEY` is unset, preventing JWT forgery with empty key. **NIT fixed:** Set `login_redirect_url="/docs"` instead of default `/` (which would 404). **Added:** `tests/conftest.py` with auth env defaults so tests can import `main.py` without crashing. Other NITs (memory limits, static metrics) are pre-existing and out of scope for this PR.
Sign in to join this conversation.
No description provided.