UNPKG

vaultace-cli

Version:

AI-powered security scanner that detects vulnerabilities in AI-generated code. Proactive scanning, autonomous fixing, and emergency response for modern development teams.

394 lines (337 loc) • 14.1 kB
/** * Advanced Workflows - Multi-environment orchestration with conditional logic */ const { Command } = require('commander') const chalk = require('chalk') const ora = require('ora') const inquirer = require('inquirer') const fs = require('fs-extra') const { getAPIClient } = require('../services/api-client') const advancedWorkflowsCommand = new Command('workflows-advanced') .alias('wf-adv') .description('šŸ”„ Advanced workflow orchestration with multi-environment support') // Multi-environment workflow execution advancedWorkflowsCommand .command('deploy-pipeline <workflow-id>') .description('Execute workflow across multiple environments') .option('--environments <envs>', 'comma-separated environments', 'dev,staging,prod') .option('--approval-gates', 'require manual approval between environments') .option('--rollback-on-failure', 'auto-rollback on failure') .option('--parallel', 'run environments in parallel where possible') .action(async (workflowId, options) => { const spinner = ora('Initializing multi-environment deployment...').start() const apiClient = getAPIClient() try { if (!apiClient.isAuthenticated()) { spinner.fail('Authentication required') console.log(chalk.yellow('Please login first: vaultace auth login')) return } const environments = options.environments.split(',').map(env => env.trim()) spinner.succeed('Deployment pipeline initialized') console.log(chalk.bold.cyan('\nšŸš€ Multi-Environment Security Workflow\n')) console.log(`Workflow: ${workflowId}`) console.log(`Environments: ${environments.join(' → ')}`) console.log(`Strategy: ${options.parallel ? 'Parallel' : 'Sequential'}`) if (options.approvalGates) { console.log(chalk.yellow('āš ļø Manual approval gates enabled')) } for (let i = 0; i < environments.length; i++) { const env = environments[i] console.log(chalk.bold.blue(`\nšŸŽÆ Deploying to ${env.toUpperCase()}`)) // Request approval if gates are enabled and not first environment if (options.approvalGates && i > 0) { const { approved } = await inquirer.prompt([{ type: 'confirm', name: 'approved', message: `Approve deployment to ${env}?`, default: false }]) if (!approved) { console.log(chalk.yellow(`āŒ Deployment to ${env} cancelled`)) break } } const envSpinner = ora(`Executing workflow in ${env}...`).start() try { // Execute workflow in environment with environment-specific config const executionResult = await executeWorkflowInEnvironment( apiClient, workflowId, env, { rollback_on_failure: options.rollbackOnFailure, environment_config: await getEnvironmentConfig(env) } ) if (executionResult.success) { envSpinner.succeed(`āœ… ${env.toUpperCase()} deployment successful`) console.log(` Vulnerabilities fixed: ${executionResult.fixes_applied}`) console.log(` Security score: ${executionResult.security_score}/100`) console.log(` Execution time: ${executionResult.duration}ms`) } else { envSpinner.fail(`āŒ ${env.toUpperCase()} deployment failed`) console.log(chalk.red(` Error: ${executionResult.error}`)) if (options.rollbackOnFailure && i > 0) { console.log(chalk.yellow('šŸ”„ Initiating rollback...')) await rollbackPreviousEnvironments(apiClient, workflowId, environments.slice(0, i)) } break } } catch (error) { envSpinner.fail(`āŒ ${env.toUpperCase()} deployment failed`) console.error(chalk.red(`Error: ${error.message}`)) break } } } catch (error) { spinner.fail('Multi-environment deployment failed') console.error(chalk.red(`Error: ${error.message}`)) } }) // Conditional workflow builder advancedWorkflowsCommand .command('create-conditional') .description('Create workflow with conditional logic') .action(async () => { console.log(chalk.bold.cyan('šŸ—ļø Interactive Conditional Workflow Builder\n')) const workflowData = await inquirer.prompt([ { type: 'input', name: 'name', message: 'Workflow name:', validate: input => input.length > 0 }, { type: 'list', name: 'trigger', message: 'Trigger condition:', choices: [ 'vulnerability_detected', 'security_scan_completed', 'compliance_violation', 'manual_trigger' ] }, { type: 'checkbox', name: 'conditions', message: 'Conditional execution rules:', choices: [ { name: 'Only run if severity >= HIGH', value: 'severity_high' }, { name: 'Only run in business hours', value: 'business_hours' }, { name: 'Require approval for CRITICAL', value: 'critical_approval' }, { name: 'Auto-fix if confidence > 90%', value: 'high_confidence_auto' }, { name: 'Skip if in maintenance window', value: 'skip_maintenance' } ] } ]) const steps = [] let addingSteps = true while (addingSteps) { const stepData = await inquirer.prompt([ { type: 'list', name: 'type', message: 'Step type:', choices: [ 'security_scan', 'vulnerability_fix', 'compliance_check', 'notification', 'approval_gate', 'conditional_branch' ] }, { type: 'input', name: 'name', message: 'Step name:' }, { type: 'input', name: 'condition', message: 'Execution condition (optional):', when: (answers) => answers.type === 'conditional_branch' } ]) steps.push(stepData) const { continueAdding } = await inquirer.prompt([{ type: 'confirm', name: 'continueAdding', message: 'Add another step?', default: false }]) addingSteps = continueAdding } const workflowDefinition = { name: workflowData.name, trigger: workflowData.trigger, conditions: workflowData.conditions, steps: steps.map((step, index) => ({ id: `step_${index + 1}`, type: step.type, name: step.name, condition: step.condition || null, parallel: false, retry_count: step.type === 'security_scan' ? 3 : 1, timeout: 300 })), metadata: { created_at: new Date().toISOString(), version: '1.0.0' } } const fileName = `${workflowData.name.replace(/\s+/g, '-').toLowerCase()}-workflow.json` await fs.writeFile(fileName, JSON.stringify(workflowDefinition, null, 2)) console.log(chalk.green(`\nāœ… Conditional workflow created: ${fileName}`)) console.log(chalk.blue('Deploy with: vaultace workflow deploy-file ' + fileName)) }) // Parallel workflow execution advancedWorkflowsCommand .command('parallel-execution <workflow-ids...>') .description('Execute multiple workflows in parallel') .option('--max-concurrent <num>', 'maximum concurrent executions', '5') .option('--fail-fast', 'stop all on first failure') .action(async (workflowIds, options) => { const spinner = ora('Initializing parallel workflow execution...').start() const apiClient = getAPIClient() try { if (!apiClient.isAuthenticated()) { spinner.fail('Authentication required') console.log(chalk.yellow('Please login first: vaultace auth login')) return } const maxConcurrent = parseInt(options.maxConcurrent) spinner.succeed(`Parallel execution initialized (max ${maxConcurrent} concurrent)`) console.log(chalk.bold.cyan('\n⚔ Parallel Workflow Execution\n')) console.log(`Workflows: ${workflowIds.length}`) console.log(`Max Concurrent: ${maxConcurrent}`) console.log(`Fail Fast: ${options.failFast ? 'Enabled' : 'Disabled'}\n`) const results = [] const executing = new Map() let completed = 0 let failed = 0 // Process workflows in batches for (let i = 0; i < workflowIds.length; i += maxConcurrent) { const batch = workflowIds.slice(i, i + maxConcurrent) console.log(chalk.blue(`šŸ”„ Executing batch ${Math.floor(i / maxConcurrent) + 1}`)) const batchPromises = batch.map(async (workflowId) => { const workflowSpinner = ora(`Running ${workflowId}...`).start() try { const result = await apiClient.executeWorkflow(workflowId, { parallel_execution: true, execution_id: `parallel_${Date.now()}_${workflowId}` }) if (result.success) { workflowSpinner.succeed(`āœ… ${workflowId} completed`) completed++ return { workflowId, success: true, result: result.execution } } else { workflowSpinner.fail(`āŒ ${workflowId} failed`) failed++ if (options.failFast) { throw new Error(`Workflow ${workflowId} failed: ${result.error}`) } return { workflowId, success: false, error: result.error } } } catch (error) { workflowSpinner.fail(`āŒ ${workflowId} error`) failed++ if (options.failFast) { throw error } return { workflowId, success: false, error: error.message } } }) const batchResults = await Promise.allSettled(batchPromises) results.push(...batchResults.map(r => r.value || r.reason)) } console.log(chalk.bold.green('\nšŸ“Š Parallel Execution Summary')) console.log(`Total: ${workflowIds.length}`) console.log(`Completed: ${chalk.green(completed)}`) console.log(`Failed: ${chalk.red(failed)}`) console.log(`Success Rate: ${((completed / workflowIds.length) * 100).toFixed(1)}%`) } catch (error) { spinner.fail('Parallel execution failed') console.error(chalk.red(`Error: ${error.message}`)) } }) // Workflow dependency management advancedWorkflowsCommand .command('dependency-chain <primary-workflow>') .description('Execute workflow with dependency chain') .option('--dependencies <workflows>', 'comma-separated dependency workflows') .action(async (primaryWorkflow, options) => { const spinner = ora('Analyzing workflow dependencies...').start() const apiClient = getAPIClient() try { if (!apiClient.isAuthenticated()) { spinner.fail('Authentication required') console.log(chalk.yellow('Please login first: vaultace auth login')) return } const dependencies = options.dependencies ? options.dependencies.split(',').map(w => w.trim()) : [] spinner.succeed('Dependency chain analyzed') console.log(chalk.bold.cyan('\nšŸ”— Workflow Dependency Execution\n')) console.log(`Primary Workflow: ${primaryWorkflow}`) if (dependencies.length > 0) { console.log(`Dependencies: ${dependencies.join(' → ')}`) } // Execute dependencies first for (const dependency of dependencies) { const depSpinner = ora(`Executing dependency: ${dependency}...`).start() const result = await apiClient.executeWorkflow(dependency, { dependency_execution: true, primary_workflow: primaryWorkflow }) if (result.success) { depSpinner.succeed(`āœ… Dependency ${dependency} completed`) } else { depSpinner.fail(`āŒ Dependency ${dependency} failed`) throw new Error(`Dependency failure blocks primary workflow: ${result.error}`) } } // Execute primary workflow const primarySpinner = ora(`Executing primary workflow: ${primaryWorkflow}...`).start() const primaryResult = await apiClient.executeWorkflow(primaryWorkflow, { dependencies_completed: dependencies, execution_type: 'primary' }) if (primaryResult.success) { primarySpinner.succeed(`āœ… Primary workflow ${primaryWorkflow} completed`) console.log(chalk.green('\nšŸŽ‰ Dependency chain execution successful')) } else { primarySpinner.fail(`āŒ Primary workflow ${primaryWorkflow} failed`) console.error(chalk.red(`Error: ${primaryResult.error}`)) } } catch (error) { spinner.fail('Dependency chain execution failed') console.error(chalk.red(`Error: ${error.message}`)) } }) // Helper functions async function executeWorkflowInEnvironment(apiClient, workflowId, environment, options) { // Mock implementation - would call your backend with environment-specific config await new Promise(resolve => setTimeout(resolve, 2000)) // Simulate execution time return { success: Math.random() > 0.1, // 90% success rate fixes_applied: Math.floor(Math.random() * 5) + 1, security_score: Math.floor(Math.random() * 20) + 80, duration: Math.floor(Math.random() * 5000) + 1000, environment } } async function getEnvironmentConfig(environment) { const configs = { dev: { auto_fix: true, notification_level: 'low' }, staging: { auto_fix: false, notification_level: 'medium' }, prod: { auto_fix: false, notification_level: 'high', approval_required: true } } return configs[environment] || {} } async function rollbackPreviousEnvironments(apiClient, workflowId, environments) { console.log(chalk.yellow(`Rolling back environments: ${environments.join(', ')}`)) // Implementation would call your backend rollback API await new Promise(resolve => setTimeout(resolve, 1000)) console.log(chalk.green('āœ… Rollback completed')) } module.exports = advancedWorkflowsCommand