< Summary

Information
Class: Elsa.Permissions.PermissionGrantValidator
Assembly: Elsa.Api.Common
File(s): /home/runner/work/elsa-core/elsa-core/src/common/Elsa.Api.Common/Permissions/PermissionGrantValidator.cs
Line coverage
100%
Covered lines: 20
Uncovered lines: 0
Coverable lines: 20
Total lines: 79
Line coverage: 100%
Branch coverage
100%
Covered branches: 20
Total branches: 20
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
Validate(...)100%2020100%

File(s)

/home/runner/work/elsa-core/elsa-core/src/common/Elsa.Api.Common/Permissions/PermissionGrantValidator.cs

#LineLine coverage
 1using Elsa.Authorization;
 2
 3namespace Elsa.Permissions;
 4
 5/// <summary>Why one submitted permission was rejected.</summary>
 6public record PermissionGrantError(string Permission, string Reason);
 7
 8/// <summary>The outcome of validating a set of submitted permissions.</summary>
 9public record PermissionGrantValidationResult(IReadOnlyCollection<PermissionGrantError> Errors)
 10{
 11    /// <summary>Whether every submitted permission was acceptable.</summary>
 12    public bool IsValid => Errors.Count == 0;
 13
 14    /// <summary>An accepted result.</summary>
 15    public static PermissionGrantValidationResult Valid { get; } = new([]);
 16}
 17
 18/// <summary>Validates permissions submitted when authoring a role, before they are persisted.</summary>
 19public interface IPermissionGrantValidator
 20{
 21    /// <summary>Validates <paramref name="permissions"/> against the catalog.</summary>
 22    PermissionGrantValidationResult Validate(IEnumerable<string>? permissions);
 23}
 24
 25/// <inheritdoc />
 26/// <remarks>
 27/// Concrete segments are validated against the registry; wildcard segments are validated structurally
 28/// only. A wildcard is deliberately accepted **even when it currently matches nothing** — a grant naming
 29/// a module that is not installed yet must survive, because installing that module later is exactly what
 30/// gives the grant meaning. Validating wildcards against the catalog would reject <c>workflows/*:view</c>,
 31/// which is the grant the hierarchy exists to make possible.
 32/// </remarks>
 433public sealed class PermissionGrantValidator(IPermissionDescriptorRegistry registry) : IPermissionGrantValidator
 34{
 35    /// <inheritdoc />
 36    public PermissionGrantValidationResult Validate(IEnumerable<string>? permissions)
 37    {
 2138        if (permissions is null)
 139            return PermissionGrantValidationResult.Valid;
 40
 2041        var errors = new List<PermissionGrantError>();
 42
 10243        foreach (var value in permissions.Where(x => !string.IsNullOrWhiteSpace(x)).Distinct(StringComparer.Ordinal))
 44        {
 2045            if (!Permission.TryParse(value, out var permission))
 46            {
 347                errors.Add(new(value, "Not a well-formed permission. Expected '{resource}:{verb}'."));
 348                continue;
 49            }
 50
 51            // An entry like 'workflows*:delete' parses but the matcher never satisfies it, so it would
 52            // be persisted as a grant that silently reaches nothing.
 1753            if (!permission.IsValidPattern)
 54            {
 455                errors.Add(new(value, "Places '*' where it has no meaning and would match nothing. A wildcard may only b
 456                continue;
 57            }
 58
 1359            if (permission.IsResourceWildcard || permission.IsSubtree)
 60                continue;
 61
 962            var descriptor = registry.Find(permission.Resource);
 63
 964            if (descriptor is null)
 65            {
 266                errors.Add(new(value, $"No module registers the resource '{permission.Resource}'."));
 267                continue;
 68            }
 69
 770            if (permission.IsVerbWildcard)
 71                continue;
 72
 673            if (!descriptor.Supports(permission.Verb))
 274                errors.Add(new(value, $"The resource '{permission.Resource}' does not support the verb '{permission.Verb
 75        }
 76
 2077        return errors.Count == 0 ? PermissionGrantValidationResult.Valid : new(errors);
 78    }
 79}