elsa-core/test/integration/Elsa.Diagnostics.OpenTelemetry.IntegrationTests/OpenTelemetryHubTests.cs

305 lines
14 KiB
C#
Raw Normal View History

[codex] Fix console log metadata and type resolution (#7542) * Avoid null endpoint DTO metadata in tests * Enforce console logs hub read permission * Remove unused console logs hub import * Support mapped endpoint metadata in auth tests * Reduce console log capture throughput impact * Address Copilot console logs review * Refactor task scheduling to support tenant-level background work and enhance logging functionality. * Introduce ConsoleStreamHook for stdout/stderr tee and enhance logging validation. Adjust test cases and startup warnings for distributed lock provider usage. * Refactor console logging pipeline with capture optimization and new ConsoleLogsHost; update tests accordingly. * Add Ansi SGR parser for console logs and associated unit tests * Remove ANSI color renderings and parsers; integrate ConsoleLogScopeAccessor for improved logging context with workflow instance ID support. * Address console logs code quality feedback * Address PR review feedback * Preserve console logs extension points * Stabilize console logs host lifecycle * Address final automated review comments * Tighten console log capture shutdown * Address console log review feedback * Address follow-up review feedback * Cover final review feedback * Avoid recursive console provider initialization * Guard console host lease shutdown * Preserve console log scope and provider lifetime * Correlate console log scope fallback * Tighten console scope correlation * Expose host services during provider construction * Redact ANSI-normalized console lines * Add OpenTelemetry diagnostics backend foundation * Add OTLP HTTP ingestion parsing * Document OpenTelemetry diagnostics setup * Enforce OpenTelemetry hub permissions * Remove `ConsoleCaptureTee` and related services and tests * Add OpenTelemetry HTTP ingestion integration test * Use pipeline contributors for console log context * Update CShells package versions to 0.0.24-preview.132 * Add OpenTelemetry ingestion security tests * Add OpenTelemetry API authorization tests * Filter live console logs by workflow instance * Add OpenTelemetry hub tests * Add OpenTelemetry gRPC metadata hook * Assert OpenTelemetry workflow tags survive ingestion * Mark OpenTelemetry core build verified * Enhance console logging with activity execution metadata and extend test coverage. * Address console logs stream consumption comment * Wire OpenTelemetry diagnostics into core sample * Address Core diagnostics review feedback * Address Core Copilot follow-up feedback * Add OpenTelemetry metric instrument names * Address Core Copilot provider feedback * Address Core Copilot diagnostics follow-up * Address Core Copilot live feed feedback * Address Core Copilot store feedback * Integrate OpenTelemetry for logging, tracing, and metrics in ModularServer and update launch settings and docker-compose configuration. * Refactor to replace `ConsoleLogStream.Core` with `ConsoleLogStreaming.Core` across codebase and update `ConsoleStreamHook` installation. * Add diagnostics OpenTelemetry backend * Fix OpenTelemetry live hub subscription * Fix modular OpenTelemetry exporter endpoints * Add CShells logging configuration in appsettings.json * Remove obsolete unit tests and helper classes * Restore default activity exception handling * Simplify type serialization and alias management This commit refactors the internal type serialization and alias management system to reduce boilerplate, improve robustness, and simplify the developer experience: - Removed numerous explicit `ExpressionOptions` type alias registrations across various modules. - Updated `TypeJsonConverter` and polymorphic serialization to reliably handle types using assembly-qualified names when a short alias is not explicitly registered. - Streamlined `ExcludeFromHashConverter` to strictly adhere to `ExcludeFromHashAttribute` for hash calculations, removing complex `JsonIgnoreCondition` logic. - Eliminated several helper classes (`WorkflowJsonTypeResolver`, `WorkflowTypeValidator`, `IWorkflowTypeRegistry`, `WorkflowFactoryDictionary`, `JavaScriptExceptionTypeAliasRegistrar`, `WorkflowRuntimeTypeAliasRegistrar`) and their associated unit tests, simplifying the codebase. Additionally, this commit introduces a comprehensive markdown document (`product-website-feature-source.md`) outlining Elsa's core features, Studio capabilities, extension ecosystem, and architectural selling points, intended as source material for the product website. * Refine type serialization for improved robustness and alias handling This commit further enhances the type serialization and deserialization mechanisms: * Centralizes type resolution and alias management through `IWellKnownTypeRegistry` and `WorkflowJsonTypeResolver`. * Prioritizes registered type aliases when serializing type metadata in `PolymorphicObjectConverter`, resulting in more concise JSON output. * Enhances deserialization in `PolymorphicObjectConverter` and `VariableMapper` to gracefully handle unknown or non-instantiable types, providing fallbacks and logging warnings. * Simplifies `TypeJsonConverter` by delegating complex type resolution logic to the `WorkflowJsonTypeResolver`. * Adds `JsonArray` to the well-known type aliases for direct recognition. * Fix console logs packaging and workflow type resolution * Fix console log metadata and type resolution * Address Copilot review feedback * Enhance type resolution, improve console log handling, and update tests - Streamlined `WorkflowDictionaryExtensions` for better workflow registration validation. - Refined `ConsoleLogsAuthorizationTests` with the new `SetJsonRequest` helper to improve test requests handling. - Updated `OrderDefinition` to ignore JSON serialization for `KeySelector`. - Enhanced `WorkflowRuntimeFeature` for improved workflow registration and type alias configuration. - Added tests to ensure `ConsoleLogProvider` metadata filtration in various scenarios. - Improved type serialization logic in `WorkflowJsonTypeResolver`. - Updated README to fix references related to diagnostics. - Optimized `ExcludeFromHashConverter` for property serialization conditions. - Modified `TriggerIndexer` for streamlined trigger management. - Tested payload checks in `PublishEventTests`. - Adjusted `Endpoint` in `ConsoleLogs` for automatic JSON request handling. - Ensured registration of workflow type aliases in `WorkflowsFeature`. * Restore CLR workflow registration compatibility * Align JSON island serialization fixtures * Add Console Logs Services and Enhance Endpoint Handling - Introduced `ActivityExecutionsEndpointTests` to validate route exposure. - Added `ConsoleLogCaptureHostedService` for console log streaming. - Implemented `ConsoleStreamJsonConverter` for JSON conversion of console streams. - Developed `ElsaConsoleLogRecentBuffer` to handle recent log buffering. - Updated `ConsoleLogsAuthorizationTests` with new test cases for stream filter mapping. - Consolidated console log provider dependencies and registration, including recent buffering. - Enhanced `ElsaConsoleLogProvider` to use recent buffer for filtering. - Adjusted `Program.cs` for streamlined logging service setup. * Enhance type resolution and test coverage; streamline console log integration - Added `ConsoleStreamHook` for streamlined log streaming. - Updated `WorkflowJsonTypeResolverTests` to improve type resolution and test new scenarios. - Simplified type resolution by removing trusted assembly checks. * Fix CI smoke and package restore failures * Fix Docker smoke image project paths * Fix Docker Python runtime packages * Fix Docker CA smoke teardown * Refresh Elsa roadmap * Implement background processors and mediation coordination - Added `BackgroundCommandProcessor`, `BackgroundJobProcessor`, and `BackgroundNotificationProcessor` classes for handling commands, jobs, and notifications, respectively. - Introduced `MediatorBackgroundProcessingCoordinator` to coordinate the execution of all background processors. - Implemented `MediatorBackgroundTask` for wrapping `MediatorBackgroundProcessingCoordinator` in `BackgroundTask`. - Added unit tests for `MediatorBackgroundTask` to ensure proper start and stop behavior. - Refactored `BackgroundCommandSenderHostedService` to utilize `BackgroundCommandProcessor`. - Introduced 'elsa-roadmap-refresh' skill configuration for roadmap updates. * Address workflow type resolution review feedback * Address follow-up review feedback * Restore recent console logs execute path * Address Copilot follow-up review * Decouple workflow JSON aliases from expressions * Fix workflow management unit test setup * Fix console logs recent endpoint handler shape * Respect workflow JSON strict type aliases * Remove unused console log contracts reference * Address Copilot review feedback * Address Copilot follow-up comments * Synchronize ring buffer dropped count * Address background processor strategy replay
2026-05-30 20:52:01 +00:00
using System.Security.Claims;
using Elsa.Diagnostics.OpenTelemetry.Contracts;
using Elsa.Diagnostics.OpenTelemetry.Models;
using Elsa.Diagnostics.OpenTelemetry.Options;
using Elsa.Diagnostics.OpenTelemetry.Permissions;
using Elsa.Diagnostics.OpenTelemetry.Providers.InMemory;
using Elsa.Diagnostics.OpenTelemetry.RealTime;
using FastEndpoints;
using FastEndpoints.Security;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.SignalR;
using Microsoft.Extensions.Logging.Abstractions;
using Xunit.Sdk;
using OptionsFactory = Microsoft.Extensions.Options.Options;
namespace Elsa.Diagnostics.OpenTelemetry.IntegrationTests;
public class OpenTelemetryHubTests
{
private readonly DateTimeOffset _now = new(2026, 5, 26, 10, 0, 0, TimeSpan.Zero);
[Fact]
public async Task SubscribeAsync_WhenUserLacksPermission_DeniesAccess()
{
feat(auth)!: structured authorization model, phases 1-6 (#7980) * feat(auth): add the permission model and evaluator (Phase 1) Additive only. Nothing changes behavior: no endpoint declares against this yet, and no existing enforcement path routes through it. A permission is {resource}:{verb}, both axes open and string-keyed. A trailing wildcard on the resource axis matches the named node and every descendant at any depth, so workflows/definitions/* covers workflows/definitions itself; * on the verb axis matches any verb. Wildcards are the only construct with forward reach. A bare * parses to *:* at parse time rather than being special-cased in the evaluator, so superuser stays an ordinary grant and a stored or seeded * keeps authorizing across the vocabulary migration without a lock-out window. Adds: - Permission, with parsing that rejects a value containing a comma, since the persistence converter joins collections with one - CoreVerbs, the recommended set modules should reuse; a convention rather than a closed vocabulary - PermissionMatcher, one matching rule shape on both axes - IPermissionEvaluator, the single place permission decisions are made, skipping malformed claims so one bad stored grant cannot deny a principal - PermissionRequirement and PermissionAuthorizationHandler - The descriptor catalog in core: PermissionDescriptor now carries the verbs a resource supports and marks non-core ones, and the registry can report what a wildcard covers today External Authentication keeps its own descriptor types for now; it moves to the core catalog with the other modules in Phase 2, which keeps this change purely additive. 55 unit tests cover the matcher table, wildcard forward reach, the counterpart that concrete grants stay frozen, absence-is-denial, and the seeded * case. Refs #7974 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * feat(auth): contribute the permission catalog from every module (Phase 2) Still additive. Existing endpoints keep their legacy declarations; nothing changes behavior for them. Every module exposing protected endpoints now declares its resources and the verbs each accepts, following the pattern already proven in External Authentication -- constants and descriptors colocated -- refined to one constant per resource, with the verb supplied separately. 47 resources across 15 modules, matching the settled vocabulary. Descriptors are discovered from the same assemblies as a module's endpoints, in AddFastEndpointsFromModule. Registering them per module would let the catalog and the endpoints drift, which is the failure this model exists to remove; tying them to one registration makes the catalog necessarily describe the endpoints that exist. Adds: - GET /identity/permissions, the catalog a role editor renders from, so no client hard-codes permission strings - GET /identity/permissions/reach, reporting what a wildcard covers today. This is the mitigation for forward reach on the resource axis: a wildcard is useful precisely because it covers things that do not exist yet, so an author needs to see what it reaches now - GET /identity/me/permissions, resolving wildcards to concrete verbs so a client needs no matching logic, and listing denied resources with an empty verb list so "denied" is distinguishable from "unknown" - IPermissionGrantValidator, wired into Roles/Create and Roles/Update, which previously persisted request.Permissions after only the caller-subset check. Concrete segments validate against the catalog; wildcards validate structurally and are accepted even when they match nothing today, since installing a module later is what gives such a grant meaning - RequirePermission(resource, verb) and RequireAuthenticatedOnly() on the endpoint base classes, with the six copy-pasted ConfigurePermissions bodies collapsed into one implementation New endpoints require new-format grants, so during the transition they authorize only for holders of *, which parses to *:*. Phase 3 migrates the rest and closes that gap. 70 unit tests, including the wildcard-accepting validator cases. Refs #7974 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * feat(auth)!: cut every endpoint over to the permission model (Phase 3) BREAKING: legacy permission strings no longer authorize. A permanent alias layer would keep two vocabularies valid forever, so the break is deliberate and reported rather than absorbed. `*` survives unchanged -- it parses to `*:*` -- so an administrator cannot be locked out while roles are re-authored. All 168 declaration call sites across 151 files now use RequirePermission(resource, verb) with the constants their module declares, so a typo is a compile error rather than an unreachable endpoint. Enforcement consolidated onto IPermissionEvaluator: - RoleAuthorizationService evaluates containment through the evaluator rather than by set membership. This matters: a caller holding workflows/*:view can now delegate workflows/definitions:view, which set membership got wrong and which would otherwise force administrators to hold every concrete grant they wish to delegate. - The two Broker/Logout.cs endpoints declare explicitly. Logout is authenticated-only; ContinueLogout is anonymous, matching every other broker callback -- the route handle carries the authority and a top-level browser navigation sends no Authorization header. Removes the C#/Python expression permissions (#7975). They conflated an incoherent execution-side gate -- a workflow runs under the server's authority, not the caller's, so the check never constrained what a script could do -- with a meaningful authoring-side one. The host switch (AllowHostCodeExecution) becomes the single control. This is a deliberate reduction in control: where host code is enabled, any author who may write definitions may use C# and Python. Adds the fail-closed gate. Omitting a declaration previously inherited the FastEndpoints default with no Elsa-level fallback, so an endpoint could ship ungated unnoticed. EndpointCoverage asserts every endpoint declares exactly one of RequirePermission, RequireAuthenticatedOnly or AllowAnonymous, with no exemption list. Its canary assertion earned its keep immediately by catching that the gate was scanning an assembly containing no endpoints. EndpointPermissionRegistry records what each endpoint declares. The requirement is attached as an inline policy and is not readable back from the definition, so this keeps the declaration introspectable -- and lets tests assert a specific requirement rather than merely that one exists. Two behavior notes worth calling out: - The runtime status endpoint previously accepted either the read or the manage permission. It now requires workflows/runtime:view alone, which is least privilege; a role holding only control must also be granted view to read status. - BPMN interchange repeats the workflow-definitions path locally rather than taking a dependency on Elsa.Workflows.Api for one constant. It contributes no descriptor: the resource is owned and described by Workflows.Api, and the registry keeps one entry per resource. Also adds a startup validator that logs every stored role permission that no longer resolves, identified by role, so an upgrade is loud. 188 unit tests pass across Api.Common, Workflows.Api and Identity. Refs #7974, #7975, #7976 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * feat(auth): revocation bound and role audit notifications (Phase 4) Default access-token lifetime drops from 1 hour to 15 minutes. This is the revocation bound: permission claims are issued at sign-in and refresh re-reads the user's roles, so removing a role takes effect at most one access-token lifetime later. Refresh already rotates both tokens, so no client change is required and the refresh lifetime is unchanged. Adds an optional permission stamp for deployments needing a tighter bound. The stamp is derived from the user's roles and their permissions rather than stored as a counter on the user. That avoids changing the Identity schema, which would have required migrations across all five EF providers and made this milestone depend on the tenancy work. It also means every node computes the same value from the same store with no cross-node cache invalidation, which matters because Elsa has none. The stamp is issued unconditionally and only validated when enabled, so turning it on does not invalidate tokens already in flight; an absent stamp is not treated as a mismatch for the same reason. It changes when a role is added to or removed from the user and when a held role's permissions change, but not when an unrelated role changes. Role create and update now publish typed security notifications per ADR 0007, carrying the resulting grants so a reviewer can reconstruct what a role conferred at a point in time without replaying every prior event. This module owns no audit store: a future audit module subscribes and sets its own retention. Refs #7974 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * feat(auth): tenancy hardening for identity (Phase 5) Closes the gaps that made "roles are configurable per tenant" untrue however the rest of the stack behaved. Uniqueness becomes per tenant. User.Name, Role.Name, Application.Name and Application.ClientId carried globally unique indexes, so two tenants could not both hold a role named Admin. Migrations for all five EF providers drop the global indexes and create composite ones on (TenantId, Name). The in-memory user and role stores now scope to the ambient tenant. Isolation previously existed only on the Entity Framework path, and only when multitenancy was enabled, so a deployment running the default stores had none at all. The tenant-agnostic sentinel is honored, matching the EF query filter, so a shared platform role stays visible from every tenant. RoleFilter gains TenantId, matching UserFilter, and the role and user list endpoints pass it explicitly rather than relying on an ambient filter that only exists on one persistence path. UserManager.CreateUserAsync sets TenantId explicitly instead of relying on the EF saving handler, which does not run in memory and left users unassigned there. Refs #7974 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * docs: migration guide, ADR, and security wiki for the authorization model Adds docs/migrations/authorization-model.md, following the shape of the external-authentication persistence guide. It leads with the three things that are not a simple rename, because each silently produces a wrong result if treated as one: - The migration expands where new sub-resources are finer-grained than what they replace, so a one-for-one substitution narrows roles. - read:* and exec:* become materially more powerful. They are literal claim values today, authorizing twelve of roughly forty read endpoints; their replacements work as the names always implied. Any role holding them needs review by hand, not an automated rewrite. - The C#/Python expression permissions are removed rather than translated, which is a deliberate reduction in control where host code is enabled. It also states plainly that `*` keeps working, and says to do that first, since it is what stops an instance locking itself out mid-migration. ADR 0012 records the model and, more usefully, why a closed verb enumeration was drafted and rejected: it was justified on implication, but aggregates were already excluded and no verb implies another, so the bitwise check was expressing set containment all along. The security wiki's API Authorization section replaces its Secrets-only route table with the catalog endpoint as the authoritative source, and states why read-only mode is a separate axis rather than a permission. Refs #7974 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * test(auth): restore the suites after the tenancy and evaluator changes The whole solution builds with zero errors and every affected suite passes: 70 Api.Common, 23 Workflows.Api, 95 Identity, 154 External Authentication unit, 133 External Authentication integration. Most breakage was test call sites constructing the tenant-aware stores and the evaluator-backed RoleAuthorizationService directly. Adds TestTenantAccessor to Elsa.Testing.Shared rather than giving the production constructors an optional accessor, which would have let a missing registration silently disable isolation. Several External Authentication tests created fixtures in tenant-a while running under the default tenant, so the newly isolating store correctly stopped finding them. They are now scoped to the tenant their own fixtures use; JustInTimeProvisioningTests, which genuinely spans two tenants, is scoped per case. One production fix came out of it: IdentityFeature now ensures an ITenantAccessor with TryAdd. The identity stores are tenant-scoped, so a host that never enables multitenancy would otherwise fail to construct them -- which is what the DI registration tests were reporting. TryAdd leaves MultitenancyFeature's own registration untouched. Refs #7974 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(auth): register the identity services on the classic feature path Found by running Elsa.Server.Web, not by the test suites: the app failed at startup with "Unable to resolve service for type RoleSecurityNotifier while attempting to activate Roles.Update". RoleSecurityNotifier, the permission stamp services, the memory cache and the stored-permission validator were registered only in the CShells shell feature. Elsa.Server.Web uses the classic UseIdentity() path, whose IdentityFeature registered none of them, so every host on that path crashed while mapping endpoints. Unit tests did not catch it because they construct services directly rather than through either feature. Verified end to end against the running server: - The seeded admin role stores "*". It parsed to *:* and resolved to concrete verbs across all 27 registered resources, which is the bare-wildcard parse rule working on real data rather than in a test. - GET /identity/permissions returns the catalog for the modules this app installs -- 27 resources, 0 unverified, categories Dashboard, Identity, Resilience and Workflows -- rather than all 47, which is correct: the catalog describes what is installed. - GET /identity/permissions/reach?resource=workflows/* reports 19 covered resources. - A role holding only dashboard:view gets 200 on /dashboard/overview and 403 on /identity/roles, /identity/users, /workflow-definitions and /identity/permissions, while /identity/me/permissions returns 200 because it declares RequireAuthenticatedOnly -- confirming FR-019's third declaration state behaves as designed. - That same principal's /me/permissions lists all 27 resources with 26 carrying an empty verb list, so "denied" stays distinguishable from "unknown to this server". - The startup validator logged no unresolvable permissions, as expected for a seed holding only "*". Refs #7974 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(auth): discover permission descriptors on the shell host path Found by running Elsa.ModularServer.Web. The shell host started cleanly and authorized correctly, but GET /identity/permissions returned zero resources and /identity/me/permissions returned no grants. Descriptor discovery was wired into AddFastEndpointsFromModule, which only the classic module path calls. CShells discovers endpoints from features implementing its own marker interface, so on a shell host no provider was ever registered. Authorization still worked, because the evaluator reads claims and needs no descriptors -- which is exactly why nothing failed loudly. What silently broke was everything built on the catalog: role authoring would have rejected every concrete grant as an unknown resource, introspection returned nothing for clients to render, and the stored-permission validator would have reported every concrete stored permission as unresolvable. ElsaFastEndpointsFeature now contributes descriptors from the loaded Elsa assemblies, bounded to those and run once per shell. Verified on the modular host, which installs far more modules than Elsa.Server.Web: - 47 resources registered, 0 unverified, across all 12 categories, with all 17 module-specific verbs present. That is the entire published vocabulary confirmed against a running server rather than a document. - Reach reports workflows/* covering 20, external-authentication/* covering 8, and * covering 47. - Creating a role with dashboard:view and workflows/*:view succeeds, confirming a wildcard grant survives authoring validation. - Creating one with invented/resource:view and secrets:publish is rejected with 400. Also makes those rejections actionable. The permission was reported without the reason, so an operator learned which entry was wrong but not why; both parts are now in the message, including the supported verbs for the resource. Refs #7974 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * wip: bpmn test vocabulary * fix(auth): make enforcement DI-independent and finish the hub cutover CI on #7980 was red. Running the full suite locally rather than the subset I had been checking surfaced 24 failures across four projects, in three distinct classes. Enforcement no longer depends on a DI registration. RequirePermission attached a PermissionRequirement evaluated by a registered handler, so a host that had not called AddElsaAuthorization got 403 on every endpoint with nothing to indicate why. Several test hosts wire FastEndpoints directly and did exactly that. The requirement is now evaluated inline against a shared stateless evaluator, with a host-registered IPermissionEvaluator still taking precedence. Registration remains worthwhile for the catalog and the validator; authorization can no longer silently fail closed because of a missing one. Registration also moved from AddFastEndpointsFromModule to AddFastEndpointsAssembly. Registering an endpoint assembly is what should guarantee its permissions work, and a host may never call the former. Finishes T039. The four SignalR hubs still matched hard-coded legacy permission strings, which no longer exist, so every hub denied access. They now route through the evaluator like every other enforcement path. Test fixtures granting legacy strings were updated to the new vocabulary. Two categories were deliberately left alone: naming tests asserting the legacy constants still hold their old values, which is true and worth keeping, and the workflow script authorization tests, which asserted a MissingPermission outcome that D21 removed -- those now assert the host switch is the only control. One test previously pinned that the hub honors a FastEndpoints-configured permissions claim type. It now asserts the opposite, and says why: Elsa is the only authority that expands roles into permission claims (ADR 0009), and this model no longer uses the FastEndpoints permission mechanism, so its separately configurable claim type is not consulted. That property is also unreadable outside reflection. Whole solution builds with 0 errors and every test project passes. Refs #7974 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(auth): scope the permission-stamp cache to the tenant Greptile found and reproduced a cross-tenant authorization bug, and it was mine: Phase 5 made user names unique per tenant rather than globally, but PermissionStampValidator kept caching by user name alone. Tenant A's lookup could therefore populate the cache with its own stamp and satisfy a revoked token belonging to a same-named user in tenant B, without ever resolving tenant B's user. Both the cache key and the user lookup are now tenant-scoped. Added PermissionStampValidatorTests, including the cross-tenant case; verified it fails without the fix and passes with it. Also from review: - Removed the legacy permission constants left unused in the three hubs after they moved to the evaluator, so no stale vocabulary lingers. - Narrowed two generic catch clauses. The IL scanner now catches only the exceptions an unresolvable metadata token actually throws, and the startup validator rethrows cancellation while still refusing to stop the host for anything else -- an unreachable or half-migrated store is exactly when an operator most needs the host up. Whole solution builds with 0 errors and every test project passes. Refs #7974 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(docs): correct path in log message for authorization model migration link Aligns the log message path to the correct documentation directory, changing `docs` to `doc` to avoid confusion and incorrect linking during log output. * fix(auth): update permissions method to use new syntax * docs: consolidate docs/ into doc/ The repository had two documentation roots. Merge docs/ into doc/ and remove the empty docs/ tree. The two adr/ folders both numbered from 0001, so the identity and authorization series is renumbered to continue the core series rather than collide with it: docs/adr/0001-0012 -> doc/adr/0014-0025 Every reference is updated to match: the Status cross-links between the renumbered ADRs, the ADR and path links in specs/012-external-authentication and specs/013-rbac-authorization-model, and doc/wiki/identity-tenancy-security.md. doc/adr/toc.md gains entries 14-25. doc/adr/graph.dot is regenerated out to 25; it had been stale since ADR 10 and now also carries the partial supersession edges declared by the ADRs themselves. docs/codebase/ and docs/migrations/ move across unchanged. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * refactor(auth): simplify syntax in PermissionEvaluator and related classes Streamlined syntax for method definitions by using expression-bodied members and simplified object instantiations across the Authorization module. This includes adjustments in `PermissionEvaluator`, `LocalHostRequirement`, and `WebApplicationExtensions` for better readability and maintainability. * ci(bounty): point the footer step at the file's real path The bounty workflow read docs/bounty-footer.md, the path the file had when the workflow was added in b421b00e1. The file later moved to doc/bounty/bounty-footer.md and the workflow was never updated, so the read step has been resolving nothing and the appended comment was empty. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-08-24 21:44:55 +00:00
var hub = CreateHub(new TestLiveFeed(), "diagnostics/opentelemetry:write");
[codex] Fix console log metadata and type resolution (#7542) * Avoid null endpoint DTO metadata in tests * Enforce console logs hub read permission * Remove unused console logs hub import * Support mapped endpoint metadata in auth tests * Reduce console log capture throughput impact * Address Copilot console logs review * Refactor task scheduling to support tenant-level background work and enhance logging functionality. * Introduce ConsoleStreamHook for stdout/stderr tee and enhance logging validation. Adjust test cases and startup warnings for distributed lock provider usage. * Refactor console logging pipeline with capture optimization and new ConsoleLogsHost; update tests accordingly. * Add Ansi SGR parser for console logs and associated unit tests * Remove ANSI color renderings and parsers; integrate ConsoleLogScopeAccessor for improved logging context with workflow instance ID support. * Address console logs code quality feedback * Address PR review feedback * Preserve console logs extension points * Stabilize console logs host lifecycle * Address final automated review comments * Tighten console log capture shutdown * Address console log review feedback * Address follow-up review feedback * Cover final review feedback * Avoid recursive console provider initialization * Guard console host lease shutdown * Preserve console log scope and provider lifetime * Correlate console log scope fallback * Tighten console scope correlation * Expose host services during provider construction * Redact ANSI-normalized console lines * Add OpenTelemetry diagnostics backend foundation * Add OTLP HTTP ingestion parsing * Document OpenTelemetry diagnostics setup * Enforce OpenTelemetry hub permissions * Remove `ConsoleCaptureTee` and related services and tests * Add OpenTelemetry HTTP ingestion integration test * Use pipeline contributors for console log context * Update CShells package versions to 0.0.24-preview.132 * Add OpenTelemetry ingestion security tests * Add OpenTelemetry API authorization tests * Filter live console logs by workflow instance * Add OpenTelemetry hub tests * Add OpenTelemetry gRPC metadata hook * Assert OpenTelemetry workflow tags survive ingestion * Mark OpenTelemetry core build verified * Enhance console logging with activity execution metadata and extend test coverage. * Address console logs stream consumption comment * Wire OpenTelemetry diagnostics into core sample * Address Core diagnostics review feedback * Address Core Copilot follow-up feedback * Add OpenTelemetry metric instrument names * Address Core Copilot provider feedback * Address Core Copilot diagnostics follow-up * Address Core Copilot live feed feedback * Address Core Copilot store feedback * Integrate OpenTelemetry for logging, tracing, and metrics in ModularServer and update launch settings and docker-compose configuration. * Refactor to replace `ConsoleLogStream.Core` with `ConsoleLogStreaming.Core` across codebase and update `ConsoleStreamHook` installation. * Add diagnostics OpenTelemetry backend * Fix OpenTelemetry live hub subscription * Fix modular OpenTelemetry exporter endpoints * Add CShells logging configuration in appsettings.json * Remove obsolete unit tests and helper classes * Restore default activity exception handling * Simplify type serialization and alias management This commit refactors the internal type serialization and alias management system to reduce boilerplate, improve robustness, and simplify the developer experience: - Removed numerous explicit `ExpressionOptions` type alias registrations across various modules. - Updated `TypeJsonConverter` and polymorphic serialization to reliably handle types using assembly-qualified names when a short alias is not explicitly registered. - Streamlined `ExcludeFromHashConverter` to strictly adhere to `ExcludeFromHashAttribute` for hash calculations, removing complex `JsonIgnoreCondition` logic. - Eliminated several helper classes (`WorkflowJsonTypeResolver`, `WorkflowTypeValidator`, `IWorkflowTypeRegistry`, `WorkflowFactoryDictionary`, `JavaScriptExceptionTypeAliasRegistrar`, `WorkflowRuntimeTypeAliasRegistrar`) and their associated unit tests, simplifying the codebase. Additionally, this commit introduces a comprehensive markdown document (`product-website-feature-source.md`) outlining Elsa's core features, Studio capabilities, extension ecosystem, and architectural selling points, intended as source material for the product website. * Refine type serialization for improved robustness and alias handling This commit further enhances the type serialization and deserialization mechanisms: * Centralizes type resolution and alias management through `IWellKnownTypeRegistry` and `WorkflowJsonTypeResolver`. * Prioritizes registered type aliases when serializing type metadata in `PolymorphicObjectConverter`, resulting in more concise JSON output. * Enhances deserialization in `PolymorphicObjectConverter` and `VariableMapper` to gracefully handle unknown or non-instantiable types, providing fallbacks and logging warnings. * Simplifies `TypeJsonConverter` by delegating complex type resolution logic to the `WorkflowJsonTypeResolver`. * Adds `JsonArray` to the well-known type aliases for direct recognition. * Fix console logs packaging and workflow type resolution * Fix console log metadata and type resolution * Address Copilot review feedback * Enhance type resolution, improve console log handling, and update tests - Streamlined `WorkflowDictionaryExtensions` for better workflow registration validation. - Refined `ConsoleLogsAuthorizationTests` with the new `SetJsonRequest` helper to improve test requests handling. - Updated `OrderDefinition` to ignore JSON serialization for `KeySelector`. - Enhanced `WorkflowRuntimeFeature` for improved workflow registration and type alias configuration. - Added tests to ensure `ConsoleLogProvider` metadata filtration in various scenarios. - Improved type serialization logic in `WorkflowJsonTypeResolver`. - Updated README to fix references related to diagnostics. - Optimized `ExcludeFromHashConverter` for property serialization conditions. - Modified `TriggerIndexer` for streamlined trigger management. - Tested payload checks in `PublishEventTests`. - Adjusted `Endpoint` in `ConsoleLogs` for automatic JSON request handling. - Ensured registration of workflow type aliases in `WorkflowsFeature`. * Restore CLR workflow registration compatibility * Align JSON island serialization fixtures * Add Console Logs Services and Enhance Endpoint Handling - Introduced `ActivityExecutionsEndpointTests` to validate route exposure. - Added `ConsoleLogCaptureHostedService` for console log streaming. - Implemented `ConsoleStreamJsonConverter` for JSON conversion of console streams. - Developed `ElsaConsoleLogRecentBuffer` to handle recent log buffering. - Updated `ConsoleLogsAuthorizationTests` with new test cases for stream filter mapping. - Consolidated console log provider dependencies and registration, including recent buffering. - Enhanced `ElsaConsoleLogProvider` to use recent buffer for filtering. - Adjusted `Program.cs` for streamlined logging service setup. * Enhance type resolution and test coverage; streamline console log integration - Added `ConsoleStreamHook` for streamlined log streaming. - Updated `WorkflowJsonTypeResolverTests` to improve type resolution and test new scenarios. - Simplified type resolution by removing trusted assembly checks. * Fix CI smoke and package restore failures * Fix Docker smoke image project paths * Fix Docker Python runtime packages * Fix Docker CA smoke teardown * Refresh Elsa roadmap * Implement background processors and mediation coordination - Added `BackgroundCommandProcessor`, `BackgroundJobProcessor`, and `BackgroundNotificationProcessor` classes for handling commands, jobs, and notifications, respectively. - Introduced `MediatorBackgroundProcessingCoordinator` to coordinate the execution of all background processors. - Implemented `MediatorBackgroundTask` for wrapping `MediatorBackgroundProcessingCoordinator` in `BackgroundTask`. - Added unit tests for `MediatorBackgroundTask` to ensure proper start and stop behavior. - Refactored `BackgroundCommandSenderHostedService` to utilize `BackgroundCommandProcessor`. - Introduced 'elsa-roadmap-refresh' skill configuration for roadmap updates. * Address workflow type resolution review feedback * Address follow-up review feedback * Restore recent console logs execute path * Address Copilot follow-up review * Decouple workflow JSON aliases from expressions * Fix workflow management unit test setup * Fix console logs recent endpoint handler shape * Respect workflow JSON strict type aliases * Remove unused console log contracts reference * Address Copilot review feedback * Address Copilot follow-up comments * Synchronize ring buffer dropped count * Address background processor strategy replay
2026-05-30 20:52:01 +00:00
await Assert.ThrowsAsync<HubException>(() => hub.SubscribeAsync(new()));
}
[Theory]
feat(auth)!: structured authorization model, phases 1-6 (#7980) * feat(auth): add the permission model and evaluator (Phase 1) Additive only. Nothing changes behavior: no endpoint declares against this yet, and no existing enforcement path routes through it. A permission is {resource}:{verb}, both axes open and string-keyed. A trailing wildcard on the resource axis matches the named node and every descendant at any depth, so workflows/definitions/* covers workflows/definitions itself; * on the verb axis matches any verb. Wildcards are the only construct with forward reach. A bare * parses to *:* at parse time rather than being special-cased in the evaluator, so superuser stays an ordinary grant and a stored or seeded * keeps authorizing across the vocabulary migration without a lock-out window. Adds: - Permission, with parsing that rejects a value containing a comma, since the persistence converter joins collections with one - CoreVerbs, the recommended set modules should reuse; a convention rather than a closed vocabulary - PermissionMatcher, one matching rule shape on both axes - IPermissionEvaluator, the single place permission decisions are made, skipping malformed claims so one bad stored grant cannot deny a principal - PermissionRequirement and PermissionAuthorizationHandler - The descriptor catalog in core: PermissionDescriptor now carries the verbs a resource supports and marks non-core ones, and the registry can report what a wildcard covers today External Authentication keeps its own descriptor types for now; it moves to the core catalog with the other modules in Phase 2, which keeps this change purely additive. 55 unit tests cover the matcher table, wildcard forward reach, the counterpart that concrete grants stay frozen, absence-is-denial, and the seeded * case. Refs #7974 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * feat(auth): contribute the permission catalog from every module (Phase 2) Still additive. Existing endpoints keep their legacy declarations; nothing changes behavior for them. Every module exposing protected endpoints now declares its resources and the verbs each accepts, following the pattern already proven in External Authentication -- constants and descriptors colocated -- refined to one constant per resource, with the verb supplied separately. 47 resources across 15 modules, matching the settled vocabulary. Descriptors are discovered from the same assemblies as a module's endpoints, in AddFastEndpointsFromModule. Registering them per module would let the catalog and the endpoints drift, which is the failure this model exists to remove; tying them to one registration makes the catalog necessarily describe the endpoints that exist. Adds: - GET /identity/permissions, the catalog a role editor renders from, so no client hard-codes permission strings - GET /identity/permissions/reach, reporting what a wildcard covers today. This is the mitigation for forward reach on the resource axis: a wildcard is useful precisely because it covers things that do not exist yet, so an author needs to see what it reaches now - GET /identity/me/permissions, resolving wildcards to concrete verbs so a client needs no matching logic, and listing denied resources with an empty verb list so "denied" is distinguishable from "unknown" - IPermissionGrantValidator, wired into Roles/Create and Roles/Update, which previously persisted request.Permissions after only the caller-subset check. Concrete segments validate against the catalog; wildcards validate structurally and are accepted even when they match nothing today, since installing a module later is what gives such a grant meaning - RequirePermission(resource, verb) and RequireAuthenticatedOnly() on the endpoint base classes, with the six copy-pasted ConfigurePermissions bodies collapsed into one implementation New endpoints require new-format grants, so during the transition they authorize only for holders of *, which parses to *:*. Phase 3 migrates the rest and closes that gap. 70 unit tests, including the wildcard-accepting validator cases. Refs #7974 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * feat(auth)!: cut every endpoint over to the permission model (Phase 3) BREAKING: legacy permission strings no longer authorize. A permanent alias layer would keep two vocabularies valid forever, so the break is deliberate and reported rather than absorbed. `*` survives unchanged -- it parses to `*:*` -- so an administrator cannot be locked out while roles are re-authored. All 168 declaration call sites across 151 files now use RequirePermission(resource, verb) with the constants their module declares, so a typo is a compile error rather than an unreachable endpoint. Enforcement consolidated onto IPermissionEvaluator: - RoleAuthorizationService evaluates containment through the evaluator rather than by set membership. This matters: a caller holding workflows/*:view can now delegate workflows/definitions:view, which set membership got wrong and which would otherwise force administrators to hold every concrete grant they wish to delegate. - The two Broker/Logout.cs endpoints declare explicitly. Logout is authenticated-only; ContinueLogout is anonymous, matching every other broker callback -- the route handle carries the authority and a top-level browser navigation sends no Authorization header. Removes the C#/Python expression permissions (#7975). They conflated an incoherent execution-side gate -- a workflow runs under the server's authority, not the caller's, so the check never constrained what a script could do -- with a meaningful authoring-side one. The host switch (AllowHostCodeExecution) becomes the single control. This is a deliberate reduction in control: where host code is enabled, any author who may write definitions may use C# and Python. Adds the fail-closed gate. Omitting a declaration previously inherited the FastEndpoints default with no Elsa-level fallback, so an endpoint could ship ungated unnoticed. EndpointCoverage asserts every endpoint declares exactly one of RequirePermission, RequireAuthenticatedOnly or AllowAnonymous, with no exemption list. Its canary assertion earned its keep immediately by catching that the gate was scanning an assembly containing no endpoints. EndpointPermissionRegistry records what each endpoint declares. The requirement is attached as an inline policy and is not readable back from the definition, so this keeps the declaration introspectable -- and lets tests assert a specific requirement rather than merely that one exists. Two behavior notes worth calling out: - The runtime status endpoint previously accepted either the read or the manage permission. It now requires workflows/runtime:view alone, which is least privilege; a role holding only control must also be granted view to read status. - BPMN interchange repeats the workflow-definitions path locally rather than taking a dependency on Elsa.Workflows.Api for one constant. It contributes no descriptor: the resource is owned and described by Workflows.Api, and the registry keeps one entry per resource. Also adds a startup validator that logs every stored role permission that no longer resolves, identified by role, so an upgrade is loud. 188 unit tests pass across Api.Common, Workflows.Api and Identity. Refs #7974, #7975, #7976 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * feat(auth): revocation bound and role audit notifications (Phase 4) Default access-token lifetime drops from 1 hour to 15 minutes. This is the revocation bound: permission claims are issued at sign-in and refresh re-reads the user's roles, so removing a role takes effect at most one access-token lifetime later. Refresh already rotates both tokens, so no client change is required and the refresh lifetime is unchanged. Adds an optional permission stamp for deployments needing a tighter bound. The stamp is derived from the user's roles and their permissions rather than stored as a counter on the user. That avoids changing the Identity schema, which would have required migrations across all five EF providers and made this milestone depend on the tenancy work. It also means every node computes the same value from the same store with no cross-node cache invalidation, which matters because Elsa has none. The stamp is issued unconditionally and only validated when enabled, so turning it on does not invalidate tokens already in flight; an absent stamp is not treated as a mismatch for the same reason. It changes when a role is added to or removed from the user and when a held role's permissions change, but not when an unrelated role changes. Role create and update now publish typed security notifications per ADR 0007, carrying the resulting grants so a reviewer can reconstruct what a role conferred at a point in time without replaying every prior event. This module owns no audit store: a future audit module subscribes and sets its own retention. Refs #7974 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * feat(auth): tenancy hardening for identity (Phase 5) Closes the gaps that made "roles are configurable per tenant" untrue however the rest of the stack behaved. Uniqueness becomes per tenant. User.Name, Role.Name, Application.Name and Application.ClientId carried globally unique indexes, so two tenants could not both hold a role named Admin. Migrations for all five EF providers drop the global indexes and create composite ones on (TenantId, Name). The in-memory user and role stores now scope to the ambient tenant. Isolation previously existed only on the Entity Framework path, and only when multitenancy was enabled, so a deployment running the default stores had none at all. The tenant-agnostic sentinel is honored, matching the EF query filter, so a shared platform role stays visible from every tenant. RoleFilter gains TenantId, matching UserFilter, and the role and user list endpoints pass it explicitly rather than relying on an ambient filter that only exists on one persistence path. UserManager.CreateUserAsync sets TenantId explicitly instead of relying on the EF saving handler, which does not run in memory and left users unassigned there. Refs #7974 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * docs: migration guide, ADR, and security wiki for the authorization model Adds docs/migrations/authorization-model.md, following the shape of the external-authentication persistence guide. It leads with the three things that are not a simple rename, because each silently produces a wrong result if treated as one: - The migration expands where new sub-resources are finer-grained than what they replace, so a one-for-one substitution narrows roles. - read:* and exec:* become materially more powerful. They are literal claim values today, authorizing twelve of roughly forty read endpoints; their replacements work as the names always implied. Any role holding them needs review by hand, not an automated rewrite. - The C#/Python expression permissions are removed rather than translated, which is a deliberate reduction in control where host code is enabled. It also states plainly that `*` keeps working, and says to do that first, since it is what stops an instance locking itself out mid-migration. ADR 0012 records the model and, more usefully, why a closed verb enumeration was drafted and rejected: it was justified on implication, but aggregates were already excluded and no verb implies another, so the bitwise check was expressing set containment all along. The security wiki's API Authorization section replaces its Secrets-only route table with the catalog endpoint as the authoritative source, and states why read-only mode is a separate axis rather than a permission. Refs #7974 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * test(auth): restore the suites after the tenancy and evaluator changes The whole solution builds with zero errors and every affected suite passes: 70 Api.Common, 23 Workflows.Api, 95 Identity, 154 External Authentication unit, 133 External Authentication integration. Most breakage was test call sites constructing the tenant-aware stores and the evaluator-backed RoleAuthorizationService directly. Adds TestTenantAccessor to Elsa.Testing.Shared rather than giving the production constructors an optional accessor, which would have let a missing registration silently disable isolation. Several External Authentication tests created fixtures in tenant-a while running under the default tenant, so the newly isolating store correctly stopped finding them. They are now scoped to the tenant their own fixtures use; JustInTimeProvisioningTests, which genuinely spans two tenants, is scoped per case. One production fix came out of it: IdentityFeature now ensures an ITenantAccessor with TryAdd. The identity stores are tenant-scoped, so a host that never enables multitenancy would otherwise fail to construct them -- which is what the DI registration tests were reporting. TryAdd leaves MultitenancyFeature's own registration untouched. Refs #7974 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(auth): register the identity services on the classic feature path Found by running Elsa.Server.Web, not by the test suites: the app failed at startup with "Unable to resolve service for type RoleSecurityNotifier while attempting to activate Roles.Update". RoleSecurityNotifier, the permission stamp services, the memory cache and the stored-permission validator were registered only in the CShells shell feature. Elsa.Server.Web uses the classic UseIdentity() path, whose IdentityFeature registered none of them, so every host on that path crashed while mapping endpoints. Unit tests did not catch it because they construct services directly rather than through either feature. Verified end to end against the running server: - The seeded admin role stores "*". It parsed to *:* and resolved to concrete verbs across all 27 registered resources, which is the bare-wildcard parse rule working on real data rather than in a test. - GET /identity/permissions returns the catalog for the modules this app installs -- 27 resources, 0 unverified, categories Dashboard, Identity, Resilience and Workflows -- rather than all 47, which is correct: the catalog describes what is installed. - GET /identity/permissions/reach?resource=workflows/* reports 19 covered resources. - A role holding only dashboard:view gets 200 on /dashboard/overview and 403 on /identity/roles, /identity/users, /workflow-definitions and /identity/permissions, while /identity/me/permissions returns 200 because it declares RequireAuthenticatedOnly -- confirming FR-019's third declaration state behaves as designed. - That same principal's /me/permissions lists all 27 resources with 26 carrying an empty verb list, so "denied" stays distinguishable from "unknown to this server". - The startup validator logged no unresolvable permissions, as expected for a seed holding only "*". Refs #7974 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(auth): discover permission descriptors on the shell host path Found by running Elsa.ModularServer.Web. The shell host started cleanly and authorized correctly, but GET /identity/permissions returned zero resources and /identity/me/permissions returned no grants. Descriptor discovery was wired into AddFastEndpointsFromModule, which only the classic module path calls. CShells discovers endpoints from features implementing its own marker interface, so on a shell host no provider was ever registered. Authorization still worked, because the evaluator reads claims and needs no descriptors -- which is exactly why nothing failed loudly. What silently broke was everything built on the catalog: role authoring would have rejected every concrete grant as an unknown resource, introspection returned nothing for clients to render, and the stored-permission validator would have reported every concrete stored permission as unresolvable. ElsaFastEndpointsFeature now contributes descriptors from the loaded Elsa assemblies, bounded to those and run once per shell. Verified on the modular host, which installs far more modules than Elsa.Server.Web: - 47 resources registered, 0 unverified, across all 12 categories, with all 17 module-specific verbs present. That is the entire published vocabulary confirmed against a running server rather than a document. - Reach reports workflows/* covering 20, external-authentication/* covering 8, and * covering 47. - Creating a role with dashboard:view and workflows/*:view succeeds, confirming a wildcard grant survives authoring validation. - Creating one with invented/resource:view and secrets:publish is rejected with 400. Also makes those rejections actionable. The permission was reported without the reason, so an operator learned which entry was wrong but not why; both parts are now in the message, including the supported verbs for the resource. Refs #7974 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * wip: bpmn test vocabulary * fix(auth): make enforcement DI-independent and finish the hub cutover CI on #7980 was red. Running the full suite locally rather than the subset I had been checking surfaced 24 failures across four projects, in three distinct classes. Enforcement no longer depends on a DI registration. RequirePermission attached a PermissionRequirement evaluated by a registered handler, so a host that had not called AddElsaAuthorization got 403 on every endpoint with nothing to indicate why. Several test hosts wire FastEndpoints directly and did exactly that. The requirement is now evaluated inline against a shared stateless evaluator, with a host-registered IPermissionEvaluator still taking precedence. Registration remains worthwhile for the catalog and the validator; authorization can no longer silently fail closed because of a missing one. Registration also moved from AddFastEndpointsFromModule to AddFastEndpointsAssembly. Registering an endpoint assembly is what should guarantee its permissions work, and a host may never call the former. Finishes T039. The four SignalR hubs still matched hard-coded legacy permission strings, which no longer exist, so every hub denied access. They now route through the evaluator like every other enforcement path. Test fixtures granting legacy strings were updated to the new vocabulary. Two categories were deliberately left alone: naming tests asserting the legacy constants still hold their old values, which is true and worth keeping, and the workflow script authorization tests, which asserted a MissingPermission outcome that D21 removed -- those now assert the host switch is the only control. One test previously pinned that the hub honors a FastEndpoints-configured permissions claim type. It now asserts the opposite, and says why: Elsa is the only authority that expands roles into permission claims (ADR 0009), and this model no longer uses the FastEndpoints permission mechanism, so its separately configurable claim type is not consulted. That property is also unreadable outside reflection. Whole solution builds with 0 errors and every test project passes. Refs #7974 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(auth): scope the permission-stamp cache to the tenant Greptile found and reproduced a cross-tenant authorization bug, and it was mine: Phase 5 made user names unique per tenant rather than globally, but PermissionStampValidator kept caching by user name alone. Tenant A's lookup could therefore populate the cache with its own stamp and satisfy a revoked token belonging to a same-named user in tenant B, without ever resolving tenant B's user. Both the cache key and the user lookup are now tenant-scoped. Added PermissionStampValidatorTests, including the cross-tenant case; verified it fails without the fix and passes with it. Also from review: - Removed the legacy permission constants left unused in the three hubs after they moved to the evaluator, so no stale vocabulary lingers. - Narrowed two generic catch clauses. The IL scanner now catches only the exceptions an unresolvable metadata token actually throws, and the startup validator rethrows cancellation while still refusing to stop the host for anything else -- an unreachable or half-migrated store is exactly when an operator most needs the host up. Whole solution builds with 0 errors and every test project passes. Refs #7974 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(docs): correct path in log message for authorization model migration link Aligns the log message path to the correct documentation directory, changing `docs` to `doc` to avoid confusion and incorrect linking during log output. * fix(auth): update permissions method to use new syntax * docs: consolidate docs/ into doc/ The repository had two documentation roots. Merge docs/ into doc/ and remove the empty docs/ tree. The two adr/ folders both numbered from 0001, so the identity and authorization series is renumbered to continue the core series rather than collide with it: docs/adr/0001-0012 -> doc/adr/0014-0025 Every reference is updated to match: the Status cross-links between the renumbered ADRs, the ADR and path links in specs/012-external-authentication and specs/013-rbac-authorization-model, and doc/wiki/identity-tenancy-security.md. doc/adr/toc.md gains entries 14-25. doc/adr/graph.dot is regenerated out to 25; it had been stale since ADR 10 and now also carries the partial supersession edges declared by the ADRs themselves. docs/codebase/ and docs/migrations/ move across unchanged. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * refactor(auth): simplify syntax in PermissionEvaluator and related classes Streamlined syntax for method definitions by using expression-bodied members and simplified object instantiations across the Authorization module. This includes adjustments in `PermissionEvaluator`, `LocalHostRequirement`, and `WebApplicationExtensions` for better readability and maintainability. * ci(bounty): point the footer step at the file's real path The bounty workflow read docs/bounty-footer.md, the path the file had when the workflow was added in b421b00e1. The file later moved to doc/bounty/bounty-footer.md and the workflow was never updated, so the read step has been resolving nothing and the appended comment was empty. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-08-24 21:44:55 +00:00
[InlineData("diagnostics/opentelemetry:view")]
[codex] Fix console log metadata and type resolution (#7542) * Avoid null endpoint DTO metadata in tests * Enforce console logs hub read permission * Remove unused console logs hub import * Support mapped endpoint metadata in auth tests * Reduce console log capture throughput impact * Address Copilot console logs review * Refactor task scheduling to support tenant-level background work and enhance logging functionality. * Introduce ConsoleStreamHook for stdout/stderr tee and enhance logging validation. Adjust test cases and startup warnings for distributed lock provider usage. * Refactor console logging pipeline with capture optimization and new ConsoleLogsHost; update tests accordingly. * Add Ansi SGR parser for console logs and associated unit tests * Remove ANSI color renderings and parsers; integrate ConsoleLogScopeAccessor for improved logging context with workflow instance ID support. * Address console logs code quality feedback * Address PR review feedback * Preserve console logs extension points * Stabilize console logs host lifecycle * Address final automated review comments * Tighten console log capture shutdown * Address console log review feedback * Address follow-up review feedback * Cover final review feedback * Avoid recursive console provider initialization * Guard console host lease shutdown * Preserve console log scope and provider lifetime * Correlate console log scope fallback * Tighten console scope correlation * Expose host services during provider construction * Redact ANSI-normalized console lines * Add OpenTelemetry diagnostics backend foundation * Add OTLP HTTP ingestion parsing * Document OpenTelemetry diagnostics setup * Enforce OpenTelemetry hub permissions * Remove `ConsoleCaptureTee` and related services and tests * Add OpenTelemetry HTTP ingestion integration test * Use pipeline contributors for console log context * Update CShells package versions to 0.0.24-preview.132 * Add OpenTelemetry ingestion security tests * Add OpenTelemetry API authorization tests * Filter live console logs by workflow instance * Add OpenTelemetry hub tests * Add OpenTelemetry gRPC metadata hook * Assert OpenTelemetry workflow tags survive ingestion * Mark OpenTelemetry core build verified * Enhance console logging with activity execution metadata and extend test coverage. * Address console logs stream consumption comment * Wire OpenTelemetry diagnostics into core sample * Address Core diagnostics review feedback * Address Core Copilot follow-up feedback * Add OpenTelemetry metric instrument names * Address Core Copilot provider feedback * Address Core Copilot diagnostics follow-up * Address Core Copilot live feed feedback * Address Core Copilot store feedback * Integrate OpenTelemetry for logging, tracing, and metrics in ModularServer and update launch settings and docker-compose configuration. * Refactor to replace `ConsoleLogStream.Core` with `ConsoleLogStreaming.Core` across codebase and update `ConsoleStreamHook` installation. * Add diagnostics OpenTelemetry backend * Fix OpenTelemetry live hub subscription * Fix modular OpenTelemetry exporter endpoints * Add CShells logging configuration in appsettings.json * Remove obsolete unit tests and helper classes * Restore default activity exception handling * Simplify type serialization and alias management This commit refactors the internal type serialization and alias management system to reduce boilerplate, improve robustness, and simplify the developer experience: - Removed numerous explicit `ExpressionOptions` type alias registrations across various modules. - Updated `TypeJsonConverter` and polymorphic serialization to reliably handle types using assembly-qualified names when a short alias is not explicitly registered. - Streamlined `ExcludeFromHashConverter` to strictly adhere to `ExcludeFromHashAttribute` for hash calculations, removing complex `JsonIgnoreCondition` logic. - Eliminated several helper classes (`WorkflowJsonTypeResolver`, `WorkflowTypeValidator`, `IWorkflowTypeRegistry`, `WorkflowFactoryDictionary`, `JavaScriptExceptionTypeAliasRegistrar`, `WorkflowRuntimeTypeAliasRegistrar`) and their associated unit tests, simplifying the codebase. Additionally, this commit introduces a comprehensive markdown document (`product-website-feature-source.md`) outlining Elsa's core features, Studio capabilities, extension ecosystem, and architectural selling points, intended as source material for the product website. * Refine type serialization for improved robustness and alias handling This commit further enhances the type serialization and deserialization mechanisms: * Centralizes type resolution and alias management through `IWellKnownTypeRegistry` and `WorkflowJsonTypeResolver`. * Prioritizes registered type aliases when serializing type metadata in `PolymorphicObjectConverter`, resulting in more concise JSON output. * Enhances deserialization in `PolymorphicObjectConverter` and `VariableMapper` to gracefully handle unknown or non-instantiable types, providing fallbacks and logging warnings. * Simplifies `TypeJsonConverter` by delegating complex type resolution logic to the `WorkflowJsonTypeResolver`. * Adds `JsonArray` to the well-known type aliases for direct recognition. * Fix console logs packaging and workflow type resolution * Fix console log metadata and type resolution * Address Copilot review feedback * Enhance type resolution, improve console log handling, and update tests - Streamlined `WorkflowDictionaryExtensions` for better workflow registration validation. - Refined `ConsoleLogsAuthorizationTests` with the new `SetJsonRequest` helper to improve test requests handling. - Updated `OrderDefinition` to ignore JSON serialization for `KeySelector`. - Enhanced `WorkflowRuntimeFeature` for improved workflow registration and type alias configuration. - Added tests to ensure `ConsoleLogProvider` metadata filtration in various scenarios. - Improved type serialization logic in `WorkflowJsonTypeResolver`. - Updated README to fix references related to diagnostics. - Optimized `ExcludeFromHashConverter` for property serialization conditions. - Modified `TriggerIndexer` for streamlined trigger management. - Tested payload checks in `PublishEventTests`. - Adjusted `Endpoint` in `ConsoleLogs` for automatic JSON request handling. - Ensured registration of workflow type aliases in `WorkflowsFeature`. * Restore CLR workflow registration compatibility * Align JSON island serialization fixtures * Add Console Logs Services and Enhance Endpoint Handling - Introduced `ActivityExecutionsEndpointTests` to validate route exposure. - Added `ConsoleLogCaptureHostedService` for console log streaming. - Implemented `ConsoleStreamJsonConverter` for JSON conversion of console streams. - Developed `ElsaConsoleLogRecentBuffer` to handle recent log buffering. - Updated `ConsoleLogsAuthorizationTests` with new test cases for stream filter mapping. - Consolidated console log provider dependencies and registration, including recent buffering. - Enhanced `ElsaConsoleLogProvider` to use recent buffer for filtering. - Adjusted `Program.cs` for streamlined logging service setup. * Enhance type resolution and test coverage; streamline console log integration - Added `ConsoleStreamHook` for streamlined log streaming. - Updated `WorkflowJsonTypeResolverTests` to improve type resolution and test new scenarios. - Simplified type resolution by removing trusted assembly checks. * Fix CI smoke and package restore failures * Fix Docker smoke image project paths * Fix Docker Python runtime packages * Fix Docker CA smoke teardown * Refresh Elsa roadmap * Implement background processors and mediation coordination - Added `BackgroundCommandProcessor`, `BackgroundJobProcessor`, and `BackgroundNotificationProcessor` classes for handling commands, jobs, and notifications, respectively. - Introduced `MediatorBackgroundProcessingCoordinator` to coordinate the execution of all background processors. - Implemented `MediatorBackgroundTask` for wrapping `MediatorBackgroundProcessingCoordinator` in `BackgroundTask`. - Added unit tests for `MediatorBackgroundTask` to ensure proper start and stop behavior. - Refactored `BackgroundCommandSenderHostedService` to utilize `BackgroundCommandProcessor`. - Introduced 'elsa-roadmap-refresh' skill configuration for roadmap updates. * Address workflow type resolution review feedback * Address follow-up review feedback * Restore recent console logs execute path * Address Copilot follow-up review * Decouple workflow JSON aliases from expressions * Fix workflow management unit test setup * Fix console logs recent endpoint handler shape * Respect workflow JSON strict type aliases * Remove unused console log contracts reference * Address Copilot review feedback * Address Copilot follow-up comments * Synchronize ring buffer dropped count * Address background processor strategy replay
2026-05-30 20:52:01 +00:00
[InlineData(PermissionNames.All)]
feat(auth)!: structured authorization model, phases 1-6 (#7980) * feat(auth): add the permission model and evaluator (Phase 1) Additive only. Nothing changes behavior: no endpoint declares against this yet, and no existing enforcement path routes through it. A permission is {resource}:{verb}, both axes open and string-keyed. A trailing wildcard on the resource axis matches the named node and every descendant at any depth, so workflows/definitions/* covers workflows/definitions itself; * on the verb axis matches any verb. Wildcards are the only construct with forward reach. A bare * parses to *:* at parse time rather than being special-cased in the evaluator, so superuser stays an ordinary grant and a stored or seeded * keeps authorizing across the vocabulary migration without a lock-out window. Adds: - Permission, with parsing that rejects a value containing a comma, since the persistence converter joins collections with one - CoreVerbs, the recommended set modules should reuse; a convention rather than a closed vocabulary - PermissionMatcher, one matching rule shape on both axes - IPermissionEvaluator, the single place permission decisions are made, skipping malformed claims so one bad stored grant cannot deny a principal - PermissionRequirement and PermissionAuthorizationHandler - The descriptor catalog in core: PermissionDescriptor now carries the verbs a resource supports and marks non-core ones, and the registry can report what a wildcard covers today External Authentication keeps its own descriptor types for now; it moves to the core catalog with the other modules in Phase 2, which keeps this change purely additive. 55 unit tests cover the matcher table, wildcard forward reach, the counterpart that concrete grants stay frozen, absence-is-denial, and the seeded * case. Refs #7974 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * feat(auth): contribute the permission catalog from every module (Phase 2) Still additive. Existing endpoints keep their legacy declarations; nothing changes behavior for them. Every module exposing protected endpoints now declares its resources and the verbs each accepts, following the pattern already proven in External Authentication -- constants and descriptors colocated -- refined to one constant per resource, with the verb supplied separately. 47 resources across 15 modules, matching the settled vocabulary. Descriptors are discovered from the same assemblies as a module's endpoints, in AddFastEndpointsFromModule. Registering them per module would let the catalog and the endpoints drift, which is the failure this model exists to remove; tying them to one registration makes the catalog necessarily describe the endpoints that exist. Adds: - GET /identity/permissions, the catalog a role editor renders from, so no client hard-codes permission strings - GET /identity/permissions/reach, reporting what a wildcard covers today. This is the mitigation for forward reach on the resource axis: a wildcard is useful precisely because it covers things that do not exist yet, so an author needs to see what it reaches now - GET /identity/me/permissions, resolving wildcards to concrete verbs so a client needs no matching logic, and listing denied resources with an empty verb list so "denied" is distinguishable from "unknown" - IPermissionGrantValidator, wired into Roles/Create and Roles/Update, which previously persisted request.Permissions after only the caller-subset check. Concrete segments validate against the catalog; wildcards validate structurally and are accepted even when they match nothing today, since installing a module later is what gives such a grant meaning - RequirePermission(resource, verb) and RequireAuthenticatedOnly() on the endpoint base classes, with the six copy-pasted ConfigurePermissions bodies collapsed into one implementation New endpoints require new-format grants, so during the transition they authorize only for holders of *, which parses to *:*. Phase 3 migrates the rest and closes that gap. 70 unit tests, including the wildcard-accepting validator cases. Refs #7974 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * feat(auth)!: cut every endpoint over to the permission model (Phase 3) BREAKING: legacy permission strings no longer authorize. A permanent alias layer would keep two vocabularies valid forever, so the break is deliberate and reported rather than absorbed. `*` survives unchanged -- it parses to `*:*` -- so an administrator cannot be locked out while roles are re-authored. All 168 declaration call sites across 151 files now use RequirePermission(resource, verb) with the constants their module declares, so a typo is a compile error rather than an unreachable endpoint. Enforcement consolidated onto IPermissionEvaluator: - RoleAuthorizationService evaluates containment through the evaluator rather than by set membership. This matters: a caller holding workflows/*:view can now delegate workflows/definitions:view, which set membership got wrong and which would otherwise force administrators to hold every concrete grant they wish to delegate. - The two Broker/Logout.cs endpoints declare explicitly. Logout is authenticated-only; ContinueLogout is anonymous, matching every other broker callback -- the route handle carries the authority and a top-level browser navigation sends no Authorization header. Removes the C#/Python expression permissions (#7975). They conflated an incoherent execution-side gate -- a workflow runs under the server's authority, not the caller's, so the check never constrained what a script could do -- with a meaningful authoring-side one. The host switch (AllowHostCodeExecution) becomes the single control. This is a deliberate reduction in control: where host code is enabled, any author who may write definitions may use C# and Python. Adds the fail-closed gate. Omitting a declaration previously inherited the FastEndpoints default with no Elsa-level fallback, so an endpoint could ship ungated unnoticed. EndpointCoverage asserts every endpoint declares exactly one of RequirePermission, RequireAuthenticatedOnly or AllowAnonymous, with no exemption list. Its canary assertion earned its keep immediately by catching that the gate was scanning an assembly containing no endpoints. EndpointPermissionRegistry records what each endpoint declares. The requirement is attached as an inline policy and is not readable back from the definition, so this keeps the declaration introspectable -- and lets tests assert a specific requirement rather than merely that one exists. Two behavior notes worth calling out: - The runtime status endpoint previously accepted either the read or the manage permission. It now requires workflows/runtime:view alone, which is least privilege; a role holding only control must also be granted view to read status. - BPMN interchange repeats the workflow-definitions path locally rather than taking a dependency on Elsa.Workflows.Api for one constant. It contributes no descriptor: the resource is owned and described by Workflows.Api, and the registry keeps one entry per resource. Also adds a startup validator that logs every stored role permission that no longer resolves, identified by role, so an upgrade is loud. 188 unit tests pass across Api.Common, Workflows.Api and Identity. Refs #7974, #7975, #7976 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * feat(auth): revocation bound and role audit notifications (Phase 4) Default access-token lifetime drops from 1 hour to 15 minutes. This is the revocation bound: permission claims are issued at sign-in and refresh re-reads the user's roles, so removing a role takes effect at most one access-token lifetime later. Refresh already rotates both tokens, so no client change is required and the refresh lifetime is unchanged. Adds an optional permission stamp for deployments needing a tighter bound. The stamp is derived from the user's roles and their permissions rather than stored as a counter on the user. That avoids changing the Identity schema, which would have required migrations across all five EF providers and made this milestone depend on the tenancy work. It also means every node computes the same value from the same store with no cross-node cache invalidation, which matters because Elsa has none. The stamp is issued unconditionally and only validated when enabled, so turning it on does not invalidate tokens already in flight; an absent stamp is not treated as a mismatch for the same reason. It changes when a role is added to or removed from the user and when a held role's permissions change, but not when an unrelated role changes. Role create and update now publish typed security notifications per ADR 0007, carrying the resulting grants so a reviewer can reconstruct what a role conferred at a point in time without replaying every prior event. This module owns no audit store: a future audit module subscribes and sets its own retention. Refs #7974 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * feat(auth): tenancy hardening for identity (Phase 5) Closes the gaps that made "roles are configurable per tenant" untrue however the rest of the stack behaved. Uniqueness becomes per tenant. User.Name, Role.Name, Application.Name and Application.ClientId carried globally unique indexes, so two tenants could not both hold a role named Admin. Migrations for all five EF providers drop the global indexes and create composite ones on (TenantId, Name). The in-memory user and role stores now scope to the ambient tenant. Isolation previously existed only on the Entity Framework path, and only when multitenancy was enabled, so a deployment running the default stores had none at all. The tenant-agnostic sentinel is honored, matching the EF query filter, so a shared platform role stays visible from every tenant. RoleFilter gains TenantId, matching UserFilter, and the role and user list endpoints pass it explicitly rather than relying on an ambient filter that only exists on one persistence path. UserManager.CreateUserAsync sets TenantId explicitly instead of relying on the EF saving handler, which does not run in memory and left users unassigned there. Refs #7974 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * docs: migration guide, ADR, and security wiki for the authorization model Adds docs/migrations/authorization-model.md, following the shape of the external-authentication persistence guide. It leads with the three things that are not a simple rename, because each silently produces a wrong result if treated as one: - The migration expands where new sub-resources are finer-grained than what they replace, so a one-for-one substitution narrows roles. - read:* and exec:* become materially more powerful. They are literal claim values today, authorizing twelve of roughly forty read endpoints; their replacements work as the names always implied. Any role holding them needs review by hand, not an automated rewrite. - The C#/Python expression permissions are removed rather than translated, which is a deliberate reduction in control where host code is enabled. It also states plainly that `*` keeps working, and says to do that first, since it is what stops an instance locking itself out mid-migration. ADR 0012 records the model and, more usefully, why a closed verb enumeration was drafted and rejected: it was justified on implication, but aggregates were already excluded and no verb implies another, so the bitwise check was expressing set containment all along. The security wiki's API Authorization section replaces its Secrets-only route table with the catalog endpoint as the authoritative source, and states why read-only mode is a separate axis rather than a permission. Refs #7974 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * test(auth): restore the suites after the tenancy and evaluator changes The whole solution builds with zero errors and every affected suite passes: 70 Api.Common, 23 Workflows.Api, 95 Identity, 154 External Authentication unit, 133 External Authentication integration. Most breakage was test call sites constructing the tenant-aware stores and the evaluator-backed RoleAuthorizationService directly. Adds TestTenantAccessor to Elsa.Testing.Shared rather than giving the production constructors an optional accessor, which would have let a missing registration silently disable isolation. Several External Authentication tests created fixtures in tenant-a while running under the default tenant, so the newly isolating store correctly stopped finding them. They are now scoped to the tenant their own fixtures use; JustInTimeProvisioningTests, which genuinely spans two tenants, is scoped per case. One production fix came out of it: IdentityFeature now ensures an ITenantAccessor with TryAdd. The identity stores are tenant-scoped, so a host that never enables multitenancy would otherwise fail to construct them -- which is what the DI registration tests were reporting. TryAdd leaves MultitenancyFeature's own registration untouched. Refs #7974 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(auth): register the identity services on the classic feature path Found by running Elsa.Server.Web, not by the test suites: the app failed at startup with "Unable to resolve service for type RoleSecurityNotifier while attempting to activate Roles.Update". RoleSecurityNotifier, the permission stamp services, the memory cache and the stored-permission validator were registered only in the CShells shell feature. Elsa.Server.Web uses the classic UseIdentity() path, whose IdentityFeature registered none of them, so every host on that path crashed while mapping endpoints. Unit tests did not catch it because they construct services directly rather than through either feature. Verified end to end against the running server: - The seeded admin role stores "*". It parsed to *:* and resolved to concrete verbs across all 27 registered resources, which is the bare-wildcard parse rule working on real data rather than in a test. - GET /identity/permissions returns the catalog for the modules this app installs -- 27 resources, 0 unverified, categories Dashboard, Identity, Resilience and Workflows -- rather than all 47, which is correct: the catalog describes what is installed. - GET /identity/permissions/reach?resource=workflows/* reports 19 covered resources. - A role holding only dashboard:view gets 200 on /dashboard/overview and 403 on /identity/roles, /identity/users, /workflow-definitions and /identity/permissions, while /identity/me/permissions returns 200 because it declares RequireAuthenticatedOnly -- confirming FR-019's third declaration state behaves as designed. - That same principal's /me/permissions lists all 27 resources with 26 carrying an empty verb list, so "denied" stays distinguishable from "unknown to this server". - The startup validator logged no unresolvable permissions, as expected for a seed holding only "*". Refs #7974 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(auth): discover permission descriptors on the shell host path Found by running Elsa.ModularServer.Web. The shell host started cleanly and authorized correctly, but GET /identity/permissions returned zero resources and /identity/me/permissions returned no grants. Descriptor discovery was wired into AddFastEndpointsFromModule, which only the classic module path calls. CShells discovers endpoints from features implementing its own marker interface, so on a shell host no provider was ever registered. Authorization still worked, because the evaluator reads claims and needs no descriptors -- which is exactly why nothing failed loudly. What silently broke was everything built on the catalog: role authoring would have rejected every concrete grant as an unknown resource, introspection returned nothing for clients to render, and the stored-permission validator would have reported every concrete stored permission as unresolvable. ElsaFastEndpointsFeature now contributes descriptors from the loaded Elsa assemblies, bounded to those and run once per shell. Verified on the modular host, which installs far more modules than Elsa.Server.Web: - 47 resources registered, 0 unverified, across all 12 categories, with all 17 module-specific verbs present. That is the entire published vocabulary confirmed against a running server rather than a document. - Reach reports workflows/* covering 20, external-authentication/* covering 8, and * covering 47. - Creating a role with dashboard:view and workflows/*:view succeeds, confirming a wildcard grant survives authoring validation. - Creating one with invented/resource:view and secrets:publish is rejected with 400. Also makes those rejections actionable. The permission was reported without the reason, so an operator learned which entry was wrong but not why; both parts are now in the message, including the supported verbs for the resource. Refs #7974 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * wip: bpmn test vocabulary * fix(auth): make enforcement DI-independent and finish the hub cutover CI on #7980 was red. Running the full suite locally rather than the subset I had been checking surfaced 24 failures across four projects, in three distinct classes. Enforcement no longer depends on a DI registration. RequirePermission attached a PermissionRequirement evaluated by a registered handler, so a host that had not called AddElsaAuthorization got 403 on every endpoint with nothing to indicate why. Several test hosts wire FastEndpoints directly and did exactly that. The requirement is now evaluated inline against a shared stateless evaluator, with a host-registered IPermissionEvaluator still taking precedence. Registration remains worthwhile for the catalog and the validator; authorization can no longer silently fail closed because of a missing one. Registration also moved from AddFastEndpointsFromModule to AddFastEndpointsAssembly. Registering an endpoint assembly is what should guarantee its permissions work, and a host may never call the former. Finishes T039. The four SignalR hubs still matched hard-coded legacy permission strings, which no longer exist, so every hub denied access. They now route through the evaluator like every other enforcement path. Test fixtures granting legacy strings were updated to the new vocabulary. Two categories were deliberately left alone: naming tests asserting the legacy constants still hold their old values, which is true and worth keeping, and the workflow script authorization tests, which asserted a MissingPermission outcome that D21 removed -- those now assert the host switch is the only control. One test previously pinned that the hub honors a FastEndpoints-configured permissions claim type. It now asserts the opposite, and says why: Elsa is the only authority that expands roles into permission claims (ADR 0009), and this model no longer uses the FastEndpoints permission mechanism, so its separately configurable claim type is not consulted. That property is also unreadable outside reflection. Whole solution builds with 0 errors and every test project passes. Refs #7974 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(auth): scope the permission-stamp cache to the tenant Greptile found and reproduced a cross-tenant authorization bug, and it was mine: Phase 5 made user names unique per tenant rather than globally, but PermissionStampValidator kept caching by user name alone. Tenant A's lookup could therefore populate the cache with its own stamp and satisfy a revoked token belonging to a same-named user in tenant B, without ever resolving tenant B's user. Both the cache key and the user lookup are now tenant-scoped. Added PermissionStampValidatorTests, including the cross-tenant case; verified it fails without the fix and passes with it. Also from review: - Removed the legacy permission constants left unused in the three hubs after they moved to the evaluator, so no stale vocabulary lingers. - Narrowed two generic catch clauses. The IL scanner now catches only the exceptions an unresolvable metadata token actually throws, and the startup validator rethrows cancellation while still refusing to stop the host for anything else -- an unreachable or half-migrated store is exactly when an operator most needs the host up. Whole solution builds with 0 errors and every test project passes. Refs #7974 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(docs): correct path in log message for authorization model migration link Aligns the log message path to the correct documentation directory, changing `docs` to `doc` to avoid confusion and incorrect linking during log output. * fix(auth): update permissions method to use new syntax * docs: consolidate docs/ into doc/ The repository had two documentation roots. Merge docs/ into doc/ and remove the empty docs/ tree. The two adr/ folders both numbered from 0001, so the identity and authorization series is renumbered to continue the core series rather than collide with it: docs/adr/0001-0012 -> doc/adr/0014-0025 Every reference is updated to match: the Status cross-links between the renumbered ADRs, the ADR and path links in specs/012-external-authentication and specs/013-rbac-authorization-model, and doc/wiki/identity-tenancy-security.md. doc/adr/toc.md gains entries 14-25. doc/adr/graph.dot is regenerated out to 25; it had been stale since ADR 10 and now also carries the partial supersession edges declared by the ADRs themselves. docs/codebase/ and docs/migrations/ move across unchanged. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * refactor(auth): simplify syntax in PermissionEvaluator and related classes Streamlined syntax for method definitions by using expression-bodied members and simplified object instantiations across the Authorization module. This includes adjustments in `PermissionEvaluator`, `LocalHostRequirement`, and `WebApplicationExtensions` for better readability and maintainability. * ci(bounty): point the footer step at the file's real path The bounty workflow read docs/bounty-footer.md, the path the file had when the workflow was added in b421b00e1. The file later moved to doc/bounty/bounty-footer.md and the workflow was never updated, so the read step has been resolving nothing and the appended comment was empty. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-08-24 21:44:55 +00:00
[InlineData("*:view")]
[codex] Fix console log metadata and type resolution (#7542) * Avoid null endpoint DTO metadata in tests * Enforce console logs hub read permission * Remove unused console logs hub import * Support mapped endpoint metadata in auth tests * Reduce console log capture throughput impact * Address Copilot console logs review * Refactor task scheduling to support tenant-level background work and enhance logging functionality. * Introduce ConsoleStreamHook for stdout/stderr tee and enhance logging validation. Adjust test cases and startup warnings for distributed lock provider usage. * Refactor console logging pipeline with capture optimization and new ConsoleLogsHost; update tests accordingly. * Add Ansi SGR parser for console logs and associated unit tests * Remove ANSI color renderings and parsers; integrate ConsoleLogScopeAccessor for improved logging context with workflow instance ID support. * Address console logs code quality feedback * Address PR review feedback * Preserve console logs extension points * Stabilize console logs host lifecycle * Address final automated review comments * Tighten console log capture shutdown * Address console log review feedback * Address follow-up review feedback * Cover final review feedback * Avoid recursive console provider initialization * Guard console host lease shutdown * Preserve console log scope and provider lifetime * Correlate console log scope fallback * Tighten console scope correlation * Expose host services during provider construction * Redact ANSI-normalized console lines * Add OpenTelemetry diagnostics backend foundation * Add OTLP HTTP ingestion parsing * Document OpenTelemetry diagnostics setup * Enforce OpenTelemetry hub permissions * Remove `ConsoleCaptureTee` and related services and tests * Add OpenTelemetry HTTP ingestion integration test * Use pipeline contributors for console log context * Update CShells package versions to 0.0.24-preview.132 * Add OpenTelemetry ingestion security tests * Add OpenTelemetry API authorization tests * Filter live console logs by workflow instance * Add OpenTelemetry hub tests * Add OpenTelemetry gRPC metadata hook * Assert OpenTelemetry workflow tags survive ingestion * Mark OpenTelemetry core build verified * Enhance console logging with activity execution metadata and extend test coverage. * Address console logs stream consumption comment * Wire OpenTelemetry diagnostics into core sample * Address Core diagnostics review feedback * Address Core Copilot follow-up feedback * Add OpenTelemetry metric instrument names * Address Core Copilot provider feedback * Address Core Copilot diagnostics follow-up * Address Core Copilot live feed feedback * Address Core Copilot store feedback * Integrate OpenTelemetry for logging, tracing, and metrics in ModularServer and update launch settings and docker-compose configuration. * Refactor to replace `ConsoleLogStream.Core` with `ConsoleLogStreaming.Core` across codebase and update `ConsoleStreamHook` installation. * Add diagnostics OpenTelemetry backend * Fix OpenTelemetry live hub subscription * Fix modular OpenTelemetry exporter endpoints * Add CShells logging configuration in appsettings.json * Remove obsolete unit tests and helper classes * Restore default activity exception handling * Simplify type serialization and alias management This commit refactors the internal type serialization and alias management system to reduce boilerplate, improve robustness, and simplify the developer experience: - Removed numerous explicit `ExpressionOptions` type alias registrations across various modules. - Updated `TypeJsonConverter` and polymorphic serialization to reliably handle types using assembly-qualified names when a short alias is not explicitly registered. - Streamlined `ExcludeFromHashConverter` to strictly adhere to `ExcludeFromHashAttribute` for hash calculations, removing complex `JsonIgnoreCondition` logic. - Eliminated several helper classes (`WorkflowJsonTypeResolver`, `WorkflowTypeValidator`, `IWorkflowTypeRegistry`, `WorkflowFactoryDictionary`, `JavaScriptExceptionTypeAliasRegistrar`, `WorkflowRuntimeTypeAliasRegistrar`) and their associated unit tests, simplifying the codebase. Additionally, this commit introduces a comprehensive markdown document (`product-website-feature-source.md`) outlining Elsa's core features, Studio capabilities, extension ecosystem, and architectural selling points, intended as source material for the product website. * Refine type serialization for improved robustness and alias handling This commit further enhances the type serialization and deserialization mechanisms: * Centralizes type resolution and alias management through `IWellKnownTypeRegistry` and `WorkflowJsonTypeResolver`. * Prioritizes registered type aliases when serializing type metadata in `PolymorphicObjectConverter`, resulting in more concise JSON output. * Enhances deserialization in `PolymorphicObjectConverter` and `VariableMapper` to gracefully handle unknown or non-instantiable types, providing fallbacks and logging warnings. * Simplifies `TypeJsonConverter` by delegating complex type resolution logic to the `WorkflowJsonTypeResolver`. * Adds `JsonArray` to the well-known type aliases for direct recognition. * Fix console logs packaging and workflow type resolution * Fix console log metadata and type resolution * Address Copilot review feedback * Enhance type resolution, improve console log handling, and update tests - Streamlined `WorkflowDictionaryExtensions` for better workflow registration validation. - Refined `ConsoleLogsAuthorizationTests` with the new `SetJsonRequest` helper to improve test requests handling. - Updated `OrderDefinition` to ignore JSON serialization for `KeySelector`. - Enhanced `WorkflowRuntimeFeature` for improved workflow registration and type alias configuration. - Added tests to ensure `ConsoleLogProvider` metadata filtration in various scenarios. - Improved type serialization logic in `WorkflowJsonTypeResolver`. - Updated README to fix references related to diagnostics. - Optimized `ExcludeFromHashConverter` for property serialization conditions. - Modified `TriggerIndexer` for streamlined trigger management. - Tested payload checks in `PublishEventTests`. - Adjusted `Endpoint` in `ConsoleLogs` for automatic JSON request handling. - Ensured registration of workflow type aliases in `WorkflowsFeature`. * Restore CLR workflow registration compatibility * Align JSON island serialization fixtures * Add Console Logs Services and Enhance Endpoint Handling - Introduced `ActivityExecutionsEndpointTests` to validate route exposure. - Added `ConsoleLogCaptureHostedService` for console log streaming. - Implemented `ConsoleStreamJsonConverter` for JSON conversion of console streams. - Developed `ElsaConsoleLogRecentBuffer` to handle recent log buffering. - Updated `ConsoleLogsAuthorizationTests` with new test cases for stream filter mapping. - Consolidated console log provider dependencies and registration, including recent buffering. - Enhanced `ElsaConsoleLogProvider` to use recent buffer for filtering. - Adjusted `Program.cs` for streamlined logging service setup. * Enhance type resolution and test coverage; streamline console log integration - Added `ConsoleStreamHook` for streamlined log streaming. - Updated `WorkflowJsonTypeResolverTests` to improve type resolution and test new scenarios. - Simplified type resolution by removing trusted assembly checks. * Fix CI smoke and package restore failures * Fix Docker smoke image project paths * Fix Docker Python runtime packages * Fix Docker CA smoke teardown * Refresh Elsa roadmap * Implement background processors and mediation coordination - Added `BackgroundCommandProcessor`, `BackgroundJobProcessor`, and `BackgroundNotificationProcessor` classes for handling commands, jobs, and notifications, respectively. - Introduced `MediatorBackgroundProcessingCoordinator` to coordinate the execution of all background processors. - Implemented `MediatorBackgroundTask` for wrapping `MediatorBackgroundProcessingCoordinator` in `BackgroundTask`. - Added unit tests for `MediatorBackgroundTask` to ensure proper start and stop behavior. - Refactored `BackgroundCommandSenderHostedService` to utilize `BackgroundCommandProcessor`. - Introduced 'elsa-roadmap-refresh' skill configuration for roadmap updates. * Address workflow type resolution review feedback * Address follow-up review feedback * Restore recent console logs execute path * Address Copilot follow-up review * Decouple workflow JSON aliases from expressions * Fix workflow management unit test setup * Fix console logs recent endpoint handler shape * Respect workflow JSON strict type aliases * Remove unused console log contracts reference * Address Copilot review feedback * Address Copilot follow-up comments * Synchronize ring buffer dropped count * Address background processor strategy replay
2026-05-30 20:52:01 +00:00
public async Task SubscribeAsync_WhenUserCanRead_ForwardsItemsToCaller(string permission)
{
var liveFeed = new TestLiveFeed(new OpenTelemetryStreamItem { Trace = Trace("trace-1") });
var caller = new CapturingOpenTelemetryClient();
var hub = CreateHub(liveFeed, permission, caller);
await hub.SubscribeAsync(new OpenTelemetryTraceFilter { TraceId = "trace-1" });
await AssertEventuallyAsync(() =>
{
Assert.Equal("trace-1", Assert.Single(caller.Items).Trace?.TraceId);
Assert.Equal("trace-1", liveFeed.Filter?.TraceId);
});
}
[Fact]
public async Task SubscribeAsync_WhenFilterTimeRangeIsInvalid_RejectsFilter()
{
feat(auth)!: structured authorization model, phases 1-6 (#7980) * feat(auth): add the permission model and evaluator (Phase 1) Additive only. Nothing changes behavior: no endpoint declares against this yet, and no existing enforcement path routes through it. A permission is {resource}:{verb}, both axes open and string-keyed. A trailing wildcard on the resource axis matches the named node and every descendant at any depth, so workflows/definitions/* covers workflows/definitions itself; * on the verb axis matches any verb. Wildcards are the only construct with forward reach. A bare * parses to *:* at parse time rather than being special-cased in the evaluator, so superuser stays an ordinary grant and a stored or seeded * keeps authorizing across the vocabulary migration without a lock-out window. Adds: - Permission, with parsing that rejects a value containing a comma, since the persistence converter joins collections with one - CoreVerbs, the recommended set modules should reuse; a convention rather than a closed vocabulary - PermissionMatcher, one matching rule shape on both axes - IPermissionEvaluator, the single place permission decisions are made, skipping malformed claims so one bad stored grant cannot deny a principal - PermissionRequirement and PermissionAuthorizationHandler - The descriptor catalog in core: PermissionDescriptor now carries the verbs a resource supports and marks non-core ones, and the registry can report what a wildcard covers today External Authentication keeps its own descriptor types for now; it moves to the core catalog with the other modules in Phase 2, which keeps this change purely additive. 55 unit tests cover the matcher table, wildcard forward reach, the counterpart that concrete grants stay frozen, absence-is-denial, and the seeded * case. Refs #7974 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * feat(auth): contribute the permission catalog from every module (Phase 2) Still additive. Existing endpoints keep their legacy declarations; nothing changes behavior for them. Every module exposing protected endpoints now declares its resources and the verbs each accepts, following the pattern already proven in External Authentication -- constants and descriptors colocated -- refined to one constant per resource, with the verb supplied separately. 47 resources across 15 modules, matching the settled vocabulary. Descriptors are discovered from the same assemblies as a module's endpoints, in AddFastEndpointsFromModule. Registering them per module would let the catalog and the endpoints drift, which is the failure this model exists to remove; tying them to one registration makes the catalog necessarily describe the endpoints that exist. Adds: - GET /identity/permissions, the catalog a role editor renders from, so no client hard-codes permission strings - GET /identity/permissions/reach, reporting what a wildcard covers today. This is the mitigation for forward reach on the resource axis: a wildcard is useful precisely because it covers things that do not exist yet, so an author needs to see what it reaches now - GET /identity/me/permissions, resolving wildcards to concrete verbs so a client needs no matching logic, and listing denied resources with an empty verb list so "denied" is distinguishable from "unknown" - IPermissionGrantValidator, wired into Roles/Create and Roles/Update, which previously persisted request.Permissions after only the caller-subset check. Concrete segments validate against the catalog; wildcards validate structurally and are accepted even when they match nothing today, since installing a module later is what gives such a grant meaning - RequirePermission(resource, verb) and RequireAuthenticatedOnly() on the endpoint base classes, with the six copy-pasted ConfigurePermissions bodies collapsed into one implementation New endpoints require new-format grants, so during the transition they authorize only for holders of *, which parses to *:*. Phase 3 migrates the rest and closes that gap. 70 unit tests, including the wildcard-accepting validator cases. Refs #7974 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * feat(auth)!: cut every endpoint over to the permission model (Phase 3) BREAKING: legacy permission strings no longer authorize. A permanent alias layer would keep two vocabularies valid forever, so the break is deliberate and reported rather than absorbed. `*` survives unchanged -- it parses to `*:*` -- so an administrator cannot be locked out while roles are re-authored. All 168 declaration call sites across 151 files now use RequirePermission(resource, verb) with the constants their module declares, so a typo is a compile error rather than an unreachable endpoint. Enforcement consolidated onto IPermissionEvaluator: - RoleAuthorizationService evaluates containment through the evaluator rather than by set membership. This matters: a caller holding workflows/*:view can now delegate workflows/definitions:view, which set membership got wrong and which would otherwise force administrators to hold every concrete grant they wish to delegate. - The two Broker/Logout.cs endpoints declare explicitly. Logout is authenticated-only; ContinueLogout is anonymous, matching every other broker callback -- the route handle carries the authority and a top-level browser navigation sends no Authorization header. Removes the C#/Python expression permissions (#7975). They conflated an incoherent execution-side gate -- a workflow runs under the server's authority, not the caller's, so the check never constrained what a script could do -- with a meaningful authoring-side one. The host switch (AllowHostCodeExecution) becomes the single control. This is a deliberate reduction in control: where host code is enabled, any author who may write definitions may use C# and Python. Adds the fail-closed gate. Omitting a declaration previously inherited the FastEndpoints default with no Elsa-level fallback, so an endpoint could ship ungated unnoticed. EndpointCoverage asserts every endpoint declares exactly one of RequirePermission, RequireAuthenticatedOnly or AllowAnonymous, with no exemption list. Its canary assertion earned its keep immediately by catching that the gate was scanning an assembly containing no endpoints. EndpointPermissionRegistry records what each endpoint declares. The requirement is attached as an inline policy and is not readable back from the definition, so this keeps the declaration introspectable -- and lets tests assert a specific requirement rather than merely that one exists. Two behavior notes worth calling out: - The runtime status endpoint previously accepted either the read or the manage permission. It now requires workflows/runtime:view alone, which is least privilege; a role holding only control must also be granted view to read status. - BPMN interchange repeats the workflow-definitions path locally rather than taking a dependency on Elsa.Workflows.Api for one constant. It contributes no descriptor: the resource is owned and described by Workflows.Api, and the registry keeps one entry per resource. Also adds a startup validator that logs every stored role permission that no longer resolves, identified by role, so an upgrade is loud. 188 unit tests pass across Api.Common, Workflows.Api and Identity. Refs #7974, #7975, #7976 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * feat(auth): revocation bound and role audit notifications (Phase 4) Default access-token lifetime drops from 1 hour to 15 minutes. This is the revocation bound: permission claims are issued at sign-in and refresh re-reads the user's roles, so removing a role takes effect at most one access-token lifetime later. Refresh already rotates both tokens, so no client change is required and the refresh lifetime is unchanged. Adds an optional permission stamp for deployments needing a tighter bound. The stamp is derived from the user's roles and their permissions rather than stored as a counter on the user. That avoids changing the Identity schema, which would have required migrations across all five EF providers and made this milestone depend on the tenancy work. It also means every node computes the same value from the same store with no cross-node cache invalidation, which matters because Elsa has none. The stamp is issued unconditionally and only validated when enabled, so turning it on does not invalidate tokens already in flight; an absent stamp is not treated as a mismatch for the same reason. It changes when a role is added to or removed from the user and when a held role's permissions change, but not when an unrelated role changes. Role create and update now publish typed security notifications per ADR 0007, carrying the resulting grants so a reviewer can reconstruct what a role conferred at a point in time without replaying every prior event. This module owns no audit store: a future audit module subscribes and sets its own retention. Refs #7974 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * feat(auth): tenancy hardening for identity (Phase 5) Closes the gaps that made "roles are configurable per tenant" untrue however the rest of the stack behaved. Uniqueness becomes per tenant. User.Name, Role.Name, Application.Name and Application.ClientId carried globally unique indexes, so two tenants could not both hold a role named Admin. Migrations for all five EF providers drop the global indexes and create composite ones on (TenantId, Name). The in-memory user and role stores now scope to the ambient tenant. Isolation previously existed only on the Entity Framework path, and only when multitenancy was enabled, so a deployment running the default stores had none at all. The tenant-agnostic sentinel is honored, matching the EF query filter, so a shared platform role stays visible from every tenant. RoleFilter gains TenantId, matching UserFilter, and the role and user list endpoints pass it explicitly rather than relying on an ambient filter that only exists on one persistence path. UserManager.CreateUserAsync sets TenantId explicitly instead of relying on the EF saving handler, which does not run in memory and left users unassigned there. Refs #7974 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * docs: migration guide, ADR, and security wiki for the authorization model Adds docs/migrations/authorization-model.md, following the shape of the external-authentication persistence guide. It leads with the three things that are not a simple rename, because each silently produces a wrong result if treated as one: - The migration expands where new sub-resources are finer-grained than what they replace, so a one-for-one substitution narrows roles. - read:* and exec:* become materially more powerful. They are literal claim values today, authorizing twelve of roughly forty read endpoints; their replacements work as the names always implied. Any role holding them needs review by hand, not an automated rewrite. - The C#/Python expression permissions are removed rather than translated, which is a deliberate reduction in control where host code is enabled. It also states plainly that `*` keeps working, and says to do that first, since it is what stops an instance locking itself out mid-migration. ADR 0012 records the model and, more usefully, why a closed verb enumeration was drafted and rejected: it was justified on implication, but aggregates were already excluded and no verb implies another, so the bitwise check was expressing set containment all along. The security wiki's API Authorization section replaces its Secrets-only route table with the catalog endpoint as the authoritative source, and states why read-only mode is a separate axis rather than a permission. Refs #7974 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * test(auth): restore the suites after the tenancy and evaluator changes The whole solution builds with zero errors and every affected suite passes: 70 Api.Common, 23 Workflows.Api, 95 Identity, 154 External Authentication unit, 133 External Authentication integration. Most breakage was test call sites constructing the tenant-aware stores and the evaluator-backed RoleAuthorizationService directly. Adds TestTenantAccessor to Elsa.Testing.Shared rather than giving the production constructors an optional accessor, which would have let a missing registration silently disable isolation. Several External Authentication tests created fixtures in tenant-a while running under the default tenant, so the newly isolating store correctly stopped finding them. They are now scoped to the tenant their own fixtures use; JustInTimeProvisioningTests, which genuinely spans two tenants, is scoped per case. One production fix came out of it: IdentityFeature now ensures an ITenantAccessor with TryAdd. The identity stores are tenant-scoped, so a host that never enables multitenancy would otherwise fail to construct them -- which is what the DI registration tests were reporting. TryAdd leaves MultitenancyFeature's own registration untouched. Refs #7974 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(auth): register the identity services on the classic feature path Found by running Elsa.Server.Web, not by the test suites: the app failed at startup with "Unable to resolve service for type RoleSecurityNotifier while attempting to activate Roles.Update". RoleSecurityNotifier, the permission stamp services, the memory cache and the stored-permission validator were registered only in the CShells shell feature. Elsa.Server.Web uses the classic UseIdentity() path, whose IdentityFeature registered none of them, so every host on that path crashed while mapping endpoints. Unit tests did not catch it because they construct services directly rather than through either feature. Verified end to end against the running server: - The seeded admin role stores "*". It parsed to *:* and resolved to concrete verbs across all 27 registered resources, which is the bare-wildcard parse rule working on real data rather than in a test. - GET /identity/permissions returns the catalog for the modules this app installs -- 27 resources, 0 unverified, categories Dashboard, Identity, Resilience and Workflows -- rather than all 47, which is correct: the catalog describes what is installed. - GET /identity/permissions/reach?resource=workflows/* reports 19 covered resources. - A role holding only dashboard:view gets 200 on /dashboard/overview and 403 on /identity/roles, /identity/users, /workflow-definitions and /identity/permissions, while /identity/me/permissions returns 200 because it declares RequireAuthenticatedOnly -- confirming FR-019's third declaration state behaves as designed. - That same principal's /me/permissions lists all 27 resources with 26 carrying an empty verb list, so "denied" stays distinguishable from "unknown to this server". - The startup validator logged no unresolvable permissions, as expected for a seed holding only "*". Refs #7974 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(auth): discover permission descriptors on the shell host path Found by running Elsa.ModularServer.Web. The shell host started cleanly and authorized correctly, but GET /identity/permissions returned zero resources and /identity/me/permissions returned no grants. Descriptor discovery was wired into AddFastEndpointsFromModule, which only the classic module path calls. CShells discovers endpoints from features implementing its own marker interface, so on a shell host no provider was ever registered. Authorization still worked, because the evaluator reads claims and needs no descriptors -- which is exactly why nothing failed loudly. What silently broke was everything built on the catalog: role authoring would have rejected every concrete grant as an unknown resource, introspection returned nothing for clients to render, and the stored-permission validator would have reported every concrete stored permission as unresolvable. ElsaFastEndpointsFeature now contributes descriptors from the loaded Elsa assemblies, bounded to those and run once per shell. Verified on the modular host, which installs far more modules than Elsa.Server.Web: - 47 resources registered, 0 unverified, across all 12 categories, with all 17 module-specific verbs present. That is the entire published vocabulary confirmed against a running server rather than a document. - Reach reports workflows/* covering 20, external-authentication/* covering 8, and * covering 47. - Creating a role with dashboard:view and workflows/*:view succeeds, confirming a wildcard grant survives authoring validation. - Creating one with invented/resource:view and secrets:publish is rejected with 400. Also makes those rejections actionable. The permission was reported without the reason, so an operator learned which entry was wrong but not why; both parts are now in the message, including the supported verbs for the resource. Refs #7974 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * wip: bpmn test vocabulary * fix(auth): make enforcement DI-independent and finish the hub cutover CI on #7980 was red. Running the full suite locally rather than the subset I had been checking surfaced 24 failures across four projects, in three distinct classes. Enforcement no longer depends on a DI registration. RequirePermission attached a PermissionRequirement evaluated by a registered handler, so a host that had not called AddElsaAuthorization got 403 on every endpoint with nothing to indicate why. Several test hosts wire FastEndpoints directly and did exactly that. The requirement is now evaluated inline against a shared stateless evaluator, with a host-registered IPermissionEvaluator still taking precedence. Registration remains worthwhile for the catalog and the validator; authorization can no longer silently fail closed because of a missing one. Registration also moved from AddFastEndpointsFromModule to AddFastEndpointsAssembly. Registering an endpoint assembly is what should guarantee its permissions work, and a host may never call the former. Finishes T039. The four SignalR hubs still matched hard-coded legacy permission strings, which no longer exist, so every hub denied access. They now route through the evaluator like every other enforcement path. Test fixtures granting legacy strings were updated to the new vocabulary. Two categories were deliberately left alone: naming tests asserting the legacy constants still hold their old values, which is true and worth keeping, and the workflow script authorization tests, which asserted a MissingPermission outcome that D21 removed -- those now assert the host switch is the only control. One test previously pinned that the hub honors a FastEndpoints-configured permissions claim type. It now asserts the opposite, and says why: Elsa is the only authority that expands roles into permission claims (ADR 0009), and this model no longer uses the FastEndpoints permission mechanism, so its separately configurable claim type is not consulted. That property is also unreadable outside reflection. Whole solution builds with 0 errors and every test project passes. Refs #7974 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(auth): scope the permission-stamp cache to the tenant Greptile found and reproduced a cross-tenant authorization bug, and it was mine: Phase 5 made user names unique per tenant rather than globally, but PermissionStampValidator kept caching by user name alone. Tenant A's lookup could therefore populate the cache with its own stamp and satisfy a revoked token belonging to a same-named user in tenant B, without ever resolving tenant B's user. Both the cache key and the user lookup are now tenant-scoped. Added PermissionStampValidatorTests, including the cross-tenant case; verified it fails without the fix and passes with it. Also from review: - Removed the legacy permission constants left unused in the three hubs after they moved to the evaluator, so no stale vocabulary lingers. - Narrowed two generic catch clauses. The IL scanner now catches only the exceptions an unresolvable metadata token actually throws, and the startup validator rethrows cancellation while still refusing to stop the host for anything else -- an unreachable or half-migrated store is exactly when an operator most needs the host up. Whole solution builds with 0 errors and every test project passes. Refs #7974 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(docs): correct path in log message for authorization model migration link Aligns the log message path to the correct documentation directory, changing `docs` to `doc` to avoid confusion and incorrect linking during log output. * fix(auth): update permissions method to use new syntax * docs: consolidate docs/ into doc/ The repository had two documentation roots. Merge docs/ into doc/ and remove the empty docs/ tree. The two adr/ folders both numbered from 0001, so the identity and authorization series is renumbered to continue the core series rather than collide with it: docs/adr/0001-0012 -> doc/adr/0014-0025 Every reference is updated to match: the Status cross-links between the renumbered ADRs, the ADR and path links in specs/012-external-authentication and specs/013-rbac-authorization-model, and doc/wiki/identity-tenancy-security.md. doc/adr/toc.md gains entries 14-25. doc/adr/graph.dot is regenerated out to 25; it had been stale since ADR 10 and now also carries the partial supersession edges declared by the ADRs themselves. docs/codebase/ and docs/migrations/ move across unchanged. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * refactor(auth): simplify syntax in PermissionEvaluator and related classes Streamlined syntax for method definitions by using expression-bodied members and simplified object instantiations across the Authorization module. This includes adjustments in `PermissionEvaluator`, `LocalHostRequirement`, and `WebApplicationExtensions` for better readability and maintainability. * ci(bounty): point the footer step at the file's real path The bounty workflow read docs/bounty-footer.md, the path the file had when the workflow was added in b421b00e1. The file later moved to doc/bounty/bounty-footer.md and the workflow was never updated, so the read step has been resolving nothing and the appended comment was empty. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-08-24 21:44:55 +00:00
var hub = CreateHub(new TestLiveFeed(), "diagnostics/opentelemetry:view");
[codex] Fix console log metadata and type resolution (#7542) * Avoid null endpoint DTO metadata in tests * Enforce console logs hub read permission * Remove unused console logs hub import * Support mapped endpoint metadata in auth tests * Reduce console log capture throughput impact * Address Copilot console logs review * Refactor task scheduling to support tenant-level background work and enhance logging functionality. * Introduce ConsoleStreamHook for stdout/stderr tee and enhance logging validation. Adjust test cases and startup warnings for distributed lock provider usage. * Refactor console logging pipeline with capture optimization and new ConsoleLogsHost; update tests accordingly. * Add Ansi SGR parser for console logs and associated unit tests * Remove ANSI color renderings and parsers; integrate ConsoleLogScopeAccessor for improved logging context with workflow instance ID support. * Address console logs code quality feedback * Address PR review feedback * Preserve console logs extension points * Stabilize console logs host lifecycle * Address final automated review comments * Tighten console log capture shutdown * Address console log review feedback * Address follow-up review feedback * Cover final review feedback * Avoid recursive console provider initialization * Guard console host lease shutdown * Preserve console log scope and provider lifetime * Correlate console log scope fallback * Tighten console scope correlation * Expose host services during provider construction * Redact ANSI-normalized console lines * Add OpenTelemetry diagnostics backend foundation * Add OTLP HTTP ingestion parsing * Document OpenTelemetry diagnostics setup * Enforce OpenTelemetry hub permissions * Remove `ConsoleCaptureTee` and related services and tests * Add OpenTelemetry HTTP ingestion integration test * Use pipeline contributors for console log context * Update CShells package versions to 0.0.24-preview.132 * Add OpenTelemetry ingestion security tests * Add OpenTelemetry API authorization tests * Filter live console logs by workflow instance * Add OpenTelemetry hub tests * Add OpenTelemetry gRPC metadata hook * Assert OpenTelemetry workflow tags survive ingestion * Mark OpenTelemetry core build verified * Enhance console logging with activity execution metadata and extend test coverage. * Address console logs stream consumption comment * Wire OpenTelemetry diagnostics into core sample * Address Core diagnostics review feedback * Address Core Copilot follow-up feedback * Add OpenTelemetry metric instrument names * Address Core Copilot provider feedback * Address Core Copilot diagnostics follow-up * Address Core Copilot live feed feedback * Address Core Copilot store feedback * Integrate OpenTelemetry for logging, tracing, and metrics in ModularServer and update launch settings and docker-compose configuration. * Refactor to replace `ConsoleLogStream.Core` with `ConsoleLogStreaming.Core` across codebase and update `ConsoleStreamHook` installation. * Add diagnostics OpenTelemetry backend * Fix OpenTelemetry live hub subscription * Fix modular OpenTelemetry exporter endpoints * Add CShells logging configuration in appsettings.json * Remove obsolete unit tests and helper classes * Restore default activity exception handling * Simplify type serialization and alias management This commit refactors the internal type serialization and alias management system to reduce boilerplate, improve robustness, and simplify the developer experience: - Removed numerous explicit `ExpressionOptions` type alias registrations across various modules. - Updated `TypeJsonConverter` and polymorphic serialization to reliably handle types using assembly-qualified names when a short alias is not explicitly registered. - Streamlined `ExcludeFromHashConverter` to strictly adhere to `ExcludeFromHashAttribute` for hash calculations, removing complex `JsonIgnoreCondition` logic. - Eliminated several helper classes (`WorkflowJsonTypeResolver`, `WorkflowTypeValidator`, `IWorkflowTypeRegistry`, `WorkflowFactoryDictionary`, `JavaScriptExceptionTypeAliasRegistrar`, `WorkflowRuntimeTypeAliasRegistrar`) and their associated unit tests, simplifying the codebase. Additionally, this commit introduces a comprehensive markdown document (`product-website-feature-source.md`) outlining Elsa's core features, Studio capabilities, extension ecosystem, and architectural selling points, intended as source material for the product website. * Refine type serialization for improved robustness and alias handling This commit further enhances the type serialization and deserialization mechanisms: * Centralizes type resolution and alias management through `IWellKnownTypeRegistry` and `WorkflowJsonTypeResolver`. * Prioritizes registered type aliases when serializing type metadata in `PolymorphicObjectConverter`, resulting in more concise JSON output. * Enhances deserialization in `PolymorphicObjectConverter` and `VariableMapper` to gracefully handle unknown or non-instantiable types, providing fallbacks and logging warnings. * Simplifies `TypeJsonConverter` by delegating complex type resolution logic to the `WorkflowJsonTypeResolver`. * Adds `JsonArray` to the well-known type aliases for direct recognition. * Fix console logs packaging and workflow type resolution * Fix console log metadata and type resolution * Address Copilot review feedback * Enhance type resolution, improve console log handling, and update tests - Streamlined `WorkflowDictionaryExtensions` for better workflow registration validation. - Refined `ConsoleLogsAuthorizationTests` with the new `SetJsonRequest` helper to improve test requests handling. - Updated `OrderDefinition` to ignore JSON serialization for `KeySelector`. - Enhanced `WorkflowRuntimeFeature` for improved workflow registration and type alias configuration. - Added tests to ensure `ConsoleLogProvider` metadata filtration in various scenarios. - Improved type serialization logic in `WorkflowJsonTypeResolver`. - Updated README to fix references related to diagnostics. - Optimized `ExcludeFromHashConverter` for property serialization conditions. - Modified `TriggerIndexer` for streamlined trigger management. - Tested payload checks in `PublishEventTests`. - Adjusted `Endpoint` in `ConsoleLogs` for automatic JSON request handling. - Ensured registration of workflow type aliases in `WorkflowsFeature`. * Restore CLR workflow registration compatibility * Align JSON island serialization fixtures * Add Console Logs Services and Enhance Endpoint Handling - Introduced `ActivityExecutionsEndpointTests` to validate route exposure. - Added `ConsoleLogCaptureHostedService` for console log streaming. - Implemented `ConsoleStreamJsonConverter` for JSON conversion of console streams. - Developed `ElsaConsoleLogRecentBuffer` to handle recent log buffering. - Updated `ConsoleLogsAuthorizationTests` with new test cases for stream filter mapping. - Consolidated console log provider dependencies and registration, including recent buffering. - Enhanced `ElsaConsoleLogProvider` to use recent buffer for filtering. - Adjusted `Program.cs` for streamlined logging service setup. * Enhance type resolution and test coverage; streamline console log integration - Added `ConsoleStreamHook` for streamlined log streaming. - Updated `WorkflowJsonTypeResolverTests` to improve type resolution and test new scenarios. - Simplified type resolution by removing trusted assembly checks. * Fix CI smoke and package restore failures * Fix Docker smoke image project paths * Fix Docker Python runtime packages * Fix Docker CA smoke teardown * Refresh Elsa roadmap * Implement background processors and mediation coordination - Added `BackgroundCommandProcessor`, `BackgroundJobProcessor`, and `BackgroundNotificationProcessor` classes for handling commands, jobs, and notifications, respectively. - Introduced `MediatorBackgroundProcessingCoordinator` to coordinate the execution of all background processors. - Implemented `MediatorBackgroundTask` for wrapping `MediatorBackgroundProcessingCoordinator` in `BackgroundTask`. - Added unit tests for `MediatorBackgroundTask` to ensure proper start and stop behavior. - Refactored `BackgroundCommandSenderHostedService` to utilize `BackgroundCommandProcessor`. - Introduced 'elsa-roadmap-refresh' skill configuration for roadmap updates. * Address workflow type resolution review feedback * Address follow-up review feedback * Restore recent console logs execute path * Address Copilot follow-up review * Decouple workflow JSON aliases from expressions * Fix workflow management unit test setup * Fix console logs recent endpoint handler shape * Respect workflow JSON strict type aliases * Remove unused console log contracts reference * Address Copilot review feedback * Address Copilot follow-up comments * Synchronize ring buffer dropped count * Address background processor strategy replay
2026-05-30 20:52:01 +00:00
await Assert.ThrowsAsync<HubException>(() => hub.SubscribeAsync(new OpenTelemetryTraceFilter
{
From = _now.AddMinutes(1),
To = _now
}));
}
[Fact]
public async Task LiveFeed_WhenTraceFilterIsSet_OnlyPublishesMatchingTraces()
{
var liveFeed = new InMemoryOpenTelemetryLiveFeed(OptionsFactory.Create(new OpenTelemetryDiagnosticsOptions()));
using var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(5));
await using var enumerator = liveFeed.SubscribeAsync(new OpenTelemetryTraceFilter { TraceId = "trace-keep" }, timeout.Token).GetAsyncEnumerator(timeout.Token);
var next = enumerator.MoveNextAsync().AsTask();
await liveFeed.PublishAsync(new OpenTelemetryBatch([], [Trace("trace-skip"), Trace("trace-keep")], [], [], [], []), timeout.Token);
Assert.True(await next);
Assert.Equal("trace-keep", enumerator.Current.Trace?.TraceId);
}
[codex] Fix diagnostics live feed regressions (#7548) * Avoid null endpoint DTO metadata in tests * Enforce console logs hub read permission * Remove unused console logs hub import * Support mapped endpoint metadata in auth tests * Reduce console log capture throughput impact * Address Copilot console logs review * Refactor task scheduling to support tenant-level background work and enhance logging functionality. * Introduce ConsoleStreamHook for stdout/stderr tee and enhance logging validation. Adjust test cases and startup warnings for distributed lock provider usage. * Refactor console logging pipeline with capture optimization and new ConsoleLogsHost; update tests accordingly. * Add Ansi SGR parser for console logs and associated unit tests * Remove ANSI color renderings and parsers; integrate ConsoleLogScopeAccessor for improved logging context with workflow instance ID support. * Address console logs code quality feedback * Address PR review feedback * Preserve console logs extension points * Stabilize console logs host lifecycle * Address final automated review comments * Tighten console log capture shutdown * Address console log review feedback * Address follow-up review feedback * Cover final review feedback * Avoid recursive console provider initialization * Guard console host lease shutdown * Preserve console log scope and provider lifetime * Correlate console log scope fallback * Tighten console scope correlation * Expose host services during provider construction * Redact ANSI-normalized console lines * Add OpenTelemetry diagnostics backend foundation * Add OTLP HTTP ingestion parsing * Document OpenTelemetry diagnostics setup * Enforce OpenTelemetry hub permissions * Remove `ConsoleCaptureTee` and related services and tests * Add OpenTelemetry HTTP ingestion integration test * Use pipeline contributors for console log context * Update CShells package versions to 0.0.24-preview.132 * Add OpenTelemetry ingestion security tests * Add OpenTelemetry API authorization tests * Filter live console logs by workflow instance * Add OpenTelemetry hub tests * Add OpenTelemetry gRPC metadata hook * Assert OpenTelemetry workflow tags survive ingestion * Mark OpenTelemetry core build verified * Enhance console logging with activity execution metadata and extend test coverage. * Address console logs stream consumption comment * Wire OpenTelemetry diagnostics into core sample * Address Core diagnostics review feedback * Address Core Copilot follow-up feedback * Add OpenTelemetry metric instrument names * Address Core Copilot provider feedback * Address Core Copilot diagnostics follow-up * Address Core Copilot live feed feedback * Address Core Copilot store feedback * Integrate OpenTelemetry for logging, tracing, and metrics in ModularServer and update launch settings and docker-compose configuration. * Refactor to replace `ConsoleLogStream.Core` with `ConsoleLogStreaming.Core` across codebase and update `ConsoleStreamHook` installation. * Add diagnostics OpenTelemetry backend * Fix OpenTelemetry live hub subscription * Fix modular OpenTelemetry exporter endpoints * Add CShells logging configuration in appsettings.json * Remove obsolete unit tests and helper classes * Restore default activity exception handling * Simplify type serialization and alias management This commit refactors the internal type serialization and alias management system to reduce boilerplate, improve robustness, and simplify the developer experience: - Removed numerous explicit `ExpressionOptions` type alias registrations across various modules. - Updated `TypeJsonConverter` and polymorphic serialization to reliably handle types using assembly-qualified names when a short alias is not explicitly registered. - Streamlined `ExcludeFromHashConverter` to strictly adhere to `ExcludeFromHashAttribute` for hash calculations, removing complex `JsonIgnoreCondition` logic. - Eliminated several helper classes (`WorkflowJsonTypeResolver`, `WorkflowTypeValidator`, `IWorkflowTypeRegistry`, `WorkflowFactoryDictionary`, `JavaScriptExceptionTypeAliasRegistrar`, `WorkflowRuntimeTypeAliasRegistrar`) and their associated unit tests, simplifying the codebase. Additionally, this commit introduces a comprehensive markdown document (`product-website-feature-source.md`) outlining Elsa's core features, Studio capabilities, extension ecosystem, and architectural selling points, intended as source material for the product website. * Refine type serialization for improved robustness and alias handling This commit further enhances the type serialization and deserialization mechanisms: * Centralizes type resolution and alias management through `IWellKnownTypeRegistry` and `WorkflowJsonTypeResolver`. * Prioritizes registered type aliases when serializing type metadata in `PolymorphicObjectConverter`, resulting in more concise JSON output. * Enhances deserialization in `PolymorphicObjectConverter` and `VariableMapper` to gracefully handle unknown or non-instantiable types, providing fallbacks and logging warnings. * Simplifies `TypeJsonConverter` by delegating complex type resolution logic to the `WorkflowJsonTypeResolver`. * Adds `JsonArray` to the well-known type aliases for direct recognition. * Fix console logs packaging and workflow type resolution * Fix console log metadata and type resolution * Address Copilot review feedback * Enhance type resolution, improve console log handling, and update tests - Streamlined `WorkflowDictionaryExtensions` for better workflow registration validation. - Refined `ConsoleLogsAuthorizationTests` with the new `SetJsonRequest` helper to improve test requests handling. - Updated `OrderDefinition` to ignore JSON serialization for `KeySelector`. - Enhanced `WorkflowRuntimeFeature` for improved workflow registration and type alias configuration. - Added tests to ensure `ConsoleLogProvider` metadata filtration in various scenarios. - Improved type serialization logic in `WorkflowJsonTypeResolver`. - Updated README to fix references related to diagnostics. - Optimized `ExcludeFromHashConverter` for property serialization conditions. - Modified `TriggerIndexer` for streamlined trigger management. - Tested payload checks in `PublishEventTests`. - Adjusted `Endpoint` in `ConsoleLogs` for automatic JSON request handling. - Ensured registration of workflow type aliases in `WorkflowsFeature`. * Restore CLR workflow registration compatibility * Align JSON island serialization fixtures * Add Console Logs Services and Enhance Endpoint Handling - Introduced `ActivityExecutionsEndpointTests` to validate route exposure. - Added `ConsoleLogCaptureHostedService` for console log streaming. - Implemented `ConsoleStreamJsonConverter` for JSON conversion of console streams. - Developed `ElsaConsoleLogRecentBuffer` to handle recent log buffering. - Updated `ConsoleLogsAuthorizationTests` with new test cases for stream filter mapping. - Consolidated console log provider dependencies and registration, including recent buffering. - Enhanced `ElsaConsoleLogProvider` to use recent buffer for filtering. - Adjusted `Program.cs` for streamlined logging service setup. * Enhance type resolution and test coverage; streamline console log integration - Added `ConsoleStreamHook` for streamlined log streaming. - Updated `WorkflowJsonTypeResolverTests` to improve type resolution and test new scenarios. - Simplified type resolution by removing trusted assembly checks. * Fix CI smoke and package restore failures * Fix Docker smoke image project paths * Fix Docker Python runtime packages * Fix Docker CA smoke teardown * Refresh Elsa roadmap * Implement background processors and mediation coordination - Added `BackgroundCommandProcessor`, `BackgroundJobProcessor`, and `BackgroundNotificationProcessor` classes for handling commands, jobs, and notifications, respectively. - Introduced `MediatorBackgroundProcessingCoordinator` to coordinate the execution of all background processors. - Implemented `MediatorBackgroundTask` for wrapping `MediatorBackgroundProcessingCoordinator` in `BackgroundTask`. - Added unit tests for `MediatorBackgroundTask` to ensure proper start and stop behavior. - Refactored `BackgroundCommandSenderHostedService` to utilize `BackgroundCommandProcessor`. - Introduced 'elsa-roadmap-refresh' skill configuration for roadmap updates. * Address workflow type resolution review feedback * Address follow-up review feedback * Restore recent console logs execute path * Address Copilot follow-up review * Decouple workflow JSON aliases from expressions * Fix workflow management unit test setup * Fix console logs recent endpoint handler shape * Respect workflow JSON strict type aliases * Remove unused console log contracts reference * Address Copilot review feedback * Address Copilot follow-up comments * Synchronize ring buffer dropped count * Address background processor strategy replay * Fix diagnostics live feed regressions
2026-05-31 07:40:02 +00:00
[Fact]
public async Task LiveFeed_WhenServiceNameFilterIsSet_OnlyPublishesMatchingResourcesAndTraces()
{
var liveFeed = new InMemoryOpenTelemetryLiveFeed(OptionsFactory.Create(new OpenTelemetryDiagnosticsOptions()));
using var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(5));
await using var enumerator = liveFeed.SubscribeAsync(new OpenTelemetryTraceFilter { ServiceName = "api" }, timeout.Token).GetAsyncEnumerator(timeout.Token);
var next = enumerator.MoveNextAsync().AsTask();
await liveFeed.PublishAsync(new OpenTelemetryBatch(
[Resource("resource-skip", "worker")],
[Trace("trace-skip", ["resource-skip"])],
[], [], [], []), timeout.Token);
var completed = await Task.WhenAny(next, Task.Delay(TimeSpan.FromMilliseconds(150), timeout.Token));
Assert.NotSame(next, completed);
await liveFeed.PublishAsync(new OpenTelemetryBatch(
[Resource("resource-keep", "api")],
[Trace("trace-keep", ["resource-keep"])],
[], [], [], []), timeout.Token);
Assert.True(await next);
Assert.Equal("resource-keep", enumerator.Current.Resource?.Id);
Assert.True(await enumerator.MoveNextAsync());
Assert.Equal("trace-keep", enumerator.Current.Trace?.TraceId);
}
[Fact]
public async Task LiveFeed_WhenResourceFilterIsSet_FiltersLogsAndMetricPoints()
{
var liveFeed = new InMemoryOpenTelemetryLiveFeed(OptionsFactory.Create(new OpenTelemetryDiagnosticsOptions()));
using var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(5));
await using var enumerator = liveFeed.SubscribeAsync(new OpenTelemetryTraceFilter { ResourceId = "resource-keep" }, timeout.Token).GetAsyncEnumerator(timeout.Token);
var first = enumerator.MoveNextAsync().AsTask();
await liveFeed.PublishAsync(new OpenTelemetryBatch(
[],
[],
[],
[],
[MetricPoint("point-skip", "resource-skip"), MetricPoint("point-keep", "resource-keep")],
[Log("log-skip", "resource-skip"), Log("log-keep", "resource-keep")]), timeout.Token);
Assert.True(await first);
Assert.Equal("log-keep", enumerator.Current.Log?.Id);
Assert.True(await enumerator.MoveNextAsync());
Assert.Equal("point-keep", enumerator.Current.MetricPoint?.Id);
}
[codex] Fix console log metadata and type resolution (#7542) * Avoid null endpoint DTO metadata in tests * Enforce console logs hub read permission * Remove unused console logs hub import * Support mapped endpoint metadata in auth tests * Reduce console log capture throughput impact * Address Copilot console logs review * Refactor task scheduling to support tenant-level background work and enhance logging functionality. * Introduce ConsoleStreamHook for stdout/stderr tee and enhance logging validation. Adjust test cases and startup warnings for distributed lock provider usage. * Refactor console logging pipeline with capture optimization and new ConsoleLogsHost; update tests accordingly. * Add Ansi SGR parser for console logs and associated unit tests * Remove ANSI color renderings and parsers; integrate ConsoleLogScopeAccessor for improved logging context with workflow instance ID support. * Address console logs code quality feedback * Address PR review feedback * Preserve console logs extension points * Stabilize console logs host lifecycle * Address final automated review comments * Tighten console log capture shutdown * Address console log review feedback * Address follow-up review feedback * Cover final review feedback * Avoid recursive console provider initialization * Guard console host lease shutdown * Preserve console log scope and provider lifetime * Correlate console log scope fallback * Tighten console scope correlation * Expose host services during provider construction * Redact ANSI-normalized console lines * Add OpenTelemetry diagnostics backend foundation * Add OTLP HTTP ingestion parsing * Document OpenTelemetry diagnostics setup * Enforce OpenTelemetry hub permissions * Remove `ConsoleCaptureTee` and related services and tests * Add OpenTelemetry HTTP ingestion integration test * Use pipeline contributors for console log context * Update CShells package versions to 0.0.24-preview.132 * Add OpenTelemetry ingestion security tests * Add OpenTelemetry API authorization tests * Filter live console logs by workflow instance * Add OpenTelemetry hub tests * Add OpenTelemetry gRPC metadata hook * Assert OpenTelemetry workflow tags survive ingestion * Mark OpenTelemetry core build verified * Enhance console logging with activity execution metadata and extend test coverage. * Address console logs stream consumption comment * Wire OpenTelemetry diagnostics into core sample * Address Core diagnostics review feedback * Address Core Copilot follow-up feedback * Add OpenTelemetry metric instrument names * Address Core Copilot provider feedback * Address Core Copilot diagnostics follow-up * Address Core Copilot live feed feedback * Address Core Copilot store feedback * Integrate OpenTelemetry for logging, tracing, and metrics in ModularServer and update launch settings and docker-compose configuration. * Refactor to replace `ConsoleLogStream.Core` with `ConsoleLogStreaming.Core` across codebase and update `ConsoleStreamHook` installation. * Add diagnostics OpenTelemetry backend * Fix OpenTelemetry live hub subscription * Fix modular OpenTelemetry exporter endpoints * Add CShells logging configuration in appsettings.json * Remove obsolete unit tests and helper classes * Restore default activity exception handling * Simplify type serialization and alias management This commit refactors the internal type serialization and alias management system to reduce boilerplate, improve robustness, and simplify the developer experience: - Removed numerous explicit `ExpressionOptions` type alias registrations across various modules. - Updated `TypeJsonConverter` and polymorphic serialization to reliably handle types using assembly-qualified names when a short alias is not explicitly registered. - Streamlined `ExcludeFromHashConverter` to strictly adhere to `ExcludeFromHashAttribute` for hash calculations, removing complex `JsonIgnoreCondition` logic. - Eliminated several helper classes (`WorkflowJsonTypeResolver`, `WorkflowTypeValidator`, `IWorkflowTypeRegistry`, `WorkflowFactoryDictionary`, `JavaScriptExceptionTypeAliasRegistrar`, `WorkflowRuntimeTypeAliasRegistrar`) and their associated unit tests, simplifying the codebase. Additionally, this commit introduces a comprehensive markdown document (`product-website-feature-source.md`) outlining Elsa's core features, Studio capabilities, extension ecosystem, and architectural selling points, intended as source material for the product website. * Refine type serialization for improved robustness and alias handling This commit further enhances the type serialization and deserialization mechanisms: * Centralizes type resolution and alias management through `IWellKnownTypeRegistry` and `WorkflowJsonTypeResolver`. * Prioritizes registered type aliases when serializing type metadata in `PolymorphicObjectConverter`, resulting in more concise JSON output. * Enhances deserialization in `PolymorphicObjectConverter` and `VariableMapper` to gracefully handle unknown or non-instantiable types, providing fallbacks and logging warnings. * Simplifies `TypeJsonConverter` by delegating complex type resolution logic to the `WorkflowJsonTypeResolver`. * Adds `JsonArray` to the well-known type aliases for direct recognition. * Fix console logs packaging and workflow type resolution * Fix console log metadata and type resolution * Address Copilot review feedback * Enhance type resolution, improve console log handling, and update tests - Streamlined `WorkflowDictionaryExtensions` for better workflow registration validation. - Refined `ConsoleLogsAuthorizationTests` with the new `SetJsonRequest` helper to improve test requests handling. - Updated `OrderDefinition` to ignore JSON serialization for `KeySelector`. - Enhanced `WorkflowRuntimeFeature` for improved workflow registration and type alias configuration. - Added tests to ensure `ConsoleLogProvider` metadata filtration in various scenarios. - Improved type serialization logic in `WorkflowJsonTypeResolver`. - Updated README to fix references related to diagnostics. - Optimized `ExcludeFromHashConverter` for property serialization conditions. - Modified `TriggerIndexer` for streamlined trigger management. - Tested payload checks in `PublishEventTests`. - Adjusted `Endpoint` in `ConsoleLogs` for automatic JSON request handling. - Ensured registration of workflow type aliases in `WorkflowsFeature`. * Restore CLR workflow registration compatibility * Align JSON island serialization fixtures * Add Console Logs Services and Enhance Endpoint Handling - Introduced `ActivityExecutionsEndpointTests` to validate route exposure. - Added `ConsoleLogCaptureHostedService` for console log streaming. - Implemented `ConsoleStreamJsonConverter` for JSON conversion of console streams. - Developed `ElsaConsoleLogRecentBuffer` to handle recent log buffering. - Updated `ConsoleLogsAuthorizationTests` with new test cases for stream filter mapping. - Consolidated console log provider dependencies and registration, including recent buffering. - Enhanced `ElsaConsoleLogProvider` to use recent buffer for filtering. - Adjusted `Program.cs` for streamlined logging service setup. * Enhance type resolution and test coverage; streamline console log integration - Added `ConsoleStreamHook` for streamlined log streaming. - Updated `WorkflowJsonTypeResolverTests` to improve type resolution and test new scenarios. - Simplified type resolution by removing trusted assembly checks. * Fix CI smoke and package restore failures * Fix Docker smoke image project paths * Fix Docker Python runtime packages * Fix Docker CA smoke teardown * Refresh Elsa roadmap * Implement background processors and mediation coordination - Added `BackgroundCommandProcessor`, `BackgroundJobProcessor`, and `BackgroundNotificationProcessor` classes for handling commands, jobs, and notifications, respectively. - Introduced `MediatorBackgroundProcessingCoordinator` to coordinate the execution of all background processors. - Implemented `MediatorBackgroundTask` for wrapping `MediatorBackgroundProcessingCoordinator` in `BackgroundTask`. - Added unit tests for `MediatorBackgroundTask` to ensure proper start and stop behavior. - Refactored `BackgroundCommandSenderHostedService` to utilize `BackgroundCommandProcessor`. - Introduced 'elsa-roadmap-refresh' skill configuration for roadmap updates. * Address workflow type resolution review feedback * Address follow-up review feedback * Restore recent console logs execute path * Address Copilot follow-up review * Decouple workflow JSON aliases from expressions * Fix workflow management unit test setup * Fix console logs recent endpoint handler shape * Respect workflow JSON strict type aliases * Remove unused console log contracts reference * Address Copilot review feedback * Address Copilot follow-up comments * Synchronize ring buffer dropped count * Address background processor strategy replay
2026-05-30 20:52:01 +00:00
[Fact]
public async Task LiveFeed_WhenSubscriberQueueOverflows_PublishesDroppedItemSummary()
{
var liveFeed = new InMemoryOpenTelemetryLiveFeed(OptionsFactory.Create(new OpenTelemetryDiagnosticsOptions { SubscriberChannelCapacity = 1 }));
using var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(5));
await using var enumerator = liveFeed.SubscribeAsync(new OpenTelemetryTraceFilter(), timeout.Token).GetAsyncEnumerator(timeout.Token);
var first = enumerator.MoveNextAsync().AsTask();
await liveFeed.PublishAsync(new OpenTelemetryBatch([], [Trace("trace-1"), Trace("trace-2"), Trace("trace-3")], [], [], [], []), timeout.Token);
Assert.True(await first);
OpenTelemetryStreamItem? summary = enumerator.Current.DroppedItems != null ? enumerator.Current : null;
for (var i = 0; summary == null && i < 5 && await enumerator.MoveNextAsync(); i++)
{
if (enumerator.Current.DroppedItems != null)
summary = enumerator.Current;
}
Assert.NotNull(summary);
var nonNullSummary = summary!;
Assert.Equal(OpenTelemetrySignalType.Trace, nonNullSummary.DroppedItems!.SignalType);
Assert.Equal("SubscriberQueueFull", nonNullSummary.DroppedItems.Reason);
Assert.True(nonNullSummary.DroppedItems.Count > 0);
}
private OpenTelemetryHub CreateHub(IOpenTelemetryLiveFeed liveFeed, string permission, IOpenTelemetryClient? caller = null)
{
caller ??= new CapturingOpenTelemetryClient();
var hubContext = new TestHubContext(caller);
var subscriptionManager = new OpenTelemetrySubscriptionManager(liveFeed, hubContext, NullLogger<OpenTelemetrySubscriptionManager>.Instance);
return new OpenTelemetryHub(subscriptionManager)
{
Context = new TestHubCallerContext(CreateUser(permission)),
Clients = new TestHubCallerClients(caller)
};
}
private ClaimsPrincipal CreateUser(string permission)
{
var permissionClaimType = (string)typeof(SecurityOptions)
.GetProperty(nameof(SecurityOptions.PermissionsClaimType))!
.GetValue(new Config().Security)!;
var identity = new ClaimsIdentity([new Claim(permissionClaimType, permission)], "Test");
return new ClaimsPrincipal(identity);
}
[codex] Fix diagnostics live feed regressions (#7548) * Avoid null endpoint DTO metadata in tests * Enforce console logs hub read permission * Remove unused console logs hub import * Support mapped endpoint metadata in auth tests * Reduce console log capture throughput impact * Address Copilot console logs review * Refactor task scheduling to support tenant-level background work and enhance logging functionality. * Introduce ConsoleStreamHook for stdout/stderr tee and enhance logging validation. Adjust test cases and startup warnings for distributed lock provider usage. * Refactor console logging pipeline with capture optimization and new ConsoleLogsHost; update tests accordingly. * Add Ansi SGR parser for console logs and associated unit tests * Remove ANSI color renderings and parsers; integrate ConsoleLogScopeAccessor for improved logging context with workflow instance ID support. * Address console logs code quality feedback * Address PR review feedback * Preserve console logs extension points * Stabilize console logs host lifecycle * Address final automated review comments * Tighten console log capture shutdown * Address console log review feedback * Address follow-up review feedback * Cover final review feedback * Avoid recursive console provider initialization * Guard console host lease shutdown * Preserve console log scope and provider lifetime * Correlate console log scope fallback * Tighten console scope correlation * Expose host services during provider construction * Redact ANSI-normalized console lines * Add OpenTelemetry diagnostics backend foundation * Add OTLP HTTP ingestion parsing * Document OpenTelemetry diagnostics setup * Enforce OpenTelemetry hub permissions * Remove `ConsoleCaptureTee` and related services and tests * Add OpenTelemetry HTTP ingestion integration test * Use pipeline contributors for console log context * Update CShells package versions to 0.0.24-preview.132 * Add OpenTelemetry ingestion security tests * Add OpenTelemetry API authorization tests * Filter live console logs by workflow instance * Add OpenTelemetry hub tests * Add OpenTelemetry gRPC metadata hook * Assert OpenTelemetry workflow tags survive ingestion * Mark OpenTelemetry core build verified * Enhance console logging with activity execution metadata and extend test coverage. * Address console logs stream consumption comment * Wire OpenTelemetry diagnostics into core sample * Address Core diagnostics review feedback * Address Core Copilot follow-up feedback * Add OpenTelemetry metric instrument names * Address Core Copilot provider feedback * Address Core Copilot diagnostics follow-up * Address Core Copilot live feed feedback * Address Core Copilot store feedback * Integrate OpenTelemetry for logging, tracing, and metrics in ModularServer and update launch settings and docker-compose configuration. * Refactor to replace `ConsoleLogStream.Core` with `ConsoleLogStreaming.Core` across codebase and update `ConsoleStreamHook` installation. * Add diagnostics OpenTelemetry backend * Fix OpenTelemetry live hub subscription * Fix modular OpenTelemetry exporter endpoints * Add CShells logging configuration in appsettings.json * Remove obsolete unit tests and helper classes * Restore default activity exception handling * Simplify type serialization and alias management This commit refactors the internal type serialization and alias management system to reduce boilerplate, improve robustness, and simplify the developer experience: - Removed numerous explicit `ExpressionOptions` type alias registrations across various modules. - Updated `TypeJsonConverter` and polymorphic serialization to reliably handle types using assembly-qualified names when a short alias is not explicitly registered. - Streamlined `ExcludeFromHashConverter` to strictly adhere to `ExcludeFromHashAttribute` for hash calculations, removing complex `JsonIgnoreCondition` logic. - Eliminated several helper classes (`WorkflowJsonTypeResolver`, `WorkflowTypeValidator`, `IWorkflowTypeRegistry`, `WorkflowFactoryDictionary`, `JavaScriptExceptionTypeAliasRegistrar`, `WorkflowRuntimeTypeAliasRegistrar`) and their associated unit tests, simplifying the codebase. Additionally, this commit introduces a comprehensive markdown document (`product-website-feature-source.md`) outlining Elsa's core features, Studio capabilities, extension ecosystem, and architectural selling points, intended as source material for the product website. * Refine type serialization for improved robustness and alias handling This commit further enhances the type serialization and deserialization mechanisms: * Centralizes type resolution and alias management through `IWellKnownTypeRegistry` and `WorkflowJsonTypeResolver`. * Prioritizes registered type aliases when serializing type metadata in `PolymorphicObjectConverter`, resulting in more concise JSON output. * Enhances deserialization in `PolymorphicObjectConverter` and `VariableMapper` to gracefully handle unknown or non-instantiable types, providing fallbacks and logging warnings. * Simplifies `TypeJsonConverter` by delegating complex type resolution logic to the `WorkflowJsonTypeResolver`. * Adds `JsonArray` to the well-known type aliases for direct recognition. * Fix console logs packaging and workflow type resolution * Fix console log metadata and type resolution * Address Copilot review feedback * Enhance type resolution, improve console log handling, and update tests - Streamlined `WorkflowDictionaryExtensions` for better workflow registration validation. - Refined `ConsoleLogsAuthorizationTests` with the new `SetJsonRequest` helper to improve test requests handling. - Updated `OrderDefinition` to ignore JSON serialization for `KeySelector`. - Enhanced `WorkflowRuntimeFeature` for improved workflow registration and type alias configuration. - Added tests to ensure `ConsoleLogProvider` metadata filtration in various scenarios. - Improved type serialization logic in `WorkflowJsonTypeResolver`. - Updated README to fix references related to diagnostics. - Optimized `ExcludeFromHashConverter` for property serialization conditions. - Modified `TriggerIndexer` for streamlined trigger management. - Tested payload checks in `PublishEventTests`. - Adjusted `Endpoint` in `ConsoleLogs` for automatic JSON request handling. - Ensured registration of workflow type aliases in `WorkflowsFeature`. * Restore CLR workflow registration compatibility * Align JSON island serialization fixtures * Add Console Logs Services and Enhance Endpoint Handling - Introduced `ActivityExecutionsEndpointTests` to validate route exposure. - Added `ConsoleLogCaptureHostedService` for console log streaming. - Implemented `ConsoleStreamJsonConverter` for JSON conversion of console streams. - Developed `ElsaConsoleLogRecentBuffer` to handle recent log buffering. - Updated `ConsoleLogsAuthorizationTests` with new test cases for stream filter mapping. - Consolidated console log provider dependencies and registration, including recent buffering. - Enhanced `ElsaConsoleLogProvider` to use recent buffer for filtering. - Adjusted `Program.cs` for streamlined logging service setup. * Enhance type resolution and test coverage; streamline console log integration - Added `ConsoleStreamHook` for streamlined log streaming. - Updated `WorkflowJsonTypeResolverTests` to improve type resolution and test new scenarios. - Simplified type resolution by removing trusted assembly checks. * Fix CI smoke and package restore failures * Fix Docker smoke image project paths * Fix Docker Python runtime packages * Fix Docker CA smoke teardown * Refresh Elsa roadmap * Implement background processors and mediation coordination - Added `BackgroundCommandProcessor`, `BackgroundJobProcessor`, and `BackgroundNotificationProcessor` classes for handling commands, jobs, and notifications, respectively. - Introduced `MediatorBackgroundProcessingCoordinator` to coordinate the execution of all background processors. - Implemented `MediatorBackgroundTask` for wrapping `MediatorBackgroundProcessingCoordinator` in `BackgroundTask`. - Added unit tests for `MediatorBackgroundTask` to ensure proper start and stop behavior. - Refactored `BackgroundCommandSenderHostedService` to utilize `BackgroundCommandProcessor`. - Introduced 'elsa-roadmap-refresh' skill configuration for roadmap updates. * Address workflow type resolution review feedback * Address follow-up review feedback * Restore recent console logs execute path * Address Copilot follow-up review * Decouple workflow JSON aliases from expressions * Fix workflow management unit test setup * Fix console logs recent endpoint handler shape * Respect workflow JSON strict type aliases * Remove unused console log contracts reference * Address Copilot review feedback * Address Copilot follow-up comments * Synchronize ring buffer dropped count * Address background processor strategy replay * Fix diagnostics live feed regressions
2026-05-31 07:40:02 +00:00
private TelemetryResource Resource(string id, string serviceName)
{
return new(id, serviceName, null, null, new Dictionary<string, string?>(), _now, TelemetryResourceStatus.Active);
}
private TelemetryTrace Trace(string traceId, IReadOnlyCollection<string>? resourceIds = null, IReadOnlyCollection<string>? workflowInstanceIds = null)
{
return new(traceId, $"{traceId}-root", traceId, _now, _now.AddMilliseconds(10), TimeSpan.FromMilliseconds(10), SpanStatus.Ok, resourceIds ?? [], workflowInstanceIds ?? [], 1);
}
private MetricPoint MetricPoint(string id, string resourceId)
{
return new(id, $"{id}-instrument", $"{id}-instrument", resourceId, _now, 1, null, null, new Dictionary<string, string?>(), null, null);
}
private OtlpLogRecord Log(string id, string resourceId)
[codex] Fix console log metadata and type resolution (#7542) * Avoid null endpoint DTO metadata in tests * Enforce console logs hub read permission * Remove unused console logs hub import * Support mapped endpoint metadata in auth tests * Reduce console log capture throughput impact * Address Copilot console logs review * Refactor task scheduling to support tenant-level background work and enhance logging functionality. * Introduce ConsoleStreamHook for stdout/stderr tee and enhance logging validation. Adjust test cases and startup warnings for distributed lock provider usage. * Refactor console logging pipeline with capture optimization and new ConsoleLogsHost; update tests accordingly. * Add Ansi SGR parser for console logs and associated unit tests * Remove ANSI color renderings and parsers; integrate ConsoleLogScopeAccessor for improved logging context with workflow instance ID support. * Address console logs code quality feedback * Address PR review feedback * Preserve console logs extension points * Stabilize console logs host lifecycle * Address final automated review comments * Tighten console log capture shutdown * Address console log review feedback * Address follow-up review feedback * Cover final review feedback * Avoid recursive console provider initialization * Guard console host lease shutdown * Preserve console log scope and provider lifetime * Correlate console log scope fallback * Tighten console scope correlation * Expose host services during provider construction * Redact ANSI-normalized console lines * Add OpenTelemetry diagnostics backend foundation * Add OTLP HTTP ingestion parsing * Document OpenTelemetry diagnostics setup * Enforce OpenTelemetry hub permissions * Remove `ConsoleCaptureTee` and related services and tests * Add OpenTelemetry HTTP ingestion integration test * Use pipeline contributors for console log context * Update CShells package versions to 0.0.24-preview.132 * Add OpenTelemetry ingestion security tests * Add OpenTelemetry API authorization tests * Filter live console logs by workflow instance * Add OpenTelemetry hub tests * Add OpenTelemetry gRPC metadata hook * Assert OpenTelemetry workflow tags survive ingestion * Mark OpenTelemetry core build verified * Enhance console logging with activity execution metadata and extend test coverage. * Address console logs stream consumption comment * Wire OpenTelemetry diagnostics into core sample * Address Core diagnostics review feedback * Address Core Copilot follow-up feedback * Add OpenTelemetry metric instrument names * Address Core Copilot provider feedback * Address Core Copilot diagnostics follow-up * Address Core Copilot live feed feedback * Address Core Copilot store feedback * Integrate OpenTelemetry for logging, tracing, and metrics in ModularServer and update launch settings and docker-compose configuration. * Refactor to replace `ConsoleLogStream.Core` with `ConsoleLogStreaming.Core` across codebase and update `ConsoleStreamHook` installation. * Add diagnostics OpenTelemetry backend * Fix OpenTelemetry live hub subscription * Fix modular OpenTelemetry exporter endpoints * Add CShells logging configuration in appsettings.json * Remove obsolete unit tests and helper classes * Restore default activity exception handling * Simplify type serialization and alias management This commit refactors the internal type serialization and alias management system to reduce boilerplate, improve robustness, and simplify the developer experience: - Removed numerous explicit `ExpressionOptions` type alias registrations across various modules. - Updated `TypeJsonConverter` and polymorphic serialization to reliably handle types using assembly-qualified names when a short alias is not explicitly registered. - Streamlined `ExcludeFromHashConverter` to strictly adhere to `ExcludeFromHashAttribute` for hash calculations, removing complex `JsonIgnoreCondition` logic. - Eliminated several helper classes (`WorkflowJsonTypeResolver`, `WorkflowTypeValidator`, `IWorkflowTypeRegistry`, `WorkflowFactoryDictionary`, `JavaScriptExceptionTypeAliasRegistrar`, `WorkflowRuntimeTypeAliasRegistrar`) and their associated unit tests, simplifying the codebase. Additionally, this commit introduces a comprehensive markdown document (`product-website-feature-source.md`) outlining Elsa's core features, Studio capabilities, extension ecosystem, and architectural selling points, intended as source material for the product website. * Refine type serialization for improved robustness and alias handling This commit further enhances the type serialization and deserialization mechanisms: * Centralizes type resolution and alias management through `IWellKnownTypeRegistry` and `WorkflowJsonTypeResolver`. * Prioritizes registered type aliases when serializing type metadata in `PolymorphicObjectConverter`, resulting in more concise JSON output. * Enhances deserialization in `PolymorphicObjectConverter` and `VariableMapper` to gracefully handle unknown or non-instantiable types, providing fallbacks and logging warnings. * Simplifies `TypeJsonConverter` by delegating complex type resolution logic to the `WorkflowJsonTypeResolver`. * Adds `JsonArray` to the well-known type aliases for direct recognition. * Fix console logs packaging and workflow type resolution * Fix console log metadata and type resolution * Address Copilot review feedback * Enhance type resolution, improve console log handling, and update tests - Streamlined `WorkflowDictionaryExtensions` for better workflow registration validation. - Refined `ConsoleLogsAuthorizationTests` with the new `SetJsonRequest` helper to improve test requests handling. - Updated `OrderDefinition` to ignore JSON serialization for `KeySelector`. - Enhanced `WorkflowRuntimeFeature` for improved workflow registration and type alias configuration. - Added tests to ensure `ConsoleLogProvider` metadata filtration in various scenarios. - Improved type serialization logic in `WorkflowJsonTypeResolver`. - Updated README to fix references related to diagnostics. - Optimized `ExcludeFromHashConverter` for property serialization conditions. - Modified `TriggerIndexer` for streamlined trigger management. - Tested payload checks in `PublishEventTests`. - Adjusted `Endpoint` in `ConsoleLogs` for automatic JSON request handling. - Ensured registration of workflow type aliases in `WorkflowsFeature`. * Restore CLR workflow registration compatibility * Align JSON island serialization fixtures * Add Console Logs Services and Enhance Endpoint Handling - Introduced `ActivityExecutionsEndpointTests` to validate route exposure. - Added `ConsoleLogCaptureHostedService` for console log streaming. - Implemented `ConsoleStreamJsonConverter` for JSON conversion of console streams. - Developed `ElsaConsoleLogRecentBuffer` to handle recent log buffering. - Updated `ConsoleLogsAuthorizationTests` with new test cases for stream filter mapping. - Consolidated console log provider dependencies and registration, including recent buffering. - Enhanced `ElsaConsoleLogProvider` to use recent buffer for filtering. - Adjusted `Program.cs` for streamlined logging service setup. * Enhance type resolution and test coverage; streamline console log integration - Added `ConsoleStreamHook` for streamlined log streaming. - Updated `WorkflowJsonTypeResolverTests` to improve type resolution and test new scenarios. - Simplified type resolution by removing trusted assembly checks. * Fix CI smoke and package restore failures * Fix Docker smoke image project paths * Fix Docker Python runtime packages * Fix Docker CA smoke teardown * Refresh Elsa roadmap * Implement background processors and mediation coordination - Added `BackgroundCommandProcessor`, `BackgroundJobProcessor`, and `BackgroundNotificationProcessor` classes for handling commands, jobs, and notifications, respectively. - Introduced `MediatorBackgroundProcessingCoordinator` to coordinate the execution of all background processors. - Implemented `MediatorBackgroundTask` for wrapping `MediatorBackgroundProcessingCoordinator` in `BackgroundTask`. - Added unit tests for `MediatorBackgroundTask` to ensure proper start and stop behavior. - Refactored `BackgroundCommandSenderHostedService` to utilize `BackgroundCommandProcessor`. - Introduced 'elsa-roadmap-refresh' skill configuration for roadmap updates. * Address workflow type resolution review feedback * Address follow-up review feedback * Restore recent console logs execute path * Address Copilot follow-up review * Decouple workflow JSON aliases from expressions * Fix workflow management unit test setup * Fix console logs recent endpoint handler shape * Respect workflow JSON strict type aliases * Remove unused console log contracts reference * Address Copilot review feedback * Address Copilot follow-up comments * Synchronize ring buffer dropped count * Address background processor strategy replay
2026-05-30 20:52:01 +00:00
{
[codex] Fix diagnostics live feed regressions (#7548) * Avoid null endpoint DTO metadata in tests * Enforce console logs hub read permission * Remove unused console logs hub import * Support mapped endpoint metadata in auth tests * Reduce console log capture throughput impact * Address Copilot console logs review * Refactor task scheduling to support tenant-level background work and enhance logging functionality. * Introduce ConsoleStreamHook for stdout/stderr tee and enhance logging validation. Adjust test cases and startup warnings for distributed lock provider usage. * Refactor console logging pipeline with capture optimization and new ConsoleLogsHost; update tests accordingly. * Add Ansi SGR parser for console logs and associated unit tests * Remove ANSI color renderings and parsers; integrate ConsoleLogScopeAccessor for improved logging context with workflow instance ID support. * Address console logs code quality feedback * Address PR review feedback * Preserve console logs extension points * Stabilize console logs host lifecycle * Address final automated review comments * Tighten console log capture shutdown * Address console log review feedback * Address follow-up review feedback * Cover final review feedback * Avoid recursive console provider initialization * Guard console host lease shutdown * Preserve console log scope and provider lifetime * Correlate console log scope fallback * Tighten console scope correlation * Expose host services during provider construction * Redact ANSI-normalized console lines * Add OpenTelemetry diagnostics backend foundation * Add OTLP HTTP ingestion parsing * Document OpenTelemetry diagnostics setup * Enforce OpenTelemetry hub permissions * Remove `ConsoleCaptureTee` and related services and tests * Add OpenTelemetry HTTP ingestion integration test * Use pipeline contributors for console log context * Update CShells package versions to 0.0.24-preview.132 * Add OpenTelemetry ingestion security tests * Add OpenTelemetry API authorization tests * Filter live console logs by workflow instance * Add OpenTelemetry hub tests * Add OpenTelemetry gRPC metadata hook * Assert OpenTelemetry workflow tags survive ingestion * Mark OpenTelemetry core build verified * Enhance console logging with activity execution metadata and extend test coverage. * Address console logs stream consumption comment * Wire OpenTelemetry diagnostics into core sample * Address Core diagnostics review feedback * Address Core Copilot follow-up feedback * Add OpenTelemetry metric instrument names * Address Core Copilot provider feedback * Address Core Copilot diagnostics follow-up * Address Core Copilot live feed feedback * Address Core Copilot store feedback * Integrate OpenTelemetry for logging, tracing, and metrics in ModularServer and update launch settings and docker-compose configuration. * Refactor to replace `ConsoleLogStream.Core` with `ConsoleLogStreaming.Core` across codebase and update `ConsoleStreamHook` installation. * Add diagnostics OpenTelemetry backend * Fix OpenTelemetry live hub subscription * Fix modular OpenTelemetry exporter endpoints * Add CShells logging configuration in appsettings.json * Remove obsolete unit tests and helper classes * Restore default activity exception handling * Simplify type serialization and alias management This commit refactors the internal type serialization and alias management system to reduce boilerplate, improve robustness, and simplify the developer experience: - Removed numerous explicit `ExpressionOptions` type alias registrations across various modules. - Updated `TypeJsonConverter` and polymorphic serialization to reliably handle types using assembly-qualified names when a short alias is not explicitly registered. - Streamlined `ExcludeFromHashConverter` to strictly adhere to `ExcludeFromHashAttribute` for hash calculations, removing complex `JsonIgnoreCondition` logic. - Eliminated several helper classes (`WorkflowJsonTypeResolver`, `WorkflowTypeValidator`, `IWorkflowTypeRegistry`, `WorkflowFactoryDictionary`, `JavaScriptExceptionTypeAliasRegistrar`, `WorkflowRuntimeTypeAliasRegistrar`) and their associated unit tests, simplifying the codebase. Additionally, this commit introduces a comprehensive markdown document (`product-website-feature-source.md`) outlining Elsa's core features, Studio capabilities, extension ecosystem, and architectural selling points, intended as source material for the product website. * Refine type serialization for improved robustness and alias handling This commit further enhances the type serialization and deserialization mechanisms: * Centralizes type resolution and alias management through `IWellKnownTypeRegistry` and `WorkflowJsonTypeResolver`. * Prioritizes registered type aliases when serializing type metadata in `PolymorphicObjectConverter`, resulting in more concise JSON output. * Enhances deserialization in `PolymorphicObjectConverter` and `VariableMapper` to gracefully handle unknown or non-instantiable types, providing fallbacks and logging warnings. * Simplifies `TypeJsonConverter` by delegating complex type resolution logic to the `WorkflowJsonTypeResolver`. * Adds `JsonArray` to the well-known type aliases for direct recognition. * Fix console logs packaging and workflow type resolution * Fix console log metadata and type resolution * Address Copilot review feedback * Enhance type resolution, improve console log handling, and update tests - Streamlined `WorkflowDictionaryExtensions` for better workflow registration validation. - Refined `ConsoleLogsAuthorizationTests` with the new `SetJsonRequest` helper to improve test requests handling. - Updated `OrderDefinition` to ignore JSON serialization for `KeySelector`. - Enhanced `WorkflowRuntimeFeature` for improved workflow registration and type alias configuration. - Added tests to ensure `ConsoleLogProvider` metadata filtration in various scenarios. - Improved type serialization logic in `WorkflowJsonTypeResolver`. - Updated README to fix references related to diagnostics. - Optimized `ExcludeFromHashConverter` for property serialization conditions. - Modified `TriggerIndexer` for streamlined trigger management. - Tested payload checks in `PublishEventTests`. - Adjusted `Endpoint` in `ConsoleLogs` for automatic JSON request handling. - Ensured registration of workflow type aliases in `WorkflowsFeature`. * Restore CLR workflow registration compatibility * Align JSON island serialization fixtures * Add Console Logs Services and Enhance Endpoint Handling - Introduced `ActivityExecutionsEndpointTests` to validate route exposure. - Added `ConsoleLogCaptureHostedService` for console log streaming. - Implemented `ConsoleStreamJsonConverter` for JSON conversion of console streams. - Developed `ElsaConsoleLogRecentBuffer` to handle recent log buffering. - Updated `ConsoleLogsAuthorizationTests` with new test cases for stream filter mapping. - Consolidated console log provider dependencies and registration, including recent buffering. - Enhanced `ElsaConsoleLogProvider` to use recent buffer for filtering. - Adjusted `Program.cs` for streamlined logging service setup. * Enhance type resolution and test coverage; streamline console log integration - Added `ConsoleStreamHook` for streamlined log streaming. - Updated `WorkflowJsonTypeResolverTests` to improve type resolution and test new scenarios. - Simplified type resolution by removing trusted assembly checks. * Fix CI smoke and package restore failures * Fix Docker smoke image project paths * Fix Docker Python runtime packages * Fix Docker CA smoke teardown * Refresh Elsa roadmap * Implement background processors and mediation coordination - Added `BackgroundCommandProcessor`, `BackgroundJobProcessor`, and `BackgroundNotificationProcessor` classes for handling commands, jobs, and notifications, respectively. - Introduced `MediatorBackgroundProcessingCoordinator` to coordinate the execution of all background processors. - Implemented `MediatorBackgroundTask` for wrapping `MediatorBackgroundProcessingCoordinator` in `BackgroundTask`. - Added unit tests for `MediatorBackgroundTask` to ensure proper start and stop behavior. - Refactored `BackgroundCommandSenderHostedService` to utilize `BackgroundCommandProcessor`. - Introduced 'elsa-roadmap-refresh' skill configuration for roadmap updates. * Address workflow type resolution review feedback * Address follow-up review feedback * Restore recent console logs execute path * Address Copilot follow-up review * Decouple workflow JSON aliases from expressions * Fix workflow management unit test setup * Fix console logs recent endpoint handler shape * Respect workflow JSON strict type aliases * Remove unused console log contracts reference * Address Copilot review feedback * Address Copilot follow-up comments * Synchronize ring buffer dropped count * Address background processor strategy replay * Fix diagnostics live feed regressions
2026-05-31 07:40:02 +00:00
return new(id, resourceId, _now, "Information", 9, id, null, null, new Dictionary<string, string?>());
[codex] Fix console log metadata and type resolution (#7542) * Avoid null endpoint DTO metadata in tests * Enforce console logs hub read permission * Remove unused console logs hub import * Support mapped endpoint metadata in auth tests * Reduce console log capture throughput impact * Address Copilot console logs review * Refactor task scheduling to support tenant-level background work and enhance logging functionality. * Introduce ConsoleStreamHook for stdout/stderr tee and enhance logging validation. Adjust test cases and startup warnings for distributed lock provider usage. * Refactor console logging pipeline with capture optimization and new ConsoleLogsHost; update tests accordingly. * Add Ansi SGR parser for console logs and associated unit tests * Remove ANSI color renderings and parsers; integrate ConsoleLogScopeAccessor for improved logging context with workflow instance ID support. * Address console logs code quality feedback * Address PR review feedback * Preserve console logs extension points * Stabilize console logs host lifecycle * Address final automated review comments * Tighten console log capture shutdown * Address console log review feedback * Address follow-up review feedback * Cover final review feedback * Avoid recursive console provider initialization * Guard console host lease shutdown * Preserve console log scope and provider lifetime * Correlate console log scope fallback * Tighten console scope correlation * Expose host services during provider construction * Redact ANSI-normalized console lines * Add OpenTelemetry diagnostics backend foundation * Add OTLP HTTP ingestion parsing * Document OpenTelemetry diagnostics setup * Enforce OpenTelemetry hub permissions * Remove `ConsoleCaptureTee` and related services and tests * Add OpenTelemetry HTTP ingestion integration test * Use pipeline contributors for console log context * Update CShells package versions to 0.0.24-preview.132 * Add OpenTelemetry ingestion security tests * Add OpenTelemetry API authorization tests * Filter live console logs by workflow instance * Add OpenTelemetry hub tests * Add OpenTelemetry gRPC metadata hook * Assert OpenTelemetry workflow tags survive ingestion * Mark OpenTelemetry core build verified * Enhance console logging with activity execution metadata and extend test coverage. * Address console logs stream consumption comment * Wire OpenTelemetry diagnostics into core sample * Address Core diagnostics review feedback * Address Core Copilot follow-up feedback * Add OpenTelemetry metric instrument names * Address Core Copilot provider feedback * Address Core Copilot diagnostics follow-up * Address Core Copilot live feed feedback * Address Core Copilot store feedback * Integrate OpenTelemetry for logging, tracing, and metrics in ModularServer and update launch settings and docker-compose configuration. * Refactor to replace `ConsoleLogStream.Core` with `ConsoleLogStreaming.Core` across codebase and update `ConsoleStreamHook` installation. * Add diagnostics OpenTelemetry backend * Fix OpenTelemetry live hub subscription * Fix modular OpenTelemetry exporter endpoints * Add CShells logging configuration in appsettings.json * Remove obsolete unit tests and helper classes * Restore default activity exception handling * Simplify type serialization and alias management This commit refactors the internal type serialization and alias management system to reduce boilerplate, improve robustness, and simplify the developer experience: - Removed numerous explicit `ExpressionOptions` type alias registrations across various modules. - Updated `TypeJsonConverter` and polymorphic serialization to reliably handle types using assembly-qualified names when a short alias is not explicitly registered. - Streamlined `ExcludeFromHashConverter` to strictly adhere to `ExcludeFromHashAttribute` for hash calculations, removing complex `JsonIgnoreCondition` logic. - Eliminated several helper classes (`WorkflowJsonTypeResolver`, `WorkflowTypeValidator`, `IWorkflowTypeRegistry`, `WorkflowFactoryDictionary`, `JavaScriptExceptionTypeAliasRegistrar`, `WorkflowRuntimeTypeAliasRegistrar`) and their associated unit tests, simplifying the codebase. Additionally, this commit introduces a comprehensive markdown document (`product-website-feature-source.md`) outlining Elsa's core features, Studio capabilities, extension ecosystem, and architectural selling points, intended as source material for the product website. * Refine type serialization for improved robustness and alias handling This commit further enhances the type serialization and deserialization mechanisms: * Centralizes type resolution and alias management through `IWellKnownTypeRegistry` and `WorkflowJsonTypeResolver`. * Prioritizes registered type aliases when serializing type metadata in `PolymorphicObjectConverter`, resulting in more concise JSON output. * Enhances deserialization in `PolymorphicObjectConverter` and `VariableMapper` to gracefully handle unknown or non-instantiable types, providing fallbacks and logging warnings. * Simplifies `TypeJsonConverter` by delegating complex type resolution logic to the `WorkflowJsonTypeResolver`. * Adds `JsonArray` to the well-known type aliases for direct recognition. * Fix console logs packaging and workflow type resolution * Fix console log metadata and type resolution * Address Copilot review feedback * Enhance type resolution, improve console log handling, and update tests - Streamlined `WorkflowDictionaryExtensions` for better workflow registration validation. - Refined `ConsoleLogsAuthorizationTests` with the new `SetJsonRequest` helper to improve test requests handling. - Updated `OrderDefinition` to ignore JSON serialization for `KeySelector`. - Enhanced `WorkflowRuntimeFeature` for improved workflow registration and type alias configuration. - Added tests to ensure `ConsoleLogProvider` metadata filtration in various scenarios. - Improved type serialization logic in `WorkflowJsonTypeResolver`. - Updated README to fix references related to diagnostics. - Optimized `ExcludeFromHashConverter` for property serialization conditions. - Modified `TriggerIndexer` for streamlined trigger management. - Tested payload checks in `PublishEventTests`. - Adjusted `Endpoint` in `ConsoleLogs` for automatic JSON request handling. - Ensured registration of workflow type aliases in `WorkflowsFeature`. * Restore CLR workflow registration compatibility * Align JSON island serialization fixtures * Add Console Logs Services and Enhance Endpoint Handling - Introduced `ActivityExecutionsEndpointTests` to validate route exposure. - Added `ConsoleLogCaptureHostedService` for console log streaming. - Implemented `ConsoleStreamJsonConverter` for JSON conversion of console streams. - Developed `ElsaConsoleLogRecentBuffer` to handle recent log buffering. - Updated `ConsoleLogsAuthorizationTests` with new test cases for stream filter mapping. - Consolidated console log provider dependencies and registration, including recent buffering. - Enhanced `ElsaConsoleLogProvider` to use recent buffer for filtering. - Adjusted `Program.cs` for streamlined logging service setup. * Enhance type resolution and test coverage; streamline console log integration - Added `ConsoleStreamHook` for streamlined log streaming. - Updated `WorkflowJsonTypeResolverTests` to improve type resolution and test new scenarios. - Simplified type resolution by removing trusted assembly checks. * Fix CI smoke and package restore failures * Fix Docker smoke image project paths * Fix Docker Python runtime packages * Fix Docker CA smoke teardown * Refresh Elsa roadmap * Implement background processors and mediation coordination - Added `BackgroundCommandProcessor`, `BackgroundJobProcessor`, and `BackgroundNotificationProcessor` classes for handling commands, jobs, and notifications, respectively. - Introduced `MediatorBackgroundProcessingCoordinator` to coordinate the execution of all background processors. - Implemented `MediatorBackgroundTask` for wrapping `MediatorBackgroundProcessingCoordinator` in `BackgroundTask`. - Added unit tests for `MediatorBackgroundTask` to ensure proper start and stop behavior. - Refactored `BackgroundCommandSenderHostedService` to utilize `BackgroundCommandProcessor`. - Introduced 'elsa-roadmap-refresh' skill configuration for roadmap updates. * Address workflow type resolution review feedback * Address follow-up review feedback * Restore recent console logs execute path * Address Copilot follow-up review * Decouple workflow JSON aliases from expressions * Fix workflow management unit test setup * Fix console logs recent endpoint handler shape * Respect workflow JSON strict type aliases * Remove unused console log contracts reference * Address Copilot review feedback * Address Copilot follow-up comments * Synchronize ring buffer dropped count * Address background processor strategy replay
2026-05-30 20:52:01 +00:00
}
private class TestLiveFeed(params OpenTelemetryStreamItem[] items) : IOpenTelemetryLiveFeed
{
public OpenTelemetryTraceFilter? Filter { get; private set; }
public ValueTask PublishAsync(OpenTelemetryBatch batch, CancellationToken cancellationToken = default) => ValueTask.CompletedTask;
public async IAsyncEnumerable<OpenTelemetryStreamItem> SubscribeAsync(OpenTelemetryTraceFilter filter, [System.Runtime.CompilerServices.EnumeratorCancellation] CancellationToken cancellationToken = default)
{
Filter = filter;
foreach (var item in items)
{
cancellationToken.ThrowIfCancellationRequested();
yield return item;
await Task.Yield();
}
}
}
private class CapturingOpenTelemetryClient : IOpenTelemetryClient
{
public List<OpenTelemetryStreamItem> Items { get; } = [];
public Task ReceiveAsync(OpenTelemetryStreamItem item)
{
Items.Add(item);
return Task.CompletedTask;
}
}
private class TestHubCallerClients(IOpenTelemetryClient caller) : IHubCallerClients<IOpenTelemetryClient>
{
public IOpenTelemetryClient Caller { get; } = caller;
public IOpenTelemetryClient Others => throw new NotSupportedException();
public IOpenTelemetryClient All => throw new NotSupportedException();
public IOpenTelemetryClient AllExcept(IReadOnlyList<string> excludedConnectionIds) => throw new NotSupportedException();
public IOpenTelemetryClient Client(string connectionId) => throw new NotSupportedException();
public IOpenTelemetryClient Clients(IReadOnlyList<string> connectionIds) => throw new NotSupportedException();
public IOpenTelemetryClient Group(string groupName) => throw new NotSupportedException();
public IOpenTelemetryClient GroupExcept(string groupName, IReadOnlyList<string> excludedConnectionIds) => throw new NotSupportedException();
public IOpenTelemetryClient Groups(IReadOnlyList<string> groupNames) => throw new NotSupportedException();
public IOpenTelemetryClient OthersInGroup(string groupName) => throw new NotSupportedException();
public IOpenTelemetryClient User(string userId) => throw new NotSupportedException();
public IOpenTelemetryClient Users(IReadOnlyList<string> userIds) => throw new NotSupportedException();
}
private class TestHubContext(IOpenTelemetryClient caller) : IHubContext<OpenTelemetryHub, IOpenTelemetryClient>
{
public IHubClients<IOpenTelemetryClient> Clients { get; } = new TestHubClients(caller);
public IGroupManager Groups { get; } = new TestGroupManager();
}
private class TestHubClients(IOpenTelemetryClient caller) : IHubClients<IOpenTelemetryClient>
{
public IOpenTelemetryClient All => throw new NotSupportedException();
public IOpenTelemetryClient AllExcept(IReadOnlyList<string> excludedConnectionIds) => throw new NotSupportedException();
public IOpenTelemetryClient Client(string connectionId) => caller;
public IOpenTelemetryClient Clients(IReadOnlyList<string> connectionIds) => throw new NotSupportedException();
public IOpenTelemetryClient Group(string groupName) => throw new NotSupportedException();
public IOpenTelemetryClient GroupExcept(string groupName, IReadOnlyList<string> excludedConnectionIds) => throw new NotSupportedException();
public IOpenTelemetryClient Groups(IReadOnlyList<string> groupNames) => throw new NotSupportedException();
public IOpenTelemetryClient User(string userId) => throw new NotSupportedException();
public IOpenTelemetryClient Users(IReadOnlyList<string> userIds) => throw new NotSupportedException();
}
private class TestGroupManager : IGroupManager
{
public Task AddToGroupAsync(string connectionId, string groupName, CancellationToken cancellationToken = default) => Task.CompletedTask;
public Task RemoveFromGroupAsync(string connectionId, string groupName, CancellationToken cancellationToken = default) => Task.CompletedTask;
}
private static async Task AssertEventuallyAsync(Action assertion)
{
var deadline = DateTimeOffset.UtcNow.AddSeconds(3);
Exception? lastException = null;
while (DateTimeOffset.UtcNow < deadline)
{
try
{
assertion();
return;
}
catch (XunitException e)
{
lastException = e;
await Task.Delay(25);
}
}
if (lastException != null)
throw lastException;
}
private class TestHubCallerContext(ClaimsPrincipal user) : HubCallerContext
{
public override string ConnectionId { get; } = "connection-1";
public override string? UserIdentifier { get; } = "user-1";
public override ClaimsPrincipal? User { get; } = user;
public override IDictionary<object, object?> Items { get; } = new Dictionary<object, object?>();
public override IFeatureCollection Features { get; } = new FeatureCollection();
public override CancellationToken ConnectionAborted { get; } = CancellationToken.None;
public override void Abort()
{
}
}
}