e39521d51d
- TASK-03-01 server/auth/passwords.py: argon2id via argon2-cffi
PasswordHasher (t=3, m=64MiB, p=4 — exceeds OWASP). hash/verify/
needs_rehash; verify returns False on mismatch (uniform 401 path).
- TASK-03-02 server/auth/cookies.py: get_session_middleware_kwargs()
→ Starlette SessionMiddleware (itsdangerous HMAC-SHA256, D-056).
Cookie praxis_op, httpOnly, SameSite=strict, max_age=28800 (8h).
PRAXIS_COOKIE_SECURE default true; false logs WARNING (R-AUTH-01).
G-031 reframe documented: k-anon defense-in-depth is the PRIMARY
mitigation (sniffed cookie → no PII); secure flag is SECONDARY.
- TASK-03-03 server/auth/rate_limit.py: slowapi Limiter (in-memory,
D-041), 5/minute per IP on login. reset_login_rate_limit() helper.
- TASK-03-04 server/auth/dependencies.py + models.py: current_operator
Depends — reads signed-cookie session, fetches operator from PgStore,
401 on missing/invalid/inactive (clears session), 503 if no Postgres.
Never trusts the client (D-057).
- TASK-03-05 server/auth/routes.py: APIRouter(prefix=/api/operator)
with POST /login (rate-limited, rehash-on-login), POST /logout
(auth-gated, clears session), GET /me (auth-gated, React guard).
- TASK-03-06 tests/test_auth.py: 18 unit tests (mocked PgStore) —
passwords, cookie config, rate limit, 401/503 cases, login/logout/me,
rehash-on-login.
- pyproject.toml: added itsdangerous>=2.1 (SessionMiddleware dep).
---ci---
project: praxis
phase: 1
milestone: v0.4
status: execute
persona: security-engineer
task: 03-01,03-02,03-03,03-04,03-05,03-06
requirements:
covered: [REQ-AUTH-01, REQ-NFR-AUTH-01]
grill:
- G-031 (R-AUTH-01 reframe: k-anon primary, secure flag secondary)
---/ci---
72 lines
2.3 KiB
TOML
72 lines
2.3 KiB
TOML
[build-system]
|
|
requires = ["setuptools>=68", "wheel"]
|
|
build-backend = "setuptools.build_meta"
|
|
|
|
[project]
|
|
name = "praxis-server"
|
|
version = "0.1.0"
|
|
description = "Praxis — voice-first AI apprenticeship platform (v0.1 foundation: minimal viable voice loop)"
|
|
readme = "README.md"
|
|
requires-python = ">=3.11"
|
|
license = { text = "Proprietary" }
|
|
authors = [{ name = "Praxis v0.1 (CIAgent)" }]
|
|
|
|
dependencies = [
|
|
# Web framework — FastAPI serves /health + /pipecat/webrtc + StaticFiles (D-023)
|
|
"fastapi>=0.110",
|
|
# ASGI server — uvicorn runs the FastAPI app (used by server.__main__.main)
|
|
"uvicorn>=0.30",
|
|
# Orchestration — Pipecat (D-017) with the three native service extras + WebRTC transport
|
|
"pipecat-ai[deepgram,cartesia,piper,webrtc]>=1.6.0",
|
|
# LLM access — Ollama Cloud direct API (D-020). Pipecat's OLLamaLLMService uses the
|
|
# OpenAI-compatible client; we point base_url at https://ollama.com/v1 + bearer key.
|
|
"openai>=1.40",
|
|
# Scenario format — YAML DSL → Pydantic (D-018)
|
|
"pydantic>=2.7",
|
|
"pyyaml>=6.0",
|
|
# Learner state — SQLite (D-007), async access
|
|
"aiosqlite>=0.20",
|
|
# Config
|
|
"python-dotenv>=1.0",
|
|
# Latency probes — HTTP client for the integrated e2e probe
|
|
"httpx>=0.27",
|
|
"websockets>=12.0",
|
|
# Audio probe fixture generation (synthesized PCM) for the ASR probe
|
|
"numpy>=1.26",
|
|
# VC issuer (SLICE-09) — Ed25519 sign/verify (libsodium), JCS canonicalization
|
|
# (RFC 8785), base58-btc for Multikey proofValue encoding.
|
|
"pynacl>=1.5",
|
|
"canonicaljson>=2.0",
|
|
"base58>=2.1",
|
|
# v0.4 operator tier — Postgres pool (D-050), argon2id passwords (D-041),
|
|
# slowapi rate limiting (D-041). RESEARCH-v0.4 §new-deps.
|
|
"asyncpg>=0.29",
|
|
"argon2-cffi>=23.1",
|
|
"slowapi>=0.1",
|
|
# SessionMiddleware uses itsdangerous for signed cookies (D-056).
|
|
"itsdangerous>=2.1",
|
|
]
|
|
|
|
[project.optional-dependencies]
|
|
dev = [
|
|
"pytest>=8.0",
|
|
"pytest-asyncio>=0.23",
|
|
"pytest-cov>=5.0",
|
|
]
|
|
|
|
[project.scripts]
|
|
praxis-server = "server.__main__:main"
|
|
|
|
[tool.setuptools.packages.find]
|
|
where = ["."]
|
|
include = ["server*", "db*", "scenarios*"]
|
|
exclude = ["client*", "tests*", "scripts*"]
|
|
|
|
[tool.pytest.ini_options]
|
|
asyncio_mode = "auto"
|
|
testpaths = ["tests"]
|
|
python_files = ["test_*.py"]
|
|
addopts = "-ra -q"
|
|
|
|
[tool.coverage.run]
|
|
source = ["server", "db"] |