UNPKG

autopv-cli

Version:

AutoPrivacy DSAR evidence-pack generator - Automated GDPR compliance for SaaS companies

158 lines (157 loc) โ€ข 8.29 kB
import { Command, Flags } from '@oclif/core'; import { GitHubProvider } from '../providers/github.js'; import { StripeProvider } from '../providers/stripe.js'; import { scrubPII } from '../utils/scrub.js'; import { GDPRClassifier } from '../utils/classify.js'; import { EvidencePackBuilder } from '../utils/pack.js'; import { ArchiveCreator } from '../utils/archive.js'; import { FileCleanup } from '../utils/cleanup.js'; import { PerformanceMonitor } from '../utils/performance.js'; import Login from './login.js'; import { config } from 'dotenv'; // Load environment variables config(); // Load encrypted config as fallback const encryptedConfig = Login.loadConfigAsEnv(); for (const [key, value] of Object.entries(encryptedConfig)) { if (!process.env[key]) { process.env[key] = value; } } export default class Generate extends Command { static description = 'Generate DSAR evidence pack'; static flags = { email: Flags.string({ char: 'e', required: true, description: 'User email' }), githubOrg: Flags.string({ char: 'g', required: true, description: 'GitHub org' }), }; async run() { const { flags } = await this.parse(Generate); // Initialize performance monitoring const perfMonitor = new PerformanceMonitor(); perfMonitor.updateProgress('initialization', 0, 7); // Initialize cleanup system const cleanup = new FileCleanup(); await cleanup.cleanupOldFiles(); this.log(`๐Ÿ‘‰ Starting export for ${flags.email}`); this.log(`๐Ÿข GitHub organization: ${flags.githubOrg}`); this.log(`โฐ Export timestamp: ${new Date().toISOString()}`); this.log(`๐Ÿ“Š Memory limit: 300MB (current: ${perfMonitor.getCurrentMemoryMB().toFixed(1)}MB)\n`); // Step 1: GitHub Export perfMonitor.updateProgress('github-export', 1, 7); this.log('๐Ÿ“ Step 1: Exporting GitHub data...'); const githubToken = process.env.GITHUB_TOKEN || encryptedConfig.GITHUB_TOKEN; if (!githubToken) { this.log('โŒ GitHub token not found!'); this.log('๐Ÿ’ก Run: autopv login'); this.log(' Or set GITHUB_TOKEN environment variable'); throw new Error('GitHub token required for data export'); } const githubProvider = new GitHubProvider(githubToken); const githubData = await githubProvider.exportUserData(flags.email, flags.githubOrg); this.log(` โœ… GitHub: ${githubData.events.length} events, ${githubData.audit.length} audit entries`); this.log(` ๐Ÿ“Š Memory: ${perfMonitor.getCurrentMemoryMB().toFixed(1)}MB\n`); perfMonitor.forceGarbageCollection(); // Step 2: Stripe Export perfMonitor.updateProgress('stripe-export', 2, 7); this.log('๐Ÿ’ณ Step 2: Exporting Stripe data...'); let stripeData = { customers: [], charges: [], methods: [] }; const stripeKey = process.env.STRIPE_SECRET_KEY; if (stripeKey) { const stripeProvider = new StripeProvider(stripeKey); stripeData = await stripeProvider.exportCustomerData(flags.email); this.log(` โœ… Stripe: ${stripeData.customers.length} customers, ${stripeData.charges.length} charges, ${stripeData.methods.length} methods`); } else { this.log(' โญ๏ธ Stripe: No API key provided, skipping Stripe export'); } this.log(` ๐Ÿ“Š Memory: ${perfMonitor.getCurrentMemoryMB().toFixed(1)}MB\n`); perfMonitor.forceGarbageCollection(); // Step 3: Merge data perfMonitor.updateProgress('data-merge', 3, 7); this.log('๐Ÿ”— Step 3: Merging data sources...'); const mergedData = { email: flags.email, githubOrg: flags.githubOrg, exportTimestamp: new Date().toISOString(), github: githubData, stripe: stripeData }; const dataSize = JSON.stringify(mergedData).length; this.log(` โœ… Merged data: ${dataSize} bytes total`); this.log(` ๐Ÿ“Š Memory: ${perfMonitor.getCurrentMemoryMB().toFixed(1)}MB\n`); // Step 4: PII Scrubbing perfMonitor.updateProgress('pii-scrubbing', 4, 7); this.log('๐Ÿงน Step 4: Scrubbing PII...'); const scrubResult = scrubPII(mergedData); this.log(` โœ… PII scrubbing: ${scrubResult.stats.itemsFound} items found, ${scrubResult.stats.bytesReduced} bytes reduced`); this.log(` ๐Ÿ“Š Memory: ${perfMonitor.getCurrentMemoryMB().toFixed(1)}MB\n`); perfMonitor.forceGarbageCollection(); // Step 5: GDPR Classification perfMonitor.updateProgress('gdpr-classification', 5, 7); this.log('โš–๏ธ Step 5: GDPR classification...'); let gdprAnalysis = null; const openaiApiKey = process.env.OPENAI_API_KEY; if (openaiApiKey) { const classifier = new GDPRClassifier(openaiApiKey); gdprAnalysis = await classifier.classifyData(scrubResult.scrubbedData); this.log(` โœ… GDPR analysis: ${gdprAnalysis.classifications.length} fields classified`); } else { this.log(' โญ๏ธ GDPR: No OpenAI API key provided, skipping GDPR classification'); } this.log(` ๐Ÿ“Š Memory: ${perfMonitor.getCurrentMemoryMB().toFixed(1)}MB\n`); perfMonitor.forceGarbageCollection(); // Step 6: Evidence Pack Generation perfMonitor.updateProgress('evidence-generation', 6, 7); this.log('๐Ÿ“„ Step 6: Building evidence pack...'); const packBuilder = new EvidencePackBuilder(); const evidenceData = { email: flags.email, githubOrg: flags.githubOrg, exportTimestamp: new Date().toISOString(), original: { email: flags.email, githubOrg: flags.githubOrg, exportTimestamp: new Date().toISOString(), github: githubData, stripe: stripeData }, scrubbed: scrubResult.scrubbedData, scrubStats: scrubResult.stats, gdprClassification: gdprAnalysis }; const evidenceFiles = await packBuilder.generateEvidencePack(evidenceData); this.log(` โœ… Evidence pack: ${evidenceFiles.pdfPath} (${evidenceFiles.summary.pdfSize} bytes)`); this.log(` โœ… CSV mapping: ${evidenceFiles.csvPath} (${evidenceFiles.summary.csvSize} bytes)`); this.log(` ๐Ÿ“Š Memory: ${perfMonitor.getCurrentMemoryMB().toFixed(1)}MB\n`); perfMonitor.forceGarbageCollection(); // Step 7: Encrypted Archive perfMonitor.updateProgress('archive-creation', 7, 7); this.log('๐Ÿ” Step 7: Creating encrypted archive...'); const archivePassword = process.env.ARCHIVE_PW || encryptedConfig.ARCHIVE_PW; if (!archivePassword) { this.log('โŒ Archive password not found!'); this.log('๐Ÿ’ก Run: autopv login'); this.log(' Or set ARCHIVE_PW environment variable'); throw new Error('Archive password required for secure delivery'); } const archiveCreator = new ArchiveCreator('.', archivePassword); const archiveResult = await archiveCreator.createEncryptedArchive(evidenceFiles.filesCreated, `evidence_pack_${flags.email.replace(/[^a-zA-Z0-9]/g, '_')}_${new Date().toISOString().replace(/[:.]/g, '-')}.zip`); if (archiveResult.success) { this.log(` โœ… Archive created: ${archiveResult.archivePath}`); this.log(` ๐Ÿ“ฆ Archive size: ${Math.round(archiveResult.archiveSize / 1024)} KB`); this.log(` ๐Ÿงน Cleanup: ${archiveResult.filesArchived.length} files archived`); } else { this.log(` โŒ Archive creation failed: ${archiveResult.error}`); } this.log(` ๐Ÿ“Š Final memory: ${perfMonitor.getCurrentMemoryMB().toFixed(1)}MB\n`); // Final performance summary perfMonitor.stop(); this.log('๐ŸŽ‰ DSAR evidence generation complete!'); this.log(`๐Ÿ“ง Deliverable ready for: ${flags.email}`); if (archiveResult.success) { this.log(`๐Ÿ”’ Archive: ${archiveResult.archivePath}`); } } }