container-image-scanner
Version:
๐จ EMERGENCY Bitnami Migration Scanner - Critical Timeline Aug 28/Sep 29, 2025. Enterprise scanner for 280+ Bitnami images, 118+ Helm charts with emergency migration automation to AWS alternatives.
482 lines (425 loc) โข 19 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.EmergencyMigrationCommand = void 0;
const tslib_1 = require("tslib");
const chart_migration_assistant_1 = require("./chart-migration-assistant");
const scanner_1 = require("./scanner");
const chalk_1 = tslib_1.__importDefault(require("chalk"));
const fs = tslib_1.__importStar(require("fs/promises"));
const path = tslib_1.__importStar(require("path"));
class EmergencyMigrationCommand {
constructor() {
Object.defineProperty(this, "scanner", {
enumerable: true,
configurable: true,
writable: true,
value: new scanner_1.ContainerImageScanner()
});
Object.defineProperty(this, "migrationAssistant", {
enumerable: true,
configurable: true,
writable: true,
value: new chart_migration_assistant_1.ChartMigrationAssistant()
});
}
async executeEmergencyMigration(options) {
console.log(chalk_1.default.red.bold('๐จ EMERGENCY BITNAMI MIGRATION - CRITICAL TIMELINE'));
console.log(chalk_1.default.yellow('August 28, 2025: Images move to bitnamilegacy (NO UPDATES)'));
console.log(chalk_1.default.red('September 29, 2025: Complete catalog deletion'));
console.log('='.repeat(80));
const scanResults = await this.loadScanResults(options.input);
const timeline = this.scanner.getDaysUntilBreaking();
this.displayCriticalTimeline(timeline);
const actionPlan = await this.generateEmergencyActionPlan(scanResults);
this.displayEmergencySummary(actionPlan);
if (options.dryRun) {
console.log(chalk_1.default.cyan('๐งช DRY RUN MODE - No changes will be applied'));
await this.generateEmergencyScripts(actionPlan, options.outputDir);
return;
}
await this.generateEmergencyScripts(actionPlan, options.outputDir);
await this.generateMonitoringSetup(options.outputDir);
console.log(chalk_1.default.green.bold('โ
Emergency migration plan generated!'));
console.log(chalk_1.default.yellow(`๐ Scripts available in: ${options.outputDir}`));
console.log(chalk_1.default.red.bold('โ ๏ธ CRITICAL: Review and execute scripts IMMEDIATELY'));
}
displayCriticalTimeline(timeline) {
console.log('\n' + chalk_1.default.bgRed.white.bold(' CRITICAL TIMELINE '));
if (timeline.legacy <= 0) {
console.log(chalk_1.default.red.bold('๐จ DEADLINE PASSED: Images already moved to bitnamilegacy!'));
console.log(chalk_1.default.red('โ ๏ธ All Bitnami images are now LEGACY - no security updates!'));
}
else {
console.log(chalk_1.default.yellow(`๐
${timeline.legacy} days until legacy migration (Aug 28, 2025)`));
}
if (timeline.deletion <= 0) {
console.log(chalk_1.default.red.bold('๐ฅ CATALOG DELETED: All images are now unavailable!'));
}
else {
console.log(chalk_1.default.red(`๐๏ธ ${timeline.deletion} days until complete deletion (Sep 29, 2025)`));
}
if (timeline.emergency) {
console.log(chalk_1.default.bgRed.white.bold('๐จ EMERGENCY MODE ACTIVATED ๐จ'));
}
console.log();
}
displayEmergencySummary(actionPlan) {
console.log(chalk_1.default.bgYellow.black.bold(' EMERGENCY ACTION SUMMARY '));
console.log(`๐ Total Services Affected: ${actionPlan.summary.totalServices}`);
console.log(`๐จ Critical Systems: ${actionPlan.summary.criticalSystemsAffected}`);
console.log(`โฑ๏ธ Estimated Downtime: ${actionPlan.summary.estimatedDowntime}`);
console.log(`๐ง Estimated Effort: ${actionPlan.summary.estimatedEffort}`);
console.log(chalk_1.default.red.bold(`\n๐จ IMMEDIATE ACTIONS (${actionPlan.immediate.length}):`));
actionPlan.immediate.forEach(action => {
console.log(chalk_1.default.red(` โข ${action.service} (${action.namespace}) - ${action.rSig}`));
});
console.log(chalk_1.default.yellow.bold(`\nโ ๏ธ URGENT ACTIONS (${actionPlan.urgent.length}):`));
actionPlan.urgent.forEach(action => {
console.log(chalk_1.default.yellow(` โข ${action.service} (${action.namespace}) - ${action.rSig}`));
});
console.log();
}
async generateEmergencyActionPlan(scanResults) {
const timeline = this.scanner.getDaysUntilBreaking();
const immediate = [];
const urgent = [];
for (const image of scanResults.images || []) {
if (!this.scanner.isBitnamiImage(image.image))
continue;
const service = this.extractServiceName(image.image);
const migrationPlan = this.migrationAssistant.getMigrationPlan(service);
const rSig = this.scanner.generateRSig(image);
const priority = this.scanner.assessMigrationPriority(image);
const action = {
service,
namespace: image.namespace,
workload: image.workload,
workloadType: image.workloadType,
rSig,
currentImage: image.image,
temporaryMitigation: {
legacyImage: image.image.replace('/bitnami/', '/bitnamilegacy/'),
patchCommand: `kubectl patch ${image.workloadType} ${image.workload} -n ${image.namespace} --type='merge' -p='{"spec":{"template":{"spec":{"containers":[{"name":"${image.container}","image":"${image.image.replace('/bitnami/', '/bitnamilegacy/')}"}]}}}}'`,
testCommand: `kubectl get ${image.workloadType} ${image.workload} -n ${image.namespace} -o jsonpath='{.spec.template.spec.containers[0].image}'`
},
permanentMigration: {
targetChart: migrationPlan?.recommendedChart || 'manual-migration-required',
migrationScript: migrationPlan?.migrationScript || '# Manual migration required',
rollbackScript: migrationPlan?.rollbackScript || '# Manual rollback required',
estimatedTime: migrationPlan?.estimatedTime || '4-8 hours'
},
businessImpact: this.assessBusinessImpact(image, service),
priority: priority
};
if (priority === 'IMMEDIATE') {
immediate.push(action);
}
else if (priority === 'URGENT') {
urgent.push(action);
}
}
const totalServices = immediate.length + urgent.length;
const criticalSystemsAffected = immediate.filter(a => a.businessImpact === 'CRITICAL_SYSTEM').length;
const estimatedDowntime = this.calculateDowntime(immediate, urgent);
const estimatedEffort = this.calculateEffort(immediate, urgent);
return {
immediate,
urgent,
timeline: {
daysUntilLegacyMigration: timeline.legacy,
daysUntilCatalogDeletion: timeline.deletion,
emergencyMode: timeline.emergency
},
summary: {
totalServices,
criticalSystemsAffected,
estimatedDowntime,
estimatedEffort
}
};
}
async generateEmergencyScripts(actionPlan, outputDir) {
await fs.mkdir(outputDir, { recursive: true });
const immediateScript = this.generateImmediateMitigationScript(actionPlan.immediate);
await fs.writeFile(path.join(outputDir, '01-immediate-mitigation.sh'), immediateScript);
const urgentScript = this.generateUrgentMitigationScript(actionPlan.urgent);
await fs.writeFile(path.join(outputDir, '02-urgent-mitigation.sh'), urgentScript);
const permanentScript = this.generatePermanentMigrationScript([...actionPlan.immediate, ...actionPlan.urgent]);
await fs.writeFile(path.join(outputDir, '03-permanent-migration.sh'), permanentScript);
const rollbackScript = this.generateRollbackScript([...actionPlan.immediate, ...actionPlan.urgent]);
await fs.writeFile(path.join(outputDir, '04-rollback.sh'), rollbackScript);
const testScript = this.generateTestingScript([...actionPlan.immediate, ...actionPlan.urgent]);
await fs.writeFile(path.join(outputDir, '05-test-validation.sh'), testScript);
const readme = this.generateEmergencyReadme(actionPlan);
await fs.writeFile(path.join(outputDir, 'README-EMERGENCY.md'), readme);
}
generateImmediateMitigationScript(immediateActions) {
return `#!/bin/bash
# EMERGENCY MITIGATION SCRIPT - EXECUTE IMMEDIATELY
# This provides temporary relief using bitnamilegacy images
# August 28, 2025 deadline: ${this.scanner.getDaysUntilBreaking().legacy} days remaining
set -euo pipefail
echo "๐จ EMERGENCY BITNAMI MITIGATION - TEMPORARY FIX"
echo "โ ๏ธ WARNING: This is a temporary fix using legacy images"
echo "โ ๏ธ Legacy images receive NO SECURITY UPDATES"
echo "=================================================="
# Backup current configurations
kubectl get deployments,statefulsets,daemonsets -A -o yaml > emergency-backup-$(date +%Y%m%d-%H%M%S).yaml
${immediateActions.map(action => `
echo "๐ง Patching ${action.service} in ${action.namespace}..."
${action.temporaryMitigation.patchCommand}
echo "โ
Testing ${action.service}..."
${action.temporaryMitigation.testCommand}
echo "โฑ๏ธ Waiting for rollout..."
kubectl rollout status ${action.workloadType}/${action.workload} -n ${action.namespace} --timeout=300s
`).join('')}
echo "โ
Emergency mitigation complete!"
echo "โ ๏ธ CRITICAL: Plan permanent migration IMMEDIATELY"
echo "โ ๏ธ Legacy images are security risks - no updates!"
`;
}
generateUrgentMitigationScript(urgentActions) {
return `#!/bin/bash
# URGENT MITIGATION SCRIPT - EXECUTE WITHIN 24-48 HOURS
# Temporary migration to bitnamilegacy for urgent services
set -euo pipefail
echo "โ ๏ธ URGENT BITNAMI MITIGATION"
echo "Days until catalog deletion: ${this.scanner.getDaysUntilBreaking().deletion}"
echo "=================================="
${urgentActions.map(action => `
echo "๐ง Patching ${action.service} in ${action.namespace}..."
${action.temporaryMitigation.patchCommand}
echo "โ
Validating ${action.service}..."
${action.temporaryMitigation.testCommand}
`).join('')}
echo "โ
Urgent mitigation complete!"
`;
}
generatePermanentMigrationScript(allActions) {
return `#!/bin/bash
# PERMANENT MIGRATION SCRIPT - REPLACE BITNAMI COMPLETELY
# This performs the full migration to upstream/alternative charts
set -euo pipefail
echo "๐ PERMANENT BITNAMI MIGRATION"
echo "Moving to upstream/official charts"
echo "===================================="
${allActions.map(action => `
echo "๐ Migrating ${action.service} to ${action.permanentMigration.targetChart}..."
echo "Estimated time: ${action.permanentMigration.estimatedTime}"
${action.permanentMigration.migrationScript}
echo "โ
${action.service} migration complete!"
echo ""
`).join('')}
echo "๐ Permanent migration complete!"
echo "โ
All services migrated from Bitnami"
`;
}
generateRollbackScript(allActions) {
return `#!/bin/bash
# ROLLBACK SCRIPT - USE ONLY IN EMERGENCY
# Rolls back to pre-migration state
set -euo pipefail
echo "๐ EMERGENCY ROLLBACK"
echo "====================="
${allActions.reverse().map(action => `
echo "๐ Rolling back ${action.service}..."
${action.permanentMigration.rollbackScript}
`).join('')}
echo "โ
Rollback complete!"
`;
}
generateTestingScript(allActions) {
return `#!/bin/bash
# TESTING AND VALIDATION SCRIPT
# Verify all migrations are working correctly
set -euo pipefail
echo "๐งช TESTING MIGRATED SERVICES"
echo "=============================="
FAILED_TESTS=0
${allActions.map(action => `
echo "Testing ${action.service} in ${action.namespace}..."
# Basic pod health check
if kubectl get pods -n ${action.namespace} -l app=${action.service} --field-selector=status.phase=Running | grep -q ${action.service}; then
echo "โ
${action.service} pods running"
else
echo "โ ${action.service} pods not running"
((FAILED_TESTS++))
fi
# Service connectivity test
if kubectl exec -n ${action.namespace} deployment/${action.workload} -- echo "Health check" >/dev/null 2>&1; then
echo "โ
${action.service} connectivity OK"
else
echo "โ ${action.service} connectivity failed"
((FAILED_TESTS++))
fi
echo ""
`).join('')}
if [ $FAILED_TESTS -eq 0 ]; then
echo "๐ ALL TESTS PASSED!"
exit 0
else
echo "โ $FAILED_TESTS tests failed!"
exit 1
fi
`;
}
generateEmergencyReadme(actionPlan) {
return `# ๐จ EMERGENCY BITNAMI MIGRATION PLAN
## CRITICAL TIMELINE
- **August 28, 2025**: Images move to bitnamilegacy (${actionPlan.timeline.daysUntilLegacyMigration} days)
- **September 29, 2025**: Complete catalog deletion (${actionPlan.timeline.daysUntilCatalogDeletion} days)
## SUMMARY
- **Total Services**: ${actionPlan.summary.totalServices}
- **Critical Systems**: ${actionPlan.summary.criticalSystemsAffected}
- **Estimated Downtime**: ${actionPlan.summary.estimatedDowntime}
- **Estimated Effort**: ${actionPlan.summary.estimatedEffort}
## EXECUTION ORDER (CRITICAL!)
### 1. IMMEDIATE ACTIONS (Execute NOW!)
\`\`\`bash
chmod +x 01-immediate-mitigation.sh
./01-immediate-mitigation.sh
\`\`\`
**Immediate Services (${actionPlan.immediate.length}):**
${actionPlan.immediate.map(action => `- **${action.service}** (${action.namespace}) - ${action.rSig} - Impact: ${action.businessImpact}`).join('\n')}
### 2. URGENT ACTIONS (Within 24-48 hours)
\`\`\`bash
chmod +x 02-urgent-mitigation.sh
./02-urgent-mitigation.sh
\`\`\`
**Urgent Services (${actionPlan.urgent.length}):**
${actionPlan.urgent.map(action => `- **${action.service}** (${action.namespace}) - ${action.rSig}`).join('\n')}
### 3. PERMANENT MIGRATION (Within 1 week)
\`\`\`bash
chmod +x 03-permanent-migration.sh
./03-permanent-migration.sh
\`\`\`
### 4. VALIDATION
\`\`\`bash
chmod +x 05-test-validation.sh
./05-test-validation.sh
\`\`\`
## EMERGENCY PROCEDURES
### If Deployments Fail (ImagePullBackOff)
1. Check image availability: \`docker pull <image-name>\`
2. Apply temporary patch: Use bitnamilegacy repository
3. Monitor for security vulnerabilities (legacy images have no updates)
### Rollback if Needed
\`\`\`bash
chmod +x 04-rollback.sh
./04-rollback.sh
\`\`\`
## MONITORING & ALERTS
- Set up continuous monitoring for Bitnami images
- Alert when new Bitnami images discovered
- Track migration progress
## SUPPORT CONTACTS
- **Enterprise Support**: Contact your AWS Account Team
- **Emergency Escalation**: AWS Specialist SAs
- **Technical Issues**: Use AWS Support channels
---
**๐จ WARNING: This is an emergency situation. Legacy images receive NO security updates. Permanent migration is CRITICAL!**
`;
}
async generateMonitoringSetup(outputDir) {
const monitoringScript = `#!/bin/bash
# CONTINUOUS MONITORING SETUP - 12-HOUR RESCANS
# Monitors for new Bitnami images and migration progress
set -euo pipefail
echo "๐ SETTING UP CONTINUOUS BITNAMI MONITORING"
echo "=============================================="
# Create monitoring namespace
kubectl create namespace bitnami-monitoring --dry-run=client -o yaml | kubectl apply -f -
# Create CronJob for 12-hour rescans
kubectl apply -f - <<EOF
apiVersion: batch/v1
kind: CronJob
metadata:
name: bitnami-scanner
namespace: bitnami-monitoring
spec:
schedule: "0 */12 * * *" # Every 12 hours
jobTemplate:
spec:
template:
spec:
containers:
- name: scanner
image: container-image-scanner:latest
command: ["/bin/sh"]
args:
- -c
- |
echo "๐ Scanning for Bitnami images..."
container-image-scanner analyze --org-scan --critical-only --output /tmp/scan-results.json
# Check for new Bitnami detections
NEW_COUNT=\$(jq '.summary.criticalRisk' /tmp/scan-results.json)
if [ "\$NEW_COUNT" -gt 0 ]; then
echo "๐จ ALERT: \$NEW_COUNT new critical Bitnami images detected!"
# Send alert (webhook, Slack, email, etc.)
fi
restartPolicy: OnFailure
EOF
echo "โ
Monitoring setup complete!"
echo "๐ Scans will run every 12 hours"
echo "๐ Configure alerts in your monitoring system"
`;
await fs.writeFile(path.join(outputDir, '06-setup-monitoring.sh'), monitoringScript);
}
async loadScanResults(inputFile) {
const data = await fs.readFile(inputFile, 'utf-8');
return JSON.parse(data);
}
extractServiceName(imageName) {
const parts = imageName.split('/');
const imageWithTag = parts[parts.length - 1];
if (!imageWithTag)
return 'unknown';
const serviceName = imageWithTag.split(':')[0];
if (!serviceName)
return 'unknown';
return serviceName.toLowerCase();
}
assessBusinessImpact(image, service) {
const criticalServices = ['mysql', 'postgresql', 'mongodb', 'redis', 'elasticsearch', 'kafka'];
const isProduction = image.namespace === 'production' || image.namespace.includes('prod');
const hasHighReplicas = image.replicas > 1;
if (criticalServices.includes(service) && isProduction) {
return 'CRITICAL_SYSTEM';
}
else if (hasHighReplicas && isProduction) {
return 'HIGH_AVAILABILITY';
}
else if (isProduction) {
return 'BUSINESS_FUNCTION';
}
else {
return 'DEV_TEST';
}
}
calculateDowntime(immediate, urgent) {
const criticalCount = immediate.filter(a => a.businessImpact === 'CRITICAL_SYSTEM').length;
const estimatedMinutes = (criticalCount * 15) + (immediate.length * 5) + (urgent.length * 3);
if (estimatedMinutes < 60) {
return `${estimatedMinutes} minutes`;
}
else {
const hours = Math.floor(estimatedMinutes / 60);
const mins = estimatedMinutes % 60;
return `${hours}h ${mins}m`;
}
}
calculateEffort(immediate, urgent) {
const immediateEffort = immediate.length * 2;
const urgentEffort = urgent.length * 1;
const totalHours = immediateEffort + urgentEffort;
if (totalHours < 24) {
return `${totalHours} hours`;
}
else {
const days = Math.floor(totalHours / 8);
const hours = totalHours % 8;
return `${days} days, ${hours} hours`;
}
}
}
exports.EmergencyMigrationCommand = EmergencyMigrationCommand;
;