Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 35 additions & 2 deletions AppInspector.RulesEngine/Schema/RuleSchemaProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,20 +35,53 @@ public RuleSchemaProvider(string? customSchemaPath = null)
}
}

/// <summary>
/// Private constructor for factory methods
/// </summary>
private RuleSchemaProvider(JsonSchema schema)
{
_schema = schema;
}

/// <summary>
/// Create a schema provider from schema content string
/// </summary>
/// <param name="schemaContent">The JSON schema content as a string</param>
/// <returns>A new RuleSchemaProvider instance</returns>
public static RuleSchemaProvider FromSchemaContent(string schemaContent)
{
if (schemaContent is null)
{
throw new ArgumentNullException(nameof(schemaContent));
}
if (string.IsNullOrWhiteSpace(schemaContent))
{
throw new ArgumentException("Schema content cannot be empty or whitespace.", nameof(schemaContent));
}

var schema = LoadSchemaFromContent(schemaContent);
return new RuleSchemaProvider(schema);
}

private JsonSchema LoadEmbeddedSchema()
{
var assembly = Assembly.GetExecutingAssembly();
using var stream = assembly.GetManifestResourceStream(SCHEMA_RESOURCE_NAME)
?? throw new InvalidOperationException($"Could not find embedded schema resource: {SCHEMA_RESOURCE_NAME}");
using var reader = new StreamReader(stream);
var schemaJson = reader.ReadToEnd();
return JsonSchema.FromText(schemaJson);
return LoadSchemaFromContent(schemaJson);
}

private JsonSchema LoadSchemaFromFile(string path)
{
var schemaJson = File.ReadAllText(path);
return JsonSchema.FromText(schemaJson);
return LoadSchemaFromContent(schemaJson);
}

private static JsonSchema LoadSchemaFromContent(string schemaContent)
{
return JsonSchema.FromText(schemaContent);
}

/// <summary>
Expand Down
86 changes: 86 additions & 0 deletions AppInspector.Tests/RuleProcessor/SchemaValidationTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,92 @@ public void SchemaProvider_LoadsEmbeddedSchema()
Assert.NotNull(schema);
}

[Fact]
public void SchemaProvider_FromSchemaContent_LoadsSchema()
{
// Load embedded schema content first to use as test data
var defaultProvider = new RuleSchemaProvider();
var schemaJson = JsonSerializer.Serialize(defaultProvider.GetSchema());

// Create provider from schema content
var provider = RuleSchemaProvider.FromSchemaContent(schemaJson);
var schema = provider.GetSchema();

Assert.NotNull(schema);
}

[Fact]
public void SchemaProvider_FromSchemaContent_WithNullContent_ThrowsException()
{
Assert.Throws<ArgumentNullException>(() => RuleSchemaProvider.FromSchemaContent(null));
}

[Fact]
public void SchemaProvider_FromSchemaContent_WithEmptyContent_ThrowsException()
{
Assert.Throws<ArgumentException>(() => RuleSchemaProvider.FromSchemaContent(string.Empty));
}

[Fact]
public void SchemaProvider_FromSchemaContent_ValidatesRules()
{
// Use a minimal schema that requires id and name
var minimalSchema = @"{
""$schema"": ""http://json-schema.org/draft-07/schema#"",
""type"": ""array"",
""items"": {
""type"": ""object"",
""required"": [""id"", ""name"", ""tags"", ""patterns""],
""properties"": {
""id"": { ""type"": ""string"", ""minLength"": 1 },
""name"": { ""type"": ""string"" },
""description"": { ""type"": ""string"" },
""tags"": {
""type"": ""array"",
""minItems"": 1,
""items"": { ""type"": ""string"" }
},
""patterns"": {
""type"": ""array"",
""minItems"": 1,
""items"": {
""type"": ""object"",
""required"": [""pattern"", ""type""],
""properties"": {
""pattern"": { ""type"": ""string"" },
""type"": { ""type"": ""string"" }
}
}
}
}
}
}";

var provider = RuleSchemaProvider.FromSchemaContent(minimalSchema);

var validRule = new Rule
{
Id = "TEST001",
Name = "Test Rule",
Description = "A test rule",
Tags = new[] { "Test.Tag" },
Patterns = new[]
{
new SearchPattern
{
Pattern = "test",
PatternType = PatternType.String,
Scopes = new[] { PatternScope.Code },
Confidence = Confidence.High
}
}
};

var result = provider.ValidateRule(validRule);

Assert.True(result.IsValid);
}

[Fact]
public void ValidRule_PassesSchemaValidation()
{
Expand Down
Loading