mrapids 0.1.31

Your OpenAPI, but executable
Documentation
# OpenAPI Specification Validation Implementation Plan

## Overview

Implement comprehensive OpenAPI specification validation using proven tools and a multi-level validation approach to ensure spec compliance, security, and governance.

## 1. Support Matrix Declaration

### Supported Versions
- **OpenAPI 2.0** (fka Swagger 2.0)
- **OpenAPI 3.0.x** (3.0.0, 3.0.1, 3.0.2, 3.0.3)
- **OpenAPI 3.1.x** (3.1.0)

### Version Detection Strategy
```rust
pub enum SpecVersion {
    Swagger2_0,
    OpenAPI3_0(String), // Store exact version
    OpenAPI3_1(String), // Store exact version
    Unknown,
}

pub fn detect_spec_version(content: &Value) -> Result<SpecVersion> {
    if let Some(swagger) = content.get("swagger").and_then(|v| v.as_str()) {
        if swagger == "2.0" {
            return Ok(SpecVersion::Swagger2_0);
        }
    }
    
    if let Some(openapi) = content.get("openapi").and_then(|v| v.as_str()) {
        if openapi.starts_with("3.0.") {
            return Ok(SpecVersion::OpenAPI3_0(openapi.to_string()));
        }
        if openapi.starts_with("3.1.") {
            return Ok(SpecVersion::OpenAPI3_1(openapi.to_string()));
        }
    }
    
    Err(anyhow!("Unknown spec format. Expected 'swagger: \"2.0\"' or 'openapi: \"3.x.y\"'"))
}
```

## 2. Validation Tool Integration

### Primary Tools
1. **Spectral** (via spectral-rs or shell integration)
   - OAS compliance validation
   - Custom security rules
   - Extensible ruleset system

2. **oasdiff** (for breaking change detection)
   - API compatibility checks
   - Governance enforcement

### Alternative Options
- **Redocly CLI** (if Spectral integration proves difficult)
- **openapi-validator** crate (Rust native)

## 3. Multi-Level Validation Architecture

### Level A: Canonical/OAS Compliance
```rust
pub struct ComplianceValidator {
    spectral_path: PathBuf,
    ruleset: RuleSet,
}

impl ComplianceValidator {
    pub async fn validate(&self, spec_path: &Path) -> Result<ValidationReport> {
        // Run Spectral with OAS ruleset
        let output = Command::new(&self.spectral_path)
            .args(&["lint", spec_path.to_str().unwrap()])
            .args(&["--ruleset", "@stoplight/spectral-oas"])
            .output()
            .await?;
        
        parse_spectral_output(output)
    }
}
```

### Level B: Security Linting
```yaml
# security-rules.yaml for Spectral
extends: [[spectral:oas, all]]

rules:
  no-http-servers:
    description: "Server URLs must use HTTPS"
    given: "$.servers[*].url"
    then:
      function: pattern
      functionOptions:
        match: "^https://"
    severity: error

  operation-security-defined:
    description: "All operations must define security"
    given: "$.paths[*][*]"
    then:
      field: security
      function: truthy
    severity: error

  no-private-ip-servers:
    description: "Server URLs must not use private IPs"
    given: "$.servers[*].url"
    then:
      function: pattern
      functionOptions:
        notMatch: "(localhost|127\\.0\\.0\\.1|192\\.168\\.|10\\.|172\\.(1[6-9]|2[0-9]|3[01])\\.)"
    severity: error
```

### Level C: Governance/Breaking Changes
```rust
pub struct GovernanceValidator {
    oasdiff_path: PathBuf,
}

impl GovernanceValidator {
    pub async fn check_breaking_changes(
        &self,
        old_spec: &Path,
        new_spec: &Path,
    ) -> Result<BreakingChangeReport> {
        let output = Command::new(&self.oasdiff_path)
            .args(&["breaking", old_spec.to_str().unwrap(), new_spec.to_str().unwrap()])
            .output()
            .await?;
        
        parse_oasdiff_output(output)
    }
}
```

## 4. JSON Schema Version Handling

### OAS 3.1 Specific Handling
```rust
pub struct JsonSchemaValidator {
    version: SpecVersion,
}

impl JsonSchemaValidator {
    pub fn validate_schema(&self, schema: &Value) -> Result<()> {
        match &self.version {
            SpecVersion::OpenAPI3_1(_) => {
                // OAS 3.1 uses JSON Schema 2020-12
                self.validate_json_schema_2020_12(schema)
            }
            _ => {
                // OAS 2.0 and 3.0.x use JSON Schema Draft 4 subset
                self.validate_json_schema_draft4_subset(schema)
            }
        }
    }
}
```

