SGuard.ConfigValidation
0.1.0
dotnet add package SGuard.ConfigValidation --version 0.1.0
NuGet\Install-Package SGuard.ConfigValidation -Version 0.1.0
<PackageReference Include="SGuard.ConfigValidation" Version="0.1.0" />
<PackageVersion Include="SGuard.ConfigValidation" Version="0.1.0" />
<PackageReference Include="SGuard.ConfigValidation" />
paket add SGuard.ConfigValidation --version 0.1.0
#r "nuget: SGuard.ConfigValidation, 0.1.0"
#:package SGuard.ConfigValidation@0.1.0
#addin nuget:?package=SGuard.ConfigValidation&version=0.1.0
#tool nuget:?package=SGuard.ConfigValidation&version=0.1.0
SGuard.ConfigValidation
A powerful yet lightweight tool to catch critical configuration issues before runtime, ensuring your .NET applications run reliably across all environments.
✨ Description
SGuard.ConfigValidation is designed to help developers and DevOps teams detect missing, invalid, or misconfigured settings in configuration files before the application runs—either at startup or (ideally) automatically during your CI/CD pipelines. The library supports both JSON (default) and YAML configuration formats and fits seamlessly into any .NET project. It offers a highly extensible architecture, making it easy to add custom validators or integrate with existing tools. Whether you use it as a CLI tool or programmatically inside your code, it helps to ensure your configuration files (like appsettings.json, environment variables, and custom config files) are complete and valid for all specified environments.
Use cases include:
- Early detection of missing connection strings, API keys, or URLs
- Preventing production outages caused by configuration errors
- Automated configuration validation in build/deploy pipelines
- Enforcing security and size limits for configuration files
- Supporting both small projects and large enterprise-grade solutions by handling thousands of environments or rules efficiently
With SGuard.ConfigValidation, you reduce the risk of runtime failures, improve deployment reliability, and enforce best practices around configuration management—leading to more robust applications and happier teams.
✨ Why?
Misconfigurations are among the most common sources of production incidents, outages, and security vulnerabilities. Mistyped keys, missing secrets, or incorrect environment variables often go unnoticed until the application is started or deployed—sometimes resulting in downtime, failed deployments, or even data loss.
SGuard.ConfigValidation helps you:
- Shift left: Catch configuration errors as early as possible, ideally before deploying to production.
- Automate checks: Integrate config validation into your CI/CD pipeline so no bad configs slip through unnoticed.
- Support all environments: Validate against every environment (development, staging, production, etc.) and ensure consistent configuration health everywhere.
- Extend easily: Create and plug in your own custom validation rules, tailored to your application's needs.
- Increase security & reliability: Enforce size, depth, and complexity limits to prevent resource exhaustion, and protect against common configuration issues like missing or weak secrets.
- Save time and resources: Debugging runtime issues caused by misconfiguration can be costly. By detecting these problems before deployment, you reduce downtime, support costs, and stress for both developers and operations teams.
In short, SGuard.ConfigValidation gives you confidence that your application will work as expected, in every environment, every time.
🚀 Features
Supported Validators
- required → Ensures a specific key must exist in the target config file
- min_len → Validates minimum string length
- max_len → Validates maximum string length
- eq → Checks if value equals a specified value
- ne → Checks if value does not equal a specified value
- gt → Checks if value is greater than a specified value
- gte → Checks if value is greater than or equal to a specified value
- lt → Checks if value is less than a specified value
- lte → Checks if value is less than or equal to a specified value
- in → Checks if value is in a specified array
Framework Support
- .NET 8.0 (LTS)
- .NET 9.0
- .NET 10.0
Additional Features
- JSON Configuration Support: Load configuration and app settings from JSON files (
.json). JSON is the default format for bothsguard.jsonconfiguration files andappsettings.jsonfiles. - YAML Configuration Support: Load configuration and app settings from YAML files (
.yaml,.yml) when YAML loader is provided - JSON Schema Validation: Validate
sguard.jsonagainst JSON Schema for structure validation - Custom Validator Plugins: Extend validation capabilities with custom validator plugins
- Performance Optimizations: Built-in caching for path resolution, schema validation, and reflection operations
📖 Usage
CLI Commands
Validate Command (Default)
# Validate all environments
dotnet run -- validate
# Validate specific environment
dotnet run -- validate --env dev
# Validate specific environment
dotnet run -- validate --env prod
# Validate with custom config file
dotnet run -- validate --config custom-sguard.json
# Validate all environments explicitly
dotnet run -- validate --all
# Output as JSON
dotnet run -- validate --output json
# Write results to JSON file
dotnet run -- validate --output json --output-file results.json
# Write results to text file
dotnet run -- validate --output text --output-file results.txt
# Enable verbose logging
dotnet run -- validate --verbose
Command Options
--config, -c- Path to the configuration file (default:sguard.json)--env, -e- Environment ID to validate (if not specified, all environments are validated)--all, -a- Validate all environments--output, -o- Output format:json,text, orconsole(default:console)--output-file, -f- Path to output file. If specified, results will be written to this file instead of console. Works with both json and text formats.--verbose, -v- Enable verbose logging
📂 Configuration Format
SGuard.ConfigValidation supports JSON (default) and YAML configuration formats. JSON is the default format and is used for both sguard.json configuration files and appsettings.json files.
Example sguard.json (JSON Format)
{
"version": "1",
"environments": [
{
"id": "dev",
"name": "Development",
"path": "appsettings.Development.json",
"description": "Development environment"
},
{
"id": "stag",
"name": "Staging",
"path": "appsettings.Staging.json",
"description": "Staging environment"
},
{
"id": "prod",
"name": "Production",
"path": "appsettings.Production.json",
"description": "Production environment"
}
],
"rules": [
{
"id": "common-rules",
"environments": ["dev", "stag", "prod"],
"rule": {
"id": "connection-string-rule",
"conditions": [
{
"key": "ConnectionStrings:DefaultConnection",
"condition": [
{
"validator": "required",
"message": "Connection string is required"
},
{
"validator": "min_len",
"value": 10,
"message": "Connection string must be at least 10 characters long"
},
{
"validator": "max_len",
"value": 200,
"message": "Connection string must be at most 200 characters long"
}
]
}
]
}
},
{
"id": "production-rules",
"environments": ["prod"],
"rule": {
"id": "api-key-rule",
"conditions": [
{
"key": "ApiKeys:ExternalService",
"condition": [
{
"validator": "required",
"message": "External service API key is required in production"
},
{
"validator": "min_len",
"value": 32,
"message": "API key must be at least 32 characters"
}
]
}
]
}
}
]
}
Configuration Schema
- version (string, required): Configuration version. Must not be null or empty.
- environments (array, required): List of environment definitions. Must contain at least one environment.
- id (string, required): Unique environment identifier. Must not be null or empty. Must be unique across all environments.
- name (string, required): Environment display name. Must not be null or empty.
- path (string, required): Path to the appsettings file for this environment. Must not be null or empty.
- description (string, optional): Environment description. Can be null or empty.
- rules (array, required): List of validation rules. Must contain at least one rule. Cannot be empty.
- id (string, required): Unique rule identifier. Must not be null or empty. Must be unique across all rules.
- environments (array, required): List of environment IDs where this rule applies. Must contain at least one environment ID. All environment IDs must exist in the environments list.
- rule (object, required): Rule definition. Must not be null.
- id (string, required): Rule detail identifier. Must not be null or empty.
- conditions (array, required): List of validation conditions. Must contain at least one condition.
🔧 Programmatic Usage
Using the Library
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;
using SGuard.ConfigValidation.Common;
using SGuard.ConfigValidation.Services;
using SGuard.ConfigValidation.Validators;
// Setup security options
var securityOptions = Options.Create(new SecurityOptions());
// Setup services with logging
var loggerFactory = NullLoggerFactory.Instance;
var validatorFactoryLogger = NullLogger<ValidatorFactory>.Instance;
var configLoaderLogger = NullLogger<ConfigLoader>.Instance;
var fileValidatorLogger = NullLogger<FileValidator>.Instance;
var ruleEngineLogger = NullLogger<RuleEngine>.Instance;
var validatorFactory = new ValidatorFactory(validatorFactoryLogger);
var configLoader = new ConfigLoader(configLoaderLogger, securityOptions);
var fileValidator = new FileValidator(validatorFactory, fileValidatorLogger);
var ruleEngine = new RuleEngine(
configLoader,
fileValidator,
validatorFactory,
ruleEngineLogger,
securityOptions);
// Validate environment
var result = await ruleEngine.ValidateEnvironmentAsync("sguard.json", "prod");
if (result.IsSuccess && !result.HasValidationErrors)
{
Console.WriteLine("Validation passed!");
}
else
{
if (!string.IsNullOrEmpty(result.ErrorMessage))
{
Console.WriteLine($"Validation failed: {result.ErrorMessage}");
}
foreach (var validationResult in result.ValidationResults)
{
foreach (var error in validationResult.Errors)
{
Console.WriteLine($" - {error.Key}: {error.Message}");
}
}
}
Dependency Injection (Recommended)
Using the extension methods for easy registration:
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using SGuard.ConfigValidation.Extensions;
var services = new ServiceCollection();
// Register logging (required)
services.AddLogging(builder => builder.AddConsole());
// Build configuration
var configuration = new ConfigurationBuilder()
.AddJsonFile("appsettings.json", optional: true)
.AddEnvironmentVariables()
.Build();
// Register all SGuard.ConfigValidation services with one line
services.AddSGuardConfigValidation(configuration);
// Or specify a logging level directly (logging will be automatically configured)
services.AddSGuardConfigValidation(configuration, logLevel: LogLevel.Debug);
var serviceProvider = services.BuildServiceProvider();
var ruleEngine = serviceProvider.GetRequiredService<IRuleEngine>();
// Example: Validate all environments
var result = await ruleEngine.ValidateAllEnvironmentsAsync("sguard.json");
if (result.IsSuccess)
{
Console.WriteLine($"Validated {result.ValidationResults.Count} environment(s)");
}
Manual Dependency Injection Registration
If you prefer manual registration or need more control:
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using SGuard.ConfigValidation.Common;
using SGuard.ConfigValidation.Services;
using SGuard.ConfigValidation.Validators;
using SGuard.ConfigValidation.Validators.Plugin;
var services = new ServiceCollection();
// Register logging (required)
services.AddLogging(builder => builder.AddConsole());
// Register configuration and security options
var configuration = new ConfigurationBuilder()
.AddJsonFile("appsettings.json", optional: true)
.AddEnvironmentVariables()
.Build();
services.Configure<SecurityOptions>(configuration.GetSection("Security"));
// Register core services
services.AddSingleton<IValidatorFactory, ValidatorFactory>();
services.AddSingleton<IConfigLoader, ConfigLoader>();
services.AddSingleton<IFileValidator, FileValidator>();
services.AddSingleton<IRuleEngine, RuleEngine>();
// Register optional services
services.AddSingleton<IYamlLoader, YamlLoader>();
services.AddSingleton<ISchemaValidator, JsonSchemaValidator>();
services.AddSingleton<ValidatorPluginDiscovery>();
var serviceProvider = services.BuildServiceProvider();
var ruleEngine = serviceProvider.GetRequiredService<IRuleEngine>();
// Example: Validate all environments
var result = await ruleEngine.ValidateAllEnvironmentsAsync("sguard.json");
if (result.IsSuccess)
{
Console.WriteLine($"Validated {result.ValidationResults.Count} environment(s)");
}
Logging Level Configuration
You can specify a logging level directly when registering services. This will automatically configure logging for SGuard namespaces:
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using SGuard.ConfigValidation.Extensions;
var services = new ServiceCollection();
// Register with Debug level (verbose logging)
services.AddSGuardConfigValidation(logLevel: LogLevel.Debug);
// Or for production, use Warning level (only warnings and errors)
services.AddSGuardConfigValidation(logLevel: LogLevel.Warning);
// Or for development, use Trace level (most verbose)
services.AddSGuardConfigValidation(logLevel: LogLevel.Trace);
var serviceProvider = services.BuildServiceProvider();
var ruleEngine = serviceProvider.GetRequiredService<IRuleEngine>();
Note: When logLevel is specified, logging is automatically configured. You don't need to call AddLogging() separately. However, you may still want to add a logging provider (e.g., AddConsole()) if you need console output.
Available Log Levels:
LogLevel.Trace- Most verbose, includes all log messagesLogLevel.Debug- Debug information for troubleshootingLogLevel.Information- General informational messages (default)LogLevel.Warning- Warning messages and aboveLogLevel.Error- Error messages and aboveLogLevel.Critical- Only critical errors
Core Services Only
If you only need core services without YAML or schema validation:
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using SGuard.ConfigValidation.Extensions;
var services = new ServiceCollection();
// Register logging
services.AddLogging(builder => builder.AddConsole());
// Register only core services
services.AddSGuardConfigValidationCore();
// Or specify a logging level directly
services.AddSGuardConfigValidationCore(logLevel: LogLevel.Debug);
// Optionally add YAML support later
// services.AddSingleton<IYamlLoader, YamlLoader>();
var serviceProvider = services.BuildServiceProvider();
var ruleEngine = serviceProvider.GetRequiredService<IRuleEngine>();
YAML Configuration Support
The library supports loading configuration and app settings from YAML files:
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;
using SGuard.ConfigValidation.Common;
using SGuard.ConfigValidation.Services;
// Setup security options
var securityOptions = Options.Create(new SecurityOptions());
var logger = NullLogger<YamlLoader>.Instance;
var yamlLoader = new YamlLoader(logger, securityOptions);
// Load configuration from YAML
var config = yamlLoader.LoadConfig("sguard.yaml");
// Load app settings from YAML
var appSettings = yamlLoader.LoadAppSettings("appsettings.yaml");
// Example: Access loaded configuration
Console.WriteLine($"Loaded {config.Environments.Count} environment(s)");
Console.WriteLine($"Loaded {config.Rules.Count} rule(s)");
JSON Schema Validation
Validate your sguard.json configuration against a JSON Schema:
using SGuard.ConfigValidation.Services;
using System.Text.Json;
var schemaValidator = new JsonSchemaValidator();
// Example 1: Validate JSON content against schema content
var jsonContent = """
{
"version": "1",
"environments": [{"id": "dev", "name": "Development", "path": "appsettings.Dev.json"}],
"rules": []
}
""";
var schemaContent = """
{
"type": "object",
"properties": {
"version": {"type": "string"},
"environments": {"type": "array"},
"rules": {"type": "array"}
},
"required": ["version", "environments"]
}
""";
var result = schemaValidator.Validate(jsonContent, schemaContent);
if (!result.IsValid)
{
Console.WriteLine("Schema validation failed:");
foreach (var error in result.Errors)
{
Console.WriteLine($" - {error}");
}
}
else
{
Console.WriteLine("Schema validation passed!");
}
// Example 2: Validate against a schema file
var fileResult = schemaValidator.ValidateAgainstFile(jsonContent, "sguard.schema.json");
if (!fileResult.IsValid)
{
foreach (var error in fileResult.Errors)
{
Console.WriteLine($"Schema validation error: {error}");
}
}
Custom Validator Plugins
Create custom validators by implementing IValidatorPlugin:
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using SGuard.ConfigValidation.Models;
using SGuard.ConfigValidation.Validators;
using SGuard.ConfigValidation.Validators.Plugin;
using System.Text.RegularExpressions;
// Step 1: Create a custom validator
public class EmailValidator : IValidator<object>
{
private static readonly Regex EmailRegex = new(@"^[^@\s]+@[^@\s]+\.[^@\s]+$", RegexOptions.Compiled);
public string ValidatorType => "email";
public ValidationResult Validate(object value, ValidatorCondition condition)
{
if (value == null)
{
return ValidationResult.Failure(condition.Message ?? "Email is required");
}
var email = value.ToString();
if (string.IsNullOrWhiteSpace(email))
{
return ValidationResult.Failure(condition.Message ?? "Email cannot be empty");
}
if (!EmailRegex.IsMatch(email))
{
return ValidationResult.Failure(
condition.Message ?? $"Invalid email format. Actual value: '{email}'");
}
return ValidationResult.Success();
}
}
// Step 2: Create a plugin wrapper
public class EmailValidatorPlugin : IValidatorPlugin
{
public string ValidatorType => "email";
public IValidator<object> Validator => new EmailValidator();
}
// Step 3: Discover and use plugins
var logger = NullLogger<ValidatorPluginDiscovery>.Instance;
var pluginDiscovery = new ValidatorPluginDiscovery(logger);
var plugins = pluginDiscovery.DiscoverValidators(new[] { "./plugins" });
// Step 4: Register plugins with ValidatorFactory
var validatorFactory = new ValidatorFactory(logger);
foreach (var plugin in plugins)
{
validatorFactory.RegisterValidator(plugin.ValidatorType, plugin.Validator);
}
Error Handling
Handle validation errors gracefully:
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;
using SGuard.ConfigValidation.Common;
using SGuard.ConfigValidation.Exceptions;
using SGuard.ConfigValidation.Services;
using SGuard.ConfigValidation.Validators;
var securityOptions = Options.Create(new SecurityOptions());
var logger = NullLogger<RuleEngine>.Instance;
var validatorFactory = new ValidatorFactory(NullLogger<ValidatorFactory>.Instance);
var configLoader = new ConfigLoader(NullLogger<ConfigLoader>.Instance, securityOptions);
var fileValidator = new FileValidator(validatorFactory, NullLogger<FileValidator>.Instance);
var ruleEngine = new RuleEngine(
configLoader,
fileValidator,
validatorFactory,
logger,
securityOptions);
try
{
var result = await ruleEngine.ValidateEnvironmentAsync("sguard.json", "prod");
if (result.IsSuccess)
{
if (result.HasValidationErrors)
{
Console.WriteLine("Validation completed with errors:");
var fileResult = result.SingleResult ?? result.ValidationResults.FirstOrDefault();
if (fileResult != null)
{
Console.WriteLine($"File: {fileResult.Path}");
foreach (var error in fileResult.Errors)
{
Console.WriteLine($" Key: {error.Key}");
Console.WriteLine($" Error: {error.Message}");
}
}
}
else
{
Console.WriteLine("All validations passed!");
}
}
else
{
Console.WriteLine($"Validation failed: {result.ErrorMessage}");
}
}
catch (FileNotFoundException ex)
{
Console.WriteLine($"Configuration file not found: {ex.FileName}");
}
catch (ConfigurationException ex)
{
Console.WriteLine($"Configuration error: {ex.Message}");
}
catch (Exception ex)
{
Console.WriteLine($"Unexpected error: {ex.Message}");
}
Advanced Usage: Validating Multiple Environments
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;
using SGuard.ConfigValidation.Common;
using SGuard.ConfigValidation.Services;
using SGuard.ConfigValidation.Validators;
var securityOptions = Options.Create(new SecurityOptions());
var logger = NullLogger<RuleEngine>.Instance;
var validatorFactory = new ValidatorFactory(NullLogger<ValidatorFactory>.Instance);
var configLoader = new ConfigLoader(NullLogger<ConfigLoader>.Instance, securityOptions);
var fileValidator = new FileValidator(validatorFactory, NullLogger<FileValidator>.Instance);
var ruleEngine = new RuleEngine(
configLoader,
fileValidator,
validatorFactory,
logger,
securityOptions);
// Validate all environments
var allResults = await ruleEngine.ValidateAllEnvironmentsAsync("sguard.json");
var successCount = allResults.ValidationResults.Count(r => r.IsValid);
var failureCount = allResults.ValidationResults.Count - successCount;
Console.WriteLine($"Validated {allResults.ValidationResults.Count} environment(s)");
Console.WriteLine($" ✅ Passed: {successCount}");
Console.WriteLine($" ❌ Failed: {failureCount}");
// Validate specific environments
var environmentsToValidate = new[] { "dev", "stag", "prod" };
foreach (var envId in environmentsToValidate)
{
var result = await ruleEngine.ValidateEnvironmentAsync("sguard.json", envId);
Console.WriteLine($"Environment '{envId}': {(result.IsSuccess && !result.HasValidationErrors ? "✅ Pass" : "❌ Fail")}");
}
CI/CD Integration Example
Example GitHub Actions workflow:
name: Validate Configuration
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main ]
jobs:
validate-config:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup .NET
uses: actions/setup-dotnet@v3
with:
dotnet-version: '8.0.x'
- name: Restore dependencies
run: dotnet restore
- name: Validate configuration
run: |
dotnet run --project SGuard.ConfigValidation.Console -- validate --all --output json > validation-results.json
- name: Check validation results
run: |
if grep -q '"HasValidationErrors":true' validation-results.json; then
echo "❌ Configuration validation failed!"
cat validation-results.json
exit 1
else
echo "✅ All configurations are valid!"
fi
Example Azure DevOps pipeline:
trigger:
branches:
include:
- main
- develop
pool:
vmImage: 'ubuntu-latest'
steps:
- task: UseDotNet@2
inputs:
packageType: 'sdk'
version: '8.0.x'
- task: DotNetCoreCLI@2
displayName: 'Restore dependencies'
inputs:
command: 'restore'
- task: DotNetCoreCLI@2
displayName: 'Validate configuration'
inputs:
command: 'run'
projects: 'SGuard.ConfigValidation.Console/SGuard.ConfigValidation.Console.csproj'
arguments: '-- validate --all --output json'
continueOnError: false
📊 Output Formats
Console Output (Default)
🔍 Validating Environments:
📁 Environment: Development
File: appsettings.Development.json
Status: ✅ PASS
Validated 2 rule(s)
📁 Environment: Production
File: appsettings.Production.json
Status: ❌ FAIL
Errors (1):
🔑 ConnectionStrings:DefaultConnection
✖ required: Connection string is required
💡 Current value:
✅ All validations passed successfully!
JSON Output (Console)
{
"Success": true,
"ErrorMessage": "",
"HasValidationErrors": false,
"Results": [
{
"Path": "appsettings.Development.json",
"IsValid": true,
"ErrorCount": 0,
"Results": [...],
"Errors": []
}
]
}
File Output
You can write validation results to a file in either text or JSON format:
Text File Output
using SGuard.ConfigValidation.Output;
using Microsoft.Extensions.Logging;
var loggerFactory = LoggerFactory.Create(builder => builder.AddConsole());
// Write text output to file
var textFormatter = OutputFormatterFactory.Create("text", loggerFactory, "validation-results.txt");
await textFormatter.FormatAsync(result);
JSON File Output
using SGuard.ConfigValidation.Output;
using Microsoft.Extensions.Logging;
var loggerFactory = LoggerFactory.Create(builder => builder.AddConsole());
// Write JSON output to file
var jsonFormatter = OutputFormatterFactory.Create("json", loggerFactory, "validation-results.json");
await jsonFormatter.FormatAsync(result);
Direct Formatter Usage
You can also use the formatters directly:
using SGuard.ConfigValidation.Output;
// Text file formatter
var fileFormatter = new FileOutputFormatter("results.txt");
await fileFormatter.FormatAsync(result);
// JSON file formatter
var jsonFileFormatter = new JsonFileOutputFormatter("results.json");
await jsonFileFormatter.FormatAsync(result);
🔒 Security Configuration
SGuard.ConfigValidation includes built-in security limits to prevent DoS (Denial of Service) attacks. These limits can be configured via appsettings.json or environment variables.
Default Security Limits
| Setting | Default Value | Hard Limit (Maximum) | Description |
|---|---|---|---|
MaxFileSizeBytes |
104857600 (100 MB) | 524288000 (500 MB) | Maximum allowed file size for configuration and app settings files |
MaxEnvironmentsCount |
1000 | 5000 | Maximum number of environments allowed in a configuration file |
MaxRulesCount |
10000 | 50000 | Maximum number of rules allowed in a configuration file |
MaxConditionsPerRule |
1000 | 5000 | Maximum number of conditions allowed per rule |
MaxValidatorsPerCondition |
100 | 500 | Maximum number of validators allowed per condition |
MaxPathCacheSize |
10000 | 100000 | Maximum number of entries in the path resolver cache |
MaxPathLength |
4096 | 16384 | Maximum length for a single path string (characters) |
MaxJsonDepth |
64 | 256 | Maximum depth for nested JSON/YAML structures |
MaxParallelEnvironments |
Environment.ProcessorCount | 100 | Maximum number of environments that can be validated in parallel |
StreamingThresholdBytes |
524288 (512 KB) | 10485760 (10 MB) | File size threshold for using streaming when loading app settings |
Note: Hard limits are absolute maximums that cannot be exceeded even if configured higher. If a configuration value exceeds the hard limit, it will be automatically clamped to the hard limit and a warning will be logged.
Configuring Security Limits
Add a Security section to your appsettings.json:
{
"Security": {
"MaxFileSizeBytes": 104857600,
"MaxEnvironmentsCount": 1000,
"MaxRulesCount": 10000,
"MaxConditionsPerRule": 1000,
"MaxValidatorsPerCondition": 100,
"MaxPathCacheSize": 10000,
"MaxPathLength": 4096,
"MaxJsonDepth": 64,
"MaxParallelEnvironments": 4,
"StreamingThresholdBytes": 524288
}
}
Environment Variables
You can also override security limits using environment variables:
# Linux/Mac
export Security__MaxFileSizeBytes=209715200 # 200 MB
export Security__MaxEnvironmentsCount=2000
# Windows
set Security__MaxFileSizeBytes=209715200
set Security__MaxEnvironmentsCount=2000
Security Features
- Path Traversal Protection: Prevents access to files outside the base directory
- Symlink Attack Protection: Validates symlinks to prevent unauthorized file access
- DoS Protection: Resource limits prevent memory exhaustion and excessive processing
- Cache Poisoning Protection: Sanitizes cache keys to prevent injection attacks
🧪 Testing
Run tests with:
dotnet test
Test Coverage
The project maintains comprehensive test coverage across all supported .NET frameworks. Coverage reports are generated automatically in the CI/CD pipeline.
Coverage Summary
| Framework | Line Coverage | Branch Coverage |
|---|---|---|
| .NET 8.0 | ~85%+ | ~80%+ |
| .NET 9.0 | ~85%+ | ~80%+ |
| .NET 10.0 | ~85%+ | ~80%+ |
Coverage percentages are approximate and may vary. Detailed coverage reports are available in CI/CD artifacts.
Running Tests with Coverage
To generate coverage reports locally:
dotnet test --collect:"XPlat Code Coverage" --results-directory:"./TestResults"
Coverage reports will be generated in the TestResults directory in Cobertura XML format.
Performance Benchmarks
The project includes BenchmarkDotNet benchmarks for performance-critical operations. Run benchmarks with:
cd SGuard.ConfigValidation.Tests
dotnet run --configuration Release --project SGuard.ConfigValidation.Tests.csproj
This will execute benchmarks for:
- Large file loading performance
- Validator factory lookup performance
- File validation performance
- Memory allocation tracking
🗺️ Roadmap
- JSON config support
- Multiple validator types
- Environment-based validation
- CLI tool with System.CommandLine
- JSON and console output formats
- Structured logging
- Dependency injection support
- YAML config support
- Custom validator plugins
- Schema validation for sguard.json
- Performance optimizations (caching, memory allocation improvements)
- CI/CD pipeline integration (GitHub Actions with test coverage)
- NuGet package publishing and distribution
🔌 Using as a Library (DLL)
The SGuard.ConfigValidation project is a standalone library that can be used in any .NET application without requiring the console application.
Installation
NuGet Package (Recommended)
<PackageReference Include="SGuard.ConfigValidation" Version="0.0.1" />
Project Reference
<ProjectReference Include="path/to/SGuard.ConfigValidation/SGuard.ConfigValidation.csproj" />
Quick Start
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using SGuard.ConfigValidation.Extensions;
using SGuard.ConfigValidation.Services.Abstract;
var services = new ServiceCollection();
services.AddLogging(builder => builder.AddConsole());
services.AddSGuardConfigValidation();
var serviceProvider = services.BuildServiceProvider();
var ruleEngine = serviceProvider.GetRequiredService<IRuleEngine>();
var result = await ruleEngine.ValidateEnvironmentAsync("sguard.json", "prod");
Use Cases
1. Web API Integration
Validate configurations during application startup:
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using SGuard.ConfigValidation.Extensions;
using SGuard.ConfigValidation.Output;
using SGuard.ConfigValidation.Services.Abstract;
var builder = WebApplication.CreateBuilder(args);
// Register SGuard services
builder.Services.AddLogging();
builder.Services.AddSGuardConfigValidation(builder.Configuration);
var app = builder.Build();
// Validate configurations at startup
var ruleEngine = app.Services.GetRequiredService<IRuleEngine>();
var loggerFactory = app.Services.GetRequiredService<ILoggerFactory>();
var result = await ruleEngine.ValidateAllEnvironmentsAsync("sguard.json");
if (!result.IsSuccess || result.HasValidationErrors)
{
app.Logger.LogError("Configuration validation failed");
// Optionally write results to file for debugging
var formatter = OutputFormatterFactory.Create("json", loggerFactory, "validation-errors.json");
await formatter.FormatAsync(result);
// Handle error appropriately
}
app.Run();
2. Worker Service Integration
Validate configurations in a background worker:
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using SGuard.ConfigValidation.Extensions;
using SGuard.ConfigValidation.Output;
using SGuard.ConfigValidation.Services.Abstract;
var builder = Host.CreateApplicationBuilder(args);
// Register SGuard services
builder.Services.AddSGuardConfigValidation(builder.Configuration);
// Register worker
builder.Services.AddHostedService<ConfigValidationWorker>();
var host = builder.Build();
host.Run();
public class ConfigValidationWorker : BackgroundService
{
private readonly IRuleEngine _ruleEngine;
private readonly ILogger<ConfigValidationWorker> _logger;
private readonly ILoggerFactory _loggerFactory;
public ConfigValidationWorker(
IRuleEngine ruleEngine,
ILogger<ConfigValidationWorker> logger,
ILoggerFactory loggerFactory)
{
_ruleEngine = ruleEngine;
_logger = logger;
_loggerFactory = loggerFactory;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
var result = await _ruleEngine.ValidateAllEnvironmentsAsync("sguard.json", stoppingToken);
if (result.IsSuccess && !result.HasValidationErrors)
{
_logger.LogInformation("All configurations are valid");
}
else
{
_logger.LogError("Configuration validation failed");
// Write validation results to file for analysis
var formatter = OutputFormatterFactory.Create("json", _loggerFactory,
$"validation-results-{DateTime.UtcNow:yyyyMMddHHmmss}.json");
await formatter.FormatAsync(result);
}
await Task.Delay(TimeSpan.FromHours(1), stoppingToken);
}
}
}
3. Unit Testing
Use the library in your test projects:
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;
using SGuard.ConfigValidation.Common;
using SGuard.ConfigValidation.Services;
using SGuard.ConfigValidation.Validators;
using Xunit;
public class MyServiceTests
{
[Fact]
public void TestConfigurationValidation()
{
var securityOptions = Options.Create(new SecurityOptions());
var logger = NullLogger<RuleEngine>.Instance;
var validatorFactory = new ValidatorFactory(NullLogger<ValidatorFactory>.Instance);
var configLoader = new ConfigLoader(NullLogger<ConfigLoader>.Instance, securityOptions);
var fileValidator = new FileValidator(validatorFactory, NullLogger<FileValidator>.Instance);
var ruleEngine = new RuleEngine(configLoader, fileValidator, validatorFactory, logger, securityOptions);
var result = await ruleEngine.ValidateEnvironmentAsync("test-sguard.json", "test-env");
Assert.True(result.IsSuccess);
}
}
4. Custom Console Application
Create your own console application using the library:
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using SGuard.ConfigValidation.Extensions;
using SGuard.ConfigValidation.Output;
using SGuard.ConfigValidation.Services.Abstract;
var services = new ServiceCollection();
services.AddLogging(builder => builder.AddConsole());
services.AddSGuardConfigValidation();
var serviceProvider = services.BuildServiceProvider();
var ruleEngine = serviceProvider.GetRequiredService<IRuleEngine>();
var loggerFactory = serviceProvider.GetRequiredService<ILoggerFactory>();
// Your custom logic here
var result = await ruleEngine.ValidateAllEnvironmentsAsync("sguard.json");
if (result.IsSuccess && !result.HasValidationErrors)
{
Console.WriteLine("✅ All configurations are valid!");
// Optionally save results to file
var formatter = OutputFormatterFactory.Create("json", loggerFactory, "validation-success.json");
await formatter.FormatAsync(result);
Environment.Exit(0);
}
else
{
Console.WriteLine("❌ Configuration validation failed!");
// Save error details to file
var formatter = OutputFormatterFactory.Create("json", loggerFactory, "validation-errors.json");
await formatter.FormatAsync(result);
Environment.Exit(1);
}
📝 License
This project is licensed under the MIT License - see the LICENSE file for details.
🤝 Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
For questions or contributions, feel free to open an issue or pull request!
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Microsoft.Extensions.Caching.Memory (>= 8.0.1)
- Microsoft.Extensions.Configuration.Abstractions (>= 8.0.0)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 8.0.2)
- Microsoft.Extensions.Http (>= 8.0.1)
- Microsoft.Extensions.Logging (>= 8.0.1)
- Microsoft.Extensions.Logging.Abstractions (>= 8.0.2)
- Microsoft.Extensions.Options (>= 8.0.2)
- Microsoft.Extensions.Options.ConfigurationExtensions (>= 8.0.0)
- NJsonSchema (>= 11.0.2)
- YamlDotNet (>= 16.0.0)
-
net8.0
- Microsoft.Extensions.Caching.Memory (>= 8.0.1)
- Microsoft.Extensions.Configuration.Abstractions (>= 8.0.0)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 8.0.2)
- Microsoft.Extensions.Http (>= 8.0.1)
- Microsoft.Extensions.Logging (>= 8.0.1)
- Microsoft.Extensions.Logging.Abstractions (>= 8.0.2)
- Microsoft.Extensions.Options (>= 8.0.2)
- Microsoft.Extensions.Options.ConfigurationExtensions (>= 8.0.0)
- NJsonSchema (>= 11.0.2)
- YamlDotNet (>= 16.0.0)
-
net9.0
- Microsoft.Extensions.Caching.Memory (>= 8.0.1)
- Microsoft.Extensions.Configuration.Abstractions (>= 8.0.0)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 8.0.2)
- Microsoft.Extensions.Http (>= 8.0.1)
- Microsoft.Extensions.Logging (>= 8.0.1)
- Microsoft.Extensions.Logging.Abstractions (>= 8.0.2)
- Microsoft.Extensions.Options (>= 8.0.2)
- Microsoft.Extensions.Options.ConfigurationExtensions (>= 8.0.0)
- NJsonSchema (>= 11.0.2)
- YamlDotNet (>= 16.0.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.1.0 | 95 | 1/21/2026 |