diff --git a/CLAUDE.md b/CLAUDE.md index d841d9f0..5214edcc 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -12,7 +12,7 @@ This is a production multi-tenant app under active attack. The two targets are a - **Scope every query by org**, then check visibility (see Reuse below), and pass `org=` on `create()` and `serializer.save()`. RLS is the safety net, not the contract. - **Server-owned fields** (`org`, `created_by`, `profile`, publish flags) are `read_only=True` or popped before save. State transitions validate the source state, not just the target. - Check by name for: org auto-join by email domain, IDOR on detail and nested routes, mass assignment, refresh tokens surviving a privilege change, SSRF, path traversal, stored-markdown XSS, and secrets or another tenant's data in responses and logs. -- **Never weaken a protection** (RLS policy, permission class, org filter, validator, CSRF or auth check) to make something work: surface it and ask. Flag vulnerabilities you notice, but never in a public issue, PR or commit message. +- **Never weaken a protection** (RLS policy, permission class, org filter, validator, CSRF or auth check) to make something work: surface it and ask. Flag vulnerabilities you notice, but never in a public issue, PR or commit message: they are reported as `SECURITY.md` describes. ## House rules @@ -71,7 +71,7 @@ pnpm run format docker compose up --build # full stack, from the repo root ``` -CI (`.github/workflows/tests.yml`) blocks on `makemigrations --check`, `ruff check`, `ruff format --check`, pytest on SQLite and on Postgres, the `postgres_only` tests as a non-superuser role, a wheel install check, `eslint`, `pnpm check`, `pnpm test`, `pnpm build` and `mkdocs --strict`. Prettier only warns. Nothing runs for mobile. +CI (`.github/workflows/tests.yml`) blocks on `makemigrations --check`, `ruff check`, `ruff format --check`, pytest on SQLite and on Postgres, the `postgres_only` tests as a non-superuser role, a wheel install check, `eslint`, `pnpm check`, `pnpm test`, `pnpm build` and `mkdocs --strict`. Prettier only warns. Nothing runs for mobile. Markers, the Postgres role and the three CI runs: `docs/contributing/testing.md`. ## Gotchas @@ -94,7 +94,7 @@ Frontend: - **Data loads on the server.** A route's `+page.server.js` calls `#lib/server/v2/.js`, which calls `apiRequest` from `#lib/api-helpers.js` with the cookies; writes are form actions with `use:enhance` and `fail()`. There are no `+page.js` files, because the JWT is an httpOnly cookie the browser cannot read. Browser code talks to `src/routes/api/*/+server.js` proxies or `?/action`, never to Django, and cannot import `#lib/server/*`. - **A load's returned names are the page's contract.** `server/v2` returns `{ results, totals }` and each load renames them; a mismatch is an SSR 500 while the API answers 200, and `pnpm check` does not catch it. Load the page. - **Forms drop values silently.** A `