tmrw-audit
Version:
tmrw audit: Your escape hatch from the cloud cage.
134 lines (133 loc) • 6.3 kB
JavaScript
;
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'),
};
}