ci / test (push) Has been cancelled
- README rewritten: Docker and native quickstarts, try-it flow, gate commands, promote-a-stub steps. - CONTRIBUTING rules 9-13 (pii_read on PII reads, __audit_redact__ for encrypted columns, retention policy per table, models.py registry, vendored-code change discipline); PR checklist updated. - docs/nist-mapping.md: per-control file:line evidence and remaining gap. - NIST_800_53_CONTROL_MAPPING.md v0.3: Phase 0 notes on 28 rows (12 implemented, 12 partial, 4 progress notes on hybrid/tailored rows) plus a status-shift table. - PHASE0_PLAN: 0.9 complete; Definition of Done 12/14 checked with how each was verified. Open: first green Gitea CI run, Docker/Postgres boot. - POA&M and status handoff updated; status TL;DR no longer claims an unverified Docker boot. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
64 lines
4.7 KiB
Markdown
64 lines
4.7 KiB
Markdown
# Contributing to YPMS
|
|
|
|
Hard rules — mirrored from OWC's `CONTRIBUTING.md` because the two systems share a stack, an ownership model, and an ISSO. If a rule feels wrong for YPMS, propose an amendment in a PR to this file, don't quietly break it.
|
|
|
|
## Repository conventions
|
|
|
|
1. **Migrations are immutable once merged.** Add a new Alembic revision, never edit `0001_baseline.py` or its successors. If a schema change requires undoing an older migration, the fix is a new revision, not a rewrite. Every migration is a paper trail an auditor can walk. Every revision's SHA-256 is pinned in `migrations/IMMUTABLE.sha256` — add a line with each new migration; a test fails if a pinned file changes. Migrations never import app code.
|
|
|
|
2. **Don't add domain logic to `src/ypms/framework/` or `src/ypms/security/`.** Those are reused by every entity; entity-specific code belongs in `src/ypms/<entity>/`. If a framework enhancement is genuinely needed, propose it in its own PR with a written reason.
|
|
|
|
3. **Every state-mutating route emits an audit row.** Enforced by `CRUDService`, the router factory, and the stub router. Don't write handlers that bypass them.
|
|
|
|
4. **501 stubs still fire RBAC + audit.** Deferred actions must route through `require_permission` and emit an audit event. Permission gaps surface at Phase 0 review, not at feature-completion.
|
|
|
|
5. **Tests required.** `src/ypms/framework/` and `src/ypms/security/` need ≥ 80% coverage. Everything else: at least one happy-path test.
|
|
|
|
6. **No `--no-verify`, `# noqa`, `# type: ignore`, `# nosec`, or `gitleaks:allow` without an inline comment naming the specific reason.** Suppressions are per-finding, never blanket. Don't lower a CI gate to get green.
|
|
|
|
7. **Sensitive fields never in logs.** SSN, banking, tokens, passwords, encryption keys — route through `sanitize_for_log` before emitting or don't emit. See `src/ypms/logging.py`.
|
|
|
|
8. **No commits attributed to a person who didn't write them.** Set `user.name` and `user.email` in `git config` to yourself before committing. Co-author trailers are welcome and encouraged for pairing.
|
|
|
|
9. **Reads of sensitive PII emit `pii_read`.** Any GET, list, or history route returning SSN-bearing, banking, FERPA, CFSA, or immigration data calls `framework.pii_audit` after RBAC passes (NIST AU-14).
|
|
|
|
10. **Encrypted columns go through `security.column_crypto` and into `__audit_redact__`.** Otherwise their ciphertext lands in `audit_log` and `version_history`. Sensitive values are write-only on the model and masked in the read schema.
|
|
|
|
11. **Every mapped table declares a retention policy.** The app refuses to start otherwise. Don't invent durations — use a `retention_classes.py` class, or an unset one citing the POA&M item that owns the decision.
|
|
|
|
12. **New model modules go in `src/ypms/models.py`.** Alembic, the retention job, and the tests all read that one list.
|
|
|
|
13. **Changes to vendored OWC code need a written reason in the module docstring** and get added to the "Upstream to OWC" list in the current phase status doc.
|
|
|
|
## Change control
|
|
|
|
- Every substantive change ties to a POA&M ID, a phase-plan milestone, or an issue. Include the reference in the PR description.
|
|
- `PHASE{N}_PLAN.md` is authoritative for the current phase's scope. Older plans lose to the current one on conflict.
|
|
- Cross-phase work needs a written scope-conflict note before it lands.
|
|
|
|
## Security review
|
|
|
|
- Any change touching auth, RBAC, encryption, or audit gets a second reviewer.
|
|
- Changes to `src/ypms/security/` require the ISSO's approval (currently Chris Tonjes).
|
|
- Additions to the RBAC seed require the same review as code changes — permissions are policy in this codebase.
|
|
|
|
## PR checklist
|
|
|
|
- [ ] Tests pass locally (`pytest`).
|
|
- [ ] Coverage doesn't drop below 80% on `framework/` or `security/`.
|
|
- [ ] `ruff check`, `mypy` clean.
|
|
- [ ] SAST (`bandit`), SCA (`pip-audit --strict .`), and secret scan (gitleaks) clean, or per-finding waivers with reasons.
|
|
- [ ] Migration added (if schema changed) and pinned in `migrations/IMMUTABLE.sha256`; no edits to older migrations.
|
|
- [ ] New tables have a retention policy; new model modules are in `src/ypms/models.py`.
|
|
- [ ] Any new endpoint has RBAC + audit + a test; PII reads emit `pii_read`.
|
|
- [ ] Any new sensitive field routes through the app-layer encryption helpers.
|
|
- [ ] `docs/nist-mapping.md` updated if the change wires a new NIST control.
|
|
- [ ] POA&M item updated if the change closes or advances one.
|
|
- [ ] Commit message names the phase milestone or POA&M ID it advances.
|
|
|
|
## Merging
|
|
|
|
- Squash-merge is the default. Merge commit messages should read like release notes for that PR.
|
|
- Force-pushes to `main` are not allowed. Force-pushes to feature branches during review are fine.
|
|
- CI (Gitea Actions, `.gitea/workflows/ci.yml`) must be green.
|