Add project guidance, security/governance/hygiene rules, and product wiki
- CLAUDE.md + AGENTS.md: canonical guiding principles for AI agents and developers (tenant isolation, no RLS, stack, security, conventions, environment gotchas) - SECURITY.md: required security controls (isolation, secrets, auth, input handling, least privilege) with VAPT status - GOVERNANCE.md: how changes are validated before merge — deterministic gates + AI review, risk tiers, human accountability - CONTRIBUTING.md: code hygiene, definition of done, file hygiene - docs/wiki/: product reference (overview, domain model, features, roles & access, API reference, glossary) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
45b5b34680
commit
035711f08c
+79
@@ -0,0 +1,79 @@
|
||||
# Security rules
|
||||
|
||||
Required security controls for TravelHub. These are not suggestions — a change
|
||||
that breaks one is rejected. They exist because this is a **multi-tenant** system
|
||||
holding traveller PII (names, passport numbers, contact details) where a single
|
||||
leaked `WHERE` clause exposes every tenant.
|
||||
|
||||
Findings from the whitebox assessment and their status are in
|
||||
[`security/VAPT-REPORT.md`](security/VAPT-REPORT.md).
|
||||
|
||||
## 1. Tenant isolation
|
||||
|
||||
- The tenant id is derived from the **authenticated identity**, never from the
|
||||
URL, query string, header value, or request body. A client cannot choose or
|
||||
forge the tenant it acts as.
|
||||
- Every query against a tenant-owned table (`users`, `flights`, `bookings`,
|
||||
`passengers`) filters on `tenant_id` as its first parameter. No exceptions.
|
||||
- A miss within the tenant returns **404**, never 403 — existence of another
|
||||
tenant's record must not be observable.
|
||||
- **No PostgreSQL row-level security.** Isolation is enforced in the repository
|
||||
layer by the rules above (see [CLAUDE.md](CLAUDE.md) for the rationale). At
|
||||
scale, prefer schema- or database-per-tenant, not RLS.
|
||||
|
||||
## 2. Secrets
|
||||
|
||||
- **Never commit a secret.** `.env` and `*.env` are git-ignored; only
|
||||
`.env.example` (placeholders) is tracked. Credentials, tokens and DB passwords
|
||||
live in `.env` and are read at runtime.
|
||||
- The `pre-commit` hook scans staged content for credential patterns and blocks
|
||||
them. Do not bypass it (`--no-verify`) to commit a secret.
|
||||
- **Never print or log a credential.** The e2e API-capture redacts the
|
||||
`Authorization` header (it is the Basic-auth secret); keep it redacted in any
|
||||
report or log.
|
||||
- **If a secret is ever committed or exposed, rotate it immediately** — assume
|
||||
it is compromised. Scrubbing history is not enough on its own.
|
||||
|
||||
## 3. Authentication & credential storage
|
||||
|
||||
- Passwords are hashed with **bcrypt in application code** at cost ≥ 12.
|
||||
- The real hash and the not-found timing-dummy hash must use the **same cost** —
|
||||
a mismatch creates a username-enumeration timing oracle (VAPT FINDING-2).
|
||||
- 401 responses omit `WWW-Authenticate` (so the browser dialog doesn't fight the
|
||||
SPA sign-in); a missing user still pays for a bcrypt comparison (timing).
|
||||
- Authentication endpoints must be **rate-limited** before any public exposure.
|
||||
|
||||
## 4. Input handling
|
||||
|
||||
- **All SQL is parameterised** (`$1…$n`). Never concatenate a value into SQL.
|
||||
Anything that must reach the SQL text (e.g. a sort column) is whitelisted.
|
||||
- JSON request bodies use `DisallowUnknownFields` (blocks mass-assignment) and
|
||||
are size-capped (`http.MaxBytesReader`).
|
||||
- Validate and normalise free-text on input; treat the API as the trust
|
||||
boundary, not the client.
|
||||
|
||||
## 5. Transport & least privilege
|
||||
|
||||
- Any non-local database connection uses **TLS** (`sslmode=verify-full`);
|
||||
`disable` is only for loopback dev.
|
||||
- The running service connects to PostgreSQL as a **least-privilege role**
|
||||
(DML only), never a superuser. Migrations run under a separate, higher
|
||||
privileged role the service never uses.
|
||||
|
||||
## 6. Dependencies & headers
|
||||
|
||||
- Run dependency scanning in CI: `govulncheck` (Go) and `npm audit` (frontend).
|
||||
- Responses carry baseline security headers (`nosniff`, `X-Frame-Options`,
|
||||
`Referrer-Policy`, `Cache-Control: no-store` on authenticated JSON, HSTS behind
|
||||
TLS); the SPA ships a restrictive CSP.
|
||||
|
||||
## 7. Data handling
|
||||
|
||||
- Treat passenger PII as sensitive. Do not log it; do not put real PII in seed
|
||||
or test data (use synthetic values).
|
||||
- Reports (evidence, test) may contain synthetic test data only.
|
||||
|
||||
## Reporting a vulnerability
|
||||
|
||||
Raise security issues privately with the repository owner (do not open a public
|
||||
issue). Include steps to reproduce and the affected files.
|
||||
Reference in New Issue
Block a user