ctrlshiftleft
Version:
AI-powered toolkit for embedding QA and security testing into development workflows
343 lines (291 loc) • 11.3 kB
JavaScript
#!/usr/bin/env node
/**
* Ctrl+Shift+Left Checklist Generator
* Automatically creates QA and security checklists for code components
*/
const fs = require('fs');
const path = require('path');
const { execSync } = require('child_process');
// Configuration
const TARGET_FILE = process.argv[2] || '/Users/johngaspar/CascadeProjects/ctrlshiftleft/demo/src/components/PaymentForm.tsx';
const OUTPUT_FILE = process.argv[3] || '/Users/johngaspar/CascadeProjects/ctrlshiftleft/vscode-ext-test/checklist.json';
const COMPONENT_NAME = path.basename(TARGET_FILE, path.extname(TARGET_FILE));
// Ensure all required directories exist
function ensureDirectoriesExist() {
// Ensure output directory for JSON and MD files exists
const outputDir = path.dirname(OUTPUT_FILE);
if (!fs.existsSync(outputDir)) {
console.log(`Creating output directory: ${outputDir}`);
fs.mkdirSync(outputDir, { recursive: true });
}
// Create other potential directories that might be needed
const dirs = [
'./security-reports',
'./checklists',
path.join(path.dirname(TARGET_FILE), 'checklists'),
'/Users/johngaspar/CascadeProjects/ctrlshiftleft/reports',
'/Users/johngaspar/CascadeProjects/ctrlshiftleft/checklists'
];
dirs.forEach(dir => {
if (!fs.existsSync(dir)) {
console.log(`Creating directory: ${dir}`);
fs.mkdirSync(dir, { recursive: true });
}
});
}
// Function to analyze a file and generate checklist items
function analyzeFileForChecklist(filePath) {
console.log(`Analyzing component: ${filePath}`);
if (!fs.existsSync(filePath)) {
console.error(`File not found: ${filePath}`);
return null;
}
const content = fs.readFileSync(filePath, 'utf8');
// Initialize checklist structure
const checklist = {
component: COMPONENT_NAME,
timestamp: new Date().toISOString(),
categories: [
{
name: "Functionality",
items: []
},
{
name: "Security",
items: []
},
{
name: "Accessibility",
items: []
},
{
name: "Performance",
items: []
},
{
name: "Testing",
items: []
}
]
};
// Analyze file content and generate checklist items
// Functionality checks
checklist.categories[0].items.push({
id: "func-1",
description: "All required form fields have validation",
status: content.includes('validate') || content.includes('validation') ? "PASS" : "REVIEW",
details: content.includes('validate') || content.includes('validation') ?
"Validation functions detected in the code" :
"No validation functions detected, please verify form validation manually"
});
checklist.categories[0].items.push({
id: "func-2",
description: "Error messages are displayed for invalid inputs",
status: content.includes('error') && content.includes('message') ? "PASS" : "REVIEW",
details: content.includes('error') && content.includes('message') ?
"Error message handling detected" :
"Could not detect error message handling, verify manually"
});
// Security checks
checklist.categories[1].items.push({
id: "sec-1",
description: "Input sanitization before processing",
status: content.includes('sanitize') || content.includes('purify') || content.includes('escape') ? "PASS" : "FAIL",
details: content.includes('sanitize') || content.includes('purify') || content.includes('escape') ?
"Input sanitization detected" :
"No input sanitization detected, please implement to prevent XSS and injection attacks"
});
checklist.categories[1].items.push({
id: "sec-2",
description: "Sensitive data handling (credit cards, PII)",
status: (content.includes('password') || content.includes('credit') || content.includes('card')) &&
!content.includes('encryption') ? "FAIL" : "PASS",
details: (content.includes('password') || content.includes('credit') || content.includes('card')) &&
!content.includes('encryption') ?
"Sensitive data detected without proper encryption" :
"No unprotected sensitive data detected"
});
checklist.categories[1].items.push({
id: "sec-3",
description: "CSRF protection mechanisms",
status: content.includes('csrf') || content.includes('token') ? "PASS" : "REVIEW",
details: content.includes('csrf') || content.includes('token') ?
"CSRF token handling detected" :
"No CSRF protection detected, verify if needed for this component"
});
checklist.categories[1].items.push({
id: "sec-4",
description: "No client-side storage of sensitive data",
status: content.includes('localStorage') || content.includes('sessionStorage') ? "FAIL" : "PASS",
details: content.includes('localStorage') || content.includes('sessionStorage') ?
"Client-side storage detected, verify no sensitive data is stored" :
"No client-side storage detected"
});
// Accessibility checks
checklist.categories[2].items.push({
id: "a11y-1",
description: "Form elements have associated labels",
status: content.includes('<label') || content.includes('aria-label') ? "PASS" : "FAIL",
details: content.includes('<label') || content.includes('aria-label') ?
"Label elements detected" :
"No label elements detected, please add for accessibility"
});
checklist.categories[2].items.push({
id: "a11y-2",
description: "Color contrast is sufficient",
status: "REVIEW",
details: "Manual verification required for color contrast"
});
checklist.categories[2].items.push({
id: "a11y-3",
description: "Keyboard navigation is supported",
status: content.includes('onKeyDown') || content.includes('onKeyPress') ? "PASS" : "REVIEW",
details: content.includes('onKeyDown') || content.includes('onKeyPress') ?
"Keyboard event handlers detected" :
"No keyboard event handlers detected, verify keyboard navigation manually"
});
// Performance checks
checklist.categories[3].items.push({
id: "perf-1",
description: "No expensive operations in render method",
status: "REVIEW",
details: "Manual code review required to identify expensive operations"
});
checklist.categories[3].items.push({
id: "perf-2",
description: "Memoization for expensive calculations",
status: content.includes('useMemo') || content.includes('useCallback') ? "PASS" : "REVIEW",
details: content.includes('useMemo') || content.includes('useCallback') ?
"Memoization hooks detected" :
"No memoization detected, verify if needed for performance optimization"
});
// Testing checks
checklist.categories[4].items.push({
id: "test-1",
description: "Unit tests cover component logic",
status: "REVIEW",
details: "Verify that unit tests exist and cover component logic"
});
checklist.categories[4].items.push({
id: "test-2",
description: "Integration tests for form submission",
status: "REVIEW",
details: "Verify that integration tests exist for form submission flow"
});
checklist.categories[4].items.push({
id: "test-3",
description: "End-to-end tests for critical paths",
status: "REVIEW",
details: "E2E tests are essential for payment forms, check existence"
});
return checklist;
}
// Function to generate a human-readable markdown report
function generateMarkdownReport(checklist) {
const markdownPath = OUTPUT_FILE.replace('.json', '.md');
let markdown = `# QA & Security Checklist for ${checklist.component}\n\n`;
markdown += `*Generated by Ctrl+Shift+Left on ${new Date().toLocaleString()}*\n\n`;
// Summary statistics
const stats = {
pass: 0,
fail: 0,
review: 0
};
checklist.categories.forEach(category => {
category.items.forEach(item => {
if (item.status === "PASS") stats.pass++;
else if (item.status === "FAIL") stats.fail++;
else if (item.status === "REVIEW") stats.review++;
});
});
markdown += `## Summary\n\n`;
markdown += `- ✅ Passed: ${stats.pass}\n`;
markdown += `- ❌ Failed: ${stats.fail}\n`;
markdown += `- ⚠️ Needs Review: ${stats.review}\n\n`;
// Results by category
checklist.categories.forEach(category => {
markdown += `## ${category.name}\n\n`;
category.items.forEach(item => {
const statusIcon = item.status === "PASS" ? "✅" : (item.status === "FAIL" ? "❌" : "⚠️");
markdown += `### ${statusIcon} ${item.description}\n\n`;
markdown += `**Status:** ${item.status}\n\n`;
markdown += `**Details:** ${item.details}\n\n`;
});
});
// Add remediation advice
markdown += `## Remediation Steps\n\n`;
if (stats.fail > 0) {
markdown += `### Critical Issues to Fix\n\n`;
checklist.categories.forEach(category => {
category.items.forEach(item => {
if (item.status === "FAIL") {
markdown += `- **${item.description}**: ${item.details}\n`;
}
});
});
markdown += `\n`;
}
if (stats.review > 0) {
markdown += `### Items Needing Manual Review\n\n`;
checklist.categories.forEach(category => {
category.items.forEach(item => {
if (item.status === "REVIEW") {
markdown += `- **${item.description}**: ${item.details}\n`;
}
});
});
}
fs.writeFileSync(markdownPath, markdown);
console.log(`Markdown report written to: ${markdownPath}`);
return markdownPath;
}
// Main function
function main() {
console.log('Ctrl+Shift+Left Checklist Generator');
console.log('==================================');
// Ensure all directories exist first
ensureDirectoriesExist();
// Analyze file and generate checklist
const checklist = analyzeFileForChecklist(TARGET_FILE);
if (!checklist) {
console.error('Failed to generate checklist');
process.exit(1);
}
// Write checklist to JSON file
fs.writeFileSync(OUTPUT_FILE, JSON.stringify(checklist, null, 2));
console.log(`Checklist written to: ${OUTPUT_FILE}`);
// Generate human-readable report
const markdownPath = generateMarkdownReport(checklist);
// Print summary
console.log('\nChecklist Generation Summary:');
let passCount = 0;
let failCount = 0;
let reviewCount = 0;
checklist.categories.forEach(category => {
category.items.forEach(item => {
if (item.status === "PASS") passCount++;
else if (item.status === "FAIL") failCount++;
else if (item.status === "REVIEW") reviewCount++;
});
});
console.log(`Component: ${checklist.component}`);
console.log(`Passed: ${passCount} items`);
console.log(`Failed: ${failCount} items`);
console.log(`Needs review: ${reviewCount} items`);
if (failCount > 0) {
console.log('\n⚠️ ATTENTION: Critical issues were found that need to be addressed!');
}
try {
if (process.platform === 'darwin') { // macOS
execSync(`open "${markdownPath}"`);
} else if (process.platform === 'win32') { // Windows
execSync(`start "" "${markdownPath}"`);
} else { // Linux
execSync(`xdg-open "${markdownPath}"`);
}
} catch (error) {
console.log('Could not automatically open the report.');
}
}
// Run the checklist generator
main();