Advanced Compiler-Compiler Platform
This document outlines the technical design for integrating the Open Policy Agent (OPA) and its policy language, Rego, into the Minotaur parsing and validation engine.
Currently, Minotaur utilizes language-specific C# visitor classes (e.g., JavaValidationVisitor, GoValidationVisitor) to enforce syntax and semantic rules. By incorporating OPA, Minotaur will allow users to define general, language-specific, and usage-specific verification rules dynamically as code. This decouples the validation logic from the core compiler-compiler engine, enabling live rule updates, sharing via the Minotaur Marketplace, and cross-language policy enforcement.
Furthermore, this integration will leverage the existing StepLexer and StepParser to load project-specific OPA rules alongside the standard processing pipeline, extending OPA’s reach into Static Application Security Testing (SAST) and more generalized structural validation across the CognitiveGraph.
unsafe blocks in Rust”, “Enforce naming conventions in Go”) without modifying Minotaur’s C# source code.ValidationResult generation across all plugins in Minotaur.Plugins.*.Minotaur.Distributed processing pipelines.Minotaur.UI.Blazor interface.StepLexer and StepParser phases before deep graph traversal.To evaluate an AST against OPA, Minotaur must serialize its in-memory tree (or graph representation) into a JSON document (input), evaluate it against the loaded Rego policies (data), and map the JSON response back to Minotaur.Validation.ValidationResult objects.
flowchart TD
A[Source Code] -->|StepLexer| B(Tokens & Lexer Context)
B -->|Early SAST Policy Check| OPA_Early{OPA Engine}
B -->|StepParser| C(CognitiveGraph / AST)
C -->|Project Rules Loaded| D[AST/Graph to JSON Serializer]
D -->|JSON 'input'| E{OPA Engine Wrapper}
F[(Rego Policies .rego)] -->|Compile/Load| E
F -->|Load via Parser| OPA_Early
E -->|JSON 'result'| G[ValidationResult Mapper]
G --> H[Minotaur ValidationContext]
H --> I[UI / Distributed Output]
Calling out to an external OPA REST API per file would introduce unacceptable latency for a high-performance parser. Instead, Minotaur will use WASM (WebAssembly) compiled Rego policies executed entirely in-process using a C# WASM runtime (like Wasmtime via Opa.Wasm).
The StepLexer and StepParser will be enhanced to support loading .rego files discovered within the target project’s directory structure (e.g., a .minotaur/policies folder).
CognitiveGraph to provide context-aware SAST and structural validation.IOpaVerificationEngineA new service residing in Minotaur.Core.Services.Validation that manages the lifecycle of OPA policies.
namespace Minotaur.Core.Services.Validation
{
public interface IOpaVerificationEngine
{
// Loads a pre-compiled OPA WASM bundle or raw Rego files
Task LoadPoliciesAsync(IEnumerable<string> regoRulePaths);
// Evaluates the AST/CognitiveGraph against the loaded policies
Task<IEnumerable<ValidationResult>> EvaluateAsync(SyntaxNode rootNode, ValidationContext context);
// Overload for early token-stream evaluation
Task<IEnumerable<ValidationResult>> EvaluateTokensAsync(IEnumerable<StepToken> tokens, ValidationContext context);
}
}
input schema)For OPA to process Minotaur’s AST or CognitiveGraph, we need a standard JSON representation. SyntaxNode objects will be flattened or hierarchically mapped.
Example OPA Input (input):
{
"language": "java",
"fileName": "AuthService.java",
"projectPolicies": ["rule1.rego", "rule2.rego"],
"ast": {
"type": "ClassDeclaration",
"name": "AuthService",
"children": [
{
"type": "MethodDeclaration",
"name": "authenticate",
"modifiers": ["public"],
"parameters": [...]
}
]
}
}
Policies will be structured to return an array of error objects. Minotaur will expect a specific output signature from the Rego queries (e.g., data.minotaur.validation.errors).
Example Usage-Specific Rego Rule (java_security.rego):
package minotaur.validation.java
# Deny methods named 'authenticate' that do not have the 'private' modifier
errors[{"nodeId": node.id, "message": msg, "severity": "Error"}] {
input.language == "java"
# Walk the AST to find MethodDeclarations
node := walk_ast(input.ast)
node.type == "MethodDeclaration"
node.name == "authenticate"
# Check if 'private' is missing
not "private" in node.modifiers
msg := sprintf("Security Violation: Method '%v' must be private.", [node.name])
}
ValidationContextCurrently, visitors like JavaValidationVisitor add errors directly to a context. The OpaValidationProvider will act as a universal visitor/validator, hooking into the StepLexer and StepParser outputs.
public class OpaValidationProvider : IValidationProvider
{
private readonly IOpaVerificationEngine _opaEngine;
public async Task ValidateAsync(SyntaxTree tree, ValidationContext context)
{
// Combine core policies with project-specific policies found during parsing
var projectPolicies = tree.GetMetadata("LoadedPolicies");
var opaResults = await _opaEngine.EvaluateAsync(tree.Root, context);
foreach(var res in opaResults)
{
context.AddResult(res); // Maps to Minotaur's existing ValidationResult
}
}
}
CognitiveGraph to avoid circular reference loops (Parent node pointers must be ignored)..rego files during the ingestion phase.*ValidationVisitor.cs files can be gradually deprecated or migrated into default .rego files shipped with the plugins.SyntaxHighlightingService.cs.Opa.Wasm (for in-process WASM evaluation).System.Text.Json (for fast AST serialization).AstJsonSerializer.OpaVerificationEngine using Opa.Wasm.Minotaur.Tests/Validation/OpaValidationTests.cs.StepLexer and StepParser to discover and attach project-level .rego files to the parsing context.RustValidationVisitor.cs) to Rego policies.Minotaur.UI.Blazor/Components/GrammarEditor/.