diff --git a/src/apps/Elsa.ModularServer.Web/Program.cs b/src/apps/Elsa.ModularServer.Web/Program.cs index 0b1248f4f..bdc52921a 100644 --- a/src/apps/Elsa.ModularServer.Web/Program.cs +++ b/src/apps/Elsa.ModularServer.Web/Program.cs @@ -35,6 +35,7 @@ var builder = WebApplication.CreateBuilder(args); var services = builder.Services; var configuration = builder.Configuration; configuration.AddJsonFile(configuration["Elsa:PlatformIntegration:ShellOverlayPath"] ?? "platform-shell-overrides.json", optional: true, reloadOnChange: false); +services.AddRoleManagementE2EFixtures(configuration); var serviceVersion = typeof(Program).Assembly.GetName().Version?.ToString(); builder.Logging.AddOpenTelemetry(logging => diff --git a/src/apps/Elsa.ModularServer.Web/RoleManagementE2EFixtures.cs b/src/apps/Elsa.ModularServer.Web/RoleManagementE2EFixtures.cs new file mode 100644 index 000000000..bc3eac891 --- /dev/null +++ b/src/apps/Elsa.ModularServer.Web/RoleManagementE2EFixtures.cs @@ -0,0 +1,46 @@ +using Elsa.Permissions; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; + +namespace Elsa.ModularServer.Web; + +/// Opt-in services used by the Elsa Studio role-management acceptance harness. +public static class RoleManagementE2EFixtureServiceCollectionExtensions +{ + /// Configuration switch that enables the role-management catalog fixture. + public const string IncludeUnverifiedPermissionDescriptorKey = "RoleManagementE2EFixtures:IncludeUnverifiedPermissionDescriptor"; + + /// + /// Adds the deterministic role-management fixture when explicitly enabled by the host configuration. + /// The default path is intentionally a no-op so ordinary sample and production hosts do not change. + /// + public static IServiceCollection AddRoleManagementE2EFixtures(this IServiceCollection services, IConfiguration configuration) + { + if (configuration.GetValue(IncludeUnverifiedPermissionDescriptorKey)) + services.AddSingleton(RoleManagementE2EFixturePermissionDescriptorProvider.Instance); + + return services; + } +} + +/// Provides the one unverified descriptor needed by the role-management acceptance harness. +/// +/// This is a value type on purpose: the shell descriptor scanner discovers class-based module providers, while +/// this provider is registered only through the explicit opt-in above. It therefore cannot leak into the normal +/// catalog merely because the host assembly is loaded. +/// +internal readonly struct RoleManagementE2EFixturePermissionDescriptorProvider : IPermissionDescriptorProvider +{ + public static RoleManagementE2EFixturePermissionDescriptorProvider Instance => new(); + + public IEnumerable GetDescriptors() => + [ + new( + "e2e/role-management/unverified", + [Authorization.CoreVerbs.View], + "E2E unverified permission", + "Fixture-only permission descriptor for role-management acceptance testing.", + "E2E fixtures", + Verified: false) + ]; +} diff --git a/test/integration/Elsa.Hosts.SmokeTests/RoleManagementE2EFixtureTests.cs b/test/integration/Elsa.Hosts.SmokeTests/RoleManagementE2EFixtureTests.cs new file mode 100644 index 000000000..b7112cfd4 --- /dev/null +++ b/test/integration/Elsa.Hosts.SmokeTests/RoleManagementE2EFixtureTests.cs @@ -0,0 +1,49 @@ +using Elsa.Authorization; +using Elsa.ModularServer.Web; +using Elsa.Permissions; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; + +namespace Elsa.Hosts.SmokeTests; + +public class RoleManagementE2EFixtureTests +{ + [Fact] + public void DisabledConfigurationLeavesServicesUnchanged() + { + var services = new ServiceCollection(); + services.AddSingleton(); + var before = services.ToArray(); + + services.AddRoleManagementE2EFixtures(new ConfigurationBuilder().Build()); + + Assert.Equal(before, services); + Assert.DoesNotContain(services, x => x.ServiceType == typeof(IPermissionDescriptorProvider)); + } + + [Fact] + public void EnabledConfigurationContributesOneUnverifiedDescriptor() + { + var configuration = new ConfigurationBuilder() + .AddInMemoryCollection(new Dictionary + { + [RoleManagementE2EFixtureServiceCollectionExtensions.IncludeUnverifiedPermissionDescriptorKey] = "true" + }) + .Build(); + var services = new ServiceCollection(); + + services.AddRoleManagementE2EFixtures(configuration); + + using var serviceProvider = services.BuildServiceProvider(); + var providers = serviceProvider.GetServices().ToArray(); + var descriptors = providers.SelectMany(x => x.GetDescriptors()).ToArray(); + + Assert.Single(providers); + var descriptor = Assert.Single(descriptors); + Assert.Equal("e2e/role-management/unverified", descriptor.Resource); + Assert.False(descriptor.Verified); + Assert.Equal([CoreVerbs.View], descriptor.SupportedVerbs); + } + + private sealed class ExistingService; +}