Repository navigation
fix(workforce-validation): reject non-callable repository capability before authorization #240
Description
Finding
A prior CodeRabbit review of Draft #235 identified a P1 that remained present through exact 4ef7ad130e4d0aa314ea59de3dafaea79cc0630c: read_validity_study(...) used isinstance(read_port, ValidityStudyReadPort) as its dependency gate, but a runtime-checkable protocol is a structural shape check, not reliable proof that resolving read_validity_study yields a safely callable capability.
A caller can expose a descriptor/property or other non-callable static member under that name. Depending on Python protocol-check implementation, structural checking can itself touch dynamic attributes or accept the static member; the application can then proceed into principal/policy validation and purpose-bound authorization before eventually failing when the repository capability is resolved/called. That violates the boundary's declared fail-fast dependency contract.
The repair must not replace this with eager getattr(...)/callable(...), which would execute a caller-controlled descriptor before authorization.
Test-first repair lineage
9794ff543c9190cdd6fa00dc37016db8391709a9: causal regression._DescriptorReadPort.read_validity_studyis a property whose getter raises if executed. The request uses a deliberately denying policy so the invalid dependency must raiseTypeErrorbefore authorization can produce a denial; descriptor behavior must never run.ccb5c0c58dc74c1d7eee59431e6337c207fcac35: minimal production successor. The owner boundary usesinspect.getattr_static(read_port, "read_validity_study", None)and rejects a missing/non-callable static capability before principal reconstruction, policy detachment, Keyverse evaluation, or persistence. Valid ordinary instance-method ports expose the class function statically and remain callable after authorization.- Compare
4ef7ad1...→ccb5c0c...is two ordinary ahead-only commits touching only the focused regression andregistry.py(+ import + static capability gate). No force-push/history rewrite, SQL/schema/role, Keyverse adapter, principal contract, requested fields, or owner-port signature was changed.
#239 remains preserved: canonical principal reconstruction/revalidation still occurs before PurposeBoundAccessRequest and Keyverse evaluation once the dependency capability has first been proven inertly callable.
Acceptance state
Current #235 exact head is ccb5c0c58dc74c1d7eee59431e6337c207fcac35 on protected develop@eb9757f8649aaad026a9865508d9aad50c1a7a4f, Draft and mechanically mergeable. Exact-head Foundation 33954469089 / Repository quality 101275139627 was queued before checkout at the latest gate read; Security 33954468968, SAST 33954468946, and CodeQL PR 33954468879 were non-terminal. Hosted GREEN/100% coverage/PostgreSQL/security completion is not claimed.
CodeRabbit reviewed exact ccb5c0c... against protected develop@eb9757f... and reported no blocking issue in the requested #240 scope. It verified the static inspect.getattr_static(...) capability read and callability gate; this is independent static evidence, not a formal qualifying approval or hosted GREEN. GitHub's formal review collection is still empty.
Keep this issue open until exact-head hosted/security/review evidence and normal protected integration are complete.
Activity