Flow Studio
Capability-Based Security
NodeCapabilityPolicy — controlling which tenants and actors can use which node capability types at both design time and execution time.
NodeCapabilityPolicy
NodeCapabilityPolicy is a ProcessSecurity entity that maps a tenant (or specific actor role) to a set of allowed capability types. It enforces capability access at two levels:
- Design time: The palette and API filter out capabilities not allowed for the tenant
- Execution time: The engine checks policy before running any node with a restricted capability
Policy Schema
public class NodeCapabilityPolicy
{
public Guid Id { get; set; }
public string TenantId { get; set; }
public string? RoleId { get; set; } // null = applies to all roles in tenant
public List<CapabilityType> AllowedTypes { get; set; }
public List<CapabilityType> DeniedTypes { get; set; }
public bool AllowAllByDefault { get; set; } // if true, DeniedTypes is the blocklist
}
Execution-Time Check
// ProcessEngine/Security/CapabilityAuthorizationService.cs
public async Task<bool> IsAllowedAsync(
CapabilityType capabilityType,
string tenantId,
string actorId)
{
var policy = await _policyRepo.GetForTenantAsync(tenantId);
if (policy == null) return true; // no policy = allow all
if (policy.AllowAllByDefault)
return !policy.DeniedTypes.Contains(capabilityType);
else
return policy.AllowedTypes.Contains(capabilityType);
}
Security Layers
| Layer | Enforcement Point | Effect |
|---|---|---|
| Palette filter | GET /api/capabilities (designer) | Capability sections hidden from UI |
| Publish validation | POST /api/processes/{id}/publish | Cannot publish workflow using denied capabilities |
| Execution check | Before each node execution | Node fails with CapabilityAccessDenied error |
Defense in depth: The execution-time check is the authoritative gate. The palette and publish filters are convenience — they improve UX but must not be relied upon as the sole security control. An attacker with direct API access could publish a workflow with restricted nodes; the execution-time check stops it at runtime.
Example Policy Configuration
{
"tenantId": "tenant-acme",
"allowAllByDefault": true,
"deniedTypes": ["DIDComm", "MCP"],
"comment": "Acme has not licensed the DIDComm or MCP add-ons"
}