w4c-workflows-api/Services/Security/NodePermissionOptions.cs
2026-09-12 01:02:46 +03:00

61 lines
2.7 KiB
C#

namespace w4c_workflows.Services.Security;
/// <summary>
/// One allow/deny rule for node execution. Shared by the global policy and the
/// per-tenant overrides, so an operator can restrict a noisy or high-risk tenant
/// without changing what everyone else may run.
///
/// Semantics, in evaluation order (deny always wins): the deny lists are checked
/// first, then the two convenience guards, then the allow lists. An empty allow
/// list means "no restriction"; a non-empty allow list means "only these match".
/// Entry patterns support <c>*</c> wildcards, e.g. <c>core.*</c> or <c>*.code</c>.
/// </summary>
public class NodePermissionRule
{
/// <summary>Node types allowed to run; empty means any (unless denied).</summary>
public List<string> AllowTypes { get; set; } = new();
/// <summary>Node types that may never run, checked before the allow list.</summary>
public List<string> DenyTypes { get; set; } = new();
/// <summary>Node kinds (<see cref="Models.Nodes.NodeKind"/>) allowed; empty means any.</summary>
public List<string> AllowKinds { get; set; } = new();
/// <summary>Node kinds that may never run.</summary>
public List<string> DenyKinds { get; set; } = new();
/// <summary>Blueprint origins (<see cref="Models.Nodes.NodeOrigin"/>) allowed; empty means any.</summary>
public List<string> AllowOrigins { get; set; } = new();
/// <summary>Blueprint origins that may never run.</summary>
public List<string> DenyOrigins { get; set; } = new();
/// <summary>
/// When false the <c>core.code</c> node is refused. It runs tenant-authored
/// scripts and is the highest-risk core node, so it has a dedicated switch.
/// </summary>
public bool AllowCodeNodes { get; set; } = true;
/// <summary>When false the <c>core.executeWorkflow</c> node is refused.</summary>
public bool AllowSubWorkflows { get; set; } = true;
}
/// <summary>
/// Operator policy deciding which node types a workflow run may use. Bound from
/// the <c>Nodes:Permissions</c> configuration section. The default is
/// permissive (nothing is restricted) so adding the feature changes no existing
/// workflow; operators opt into the restrictions they want.
/// </summary>
public sealed class NodePermissionOptions : NodePermissionRule
{
/// <summary>Configuration section this policy binds from.</summary>
public const string SectionName = "Nodes:Permissions";
/// <summary>
/// Per-tenant rules. A tenant present here is evaluated against its own rule
/// instead of the global one, so a single tenant can be locked down without
/// affecting the rest.
/// </summary>
public Dictionary<string, NodePermissionRule> Tenants { get; set; } = new(StringComparer.Ordinal);
}