Wire case-level access control into evidence, sources, findings, leads routers #65
Labels
No labels
agentic-osint
audit
blocked:commit-ready-failed
blocked:gate-fetch
blocked:gate-fetch
blocked:gate-lint
blocked:gate-plan
blocked:gate-research
blocked:needs-decision
blocked:needs-human
blocked:no-changes
blocked:preflight
blocked:verify-failed
bug
chore
deferred
enhancement
feature-request
in-progress
lint-baseline
lint-cleanup
needs-decompose
needs-triage
performance
quickfix
security/medium
triage-approved
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
Mark/osint-hub#65
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
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?
Parent Issue: #36 (Case-level access control) / #53
Scope
Wire
require_case_accessdependency into evidence, sources, findings, and leads routers.Background
These four routers follow the same pattern: LIST by
case_idquery param, GET/PUT/DELETE by{id}path param. They are the core evidence trail within a case.Acceptance Criteria
GET /evidence/?case_id=X— requiresviewercase access; filters to only evidence in cases user can viewPOST /evidence/— requireseditorcase access (case_id in body)GET /evidence/{id}— requiresviewercase access (look up case_id from evidence item)PUT /evidence/{id}— requireseditorcase accessDELETE /evidence/{id}— requireseditorcase accessDependencies
Implementation Notes
/{id}), need to look up thecase_idfrom the entity before checking accessrequire_case_accessdep extractscase_idfrom path — may need a variant that resolves case_id from entity FK⏸ Needs Decision
Blocking factors:
Scope: medium Risk: medium Spec: aligned Type: feature
Summary: Wire existing require_case_access dependency (from #64) into evidence, sources, findings, and leads routers to enforce case-level permissions — viewer for reads, editor for writes — with admin bypass.
Suggestion: Add a generic require_entity_access(model_cls, min_role) dep factory to deps.py that resolves case_id from the entity FK for /{id} endpoints. For LIST endpoints, join-filter on CaseMembership. Wire into all 4 routers. Update evidence review/lock endpoints too. Tests: add access-control test modules for each router.
Rationale: Medium scope: 4 routers x ~4 endpoints each = 16 endpoints, plus new dep factory in deps.py. The pattern already exists (require_case_access from #64, get_case_ownership in deps.py) so it's additive not novel. Medium risk: evidence router is 670 lines with complex review/lock logic — higher touch surface for regressions. Security-sensitive but the dep is well-tested and admin bypass is built into CaseAccessService. Fully aligned with parent issues #36/#53 and the existing architecture.
Action: Review each blocking factor above. Remove
blocked:needs-decisionlabel to route back to triage.GSD VERIFY phase failed after 3 attempts.
═══ Gate: verify-passed (osint-hub#65) ═══
Mode: Tier 1 (functional only)
GATE OK: All gates up to 'implement' pass
── Tier 1: Functional ────────────────────────────────
Running tests...
❌ Tests failed (exit 4)
configfile: pyproject.toml
plugins: anyio-4.13.0, httpx-0.36.2, timeout-2.4.0, xdist-3.8.0, cov-7.1.0, split-0.11.0, asyncio-1.4.0
timeout: 60.0s
timeout method: signal
timeout func_only: False
asyncio: mode=Mode.STRICT, debug=False, asyncio_default_fixture_loop_scope=None, asyncio_default_test_loop_scope=function
collected 0 items
============================ no tests ran in 0.00s =============================
ERROR: file or directory not found: tests/
============================= test session starts ==============================
platform linux -- Python 3.11.14, pytest-9.0.3, pluggy-1.6.0
rootdir: /home/b/Projects/osint-hub
configfile: pyproject.toml
plugins: anyio-4.13.0, httpx-0.36.2, timeout-2.4.0, xdist-3.8.0, cov-7.1.0, split-0.11.0, asyncio-1.4.0
asyncio: mode=Mode.STRICT, debug=False, asyncio_default_fixture_loop_scope=None, asyncio_default_test_loop_scope=function
collected 0 items
============================ no tests ran in 0.00s =============================
Running linter...
✅ Lint clean
Running type checker...
✅ Types check clean
Previous test count: unknown
❌ GATE FAIL: verify-passed
- Tests failed with exit code 4
GATE FAIL: verify — blocked at 2026-05-27T00:13:51Z
Class: test-failure
Evidence: Verification failed: 1 failures
Git tag: osint-hub#65-gate-verify-fail-c1945eb21c7c (use gate-retry after fixing)
GSD VERIFY phase found no changes after implementation.
Worker output: ]11;?\API call failed after 3 retries: HTTP 429: Error code: 429 - {'status': 429, 'title': 'Too Many Requests'}
QA Verification (2026-08-04)
Independently re-verified by tasker-worker on commit
4fe3b33(HEAD of main). The fix commitdddb058is present and:Code review of
dddb058:The previously-pending GSD VERIFY comments (id 12813, 33270) failed for unrelated reasons (HTTP 429 / test infra issue). The fix itself is correct.
Issue state matches: closed 2026-08-01T00:43:24Z (kilo-gsd-runner card t_b22133bb). Closing out the QA reconciliation queue.