All files / src index.js

98.21% Statements 55/56
93.61% Branches 44/47
100% Functions 7/7
98.21% Lines 55/56

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 1873x 3x 3x 3x 3x 3x       42x                       42x             42x 42x                 16x                 16x   16x 6x 5x 5x 1x       15x 4x 4x 4x         15x 11x 11x 11x 8x 8x 3x         15x 5x 5x 5x 2x       15x 15x     1x 1x     16x                   4x 1x     3x                         5x                     5x 2x     3x                             2x                 7x   7x 2x     5x 108x 217x 215x                             5x       3x
const OpenApiValidator = require('./validators/openApiValidator');
const EndpointValidator = require('./validators/endpointValidator');
const ConnectorValidator = require('./validators/connectorValidator');
const HealthValidator = require('./validators/healthValidator');
const TokenManager = require('./security/tokenManager');
const CertificateManager = require('./security/certificateManager');
 
class ValidationCore {
  constructor(config = {}) {
    this.config = {
      strictMode: config.strictMode || false,
      requiredConnectors: config.requiredConnectors || [
        'connector-logger',
        'connector-storage',
        'connector-registry-client',
        'connector-mq-client',
        'connector-cookbook'
      ],
      ...config
    };
 
    this.validators = {
      openApi: new OpenApiValidator(),
      endpoints: new EndpointValidator(),
      connectors: new ConnectorValidator(this.config.requiredConnectors),
      health: new HealthValidator()
    };
 
    this.tokenManager = new TokenManager();
    this.certificateManager = new CertificateManager();
  }
 
  /**
   * Validates service configuration
   * @param {object} serviceData - Service data to validate
   * @returns {Promise<object>} Validation results
   */
  async validate(serviceData) {
    const results = {
      success: true,
      validated: false,
      checks: {},
      errors: [],
      warnings: [],
      timestamp: new Date().toISOString()
    };
 
    try {
      // Run all validators
      if (serviceData.openApiSpec) {
        const openApiResult = await this.validators.openApi.validate(serviceData.openApiSpec);
        results.checks.openApi = openApiResult;
        if (!openApiResult.valid) {
          results.errors.push(...openApiResult.errors);
        }
      }
 
      if (serviceData.endpoints) {
        const endpointsResult = await this.validators.endpoints.validate(serviceData.endpoints);
        results.checks.endpoints = endpointsResult;
        Iif (!endpointsResult.valid) {
          results.errors.push(...endpointsResult.errors);
        }
      }
 
      if (serviceData.metadata) {
        const connectorsResult = await this.validators.connectors.validate(serviceData.metadata);
        results.checks.connectors = connectorsResult;
        if (!connectorsResult.valid) {
          results.warnings.push(...connectorsResult.warnings);
          if (this.config.strictMode) {
            results.errors.push(...connectorsResult.warnings);
          }
        }
      }
 
      if (serviceData.health) {
        const healthResult = await this.validators.health.validate(serviceData.health);
        results.checks.health = healthResult;
        if (!healthResult.valid) {
          results.warnings.push(...healthResult.warnings);
        }
      }
 
      results.validated = true;
      results.success = results.errors.length === 0;
 
    } catch (error) {
      results.success = false;
      results.errors.push(`Validation error: ${error.message}`);
    }
 
    return results;
  }
 
  /**
   * Generate pre-validation token
   * @param {object} validationResults - Results from validate()
   * @param {string} serviceName - Name of the service
   * @returns {Promise<string>} Pre-validation token
   */
  async generatePreValidationToken(validationResults, serviceName) {
    if (!validationResults.success) {
      throw new Error('Cannot generate token for failed validation');
    }
 
    return this.tokenManager.generateToken({
      serviceName,
      validationResults,
      type: 'pre-validation'
    });
  }
 
  /**
   * Verify pre-validation token
   * @param {string} token - Token to verify
   * @returns {Promise<object>} Token payload
   */
  async verifyPreValidationToken(token) {
    return this.tokenManager.verifyToken(token);
  }
 
  /**
   * Generate validation certificate
   * @param {object} validationResults - Results from validate()
   * @param {string} serviceName - Name of the service
   * @param {string} version - Service version
   * @returns {Promise<object>} Validation certificate
   */
  async generateCertificate(validationResults, serviceName, version) {
    if (!validationResults.success) {
      throw new Error('Cannot generate certificate for failed validation');
    }
 
    return this.certificateManager.generateCertificate({
      serviceName,
      version,
      validationResults,
      issuedAt: new Date().toISOString(),
      expiresAt: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000).toISOString() // 30 days
    });
  }
 
  /**
   * Verify validation certificate
   * @param {object} certificate - Certificate to verify
   * @returns {Promise<boolean>} Verification result
   */
  async verifyCertificate(certificate) {
    return this.certificateManager.verifyCertificate(certificate);
  }
 
  /**
   * Generate functional tests from OpenAPI spec
   * @param {object} openApiSpec - OpenAPI specification
   * @returns {Promise<array>} Generated tests
   */
  async generateFunctionalTests(openApiSpec) {
    const tests = [];
 
    if (!openApiSpec || !openApiSpec.paths) {
      return tests;
    }
 
    for (const [pathName, pathDef] of Object.entries(openApiSpec.paths)) {
      for (const [method, operation] of Object.entries(pathDef)) {
        if (['get', 'post', 'put', 'patch', 'delete'].includes(method.toLowerCase())) {
          tests.push({
            name: operation.summary || `${method.toUpperCase()} ${pathName}`,
            method: method.toUpperCase(),
            path: pathName,
            description: operation.description || '',
            parameters: operation.parameters || [],
            requestBody: operation.requestBody || null,
            expectedResponses: Object.keys(operation.responses || {}),
            expectedSuccessResponse: operation.responses?.['200'] ? '200' :
                                    operation.responses?.['201'] ? '201' : null
          });
        }
      }
    }
 
    return tests;
  }
}
 
module.exports = ValidationCore;