UNPKG

tmrw-audit

Version:

tmrw audit: Your escape hatch from the cloud cage.

134 lines (133 loc) 6.3 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.analyzeFiles = analyzeFiles; const fs_extra_1 = __importDefault(require("fs-extra")); const path_1 = __importDefault(require("path")); const hcl2_parser_1 = __importDefault(require("hcl2-parser")); const js_yaml_1 = __importDefault(require("js-yaml")); const chalk_1 = __importDefault(require("chalk")); const vendorServices = require('./vendor-services.json'); async function analyzeFiles(files, rootDir) { let vendorServicesFound = []; let totalServices = 0; let providers = new Set(); let openStandardsCount = 0; let highRiskServices = 0; for (const file of files) { const filePath = path_1.default.join(rootDir, file); try { if (file.endsWith('.tf')) { const content = await fs_extra_1.default.readFile(filePath, 'utf8'); let parsed; try { parsed = hcl2_parser_1.default.parse(content); } catch (err) { if (process.env.DEBUG === 'true') { console.warn(chalk_1.default.yellow(`Skipping invalid Terraform file: ${file}`)); } continue; } const providerBlocks = parsed.body.filter((b) => b.provider); providerBlocks.forEach((b) => providers.add(b.provider)); const resources = parsed.body.filter((b) => b.resource).map((b) => b.resource.type); vendorServicesFound.push(...resources); totalServices += resources.length; resources.forEach((res) => { const service = Object.values(vendorServices) .flat() .find((s) => s.name === res); if (service) { if (vendorServices.portable.some((s) => s.name === res)) { openStandardsCount++; } if (service.deplatformRisk > 0.3) { highRiskServices++; } } }); } else if (file.endsWith('.yml') || file.endsWith('.yaml')) { const content = await fs_extra_1.default.readFile(filePath, 'utf8'); let config; try { config = js_yaml_1.default.load(content); } catch (err) { if (process.env.DEBUG === 'true') { console.warn(chalk_1.default.yellow(`Skipping invalid YAML file: ${file}`)); } continue; } if (config.provider?.name) { providers.add(config.provider.name); const functions = (config.functions || []).map(() => `${config.provider.name}_function`); vendorServicesFound.push(...functions); totalServices += functions.length; highRiskServices += functions.length * 0.2; } if (file.includes('docker-compose')) { openStandardsCount += Object.keys(config.services || {}).length; vendorServicesFound.push('docker'); totalServices += Object.keys(config.services || {}).length; } } else if (file.endsWith('package.json')) { const pkg = await fs_extra_1.default.readJson(filePath); const deps = { ...pkg.dependencies, ...pkg.devDependencies }; if (deps['aws-sdk'] || deps['@aws-sdk/client-s3']) { providers.add('aws'); vendorServicesFound.push('aws_sdk'); totalServices++; highRiskServices += 0.1; } if (deps['@azure/storage-blob']) { providers.add('azure'); vendorServicesFound.push('azure_blob'); totalServices++; highRiskServices += 0.1; } } } catch (err) { if (process.env.DEBUG === 'true') { console.warn(chalk_1.default.yellow(`Error processing ${file}: ${err.message}`)); } } } let lockInScore = 0; vendorServicesFound.forEach((service) => { const vendorService = Object.values(vendorServices) .flat() .find((s) => s.name === service); if (vendorService) lockInScore += vendorService.lockInScore; }); lockInScore = totalServices ? (lockInScore / totalServices) * 100 : 0; const singleProviderPenalty = providers.size === 1 ? 50 : 0; const highRiskPenalty = highRiskServices * 20; const redundancyPenalty = providers.size === 1 ? 30 : 0; const deplatformingRiskScore = Math.min(100, singleProviderPenalty + highRiskPenalty + redundancyPenalty); const portabilityScore = totalServices ? openStandardsCount / totalServices : 0; const clvScore = Math.round(100 - lockInScore * 0.5 - deplatformingRiskScore * 0.3 - (1 - portabilityScore) * 20); return { clvScore, lockInScore, deplatformingRiskScore, portabilityScore, vendorServices: vendorServicesFound, providers: Array.from(providers), riskLabel: clvScore < 50 ? 'VULNERABLE' : clvScore <= 75 ? 'AT RISK' : 'CAUTIOUS', deplatformingRisk: deplatformingRiskScore > 70 ? 'HIGH' : deplatformingRiskScore > 30 ? 'Moderate' : 'Low', recommendations: [ 'Ditch proprietary services like Lambda for Dockerized functions. Run them anywhere.', 'Replace vendor-locked storage like S3 with MinIO or self-hosted solutions. Own your data.', 'Spread your infra across multiple providers or go local. Don’t trust one cloud’s mercy.', 'Deploy the Sovereign Stack: tmrw.it/stack', ], deplatformingExamples: require('./deplatforming.json'), }; }