Build Seth's changes C1 to C11 (Gitea issues 1, 8, 18, 23, 24, 25, 27, 31, 32, 33, 36)
- C1 (issue 1): over target follows VISUAL ticket hours, not the timer. - C2 (issue 24): a Q.C. reject always needs a reason; accept needs an NCR number after a reject without one. - C3 (issue 25): an incomplete unit ITP blocks filing. - C4 (issue 27): prints open the print dialog on the page, no new tab. - C5 (issue 31): filing is blocked while VISUAL shows a work order open; the feed sets vclosed on VISUAL packets. - C6 (issue 8): the data book leaves out the history pages. - C7 (issue 18): the supervisor approves each received short; accept and filing wait for it. - C8 (issue 23): per-department checklists, edited by the department supervisor or Admin, frozen at START. - C9 (issue 32): Q.C. and Clerical may run the stamp check. - C10 (issue 33): the PM screen and reports are for PS-ProjectMgmt and Admin only. - C11 (issue 36): the Stall screen lists the packets assigned to the welder, at the supervisor's stall. Migration 0011. Docs: PLAN (also issue 9 confirmed, issue 4 asked), POLICY, SECURITY, SCHEMA, FEED, README, CHANGELOG. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
+21
-9
@@ -2,7 +2,7 @@
|
||||
|
||||
This document is rewritten for the server build. The old browser build's security document is in the old repo (`C:\Users\spencerm\Coding\PacketStation\docs\SECURITY.md`). The design comes from [BRIEF.md](BRIEF.md) and [PLAN.md](PLAN.md).
|
||||
|
||||
Status: phase 9. The identity controls (sessions, PIN, rate limits, audit, Origin check, derived group map) and the policy controls (server policy on every write, workflow steps as compare-and-set, server-side validation and limits, IT edit reasons, the filed lock, the upload pipeline for drawings and documents) are built and tested. Phase 3 adds the worker controls (read-only VISUAL and M-Files reads, stack guard, advisory locks, redacted errors, audited system writes). No requirement ID closes in phase 3. Phase 4 completes the upload pipeline (a kind per upload with its own types and limit, XLSX and CSV by content, the optional ClamAV scan, the assets volume quota alert) and adds the warehouse rules (the heat gate on release, closed hold and short reasons, receive by custody). Phase 4 closes D5. Phase 5 adds the shop rules (the server as the clock of record, server-assigned mark numbers under the packet row lock, insert-only change-order verifications with a signature, VOID sheets never edited). Phase 6 adds the Q.C. rules (server gates on accept, block sign and sign-off, NCR numbers checked by pattern, Q.C. documents never deleted, the append-only ITP log, server-verified signatures on every Q.C. and ITP sign-off). No requirement ID closes in phase 6. Phase 7 adds the close and file controls (the HMAC seal with the data book filed on it, the controlled-copy and print stamps signed with the seal key, `print_log` and audit rows for every print and export, the CSV formula guard, PDF metadata, escaping in the PDFs). Phase 7 closes M2, S6, S7 and S8. Phase 8 adds the Project Management reads and exports, the server-side find bar filters and the presence rules (display name and role only, locked and revoked sessions dropped). No requirement ID closes in phase 8. Phase 9 adds the nightly AD reconcile and the 15-minute role refresh, the integrity job with its alert, email notifications over verified STARTTLS with security events nobody can mute, the security alerts and the Security tab settings, the Admin tabs (every change audited), nightly backups with a rehearsed restore, and dependency scanning in CI. Phase 9 closes the app part of I6, M3, O1, O2 and S3. Every other control names the phase that builds it.
|
||||
Status: phase 9. The identity controls (sessions, PIN, rate limits, audit, Origin check, derived group map) and the policy controls (server policy on every write, workflow steps as compare-and-set, server-side validation and limits, IT edit reasons, the filed lock, the upload pipeline for drawings and documents) are built and tested. Phase 3 adds the worker controls (read-only VISUAL and M-Files reads, stack guard, advisory locks, redacted errors, audited system writes). No requirement ID closes in phase 3. Phase 4 completes the upload pipeline (a kind per upload with its own types and limit, XLSX and CSV by content, the optional ClamAV scan, the assets volume quota alert) and adds the warehouse rules (the heat gate on release, closed hold and short reasons, receive by custody). Phase 4 closes D5. Phase 5 adds the shop rules (the server as the clock of record, server-assigned mark numbers under the packet row lock, insert-only change-order verifications with a signature, VOID sheets never edited). Phase 6 adds the Q.C. rules (server gates on accept, block sign and sign-off, NCR numbers checked by pattern, Q.C. documents never deleted, the append-only ITP log, server-verified signatures on every Q.C. and ITP sign-off). No requirement ID closes in phase 6. Phase 7 adds the close and file controls (the HMAC seal with the data book filed on it, the controlled-copy and print stamps signed with the seal key, `print_log` and audit rows for every print and export, the CSV formula guard, PDF metadata, escaping in the PDFs). Phase 7 closes M2, S6, S7 and S8. Phase 8 adds the Project Management reads and exports, the server-side find bar filters and the presence rules (display name and role only, locked and revoked sessions dropped). No requirement ID closes in phase 8. Phase 9 adds the nightly AD reconcile and the 15-minute role refresh, the integrity job with its alert, email notifications over verified STARTTLS with security events nobody can mute, the security alerts and the Security tab settings, the Admin tabs (every change audited), nightly backups with a rehearsed restore, and dependency scanning in CI. Phase 9 closes the app part of I6, M3, O1, O2 and S3. On 2026-10-30 SethD's changes C1 to C11 were built (see "SethD's changes (built 2026-10-30)"); they close D7. Every other control names the phase that builds it.
|
||||
|
||||
Contents:
|
||||
|
||||
@@ -74,9 +74,9 @@ The M: drive build had 20 layers of protection, most of them enforced in the bro
|
||||
- One policy in Python on the server (`server/packetstation/policy/`), pure functions with no I/O. Every write goes: session, policy, transition, validation, version check, packet log row, audit row, NOTIFY, in one transaction with the packet row locked. Nothing in the browser decides.
|
||||
- Every packet read returns `can: [...]`, `blocked: {...}` and `holder`, so the browser enables controls from the server's answer. The server re-checks on the write.
|
||||
- A workflow step taken twice is refused with 409 and the current state (compare-and-set on the expected status and department). Child rows carry a row version checked with If-Match. Weld, heat tag, page and change order numbers are assigned by the server under the lock.
|
||||
- Preconditions (heat map answered, drawing attached, BOM pulled or short, heats recorded on pulled lines, checklist complete, welds recorded, Q.C. items complete, closed in VISUAL before filing) run on the server and are never bypassed, Admin included.
|
||||
- Preconditions (heat map answered, drawing attached, BOM pulled or short, heats recorded on pulled lines, checklist complete, welds recorded, Q.C. items complete, an NCR number on the accept after a reject without one, every short received and approved before the Q.C. accept to complete and before filing, the unit's ITP complete before filing, closed in VISUAL before filing) run on the server and are never bypassed, Admin included.
|
||||
- Admin edits outside custody need an IT reason of at least 8 characters, recorded in the packet log and the audit row (`it_reason`). An Admin cannot write a filed packet except through the reopen action, which needs a reason and a signature and breaks the seal.
|
||||
- Signatures (PIN or domain password, verified in the same transaction; the PIN is enough everywhere, Q.C. accept and filing included, confirmed by SethD on 2026-10-26, Gitea issue 2) on submit, send to Q.C., Q.C. accept and reject, route, file, reopen, change order issue, approve, reject and verify, the revision approval and hand drawing uploads.
|
||||
- Signatures (PIN or domain password, verified in the same transaction; the PIN is enough everywhere, Q.C. accept and filing included, confirmed by SethD on 2026-10-26, Gitea issue 2) on submit, send to Q.C., Q.C. accept and reject, route, file, reopen, change order issue, approve, reject and verify, the revision approval, hand drawing uploads and the supervisor's approval of a received short.
|
||||
- Input: every string is cleaned (control and invisible characters removed, NFC, trimmed) and cut to its field limit; heat numbers, stamps, project numbers and lots are checked against the old patterns; JSON bodies over 200 KB are refused.
|
||||
- Uploads: typed by content (PDF, PNG, JPEG), 25 MB limit read in chunks, sha256, stored by id under the assets volume, served only with a session and with `Content-Disposition` and `X-Content-Type-Options: nosniff`. Phase 4 completes it (see "Uploads and storage").
|
||||
- The filed lock: a filed packet accepts only the data book date and the Admin reopen. Filing writes an HMAC-SHA256 seal with the server seal key; a reopen keeps the old seal with who broke it and why.
|
||||
@@ -157,7 +157,7 @@ The M: drive build had 20 layers of protection, most of them enforced in the bro
|
||||
- Every PDF and the CSV are built on the server. The browser only opens the URL. Reads need a signed-in session; every role that can open the packet may read them, PM included.
|
||||
- Controlled-copy stamp (S7): every exported page carries `Controlled copy - exported by Name (emp) <UTC time>`, the seal's first 12 hex or `not yet filed`, and ` - stamp <sig>`. The filed data book is the stored copy, served as it was built.
|
||||
- Printed-copy stamp (S8): every printed page carries `PRINTED COPY - <what> - printed by Name (emp) <UTC time> - <project> Lot <unit> dwg <drawing> R<rev> - verify revision before use` and the stamp signature, in a white box at the bottom of the page.
|
||||
- Stamp signature: 16 hex of HMAC-SHA256 with the seal key over the packet, the kind (a printed copy signs `print:<kind>`, so a print and an export of the same thing in the same minute never share a signature), the seal hash, the user and the time. A copy can be checked against the server with `verify_stamp`; from phase 9 the Admin Stamp check tab does it from a pasted line or a PDF.
|
||||
- Stamp signature: 16 hex of HMAC-SHA256 with the seal key over the packet, the kind (a printed copy signs `print:<kind>`, so a print and an export of the same thing in the same minute never share a signature), the seal hash, the user and the time. A copy can be checked against the server with `verify_stamp`; from phase 9 the Admin Stamp check tab does it from a pasted line or a PDF, and from 2026-10-30 Q.C. and Clerical can too, on the Stamp check screen (Gitea issue 32, change C9).
|
||||
- Logging (S7, S8): every print and export writes one `print_log` row (who, when, session, packet, unit or ITP, kind, what, pages, the stamp line, the stamp signature, the client address) and one audit row (`print` or `export`). `print_log` is append-only: the app role has SELECT and INSERT only, and a trigger refuses updates, deletes and truncate.
|
||||
- CSV formula guard (S6): a cell that starts with `=`, `+`, `-`, `@`, a tab or a CR gets a leading `'`. A cell with a quote, a comma or a line break is quoted with the quotes doubled.
|
||||
- PDF metadata: title, subject and keywords name the packet and the stamp signature; Author is PESCO and Producer is Packet Station.
|
||||
@@ -167,10 +167,10 @@ The M: drive build had 20 layers of protection, most of them enforced in the bro
|
||||
|
||||
### Project Management, find bar and presence (phase 8)
|
||||
|
||||
- Project Management reads only. Every endpoint under `/api/pm` is a GET and needs a signed-in session. Any role may read them, as any role may open any packet. The PM role passes no write action anywhere. The reports read PostgreSQL only, never VISUAL or M-Files.
|
||||
- Project Management reads only. Every endpoint under `/api/pm` is a GET and needs a PS-ProjectMgmt or Admin session; every other role is 403 (Gitea issue 33, change C10, built 2026-10-30; phase 8 let any signed-in role read them). The PM role passes no write action anywhere. The reports read PostgreSQL only, never VISUAL or M-Files.
|
||||
- Every PM export is built on the server and logged: one `print_log` row (kind `report-csv` or `report-pdf`, no packet, the scope label in `what`, the page count for the PDF) and one audit row with the action `report exported` and the detail `{name, format, scope, period}`. `print_log` stays append-only.
|
||||
- The PM CSV has the formula guard on every cell (S6), a BOM and CRLF line ends. The PDF report carries the controlled-copy stamp on every page and the PDF metadata. Both answer with `Content-Disposition`, `nosniff` and `no-store`, as the phase 7 exports do.
|
||||
- Filters never widen access. The search, the status, flag, station, worker and Mine filters are applied by the server inside each list's and board's own scope (a supervisor's departments, the stall's station). A filter can only narrow what the person may already read.
|
||||
- Filters never widen access. The search, the status, flag, station, worker and Mine filters are applied by the server inside each list's and board's own scope (a supervisor's departments, the stall's own assignments). A filter can only narrow what the person may already read.
|
||||
- Search words are bound parameters, matched with ILIKE and the LIKE escape. A query keeps at most 8 words of at most 60 characters each. IDs are matched as text, never cast.
|
||||
- Mine is decided on the server from the person's AD roles and the screen they name. Nothing the browser keeps can widen it.
|
||||
- Presence shows the display name and the role only (the user id, screen, packet id and since travel with it). No employee ID, no email, no other personal data. The server builds it from the session, not from what the browser says about itself.
|
||||
@@ -244,10 +244,21 @@ The account limit is capped at 15 so the app always stops before AD's own lockou
|
||||
### Admin (phase 9)
|
||||
|
||||
- Every Admin endpoint needs PS-Admins in a password session. Every Admin change is audited with before and after. Tests try every endpoint as every role.
|
||||
- Roles still come only from AD. The Admin edits departments (name, stations), profiles (stamp, profile active, station limits), checklists, the security settings and the notification rules. None of these grants a role. Turning a profile off hides the person from pickers and changes no right.
|
||||
- Roles still come only from AD. The Admin edits departments (name, stations), profiles (stamp, profile active, station limits), the checklists (any department's, and the default lists by kind), the security settings and the notification rules. None of these grants a role. Turning a profile off hides the person from pickers and changes no right.
|
||||
- Department codes and short names never change (a trigger, and 422 on the API). Stations are never deleted.
|
||||
- The access log CSV has the formula guard, at most 50,000 rows, and is logged in `print_log` and the audit.
|
||||
- The stamp check recomputes the stamp signature with the seal key and compares the text with the print log (S7, S8). It reads a pasted line or a PDF of up to 25 MB.
|
||||
- The stamp check recomputes the stamp signature with the seal key and compares the text with the print log (S7, S8). It reads a pasted line or a PDF of up to 25 MB. From 2026-10-30 it is open to Q.C. and Clerical as well (see below).
|
||||
|
||||
### SethD's changes (built 2026-10-30)
|
||||
|
||||
- Stamp check (Gitea issue 32, change C9): `POST /api/stamp-verify` and `/api/stamp-verify/pdf` (and the `/api/admin` aliases) are for Admin, every Q.C. role and every Clerical role, in a password session. A PIN session is 403 `password_session_required`; every other role is 403. Each check is audited (`admin.stamp_verified`). The seal key never leaves the server, and the check never trusts the pasted text.
|
||||
- Project Management (Gitea issue 33, change C10): every `/api/pm/*` endpoint, the CSV and PDF exports included, is for PS-ProjectMgmt and Admin only. Tests try every endpoint as Clerical, worker, Q.C., Warehouse and shop supervisor and expect 403.
|
||||
- Department checklists (Gitea issue 23, change C8): any session reads them. A save needs that department's Supervisor or an Admin, in a password session (a PIN session is 403 `password_session_required`), with the version it started from. A lead, Q.C. and the office roles cannot save. Each save writes an audit row `checklists.dept_updated` with the list before and after. A stage keeps the list frozen at its START, so an edit cannot change what an open stage must tick.
|
||||
- Short approvals (Gitea issue 18, change C7): the department supervisor approves each receipt with a signature. `short_approvals` is append-only (triggers, and `ps_app` has SELECT and INSERT only), one row per receipt by a unique key.
|
||||
- Filing (Gitea issues 25 and 31, changes C3 and C5): FILE needs the unit's ITP complete and, on a VISUAL packet, the feed's own observation that VISUAL closed every work order. Clerical cannot mark a VISUAL packet closed by hand. Neither can be bypassed, Admin included.
|
||||
- Q.C. (Gitea issue 24, change C2): a reject always needs a reason of 8 characters; the accept after a reject without an NCR number needs one, checked by pattern on the server.
|
||||
- The data book without the history pages (D7; Gitea issue 8, change C6): the one data book goes to the customer and leaves out the packet log. The history stays in Packet Station, readable by anyone who can open the packet, and in the audit.
|
||||
- The Stall screen (Gitea issue 36, change C11): `/api/stall/mine` lists only the packets assigned to the signed-in person. The request names no station; the session decides.
|
||||
|
||||
### Backups (phase 9)
|
||||
|
||||
@@ -298,7 +309,8 @@ The IDs come from Part 3 of the old SECURITY.md. The status follows the approved
|
||||
| D1, D2, D4 | Deferred (envelope encryption, Key Vault) |
|
||||
| D3 | IT's (host disk encryption on docker-1) |
|
||||
| D5 | Closed, phase 4 (optional ClamAV: a `clamav` compose profile; when `CLAMAV_HOST` is set every upload and every stored drawing is scanned before it is kept, a hit is refused and audited, and an unreachable scanner refuses uploads; off when the host is not set; left off in both stacks by IT on 2026-10-18, Gitea issue 19, with Microsoft Defender on the workstations) |
|
||||
| D6, D7 | Phase 10 (decided 2026-10-28, Gitea issues 7 and 8: nothing is purged, filed packets are archived to the QNAP share at filing, and the one data book leaves out the history pages) |
|
||||
| D6 | Phase 10 (decided 2026-10-28, Gitea issue 7: nothing is purged, and filed packets are archived to the QNAP share at filing) |
|
||||
| D7 | Closed 2026-10-30 (decided 2026-10-28, Gitea issue 8, change C6: the one data book, the customer copy, is built without the history pages; the history stays in Packet Station and the audit) |
|
||||
| M1 | Closed, phase 2 (append-only audit and packet log written only by the server; every packet write carries both) |
|
||||
| M2 | Closed, phase 7 (filing seal is HMAC-SHA256 with the server seal key from a Docker secret; a reopen keeps the broken seal and its data book) |
|
||||
| M3 | Closed, phase 9 (the nightly `integrity` job re-verifies seals, rehashes asset files, finds missing and orphan files and walks the audit hash chain; findings are kept in the append-only `integrity_findings` and raise `integrity_failure`, which nobody can opt out of) |
|
||||
|
||||
Reference in New Issue
Block a user