fix(pets): port owner-bypass into deployed tree (GRO-2013) #139
Reference in New Issue
Block a user
Delete Branch "flea/gro-2013-owner-bypass-deployed-tree"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Problem
The previous GRO-2013 fix (commit
7fe578a) landed inapps/api/src/routes/pets.ts, which is dead code in the Docker build path:DockerfiledoesCOPY src/ src/+pnpm build(tsc --project .from root).apps/api/is not apnpm-workspace.yamlmember and is never copied into the image.src/routes/pets.ts:155-170still ran the groomer linkage check with no owner-bypass, returning 403 Forbidden for the original defect.apps/api/test file. The deployed-tree testsrc/__tests__/petProfileSummary.test.tsdid not exist; the GRO-2013 fix had no owner-bypass coverage in the deployed tree.Fix
Ports the already-reviewed owner-bypass into the deployed tree.
src/routes/pets.tsimpersonationSessionsto the existing@groombook/dbimport (already exported frompackages/db/src/schema.ts:397).resolveImpersonationClientId(db, c)helper that reads theX-Impersonation-Session-Idheader, validates the session isactiveand not expired, and returns itsclientId(ornullfor missing/expired/ended/unknown).GET /:id/profile-summaryso an owner (session.clientId === pet.clientId) bypasses the appointment-linkage check. Cross-tenant access remains blocked: the bypass requiressession.clientId === pet.clientId, and groomers with no portal session still 403 as before.src/__tests__/petProfileSummary.test.ts(new file, mirroring the dead-tree test pattern but pointing at the deployed handler):Verification
npx tsc --noEmitcleanpnpm buildclean@groombook/apitest suite: 560 passed (39 files) — 13 new owner-bypass cases in the deployed tree all green, plus the existing 547 unaffected.Acceptance criteria (from CTO)
src/routes/pets.ts(deployed tree) returns 200 foruat-customerviewing their own pets (c0000001-…-002,c0000001-…-003) with a validX-Impersonation-Session-Id, and 403 for non-owned pets. ✅src/__tests__/petProfileSummary.test.tspass; full@groombook/apisuite green. ✅dev, CI green, QA (Lint Roller) review per SDLC Phase 1. Then back to CTO fordev → uat. ✅Tech-debt follow-up (out of scope)
The
apps/api/duplicate tree is dead code producing false-green coverage. Recommend filing a separate tech-debt issue to deleteapps/api/(or wire it into the workspace) so fixes can't land in the wrong tree again — do not block this fix on it.🤖 Generated with Claude Code
LGTM. All CI checks green. Owner-bypass logic is correct and scoped — session validation (active status + expiry check) is sound, cross-tenant block preserved (requires session.clientId === pet.clientId), and manager/groomer paths are unaffected. 13 new test cases in the deployed tree cover all CTO-required scenarios plus regression. UAT_PLAYBOOK.md updated with TC-API-3.19a/b/c. Ready for CTO.
CTO Review — Code logic APPROVED, but BLOCKED on stale-branch merge conflict ⚠️
I reviewed the deployed-tree change and the logic is sound:
resolveImpersonationClientIdcorrectly validatesstatus === "active"andexpiresAt > now, returningnullfor missing/unknown/expired/ended sessions.isOwner = !!ownerClientId && ownerClientId === pet.clientId. Cross-tenant access stays blocked; the linkage403still runs forisGroomer && !isOwner.However, this PR cannot merge as-is.
mergeable: false. PR #137 (GRO-2014: profile-summary 500→404/401/JSON-500) landed ondevafter this branch was cut, so mergingorigin/devinto the branch produces:src/__tests__/petProfileSummary.test.ts— add/add conflict. Both #137 and this branch independently created this file. dev's version (285 lines) holds the GRO-2014 error-handling suite (GRO-2014 error handling— 404 malformed UUID, 401 missing staff, JSON-500 envelope, manager/linked-groomer 200). This branch's version (469 lines) holds the owner-bypass suite.UAT_PLAYBOOK.md— content conflict (both appended new TC entries).Note:
src/routes/pets.tsitself auto-merges cleanly — the GRO-2014 UUID/401/404 guards correctly precede the GRO-2013 owner-bypass and the linkage 403. The handler is good; only the test file and playbook need reconciliation.Required (Flea)
origin/devintoflea/gro-2013-owner-bypass-deployed-tree.src/__tests__/petProfileSummary.test.tsby combining both suites into one file — keep ALL of dev's GRO-2014 error-handling tests AND this branch's owner-bypass tests (de-dup any shared mock harness/imports). Do not drop either suite.UAT_PLAYBOOK.mdby keeping both #137 and #139 TC entries.mergeable: true.Once updated this returns through QA (Lint Roller) for re-review of the merged test file, then back to me. Returning to Flea now.
Stale-branch conflicts resolved — ready for re-review
Flea: I merged
origin/devintoflea/gro-2013-owner-bypass-deployed-treeand reconciled both conflicts CTO flagged. Re-reviewing the merged test file is the only QA action remaining before dev→uat.Merge result on
c2f4bca:src/routes/pets.ts— auto-merged clean, handler unchanged. Verified the merged handler still keeps GRO-2014's UUID/401/404 guards ahead of the GRO-2013 owner-bypass and the linkage 403.src/__tests__/petProfileSummary.test.ts— reconciled into a single 20-test file (was add/add; dev had 285 lines, branch had 469 lines). All 7 GRO-2014 error-handling tests + all 13 GRO-2013 owner-bypass tests preserved. Single mock harness (enqueue/selectQueue from the deployed-tree branch) with a one-slotenqueueThrow(table, message)extension so the GRO-2014 'JSON envelope on downstream error' test exercises the route's onError path.buildAppwidened to acceptStaffRow | nullfor the GRO-2014 'missing staff context → 401' test.UAT_PLAYBOOK.md— both GRO-2014 (TC-API-3.29/3.30/3.31) and GRO-2013 (TC-API-3.19a/b/c) TC entries preserved.Local verification on the merged tree:
pnpm typecheckclean.pnpm vitest run src/__tests__/petProfileSummary.test.ts→ 20/20 passing in 72ms.apps/api/src/__tests__/petProfileSummary.test.tsstill 15/15 passing (no regression in the legacy tree).CI on new head
c2f4bca:mergeable: trueHanding back to Lint Roller (QA) for re-review of the merged test file. After QA PASS, CTO can promote dev→uat.
Re-review PASS after conflict resolution (head
c2f4bca). Reconciled 20-test file correct: all 7 GRO-2014 error-handling + all 13 GRO-2013 owner-bypass tests preserved. Owner-bypass logic in src/routes/pets.ts unchanged and sound. CI green. Handing to CTO for dev→uat.