fix auth trust boundary and enforce async job ownership - #199
AjayThorve merged 6 commits into
Conversation
Greptile SummaryThis PR closes two concrete security gaps: JWT payloads are no longer used as trusted identity (verified principal now comes exclusively from middleware ContextVar), and async job endpoints enforce per-object ownership via a new The previously-raised P1 concerns (blocking sync DB calls in Confidence Score: 4/5Safe to merge with two open items: the backward-compat alias runtime failure and the misleading 500 error message noted inline. The core security fixes (verified principal, per-object job authorization, blocking-call fixes) are solid and the previously-flagged P1s are addressed. The remaining open issues are a pre-existing compat alias gap and a confusing error message — both P2 in practice. frontends/aiq_api/src/aiq_api/jobs/submit.py (submit_deep_research_job alias), frontends/aiq_api/src/aiq_api/routes/jobs.py (500 error message) Important Files Changed
Sequence DiagramsequenceDiagram
participant Client
participant AuthMiddleware
participant JobRoute
participant access.py
participant job_access DB
participant JobStore
Client->>AuthMiddleware: POST /v1/jobs/async/submit (Bearer token)
AuthMiddleware->>AuthMiddleware: validate_token_with_validators()
AuthMiddleware->>AuthMiddleware: set _current_user ContextVar (type, sub, email)
AuthMiddleware->>JobRoute: forward request
JobRoute->>access.py: require_verified_principal()
access.py->>access.py: get_current_principal() from ContextVar
access.py-->>JobRoute: Principal(type, sub, email)
JobRoute->>JobStore: submit_job(job_id, ...)
JobStore-->>JobRoute: ok (Dask task running)
JobRoute->>access.py: create_job_access(job_id, principal) via run_in_executor
access.py->>job_access DB: INSERT job_id, owner_auth_type, owner_subject
job_access DB-->>access.py: ok
access.py-->>JobRoute: ok
JobRoute-->>Client: job_id + status submitted
Client->>JobRoute: GET /v1/jobs/async/job/job_id
JobRoute->>access.py: require_verified_principal()
access.py-->>JobRoute: Principal(type, sub)
JobRoute->>access.py: authorize_job_access(job_id, principal)
access.py->>JobStore: get_job(job_id)
JobStore-->>access.py: job
access.py->>job_access DB: SELECT WHERE job_id
job_access DB-->>access.py: owner_auth_type + owner_subject
access.py->>access.py: principal_matches_access()?
alt owner matches
access.py-->>JobRoute: job
JobRoute-->>Client: JobStatusResponse
else owner mismatch or no access row
access.py-->>JobRoute: HTTPException 404
JobRoute-->>Client: 404 Not Found
end
Reviews (4): Last reviewed commit: "skip ownership check when require auth i..." | Re-trigger Greptile |
AjayThorve
left a comment
There was a problem hiding this comment.
One issue, rest all looks good
AjayThorve
left a comment
There was a problem hiding this comment.
LGTM, works will w/ and w/o auth
…ueprints#199) * fix auth trust boundary and enforce async job ownership * fix old tests * share request identity resolution for HTTP and WebSockets * remove log and fix no auth flow * make rollback async * skip ownership check when require auth is false
Two upstream test gaps caught locally: 1. tests/aiq_agent/jobs/test_runner.py — auth_token is now the last positional arg in submit_job's job_args list (NVIDIA-AI-Blueprints#199 added it after data_sources). Update test to assert job_args[-2] == data_sources instead of [-1]. 2. frontends/aiq_api/tests/test_job_access.py::TestAuthorizeJobAccess — authorize_job_access only enforces ownership when REQUIRE_AUTH=true, but the test class never set that env var. Add an autouse monkeypatch.setenv fixture to the class so the cross-user-denied and missing-access-row tests exercise the auth-enabled branch they expect. Both are upstream issues caught by our long-running smoke; not production-code changes. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Summary
This PR fixes two auth/security issues in aiq:
Changes
1. Trusted identity now comes only from verified middleware context
2. Async job object-level authorization
3. WebSocket auth bridge for UI-backed chat (transitional)
4. DB init and cleanup
5. Code quality / cleanup
Security impact
This PR closes:
Trusted authorization decisions now use verified principal identity (type + sub), and async job access is enforced per object rather than per request only.
Testing
Validated in local/dev environments with:
Notes