tops-bmad
Version:
CLI tool to install BMAD workflow files into any project with integrated Shai-Hulud 2.0 security scanning
165 lines (138 loc) โข 5.95 kB
JavaScript
import inquirer from "inquirer";
import fs from "fs-extra";
import path from "path";
import { fileURLToPath } from "url";
import { decryptFile } from "../lib/encrypt.js";
import AdmZip from "adm-zip";
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const PROJECT_ROOT = path.join(__dirname, "..");
const ENCRYPTED_ZIP = path.join(PROJECT_ROOT, "bmad-package.zip");
const TEST_DECRYPTED_ZIP = path.join(PROJECT_ROOT, "test-decrypted.zip");
const TEST_EXTRACT_DIR = path.join(PROJECT_ROOT, "test-extract");
console.log("\n๐ BMAD Package Decryption Test Tool\n");
(async () => {
try {
// Check if encrypted zip exists
if (!await fs.pathExists(ENCRYPTED_ZIP)) {
console.error(`โ Error: Encrypted zip file not found at: ${ENCRYPTED_ZIP}`);
console.log("๐ก Make sure you have encrypted the package first using: npm run encrypt-zip");
process.exit(1);
}
const fileStats = await fs.stat(ENCRYPTED_ZIP);
console.log(`๐ฆ Found encrypted file: ${ENCRYPTED_ZIP}`);
console.log(` Size: ${(fileStats.size / 1024).toFixed(2)} KB\n`);
const answers = await inquirer.prompt([
{
name: "secretKey",
type: "password",
message: "Enter the secret key to test decryption:",
mask: "*",
validate: v => v.trim() !== "" || "Secret key cannot be empty!"
}
]);
console.log("\n๐ Attempting to decrypt...");
// Decrypt the file
await decryptFile(ENCRYPTED_ZIP, TEST_DECRYPTED_ZIP, answers.secretKey);
console.log("โ
Decryption successful!");
// Verify the decrypted file exists and has content
const decryptedStats = await fs.stat(TEST_DECRYPTED_ZIP);
console.log(`๐ฆ Decrypted file size: ${(decryptedStats.size / 1024).toFixed(2)} KB`);
// Try to open it as a zip file to verify it's valid
console.log("\n๐ Verifying zip file integrity...");
try {
const zip = new AdmZip(TEST_DECRYPTED_ZIP);
const zipEntries = zip.getEntries();
console.log(`โ
Zip file is valid!`);
console.log(` Number of entries: ${zipEntries.length}`);
// Show first few entries
if (zipEntries.length > 0) {
console.log("\n๐ Sample entries:");
zipEntries.slice(0, 5).forEach((entry, index) => {
const size = entry.header.size > 0 ? `${(entry.header.size / 1024).toFixed(2)} KB` : "dir";
console.log(` ${index + 1}. ${entry.entryName} (${size})`);
});
if (zipEntries.length > 5) {
console.log(` ... and ${zipEntries.length - 5} more entries`);
}
}
// Optionally extract to verify contents
const { extract } = await inquirer.prompt([
{
name: "extract",
type: "confirm",
message: "\nDo you want to extract the decrypted zip to verify contents?",
default: false
}
]);
if (extract) {
console.log("\n๐ Extracting zip file...");
await fs.ensureDir(TEST_EXTRACT_DIR);
zip.extractAllTo(TEST_EXTRACT_DIR, true);
// List extracted contents
const extractContents = await fs.readdir(TEST_EXTRACT_DIR);
console.log(`โ
Extraction successful!`);
console.log(` Extracted ${extractContents.length} items to: ${TEST_EXTRACT_DIR}`);
// Show directory structure
console.log("\n๐ Directory structure:");
async function listDir(dirPath, prefix = "") {
const items = await fs.readdir(dirPath);
for (let i = 0; i < items.length; i++) {
const item = items[i];
const itemPath = path.join(dirPath, item);
const stats = await fs.stat(itemPath);
const isLast = i === items.length - 1;
const currentPrefix = isLast ? "โโโ " : "โโโ ";
console.log(`${prefix}${currentPrefix}${item}${stats.isDirectory() ? "/" : ""}`);
if (stats.isDirectory() && items.length <= 10) {
await listDir(itemPath, prefix + (isLast ? " " : "โ "));
}
}
}
await listDir(TEST_EXTRACT_DIR);
}
} catch (zipError) {
console.error("โ Error: Decrypted file is not a valid zip file!");
console.error(` ${zipError.message}`);
console.log("\nโ ๏ธ This might indicate:");
console.log(" - Wrong secret key was used");
console.log(" - File was corrupted during encryption/decryption");
throw zipError;
}
console.log("\nโจ Decryption test completed successfully!");
console.log("\n๐งน Cleaning up test files...");
// Clean up test files
if (await fs.pathExists(TEST_DECRYPTED_ZIP)) {
await fs.remove(TEST_DECRYPTED_ZIP);
console.log(" โ Removed test-decrypted.zip");
}
if (await fs.pathExists(TEST_EXTRACT_DIR)) {
const { keepExtracted } = await inquirer.prompt([
{
name: "keepExtracted",
type: "confirm",
message: "Keep extracted test files?",
default: false
}
]);
if (!keepExtracted) {
await fs.remove(TEST_EXTRACT_DIR);
console.log(" โ Removed test-extract directory");
} else {
console.log(` โน๏ธ Test files kept at: ${TEST_EXTRACT_DIR}`);
}
}
console.log("\nโ
All tests passed! Your encryption/decryption is working correctly.");
} catch (error) {
// Clean up on error
if (await fs.pathExists(TEST_DECRYPTED_ZIP)) {
await fs.remove(TEST_DECRYPTED_ZIP).catch(() => {});
}
if (await fs.pathExists(TEST_EXTRACT_DIR)) {
await fs.remove(TEST_EXTRACT_DIR).catch(() => {}).catch(() => {});
}
console.error("\nโ Decryption test failed:", error.message);
process.exit(1);
}
})();