## 5. Safe External Reference Handling

### Reference Validator
```rust
pub struct ReferenceValidator {
    allowed_domains: Vec<String>,
    max_depth: usize,
}

impl ReferenceValidator {
    pub fn validate_reference(&self, ref_url: &str) -> Result<()> {
        // Use existing security validation
        validate_url(ref_url)?;
        
        // Check against allowlist
        let url = Url::parse(ref_url)?;
        if let Some(host) = url.host_str() {
            if !self.allowed_domains.iter().any(|d| host.ends_with(d)) {
                return Err(anyhow!("External reference not in allowlist: {}", host));
            }
        }
        
        Ok(())
    }
}
```

## 6. Tool Version Management

### Cargo.toml Dependencies
```toml
[dependencies]
spectral-rs = "=0.5.0"  # Pin exact version
oasdiff = "=1.2.0"      # Pin exact version

[dev-dependencies]
# For testing against known spec versions
openapi-test-specs = "=1.0.0"
```

### Version Tracking Script
```bash
#!/bin/bash
# check-tool-updates.sh

echo "Checking for validation tool updates..."

# Check Spectral
CURRENT_SPECTRAL=$(grep "spectral-rs" Cargo.toml | grep -o '"[^"]*"')
LATEST_SPECTRAL=$(cargo search spectral-rs --limit 1 | grep -o "= \"[^\"]*\"")

if [ "$CURRENT_SPECTRAL" != "$LATEST_SPECTRAL" ]; then
    echo "Spectral update available: $CURRENT_SPECTRAL -> $LATEST_SPECTRAL"
fi

# Similar for other tools...
```

## Implementation Steps

### Phase 1: Core Validation (Week 1)
1. Add version detection to parser
2. Integrate Spectral for OAS compliance
3. Implement basic validation command

### Phase 2: Security Rules (Week 2)
1. Create custom Spectral ruleset
2. Add security validation level
3. Integrate with existing security module

### Phase 3: Governance (Week 3)
1. Integrate oasdiff for breaking changes
2. Add diff validation to CI/CD
3. Create governance reports

### Phase 4: Polish (Week 4)
1. Improve error messages
2. Add validation caching
3. Create comprehensive tests

## CLI Integration

### New Commands
```bash
# Validate a spec
mrapids validate spec api.yaml --level all

# Check for breaking changes
mrapids validate diff old-api.yaml new-api.yaml

# Validate with custom rules
mrapids validate spec api.yaml --ruleset ./my-rules.yaml
```

### Integration with Existing Commands
```rust
// In init command
pub fn init_project(cmd: InitCommand) -> Result<()> {
    // ... download/load spec ...
    
    // Validate before proceeding
    let validator = SpecValidator::new();
    validator.validate_all_levels(&spec_path)?;
    
    // ... continue with project creation ...
}
```

## Testing Strategy

### Test Cases
1. Valid specs for each version (2.0, 3.0.x, 3.1.x)
2. Invalid specs with various errors
3. Security rule violations
4. Breaking change scenarios
5. External reference handling

### Example Test
```rust
#[test]
fn test_validates_oas_3_1_correctly() {
    let spec = r#"
    openapi: "3.1.0"
    info:
      title: Test API
      version: "1.0.0"
    paths:
      /test:
        get:
          operationId: getTest
          responses:
            '200':
              description: OK
    "#;
    
    let validator = SpecValidator::new();
    let result = validator.validate(spec);
    
    assert!(result.is_ok());
    assert_eq!(result.unwrap().version, SpecVersion::OpenAPI3_1("3.1.0".to_string()));
}
```

## Benefits

1. **Reliability**: Catch spec errors before they cause runtime issues
2. **Security**: Enforce security best practices automatically
3. **Governance**: Prevent breaking changes from slipping through
4. **Developer Experience**: Clear, actionable error messages
5. **Standards Compliance**: Ensure specs follow official standards

## Conclusion

This implementation plan provides a robust, multi-layered validation system that leverages proven tools while maintaining MicroRapid's ease of use. The phased approach allows for incremental delivery while building toward a comprehensive solution.