test: lock tasks and snippet tenancy - #79
Draft
cursor[bot] wants to merge 1 commit into
Draft
Conversation
Hub task and CA snippet routes only had access-helper coverage. Route tests now lock list isolation, session stamping, assignment/delete rules, and reactions. Snippet PATCH allowlists title/clause/body/tags so a body cannot overwrite unionId. Co-authored-by: Ryan Morris <ryan@ryanmorris.ca>
This was referenced Sep 6, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
After #44/#45/#68, Hub route tests still skipped the tasks board and CA snippet library — those mutating paths only had access-helper coverage. This run locks those Officer Hub surfaces so a tenancy, assignment, or mass-assign regression cannot ship unnoticed.
PRs #57 (expense/elections/documents list-create) and #68 (polls/check-ins/discussions) are still open and are not duplicated here. Today's playbook, mobile-tool, and export Brand Kit changes already ship with tests.
Risky behavior now covered
statusis ignored;mine=1scopes to the session user; futuresincereturns{ changed: false }; create rejects forged tenant keys and stamps session union/local/creator; steward cannot assign others; president can; overlay tenant withouttasksis 403; GET/PATCH/DELETE 403 another union (includingplatform_admin) with no write; assignee can mark own task done but cannot edit or delete another officer's task; extra PATCH tenant keys 400; creator can delete; reactions 404 missing / 403 other union / extra keys 400 / steward toggle.qworks; create rejects missing fields and stamps session union/creator even when the body forges tenant keys; GET/PATCH/DELETE 403 another union with no write; PATCH allowlist ignoresunionId/localId/createdById; author can delete and another steward cannot; president can delete another officer's snippet.Test files added/updated
src/lib/tasks/api-routes.test.tssrc/lib/validation/task.test.tssrc/lib/snippets/api-routes.test.tssrc/lib/tasks/memory-adapter.ts(test reset helper only)src/lib/snippets/memory-adapter.ts(test reset helper only)src/app/api/snippets/[id]/route.ts(PATCH allowlist — no longer spreads the raw body)Why this reduces regression risk
These are confidential officer writes on casework to-dos and CA clause text. A missed
unionIdfilter, a steward assigning someone else, or a snippet PATCH that copiedunionIdfrom the body would leak or re-home records across tenants. The new tests exercise the real route handlers (not just access helpers) so session gating, Zod.strict(), and the snippet allowlist stay aligned.Checklist
.env, keys, or real member/PII datamessages/en.jsonandmessages/fr.json(if applicable)unionIdscoping; no cross-union access)npm run lintandnpm run test:unitpassnpm run test:smoke)Test plan
npx vitest run src/lib/tasks/api-routes.test.ts src/lib/validation/task.test.ts src/lib/snippets/api-routes.test.ts src/lib/tasks/access.test.ts src/lib/qol(43 passed)npx eslinton the six touched files (clean)