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
JavaScript
/**
* 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