Skip to content

[Code Quality] ProcessHelper.ResolvePath — Regex.Match called inline (uncompiled) on every path validation #1046

@Christophe-Rogiers

Description

@Christophe-Rogiers

Severity

Info / Minor (Performance)

Location

src/Servy.Core/Helpers/ProcessHelper.cs lines 319

Code

```csharp
public string? ResolvePath(string? inputPath)
{
...
var expandedPath = Environment.ExpandEnvironmentVariables(inputPath);

// 2. Strict Check: If the path still contains %, expansion likely failed
var match = Regex.Match(expandedPath, @\"%[^%]+%\");
if (match.Success)
...

}
```

Explanation

Regex.Match(string, string) with an inline pattern recompiles the regex on every call (or hits the small cached compiled-pattern dictionary inside Regex, depending on framework). ResolvePath is hot — it is called once per imported config field, once per ValidatePath, and once per service install/import action.

Across a large import (hundreds of services × ~12 path fields each), that's thousands of regex compilations or cache lookups for what is a single static pattern.

Compare with Service.cs:38-41, where the project already uses the canonical pattern: a static readonly Regex field with RegexOptions.Compiled and a MatchTimeout to harden against ReDoS:

```csharp
private static readonly Regex EnvVarPlaceholderRegex = new Regex(
@"(%[a-zA-Z_][a-zA-Z0-9_]*%)",
RegexOptions.Compiled,
AppConfig.InputRegexTimeout);
```

Suggested fix

Extract the pattern to a static readonly field with RegexOptions.Compiled and AppConfig.InputRegexTimeout:

```csharp
private static readonly Regex UnexpandedEnvVarRegex = new Regex(
@"%[^%]+%",
RegexOptions.Compiled,
AppConfig.InputRegexTimeout);

// then in ResolvePath:
var match = UnexpandedEnvVarRegex.Match(expandedPath);
```

This also adds the existing project-wide ReDoS timeout protection that the inline call lacks.

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions