fix: add edge case handling and test coverage for schema-based validation

- Add defensive null checks for malformed schema data in config-validator.ts
- Improve mode extraction logic with better type safety and filtering
- Add 4 comprehensive test cases:
  * Array format modes handling
  * Malformed schema graceful degradation
  * Empty modes object handling
  * Missing typeOptions skip validation
- Add database schema coverage audit script
- Document schema coverage: 21.4% of resourceLocator nodes have modes defined

Coverage impact:
- 15 nodes with complete schemas: strict validation
- 55 nodes without schemas: graceful degradation (no false positives)

All tests passing: 99 tests (33 resourceLocator, 21 edge cases, 26 node-specific, 19 security)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
czlonkowski
2025-10-11 18:16:56 +02:00
parent 43dea68f0b
commit 4625ebf64d
3 changed files with 206 additions and 8 deletions

View File

@@ -276,17 +276,26 @@ export class ConfigValidator {
// 1. Object with mode keys: { list: {...}, id: {...}, url: {...}, name: {...} }
// 2. Array of mode objects: [{name: 'list', ...}, {name: 'id', ...}]
const modes = prop.typeOptions.resourceLocator.modes;
let allowedModes: string[] = [];
if (typeof modes === 'object' && !Array.isArray(modes)) {
// Extract keys from modes object
allowedModes = Object.keys(modes);
} else if (Array.isArray(modes)) {
// Extract name property from array of mode objects
allowedModes = modes.map(m => typeof m === 'string' ? m : m.name).filter(Boolean);
// Validate modes structure before processing to prevent crashes
if (!modes || typeof modes !== 'object') {
// Invalid schema structure - skip validation to prevent false positives
continue;
}
// Only validate if we found allowed modes
let allowedModes: string[] = [];
if (Array.isArray(modes)) {
// Array format: extract name property from each mode object
allowedModes = modes
.map(m => (typeof m === 'object' && m !== null) ? m.name : m)
.filter(m => typeof m === 'string' && m.length > 0);
} else {
// Object format: extract keys as mode names
allowedModes = Object.keys(modes).filter(k => k.length > 0);
}
// Only validate if we successfully extracted modes
if (allowedModes.length > 0 && !allowedModes.includes(value.mode)) {
errors.push({
type: 'invalid_value',