Repository navigation
fix(middleware): devolve a HTTPException que o runtime_context levanta (CRM-572) - #70
Conversation
Reviewer's GuideO PR extrai o TenantContextMiddleware para um módulo testável e passa a transformar HTTPException levantada pelo runtime_context em resposta JSON HTTP correspondente, mantendo o comportamento fail-open para outras falhas e cobrindo os fluxos principais com testes unitários. Sequence diagram for tenant context resolution and HTTPException handlingsequenceDiagram
participant Client
participant EvoAuthMiddleware
participant TenantContextMiddleware
participant RuntimeContext
participant App
Client->>EvoAuthMiddleware: HTTP request
EvoAuthMiddleware->>TenantContextMiddleware: Forward with user_context
TenantContextMiddleware->>RuntimeContext: current_context_id(request)
alt HTTPException raised
RuntimeContext-->>TenantContextMiddleware: HTTPException
TenantContextMiddleware->>TenantContextMiddleware: _error_response(exc)
TenantContextMiddleware-->>Client: JSON error response
else Context resolved
RuntimeContext-->>TenantContextMiddleware: context_id
TenantContextMiddleware->>RuntimeContext: bind_context(context_id)
TenantContextMiddleware->>App: Forward request
App-->>Client: Application response
else Other resolution exception
RuntimeContext-->>TenantContextMiddleware: Exception
TenantContextMiddleware->>App: Forward request without context
App-->>Client: Application response
end
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
Hey - I've found 1 issue
Prompt for AI Agents
Please address the comments from this code review:
## Individual Comments
### Comment 1
<location path="src/middleware/tenant_context.py" line_range="88" />
<code_context>
+
+ @staticmethod
+ def _error_response(exc: HTTPException) -> JSONResponse:
+ phrase = HTTPStatus(exc.status_code).phrase
+ return JSONResponse(
+ status_code=exc.status_code,
</code_context>
<issue_to_address>
**issue (bug_risk):** HTTPStatus(exc.status_code) raises ValueError for valid custom HTTP status codes such as 499, so an HTTPException raised by the runtime_context extension point is converted into a 500 instead of being returned to the client.
**Triggers:** When the extension point raises an HTTPException with a non-standard status code, such as the project's supported 499 Client Closed Request code.
**Suggested fix:** Use a phrase lookup with a fallback (for example, `HTTPStatus._value2member_map_.get(exc.status_code)` and a generic phrase) instead of constructing HTTPStatus unconditionally.
```suggestion
phrase = HTTPStatus._value2member_map_.get(exc.status_code, HTTPStatus.INTERNAL_SERVER_ERROR).phrase
```
</issue_to_address>Sourcery assessment
Needs a human reviewer. 1 finding to address first, and this changes tenant authorization behavior by turning an HTTPException from the runtime context extension into an immediate 4xx response instead of continuing unbound. If the classification or response handling is wrong, legitimate requests could be denied or a tenant refusal could be mishandled; reverting restores the previous behavior, but any incorrect access decision may already have affected requests.
Blocking findings: src/middleware/tenant_context.py:88
7b8ceec to
69405e4
Compare
…(CRM-572) TenantContextMiddleware treated every exception from current_context_id as a resolution failure and ran the request unbound, so a refusal the extension point decided on (a 403) surfaced downstream as a 500 or as an empty read. The class moves to src/middleware/tenant_context.py so it can be tested without importing the app.
69405e4 to
935de2d
Compare
O que
Achado M2 do review do CRM-572. O
TenantContextMiddlewaretratava qualquer exceção docurrent_context_idcomo falha de resolução e seguia com a request sem contexto. Uma recusa que o extension point decidiu (umaHTTPException403) então aparecia mais adiante como 500 no banco ou como leitura vazia — nunca como 403. Agora umaHTTPExceptionvinda doruntime_contextvira resposta com o mesmo formato de erro doEvoAuthMiddleware; qualquer outra exceção continua fail-open como antes.A classe saiu do
main.pyparasrc/middleware/tenant_context.py(sem mudança de corpo além do novoexcept) para ser testável sem importar o app, que fazcreate_allno import.Prova
tests/unit/test_tenant_context_middleware.py: 403 devolvido tal qual e sembind_context; exceção comum segue fail-open; contexto resolvido é vinculado.except HTTPException, o teste do 403 fica vermelho (1 failed, 2 passed).tests/unitna imagemevo-ai-processor:dev: 446 passed; os 8 erros emtest_perplexity_responses_roundtrip.pysão baseline dadevelop(import do litellm na imagem).Summary by Sourcery
Propagate runtime-context HTTP refusals directly to clients while retaining fail-open tenant-context resolution.
Bug Fixes:
Enhancements:
Tests: