ctrlshiftleft
Version:
AI-powered toolkit for embedding QA and security testing into development workflows
253 lines (214 loc) • 9.01 kB
JavaScript
/**
* Upgrade Script for AI-Enhanced ctrl.shift.left
*
* This script helps users upgrade to the AI-enhanced version of ctrl.shift.left
* by updating the necessary files and setting up the required configurations.
*/
const fs = require('fs');
const path = require('path');
const { exec } = require('child_process');
const { promisify } = require('util');
const readline = require('readline');
const execAsync = promisify(exec);
// ANSI color codes for terminal output
const colors = {
reset: '\x1b[0m',
bright: '\x1b[1m',
dim: '\x1b[2m',
underscore: '\x1b[4m',
blink: '\x1b[5m',
reverse: '\x1b[7m',
hidden: '\x1b[8m',
fg: {
black: '\x1b[30m',
red: '\x1b[31m',
green: '\x1b[32m',
yellow: '\x1b[33m',
blue: '\x1b[34m',
magenta: '\x1b[35m',
cyan: '\x1b[36m',
white: '\x1b[37m'
},
bg: {
black: '\x1b[40m',
red: '\x1b[41m',
green: '\x1b[42m',
yellow: '\x1b[43m',
blue: '\x1b[44m',
magenta: '\x1b[45m',
cyan: '\x1b[46m',
white: '\x1b[47m'
}
};
// Create a readline interface for user input
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
// Prompt the user for input
function prompt(question) {
return new Promise((resolve) => {
rl.question(question, (answer) => {
resolve(answer);
});
});
}
// Print colored messages
function printTitle(message) {
console.log(`\n${colors.fg.cyan}${colors.bright}${message}${colors.reset}\n`);
}
function printSuccess(message) {
console.log(`${colors.fg.green}✓ ${message}${colors.reset}`);
}
function printWarning(message) {
console.log(`${colors.fg.yellow}⚠ ${message}${colors.reset}`);
}
function printError(message) {
console.log(`${colors.fg.red}✗ ${message}${colors.reset}`);
}
function printStep(step, message) {
console.log(`${colors.fg.blue}[${step}]${colors.reset} ${message}`);
}
// Get the project root directory
const projectRoot = path.resolve(__dirname, '..');
// Paths to relevant directories and files
const vscodePath = path.join(projectRoot, 'vscode-ext-test');
const scriptsPath = path.join(projectRoot, 'scripts');
const docsPath = path.join(projectRoot, 'docs');
const binPath = path.join(projectRoot, 'bin');
// Main upgrade function
async function upgrade() {
printTitle('ctrl.shift.left AI Upgrade Utility');
console.log('This utility will upgrade your ctrl.shift.left installation to use AI-enhanced security analysis.\n');
try {
// Step 1: Check Prerequisites
printStep('1', 'Checking prerequisites...');
// Check if OpenAI API key is set
const apiKey = process.env.OPENAI_API_KEY;
if (!apiKey) {
printWarning('OpenAI API key not found in environment variables.');
const setKey = await prompt('Would you like to set an OpenAI API key now? (y/n): ');
if (setKey.toLowerCase() === 'y') {
const key = await prompt('Enter your OpenAI API key: ');
if (key && key.trim()) {
// Set key for this session
process.env.OPENAI_API_KEY = key.trim();
printSuccess('API key set for this session');
// Add to .env file
const envPath = path.join(projectRoot, '.env');
try {
let envContent = '';
if (fs.existsSync(envPath)) {
envContent = fs.readFileSync(envPath, 'utf8');
// Check if OPENAI_API_KEY is already in the file
if (envContent.includes('OPENAI_API_KEY=')) {
// Replace the existing key
envContent = envContent.replace(/OPENAI_API_KEY=.*/g, `OPENAI_API_KEY=${key.trim()}`);
} else {
// Add new key
envContent += `\nOPENAI_API_KEY=${key.trim()}\n`;
}
} else {
// Create new .env file
envContent = `OPENAI_API_KEY=${key.trim()}\n`;
}
fs.writeFileSync(envPath, envContent);
printSuccess('.env file updated with API key');
} catch (error) {
printError(`Failed to update .env file: ${error.message}`);
printWarning('Please manually add OPENAI_API_KEY to your .env file or environment variables');
}
} else {
printError('Invalid API key provided');
printWarning('AI-enhanced features will not be available without an OpenAI API key');
}
} else {
printWarning('Proceeding without API key. AI-enhanced features will not be available.');
}
} else {
printSuccess('OpenAI API key found in environment variables');
}
// Step 2: Make scripts executable
printStep('2', 'Making AI scripts executable...');
try {
// Make the AI CLI executable
await execAsync(`chmod +x ${path.join(binPath, 'ctrlshiftleft-ai')}`);
await execAsync(`chmod +x ${path.join(projectRoot, 'vscode-ext-test', 'analyze-security-enhanced.js')}`);
printSuccess('Scripts are now executable');
} catch (error) {
printError(`Failed to make scripts executable: ${error.message}`);
printWarning('You may need to manually run: chmod +x bin/ctrlshiftleft-ai');
}
// Step 3: Update VS Code Extension
printStep('3', 'Updating VS Code extension...');
try {
// Back up original files
const extensionBackupPath = path.join(vscodePath, 'extension-simple.js.bak');
const packageBackupPath = path.join(vscodePath, 'package.json.bak');
if (!fs.existsSync(extensionBackupPath)) {
fs.copyFileSync(path.join(vscodePath, 'extension-simple.js'), extensionBackupPath);
}
if (!fs.existsSync(packageBackupPath)) {
fs.copyFileSync(path.join(vscodePath, 'package.json'), packageBackupPath);
}
// Copy enhanced files
fs.copyFileSync(path.join(vscodePath, 'package-enhanced.json'), path.join(vscodePath, 'package.json'));
fs.copyFileSync(path.join(vscodePath, 'extension-enhanced.js'), path.join(vscodePath, 'extension-simple.js'));
printSuccess('VS Code extension updated with AI capabilities');
printWarning('Remember to reload VS Code window after the upgrade');
} catch (error) {
printError(`Failed to update VS Code extension: ${error.message}`);
printWarning('You may need to manually copy the enhanced files');
}
// Step 4: Test AI-enhanced security analyzer
printStep('4', 'Testing AI-enhanced security analyzer...');
const shouldTest = await prompt('Would you like to test the AI-enhanced security analyzer now? (y/n): ');
if (shouldTest.toLowerCase() === 'y') {
try {
// Check if demo file exists
const demoFile = path.join(projectRoot, 'demo', 'samples', 'vulnerable-auth.js');
if (fs.existsSync(demoFile)) {
console.log('\nRunning AI-enhanced security analysis on demo file...');
console.log('(This may take a few moments as it contacts the OpenAI API)\n');
const { stdout, stderr } = await execAsync(`${path.join(binPath, 'ctrlshiftleft-ai')} analyze --ai "${demoFile}"`, { cwd: projectRoot });
console.log(stdout);
if (stderr) console.error(stderr);
printSuccess('AI-enhanced security analyzer test complete');
} else {
printWarning(`Demo file not found: ${demoFile}`);
printWarning('Skipping test');
}
} catch (error) {
printError(`Test failed: ${error.message}`);
if (error.stdout) console.log(error.stdout);
if (error.stderr) console.error(error.stderr);
}
} else {
printWarning('Skipping test');
}
// Step 5: Complete
printTitle('Upgrade Complete!');
console.log(`${colors.bright}Your ctrl.shift.left installation has been upgraded with AI-enhanced security analysis capabilities.${colors.reset}\n`);
console.log('Documentation:');
console.log(`- AI Security Guide: ${colors.fg.cyan}${path.join(docsPath, 'AI_SECURITY_GUIDE.md')}${colors.reset}`);
console.log(`- Upgrade Guide: ${colors.fg.cyan}${path.join(docsPath, 'UPGRADE_TO_AI.md')}${colors.reset}\n`);
console.log('Quick Start:');
console.log(`1. ${colors.fg.green}Run AI-enhanced security analysis:${colors.reset}`);
console.log(` ./bin/ctrlshiftleft-ai analyze --ai <file>\n`);
console.log(`2. ${colors.fg.green}Run AI-enhanced full scan:${colors.reset}`);
console.log(` ./bin/ctrlshiftleft-ai secure --ai <file>\n`);
console.log(`3. ${colors.fg.green}In VS Code:${colors.reset}`);
console.log(` Right-click file → Ctrl+Shift+Left: AI Security Analysis\n`);
} catch (error) {
printError(`Upgrade failed: ${error.message}`);
console.error(error);
} finally {
rl.close();
}
}
// Run the upgrade
upgrade().catch(error => {
console.error('Unhandled error:', error);
process.exit(1);
});