Skip to content

fix(workforce-validation): reject non-callable repository capability before authorization #240

Description

@seonghobae

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_study is a property whose getter raises if executed. The request uses a deliberately denying policy so the invalid dependency must raise TypeError before authorization can produce a denial; descriptor behavior must never run.
  • ccb5c0c58dc74c1d7eee59431e6337c207fcac35: minimal production successor. The owner boundary uses inspect.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 and registry.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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions