UNPKG

cfn-forge

Version:

CloudFormation deployment automation tool with git-based workflows

158 lines (138 loc) 4.12 kB
/** * Configuration utilities for CFN-Forge */ const fs = require('fs').promises; const path = require('path'); const yaml = require('js-yaml'); const os = require('os'); async function loadConfig(configPath) { try { const content = await fs.readFile(configPath, 'utf8'); return yaml.load(content); } catch (error) { throw new Error(`Failed to load config from ${configPath}: ${error.message}`); } } /** * Load and merge AWS configuration into environment */ function setupAWSEnvironment(profileName = null) { try { const { setAWSEnvironmentVariables } = require('../commands/config'); setAWSEnvironmentVariables(profileName); } catch (error) { // Silently fail if AWS config not available } } /** * Get AWS profile from project configuration or global default */ function getProjectAWSProfile(environment = null) { try { // Check for project-level AWS profile in .cfn-forge.yaml const projectConfigPath = path.join(process.cwd(), '.cfn-forge.yaml'); if (require('fs').existsSync(projectConfigPath)) { const yaml = require('js-yaml'); const content = require('fs').readFileSync(projectConfigPath, 'utf8'); const config = yaml.load(content); // Check environment-specific AWS settings first if (environment && config.environments && config.environments[environment]) { const envConfig = config.environments[environment]; if (envConfig.aws && envConfig.aws.profile) { return { profile: envConfig.aws.profile, region: envConfig.aws.region, accountId: envConfig.aws.accountId, }; } } // Fall back to global AWS settings if (config.aws && config.aws.profile) { return { profile: config.aws.profile, region: config.aws.region, accountId: config.aws.accountId, }; } } return null; } catch (error) { return null; } } /** * Validate AWS account ID if specified in config */ async function validateAWSAccount(expectedAccountId) { if (!expectedAccountId) { return true; // No validation needed } try { const { execSync } = require('child_process'); const result = execSync( 'aws sts get-caller-identity --query Account --output text', { encoding: 'utf8', timeout: 10000 }, ); const actualAccountId = result.trim(); if (actualAccountId !== expectedAccountId) { throw new Error( `AWS Account ID mismatch! Expected: ${expectedAccountId}, Actual: ${actualAccountId}\n` + 'This safety check prevents deploying to the wrong AWS account.', ); } return true; } catch (error) { if (error.message.includes('Account ID mismatch')) { throw error; } // If AWS CLI not available or other error, skip validation console.warn('Warning: Could not validate AWS account ID'); return true; } } class Config { constructor(global = false) { this.global = global; this.configPath = global ? path.join(os.homedir(), '.cfn-forge', 'config.yaml') : path.join(process.cwd(), '.cfn-forge.yaml'); } async get(key) { try { const config = await this.load(); return config[key]; } catch { return null; } } async set(key, value) { const config = await this.load().catch(() => ({})); config[key] = value; await this.save(config); } async unset(key) { const config = await this.load().catch(() => ({})); delete config[key]; await this.save(config); } async list() { try { return await this.load(); } catch { return {}; } } async load() { const content = await fs.readFile(this.configPath, 'utf8'); return yaml.load(content) || {}; } async save(config) { const dir = path.dirname(this.configPath); await fs.mkdir(dir, { recursive: true }); const content = yaml.dump(config); await fs.writeFile(this.configPath, content, 'utf8'); } } module.exports = { loadConfig, Config, setupAWSEnvironment, getProjectAWSProfile, validateAWSAccount, };