feat(validator) initial and full implementation#4
Conversation
# Implementation Summary ## Core Validator Implementation A comprehensive OpenAPI Specification validator in /Users/robbie/code/oastools/internal/validator/validator.go with the following features: Data Structures: - ValidationError - Contains path, message, spec reference URL, severity, field name, and problematic value - ValidationResult - Holds validation results including errors, warnings, version info, and validity status - Severity - Enum for Error vs Warning levels ### Validation Layers: 1. OAS 2.0 Validation: - Required fields (swagger, info, paths) - Path patterns (must start with /) - Operation requirements (responses object) - Parameter validation (in, name, type constraints) - Security definitions and requirements - Path parameter consistency - Media type validation - Duplicate operationId detection 2. OAS 3.x Validation: - Required fields (openapi, info, paths/webhooks) - Server objects and variables - Path and operation validation - RequestBody content requirements - Parameter validation (schema XOR content) - Security schemes (apiKey, http, oauth2, openIdConnect) - OAuth2 flows validation - Webhooks (OAS 3.1+) - Path parameter consistency - Security requirement references 3. Schema Validation: - Type-specific constraints (array must have items, string min/max length, number min/max) - Recursive validation of properties, additionalProperties, items - Schema composition (allOf, oneOf, anyOf, not) - JSON Schema spec compliance ### CLI Integration Added validate command in /Users/robbie/code/oastools/cmd/oastools/main.go: - oastools validate <file> - Basic validation - --strict - Enable stricter validation beyond spec requirements - --no-warnings - Suppress warnings - -h, --help - Show help ### Test Coverage Comprehensive test suite with 62.6% code coverage: - Valid/invalid OAS 2.0 and 3.x documents - All OAS versions (2.0, 3.0.x, 3.1.x, 3.2.0) - Strict mode and warning suppression - Helper function validation - Example tests demonstrating usage ### Output Format ``` OpenAPI Specification Validator ================================ File: spec.yaml Version: 3.0.3 Errors (N): ✗ path: message Spec: https://spec.openapis.org/... Warnings (N): ⚠ path: message Spec: https://spec.openapis.org/... ✓ Validation passed / ✗ Validation failed ```
This comment was marked as outdated.
This comment was marked as outdated.
Changes Completed Must Fix Items: 1. Duplicate operationId detection ✓ - Added validateOAS2OperationIds() and validateOAS3OperationIds() functions - Tracks all operationIds across paths (and webhooks for OAS 3.x) - Reports errors when duplicates are found, showing where the ID was first seen 2. Path pattern validation ✓ - Added validation to validateOAS2Paths() and validateOAS3Paths() - Ensures all path patterns start with "/" - Reports clear error messages for invalid paths 3. Required fields validation (info.title, info.version) ✓ - Added validateOAS2Info() and validateOAS3Info() functions - Validates that the info object exists and contains required title and version fields - Provides spec references in error messages 4. Implemented unused helper functions ✓ - validateHTTPStatusCode() is now used in both validateOAS2Operation() and validateOAS3Operation() - Validates all response status codes to ensure they're valid HTTP codes (100-599, wildcards like 2XX, or "default") - Other helper functions (isValidURL, isValidEmail, validateSPDXLicense) remain available for future use 5. Fixed type assertion silent failure ✓ - Changed type assertions in Validate() to return errors when casting fails - No longer silently skips validation when document type doesn't match expected type 6. Test data files ✓ - All required test files already exist in testdata/ - Tests pass with the new validations Test Results All tests pass successfully: - Parser: 84.7% coverage - Validator: 63.8% coverage - No linting issues - All quality checks pass (tidy, fmt, lint, test) The validator now correctly detects and reports errors for: - Missing info.version fields (validator.go:217-225, 672-679) - Invalid path patterns not starting with "/" (validator.go:277-286, 832-841) - Duplicate operationIds (validator.go:254-263, 712-723) - Invalid HTTP status codes (validator.go:329-338, 895-904)
This comment was marked as outdated.
This comment was marked as outdated.
Summary of Changes
First Round (Must Fix Items):
1. Duplicate operationId detection ✓ (validator.go:231-251, 677-721)
- Detects duplicate operationIds across all paths and webhooks
- Shows where the duplicate was first defined
2. Path pattern validation ✓ (validator.go:278-286, 833-841)
- Validates all paths start with "/"
- Clear error messages with spec references
3. Required fields validation ✓ (validator.go:195-226, 650-681)
- Validates info.title and info.version exist
- Added for both OAS 2.0 and OAS 3.x
4. Implemented unused helper functions ✓ (validator.go:329-338, 895-904)
- validateHTTPStatusCode() now validates all response status codes
- Catches invalid codes like "999", "6XX", "abc", etc.
5. Fixed type assertion silent failure ✓ (validator.go:136-147)
- Type assertions now return errors instead of silently failing
Second Round (Performance & Code Quality):
6. Required fields in schema validation ✓ (validator.go:1354-1365)
- Validates that all fields in required array exist in properties
- Prevents referencing non-existent required fields
7. Refactored duplicate code ✓ (validator.go:1374-1410)
- Extracted common operationId validation into checkDuplicateOperationIds() helper
- Reduced code duplication between OAS2 and OAS3 validators
- More maintainable and consistent error messages
8. Performance optimization - regex compilation ✓ (validator.go:1372)
- Moved regex to package-level variable pathParamRegex
- Prevents recompilation on every path validation
9. Performance optimization - slice pre-allocation ✓ (validator.go:111-112)
- Pre-allocate error/warning slices with capacity of 10
- Reduces memory allocations for large specs
10. Documentation improvements ✓
- Added TODO comments to unused helper functions (isValidURL, isValidEmail, validateSPDXLicense)
- Added comment explaining intentionally permissive media type validation
Test Results:
- All tests passing: ✓
- No linting issues: ✓
- Code formatted: ✓
- Coverage: 64.0% for validator (up from 63.8%)
This comment was marked as outdated.
This comment was marked as outdated.
Complete Summary of Improvements
Round 1: Must-Fix Items (All Addressed ✓)
1. Duplicate operationId detection (validator.go:231-251, 677-721, 1374-1410)
- Detects duplicates across all paths and webhooks
- Shows where duplicates were first defined
- Refactored common logic into checkDuplicateOperationIds() helper
2. Path pattern validation (validator.go:278-286, 833-841)
- Validates all paths start with "/"
- Clear error messages with spec references
3. Required fields validation (validator.go:203-226, 649-681)
- Validates info.title and info.version exist
- Standardized error messages
4. HTTP status code validation (validator.go:329-338, 895-904)
- Validates all response status codes
- Rejects invalid codes (999, 6XX, abc, etc.)
5. Fixed type assertion silent failure (validator.go:136-147)
- Type assertions now return errors instead of silently failing
6. Schema required fields validation (validator.go:1354-1365)
- Validates all fields in required array exist in properties
Round 2: Code Quality & Performance (All Addressed ✓)
7. Magic numbers eliminated (validator.go:23-27, 118-119)
- Extracted to defaultErrorCapacity and defaultWarningCapacity constants
8. Error message consistency (validator.go:208, 654)
- Standardized to "Document must have..." style
9. Path parameter required validation for OAS 3.x (validator.go:935-944, 1168-1195)
- Validates path parameters have required: true in:
- Component parameters
- Path-level parameters
- Operation-level parameters
10. Media type wildcard validation fixed (validator.go:1480-1488)
- Correctly rejects */json (invalid)
- Accepts */* and application/* (valid)
11. Performance optimizations
- Regex compiled at package level (validator.go:1422)
- Slice pre-allocation with named constants
- Code duplication reduced via helper functions
12. Documentation improvements
- TODO comments for unused helper functions (validator.go:1456, 1466, 1480)
- Explanatory comment for permissive media type validation
Round 3: Test Coverage (All Addressed ✓)
13. Edge case tests added (validator_test.go:431-578)
- Empty/nil document objects
- Circular schema references
- Deeply nested schemas (10 levels deep)
- Malformed path templates (unclosed, double braces, empty, missing braces)
- Missing info object
14. Test data files created (testdata/)
- 11 new test fixture files supporting edge case tests
Results
- All tests passing: ✓
- No linting issues: ✓
- Code formatted: ✓
- Coverage improved: 63.8% → 65.5% for validator
- Total changes: 2 files modified, 11 test files added
Code Review: OpenAPI Specification Validator ImplementationSummaryThis is a comprehensive and well-structured implementation of an OpenAPI validator. The code demonstrates strong software engineering practices with clear separation of concerns, thorough documentation, and extensive test coverage. Below is my detailed feedback. ✅ Strengths1. Excellent Code Organization
2. Strong Type Safety & Error Handling
3. Comprehensive Validation Coverage
4. Documentation & Usability
5. Test Coverage
🔍 Issues & RecommendationsCritical Issues1. Missing Path Validation for Malformed Templates (validator.go:1454)The // Current implementation
func extractPathParameters(pathPattern string) map[string]bool {
params := make(map[string]bool)
matches := pathParamRegex.FindAllStringSubmatch(pathPattern, -1)
for _, match := range matches {
if len(match) > 1 {
params[match[1]] = true
}
}
return params
}Problem: Malformed paths like Recommendation: Add validation in // After line 268 in validateOAS2Paths
if err := validatePathTemplate(pathPattern); err != nil {
result.Errors = append(result.Errors, ValidationError{
Path: fmt.Sprintf("paths.%s", pathPattern),
Message: fmt.Sprintf("Invalid path template: %s", err),
SpecRef: fmt.Sprintf("%s#pathsObject", baseURL),
Severity: SeverityError,
})
}2. Potential Stack Overflow with Circular Schemas (validator.go:1295)The func (v *Validator) validateSchema(schema *parser.Schema, path string, result *ValidationResult) {
// ... validation logic
v.validateSchema(propSchema, propPath, result) // Line 1356
v.validateSchema(addProps, addPropsPath, result) // Line 1363
// etc.
}Problem: Circular schema references (even through ``) could cause infinite recursion and stack overflow. Recommendation: Add cycle detection: func (v *Validator) validateSchema(schema *parser.Schema, path string, result *ValidationResult) {
v.validateSchemaWithVisited(schema, path, result, make(map[*parser.Schema]bool))
}
func (v *Validator) validateSchemaWithVisited(schema *parser.Schema, path string, result *ValidationResult, visited map[*parser.Schema]bool) {
if schema == nil || visited[schema] {
return
}
visited[schema] = true
// ... validation logic
}High Priority Issues3. Unused Helper Functions (validator.go:1499-1532)Three helper functions are defined but never used:
The TODO comments indicate intent but implementation is missing. Recommendation:
4. HTTP Status Code Validation Too Permissive (validator.go:1535)The status code validator allows 100-599, but HTTP only defines 100-599 with specific semantics: return statusCode >= 100 && statusCode <= 599 // Line 1558Issue: This accepts undefined status codes like 199, 299, 418 (I'm a teapot), 599, etc. Recommendation: In strict mode, validate against known status codes or at least warn about non-standard codes. 5. Missing RequestBody Validation in OAS 3.x (validator.go:842)The Expected Validations:
Recommendation: Add Medium Priority Issues6. Inconsistent Parameter Validation (validator.go:906-945)In
Recommendation: Extract parameter validation to a helper and reuse it. 7. Missing Enum Validation (validator.go:1295)Schema validation doesn't check if Example Issue: type: integer
enum: ["one", "two", "three"] # Should be [1, 2, 3]Recommendation: Add enum validation in 8. Test File Dependencies Not Checked (validator_test.go:28)Tests reference files in testFile := filepath.Join("..", "..", "testdata", "petstore-2.0.yaml")
result, err := v.Validate(testFile)Problem: If test files are missing, tests fail with confusing errors. Recommendation: Add 9. Magic Numbers in Code (validator.go:1541)Hard-coded numbers like const (
httpStatusCodeLength = 3
minHTTPStatusCode = 100
maxHTTPStatusCode = 599
)Low Priority / Style Issues10. Verbose Error AppendingPattern Recommendation: Create a helper: func (v *Validator) addError(result *ValidationResult, path, message, specRef, field string, value interface{}) {
result.Errors = append(result.Errors, ValidationError{
Path: path,
Message: message,
SpecRef: specRef,
Severity: SeverityError,
Field: field,
Value: value,
})
}11. Inconsistent Naming Convention
Recommendation: Consistent naming - use 12. Media Type Validation Could Be More RFC-Compliant (validator.go:1469)Current implementation is basic. Consider using import "mime"
func isValidMediaType(mediaType string) bool {
_, _, err := mime.ParseMediaType(mediaType)
return err == nil
}🔒 Security Considerations✅ Good:
|
| Category | Rating | Notes |
|---|---|---|
| Code Quality | ⭐⭐⭐⭐⭐ | Excellent structure and documentation |
| Test Coverage | ⭐⭐⭐⭐☆ | Good coverage, room for edge cases |
| Performance | ⭐⭐⭐⭐☆ | Generally good, minor optimizations possible |
| Security | ⭐⭐⭐⭐☆ | No major concerns, watch recursion |
| Maintainability | ⭐⭐⭐⭐⭐ | Excellent documentation and structure |
Overall Score: 4.6/5
✅ Approval Recommendation
APPROVE with requested changes
The implementation is solid and ready to merge after addressing the critical issues (#1 and #2). The high/medium priority issues can be addressed in follow-up PRs.
Required Before Merge:
- Add cycle detection to
validateSchema(issue feat(parser): initial implementation #2) - Add path template validation or document limitation (issue Add Claude Code GitHub Workflow #1)
Nice to Have:
- Implement or remove unused helper functions (issue changes from merge to join #3)
- Add RequestBody validation for OAS 3.x (issue fixes oas urls in validation errors #5)
Great work on this implementation! The code demonstrates strong engineering fundamentals and will serve as an excellent foundation for the oastools project. 🎉
i failed to capture all of the change details
Code Review: OpenAPI Validator ImplementationSummaryThis PR implements a comprehensive OpenAPI Specification validator with excellent coverage of OAS 2.0 and 3.x versions. The implementation is thorough, well-structured, and follows solid engineering practices. Strengths1. Comprehensive Validation Coverage
2. Code Quality
3. Test Coverage
4. User Experience
Issues & RecommendationsCritical Issues1. Circular Reference Protection - Potential Stack Overflow // validator.go:1735
func (v *Validator) validateNestedSchemas(schema *parser.Schema, path string, result *ValidationResult, visited map[*parser.Schema]bool)The code has a Recommendation: Ensure func (v *Validator) validateSchema(schema *parser.Schema, path string, result *ValidationResult) {
visited := make(map[*parser.Schema]bool)
v.validateSchemaWithVisited(schema, path, result, visited)
}High Priority Issues2. URL Validation Too Permissive // validator.go:1931-1937
func isValidURL(s string) bool {
if s == "" {
return false
}
// Basic check - should start with http:// or https:// or be a relative URL
return strings.HasPrefix(s, "http://") || strings.HasPrefix(s, "https://") || strings.HasPrefix(s, "/")
}Issues:
Recommendation: Use func isValidURL(s string) bool {
if s == "" {
return false
}
u, err := url.Parse(s)
if err \!= nil {
return false
}
// OAuth URLs must be absolute
return u.Scheme == "http" || u.Scheme == "https" || u.Scheme == ""
}3. Email Validation Too Simple // validator.go:1941-1951
func isValidEmail(s string) bool {
// ...
parts := strings.Split(s, "@")
if len(parts) \!= 2 {
return false
}
return parts[0] \!= "" && parts[1] \!= "" && strings.Contains(parts[1], ".")
}Issues:
Recommendation: Use a proper email validation regex or library: var emailRegex = regexp.MustCompile(`^[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,}$`)
func isValidEmail(s string) bool {
if s == "" {
return true // Empty is valid (optional field)
}
return emailRegex.MatchString(s)
}4. Path Template Validation Incomplete // validator.go:1838-1882
func validatePathTemplate(pathPattern string) errorThe function validates basic template syntax but doesn't check for:
Recommendation: Add additional validation checks Medium Priority Issues5. Missing Test Files The tests reference many testdata files that aren't included in this PR:
While Recommendation: Either include these test files in the PR or use embedded test data within the test files themselves. 6. TODO Comments Indicate Incomplete Implementation These TODOs suggest the functions exist but aren't being called. The code does call Recommendation: Remove outdated TODO comments or implement missing validations. 7. Performance: Regex Compilation // validator.go:1796
var pathParamRegex = regexp.MustCompile(`\{([^}]+)\}`)Good use of package-level compiled regex! However, there might be other regexes compiled inside functions. Recommendation: Audit for any Low Priority / Style Issues8. Magic Numbers in HTTP Status Code Validation The Recommendation: Consider adding a comment explaining the source (RFC 9110, etc.) and last update date. 9. Inconsistent Error Message Formatting Some error messages use single quotes, others use no quotes:
Recommendation: Standardize on single quotes for field names/values in error messages. 10. Error Slice Capacity const (
defaultErrorCapacity = 10
defaultWarningCapacity = 10
)These are reasonable defaults, but large OAS files might have many more errors, causing slice reallocation. Recommendation: Consider making these configurable or using a heuristic based on document size. Security Considerations1. No Resource Exhaustion Protection The validator doesn't appear to have limits on:
Recommendation: Add configurable limits, especially for schema nesting depth: const maxSchemaNestingDepth = 100
func (v *Validator) validateSchemaWithVisited(schema *parser.Schema, path string, result *ValidationResult, visited map[*parser.Schema]bool) {
depth := strings.Count(path, ".")
if depth > maxSchemaNestingDepth {
result.Errors = append(result.Errors, ValidationError{
Path: path,
Message: "Schema nesting depth exceeds maximum allowed",
Severity: SeverityError,
})
return
}
// ... rest of validation
}2. External Reference Validation The code validates URLs but doesn't check if external references ( Performance Considerations1. Multiple Map Lookups In several places, the code does repeated map lookups: if _, exists := doc.SecurityDefinitions[schemeName]; \!exists {This is fine for small documents but could be optimized with a local variable if used multiple times. 2. String Concatenation in Loops Heavy use of Testing Recommendations
DocumentationThe code is well-documented, but consider adding:
ConclusionThis is a solid implementation with good architecture and comprehensive validation logic. The main concerns are:
The code demonstrates strong engineering practices and would benefit from addressing the validation function security concerns before merging. Recommendation: Approve with requested changes to validation helpers (URL/email) and verification of circular reference handling. Great work overall! The comprehensive OAS version support and detailed error messages will make this a very useful tool. 🎉 |
Critical Issues - FIXED
1. Circular Reference Protection - Already correctly implemented (verified with grep - the visited map is initialized in validateSchema)
High Priority Issues - FIXED
2. URL Validation
- Replaced basic string checks with url.Parse from standard library
- Now properly validates URLs and rejects malformed strings like "not-a-url"
- Accepts http/https schemes and relative URLs starting with /
3. Email Validation
- Replaced simple string validation with regex pattern
- Uses: ^[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,}$
- Properly rejects malformed emails
4. Path Template Validation
- Added checks for consecutive slashes (//)
- Added checks for reserved characters (#, ?)
- Added checks for empty path segments
- Added duplicate parameter name detection
- All malformed path tests now pass
Medium Priority Issues - FIXED
6. TODO Comments - All updated to reflect that functions ARE being used (verified with grep):
- isValidURL - used in 13 locations for contact.url, license.url, OAuth URLs
- isValidEmail - used in 4 locations for contact.email
- validateSPDXLicense - used in 3 locations for license.identifier
Security Issues - FIXED
1. Resource Exhaustion Protection
- Added maxSchemaNestingDepth = 100 constant
- Added depth check in validateSchemaWithVisited using strings.Count(path, ".")
- Returns error when maximum nesting depth is exceeded
Test Results
- ✅ All linter checks pass (0 issues)
- ✅ All tests pass (63.9% coverage)
- ✅ No race conditions detected
- ✅ All new validations working correctly
Pull Request Review: Validator ImplementationSummaryThis PR implements a comprehensive OpenAPI Specification validator with support for OAS 2.0, 3.0.x, 3.1.x, and 3.2.0. The implementation is extensive (~2,080 lines) with thorough validation logic and good test coverage (62.6% as noted in PR description). Strengths1. Comprehensive Validation Coverage
2. Well-Structured Code
3. Good Error Reporting
4. Security & Resource Protection
5. Testing
Issues & RecommendationsCritical Issues1. Unused Variable (Line 693)version := doc.OpenAPIThe Fix: Remove the unused variable: func (v *Validator) validateOAS3(doc *parser.OAS3Document, result *ValidationResult) {
var baseURL string
// Determine the correct spec URL based on version
switch doc.OASVersion {2. Missing Test Data FilesThe test file references several testdata files that may not exist:
Recommendation: Ensure all test data files are included in the PR, or the tests will be skipped in CI/CD. Performance Considerations3. Inefficient String Contains Implementation (Lines 594-606)The custom Fix: Use // Replace custom implementation with standard library
func contains(s, substr string) bool {
return strings.Contains(s, substr)
}4. Repeated Map Lookups in OperationsCode like this appears multiple times (lines 304-312, 350-358, 630-638): operations := map[string]*parser.Operation{
"get": pathItem.Get,
"put": pathItem.Put,
"post": pathItem.Post,
"delete": pathItem.Delete,
"options": pathItem.Options,
"head": pathItem.Head,
"patch": pathItem.Patch,
}Recommendation: Extract this to a helper function to reduce duplication and improve maintainability: func getOperations(pathItem *parser.PathItem) map[string]*parser.Operation {
return map[string]*parser.Operation{
"get": pathItem.Get,
"put": pathItem.Put,
"post": pathItem.Post,
"delete": pathItem.Delete,
"options": pathItem.Options,
"head": pathItem.Head,
"patch": pathItem.Patch,
}
}Code Quality Issues5. Weak SPDX License Validation (Lines 2008-2017)The current validation only checks for spaces: func validateSPDXLicense(identifier string) bool {
if identifier == "" {
return true
}
return !strings.Contains(identifier, " ")
}Recommendation: Add a TODO comment acknowledging this is basic validation: // TODO: Implement full SPDX license identifier validation against the official list
// Current implementation only checks for invalid characters (spaces)
func validateSPDXLicense(identifier string) bool {
if identifier == "" {
return true
}
// Basic validation - SPDX identifiers should not contain spaces
return !strings.Contains(identifier, " ")
}6. Email Regex Could Be More Robust (Line 1814)The email regex Recommendation: Add a comment noting this is basic validation: // Basic email validation - does not cover all RFC 5322 cases
var emailRegex = regexp.MustCompile(`^[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,}$`)7. Missing
|
Implementation Summary
Core Validator Implementation
A comprehensive OpenAPI Specification validator in
/oastools/internal/validator/validator.gowith the following features:Data Structures:
Validation Layers:
CLI Integration
Added validate command in
/oastools/cmd/oastools/main.go:Test Coverage
Comprehensive test suite with 62.6% code coverage:
Output Format