namespace w4c_workflows.Services.Security; /// /// 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 * wildcards, e.g. core.* or *.code. /// public class NodePermissionRule { /// Node types allowed to run; empty means any (unless denied). public List AllowTypes { get; set; } = new(); /// Node types that may never run, checked before the allow list. public List DenyTypes { get; set; } = new(); /// Node kinds () allowed; empty means any. public List AllowKinds { get; set; } = new(); /// Node kinds that may never run. public List DenyKinds { get; set; } = new(); /// Blueprint origins () allowed; empty means any. public List AllowOrigins { get; set; } = new(); /// Blueprint origins that may never run. public List DenyOrigins { get; set; } = new(); /// /// When false the core.code node is refused. Sugar for /// DenyTypes = ["core.code"]; kept as an explicit switch because it is /// the highest-risk core node (it runs tenant-authored scripts). /// public bool AllowCodeNodes { get; set; } = true; /// /// When false the core.executeWorkflow node is refused. Sugar for /// DenyTypes = ["core.executeWorkflow"]. /// public bool AllowSubWorkflows { get; set; } = true; } /// /// Operator policy deciding which node types a workflow run may use. Bound from /// the Nodes:Permissions configuration section. The default is /// permissive (nothing is restricted) so adding the feature changes no existing /// workflow; operators opt into the restrictions they want. /// public sealed class NodePermissionOptions : NodePermissionRule { /// Configuration section this policy binds from. public const string SectionName = "Nodes:Permissions"; /// /// 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. /// public Dictionary Tenants { get; set; } = new(StringComparer.Ordinal); }