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);
}