Build Seth's changes C1 to C11 (Gitea issues 1, 8, 18, 23, 24, 25, 27, 31, 32, 33, 36)
ci / frontend (pull_request) Successful in 57s
ci / server (pull_request) Successful in 12m33s
ci / image (pull_request) Skipped
ci / e2e (pull_request) Successful in 5m4s

- 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:
2026-10-30 13:33:51 -06:00
co-authored by Claude Opus 5.5
parent 1ae6819289
commit 1cd6688247
101 changed files with 3871 additions and 1098 deletions
+35 -2
View File
@@ -64,8 +64,6 @@ def endpoints(andy: str, ck_version: int) -> list[tuple[str, str, dict[str, Any]
("GET", "/api/admin/access-log", {}, 200),
("GET", "/api/admin/access-log.csv", {}, 200),
("GET", "/api/admin/presence", {}, 200),
("POST", "/api/admin/stamp-verify", {"json": {"text": "0123456789abcdef"}}, 200),
("POST", "/api/admin/stamp-verify/pdf", {"files": {"file": ("a.pdf", tiny_pdf(), "application/pdf")}}, 200),
("GET", "/api/admin/directory-flags", {}, 200),
("POST", "/api/admin/ad/refresh", {}, 202),
("GET", "/api/admin/ad/reconcile", {}, 200),
@@ -123,3 +121,38 @@ def test_every_new_admin_endpoint_as_every_role(
assert n == len(OTHER_ROLES) * len(eps)
details = conn.execute("SELECT detail FROM audit_events WHERE action = 'policy.denied' LIMIT 1").fetchone()[0]
assert set(details) == {"method", "path", "code"}
def stamp_endpoints() -> list[tuple[str, str, dict[str, Any]]]:
out = []
for base in ("/api/stamp-verify", "/api/admin/stamp-verify"):
out.append(("POST", base, {"json": {"text": "0123456789abcdef"}}))
out.append(("POST", f"{base}/pdf", {"files": {"file": ("a.pdf", tiny_pdf(), "application/pdf")}}))
return out
def test_stamp_check_roles(pg_client: TestClient, pg_settings: Settings, fake_dir: FakeDirectory) -> None:
"""Change C9: the stamp check is open to Admin, Q.C. and every Clerical level, at both paths, on a password
session. Every other role gets 403."""
eps = stamp_endpoints()
with TestClient(create_app(pg_settings, directory=fake_dir), headers=ORIGIN_HEADERS) as anon:
for method, path, kw in eps:
assert call(anon, method, path, kw).status_code == 401, path
for sam in ("admin.ann", "qc.quinn", "clerk.clara", "clerk.leo"):
assert sign_in(pg_client, sam).status_code == 200, sam
for method, path, kw in eps:
r = call(pg_client, method, path, kw)
assert r.status_code == 200, (sam, path, r.status_code, r.text)
pg_client.post("/api/auth/signout")
for sam in ("wh.wade", "pm.paula", "weld.andy", "lead.lou", "sup.wes"):
assert sign_in(pg_client, sam).status_code == 200, sam
for method, path, kw in eps:
r = call(pg_client, method, path, kw)
assert r.status_code == 403 and r.json()["code"] == "forbidden", (sam, path, r.status_code)
pg_client.post("/api/auth/signout")
# A PIN session: the password session rule stays
register_device(pg_client)
set_pin(pg_client, "admin.ann")
assert pin_signin(pg_client, "1001").status_code == 200
r = call(pg_client, eps[0][0], eps[0][1], eps[0][2])
assert r.status_code == 403 and r.json()["code"] == "password_session_required", r.text