elsa-core/test
Sipke Schoorstra 723bdc0004
fix(identity): route the remaining permission checks through the evaluator (#8001)
* fix(identity): route the remaining permission checks through the evaluator

Completes T038 of the authorization model, and fixes a live defect it was
meant to catch.

RoleDeletionCoordinator.InspectAsync gated on the legacy string "delete:role",
compared by claim-value equality. Nothing has granted that spelling since the
vocabulary migration, so a caller holding identity/roles:delete passed the
endpoint's own RequirePermission check and was then refused mid-handler by the
coordinator. In practice role deletion worked only for holders of "*", across
all three routes that reach the coordinator (Delete, RemediateAndDelete and
GetDeletionImpact). The check now evaluates identity/roles:delete through
PermissionEvaluator, so structured and wildcard grants both reach it.

Every existing coordinator test acted as an administrator holding "*", which is
why this went unnoticed; the added cases exercise identity/roles:delete,
identity/*:delete and identity/roles:* and assert an unrelated grant is still
refused.

AIHttpContextIdentity matched an agent's required permissions by
case-insensitive exact-set containment, which both admitted casing the rest of
the model rejects and refused the wildcards it honours. It now evaluates each
required permission through the same evaluator.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix(ai): restore the null-safe HttpContext access in the tools endpoint

The tools endpoint dereferenced HttpContext directly when passing the principal
to GetAuthorizedAgent, which threw a NullReferenceException and failed two
Elsa.AI.IntegrationTests cases on CI.

This was collateral from tightening a nullable warning in the chat endpoint. The
chat endpoint dereferences HttpContext.Response unconditionally a few lines
later, so HttpContext.User is safe there; the tools endpoint never does, and its
three sibling calls -- GetPermissions, GetActorId and GetTenantId -- all accept
a null context. The same edit was applied to both, and only chat could take it.

Reverting to HttpContext?.User preserves the endpoint's prior behaviour:
GetAuthorizedAgent treats a null principal as holding nothing, and an agent that
declares no required permissions stays authorized either way, because the
empty-requirements check runs before the null check.

Elsa.AI.IntegrationTests 69/69 (was 67 passed, 2 failed); Elsa.Identity.UnitTests
115/115; Elsa.AI.Host builds with no CS8602.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-08-28 22:03:15 +02:00
..
component feat(user-tasks): add identity-neutral workflow-bound human tasks (#7955) 2026-08-25 00:09:06 +02:00
integration feat(user-tasks)!: migrate endpoints to structured permissions (#7999) 2026-08-27 12:06:52 +02:00
performance Merge release/3.8.0 into main 2026-08-14 11:59:35 +02:00
TlsSmoke [codex] Fix console log metadata and type resolution (#7542) 2026-05-30 22:52:01 +02:00
unit fix(identity): route the remaining permission checks through the evaluator (#8001) 2026-08-28 22:03:15 +02:00
Directory.Build.props
Directory.Build.targets [codex] Harden initial security remediation slice (#7495) 2026-05-22 00:45:47 +02:00