UNPKG

@deploystack/docker-to-iac

Version:

Translate docker run and docker compose file to Infrastructure as Code

135 lines (134 loc) 5.19 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.validateRenderSchema = validateRenderSchema; const _2020_1 = __importDefault(require("ajv/dist/2020")); const ajv_formats_1 = __importDefault(require("ajv-formats")); // Cache for the schema to avoid repeated fetching let schemaCache = null; /** * Validates data against the Render.com schema * @param data The YAML data to validate * @param schemaUrl URL to the Render.com schema * @returns Promise<boolean> indicating if validation passed */ async function validateRenderSchema(data, schemaUrl = 'https://render.com/schema/render.yaml.json') { try { // Fetch the schema if not already cached if (!schemaCache) { console.log('Fetching Render.com schema...'); const response = await fetch(schemaUrl, { headers: { 'Accept': 'application/json' } }); if (!response.ok) { throw new Error(`Failed to fetch schema: ${response.statusText} (${response.status})`); } schemaCache = await response.json(); console.log('Schema fetched successfully'); } // Create an Ajv instance with support for 2020-12 draft const ajv = new _2020_1.default({ allErrors: true, verbose: true, strict: false, allowUnionTypes: true }); // Add format validation (0, ajv_formats_1.default)(ajv); // First, try direct validation against the schema try { // Compile the schema const validate = ajv.compile(schemaCache); // Validate the data const isValid = validate(data); if (!isValid && validate.errors) { console.error('❌ Schema validation failed:'); validate.errors.forEach((error, index) => { console.error(`Error ${index + 1}:`, JSON.stringify(error, null, 2)); }); return false; } console.log('✓ Schema validation passed'); return true; } catch (validationError) { // If we have a schema compilation issue, try manual validation of key structure console.warn('Schema compilation error, falling back to structural validation:', validationError); return validateStructure(data); } } catch (error) { console.error('❌ Schema validation error:', error); return false; } } /** * Fallback validation that checks the structure of the Render YAML * @param data Render YAML data * @returns boolean indicating if basic structure is valid */ function validateStructure(data) { try { let isValid = true; const issues = []; // Check that services is an array if (!data.services || !Array.isArray(data.services)) { issues.push('services must be an array'); isValid = false; } else { // Validate each service has the required fields data.services.forEach((service, index) => { if (!service.name) { issues.push(`Service at index ${index} is missing a name`); isValid = false; } if (!service.type) { issues.push(`Service ${service.name || index} is missing a type`); isValid = false; } if (service.type === 'web' && !service.envVars && !Array.isArray(service.envVars)) { issues.push(`Service ${service.name || index} should have envVars as an array`); // Not a critical error, so we don't set isValid to false } if (service.image && !service.image.url) { issues.push(`Service ${service.name || index} has an image object but no url`); isValid = false; } }); } // Check databases if present if (data.databases) { if (!Array.isArray(data.databases)) { issues.push('databases must be an array'); isValid = false; } else { data.databases.forEach((db, index) => { if (!db.name) { issues.push(`Database at index ${index} is missing a name`); isValid = false; } }); } } if (!isValid) { console.error('❌ Structure validation failed:'); issues.forEach((issue, index) => { console.error(` ${index + 1}. ${issue}`); }); } else { console.log('✓ Structure validation passed'); } return isValid; } catch (error) { console.error('❌ Structure validation error:', error); return false; } }