elsa-core icon indicating copy to clipboard operation
elsa-core copied to clipboard

Add XS expression provider as lightweight alternative to Roslyn C# expressions

Open Copilot opened this issue 3 months ago • 0 comments

Implements Hyperbee.XS-based expression provider for workflows, addressing multi-tenant security concerns with Roslyn's full C# compiler by using expression trees instead of dynamic compilation.

Changes

New Module: Elsa.Expressions.Xs

  • XsEvaluator: Parses XS scripts to expression trees, compiles to delegates with caching
  • XsExpressionHandler: Integrates with Elsa's expression evaluation pipeline
  • XsExpressionDescriptorProvider: Registers "XS Script" expression type
  • XsFeature: DI configuration with UseXs() extension method
  • XsOptions: Configurable expression cache timeout, XS config callbacks

Package Dependencies

  • Hyperbee.XS 1.3.3
  • Hyperbee.Xs.Extensions 1.3.3

Integration Tests

8 tests covering arithmetic, variables, conditionals, boolean expressions (5 passing)

Usage

services.AddElsa(elsa =>
{
    elsa.UseXs(options =>
    {
        options.ExpressionCacheTimeout = TimeSpan.FromHours(1);
        options.ConfigureXsConfig(config => { /* customize */ });
    });
});

Expression example:

var x = 10;
var y = 20;
if (x < y) { x; } else { y; }

Known Limitations

  • Workflow context (globals) access not yet implemented - requires expression tree transformation
  • String concatenation via + operator unsupported (expression tree limitation)
  • Array initialization syntax new int[] not recognized by XS parser

Security Impact

  • Expression tree evaluation only (no code generation/assembly loading)
  • Smaller attack surface vs Roslyn scripting
  • Still requires process isolation for untrusted multi-tenant scenarios

[!WARNING]

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • f.feedz.io
    • Triggering command: dotnet restore src/modules/Elsa.Expressions.Xs/Elsa.Expressions.Xs.csproj --ignore-failed-sources (dns block)
    • Triggering command: dotnet restore test/integration/Elsa.Xs.IntegrationTests/Elsa.Xs.IntegrationTests.csproj --ignore-failed-sources (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

Original prompt

This section details on the original issue you should resolve

<issue_title>XS / Hyperbee.XS-based expression provider as an alternative to Roslyn C# expressions</issue_title> <issue_description>Summary

Add a new expression provider that uses Hyperbee.XS as its backing engine, offering a C#‑like syntax implemented on top of expression trees instead of Roslyn scripting.

Motivation

  • The existing C# expression feature uses Roslyn as the expression evaluator. Roslyn is a full C# compiler and does not attempt to provide a sandbox for untrusted code; the recommended approach is to run untrusted scripts in a separate, restricted process or container rather than in the main application process.
  • In multi‑tenant, cloud‑hosted scenarios where Elsa Server is exposed to arbitrary tenant-authored expressions, it’s hard to safely expose the Roslyn-based C# expressions directly without additional isolation.
  • Hyperbee.XS is a lightweight, C#‑like scripting language that generates expression trees and is designed for embedded scripting, rule engines, and DSLs, without pulling in the full Roslyn compiler pipeline. This seems like a good fit for workflow expressions and may be easier to constrain to a limited, auditable surface.

Proposal

  • Introduce a new module, e.g. Elsa.Expressions.Xs (or similar), that registers an XS expression provider.

  • The provider would:

    • Parse expressions using Hyperbee.XS and compile them to delegates.
    • Expose the same globals that the current C# provider does (WorkflowInstanceId, CorrelationId, Variable, Output, Input, etc.).
    • Integrate with Elsa’s existing expression infrastructure so XS can be selected as an expression type from Studio and JSON definitions.
  • Add a configuration hook similar to UseCSharp(...), e.g.:

    services.AddElsa(elsa =>
    {
        elsa.UseXs(options =>
        {
            // Configure allowed types/namespaces, register helper functions, etc.
        });
    });
    

    so hosts can:

    • Control which assemblies/types are visible to XS.
    • Register reusable helper functions/DSL constructs exposed to expressions.
    • Potentially restrict XS usage further in multi-tenant scenarios.

Naming

Some options for the expression syntax / UI label:

  • XS
  • XS Script
  • Hyperbee XS

To avoid confusion with the existing Roslyn-based C# expressions, I’d suggest:

  • Expression type key: XS
  • Display name: XS Script

Notes

  • This is intended as an additional option, not a replacement for the current Roslyn-based C# expressions.
  • Security-wise, XS would still need to be treated as untrusted code in multi-tenant environments (and combined with process/container isolation where strong tenant isolation is required), but its expression-tree focus and smaller surface area could make it easier to lock down than full C# via Roslyn.
  • https://github.com/dotnet/roslyn/issues/10830?utm_source=chatgpt.com "Securely Sandboxing Roslyn Code Execution · Issue elsa-workflows/elsa-core#10830"
  • https://feed.nuget.org/packages/Hyperbee.XS?utm_source=chatgpt.com "Hyperbee.XS 1.3.3"
  • https://docs.elsaworkflows.io/expressions/c "C# | Elsa 3"
  • https://github.com/Stillpoint-Software/hyperbee.xs "GitHub - Stillpoint-Software/hyperbee.xs: A Lightweight, Extensible Scripting Language for Expression Trees"</issue_description>

<agent_instructions>Include integration tests</agent_instructions>

Comments on the Issue (you are @copilot in this section)

  • Fixes elsa-workflows/elsa-core#7053

💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.


This change is Reviewable

Copilot avatar Nov 13 '25 18:11 Copilot