UNPKG

@papavault/cli

Version:

CLI tool for Papa Vault Secret Manager

132 lines (131 loc) 7.32 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.syncCommand = syncCommand; const chalk_1 = __importDefault(require("chalk")); const ora_1 = __importDefault(require("ora")); const fs_1 = __importDefault(require("fs")); const path_1 = __importDefault(require("path")); const config_1 = require("../utils/config"); const api_1 = require("../utils/api"); // Debug function to log detailed information function debugLog(message, data) { const DEBUG = process.env.PAPAVAULT_DEBUG === 'true'; if (DEBUG) { console.log(chalk_1.default.cyan('[DEBUG] ') + message); if (data !== undefined) { console.log(chalk_1.default.cyan('[DEBUG DATA] '), data); } } } function syncCommand(program) { program .command('sync') .description('Sync secrets from Papa Vault to your local environment') .option('-p, --project-id <projectId>', 'Project ID (overrides config file)') .option('-s, --stage <stage>', 'Environment stage (overrides config file)') .option('-d, --debug', 'Enable debug mode') .option('-t, --token <token>', 'API token for authentication (overrides stored token)') .action(async (options) => { // Set debug mode if flag is provided if (options.debug) { process.env.PAPAVAULT_DEBUG = 'true'; debugLog('Debug mode enabled'); } // Check if authenticated if (!(0, config_1.isAuthenticated)() && !options.token) { console.log(chalk_1.default.red('You need to be logged in to sync secrets.')); console.log(chalk_1.default.yellow('Run `papavault login` to authenticate or provide a token with --token.')); return; } // Get project ID and stage from options or config const projectId = options.projectId || (0, config_1.getProjectId)(); const stage = options.stage || (0, config_1.getStage)(); const token = options.token; debugLog(`Using project ID: ${projectId}, stage: ${stage}`); if (!projectId || !stage) { console.log(chalk_1.default.red('Project ID and stage are required to sync secrets.')); console.log(chalk_1.default.yellow('Run `papavault set-project` to configure your project.')); return; } // Get the config file path to use as the base directory const configFilePath = (0, config_1.getConfigFilePath)(); debugLog(`Config file path: ${configFilePath}`); if (!configFilePath) { console.log(chalk_1.default.red('Could not find .papavault.json configuration file.')); console.log(chalk_1.default.yellow('Run `papavault set-project` to configure your project.')); return; } // Get the directory where the config file is located const baseDir = path_1.default.dirname(configFilePath); console.log(chalk_1.default.blue(`Using base directory: ${baseDir}`)); debugLog(`Base directory: ${baseDir}`); // Fetch credential files const spinner = (0, ora_1.default)('Fetching credential files...').start(); try { const credentialFiles = await (0, api_1.getCredentialFiles)(projectId, stage, token); spinner.succeed(`Found ${credentialFiles.length} credential files.`); if (credentialFiles.length === 0) { console.log(chalk_1.default.yellow('No credential files found to sync.')); return; } // Process each credential file for (const file of credentialFiles) { try { // Get the credential file details const { downloadUrl } = await (0, api_1.getCredentialFile)(projectId, stage, file.id, token); // Download the file content const content = await (0, api_1.downloadCredentialFile)(downloadUrl, token); // Normalize the file path let normalizedFilePath = file.filePath; // Special handling for different path formats if (normalizedFilePath === '/') { // For root path, use the filename directly in the base directory normalizedFilePath = file.fileName; console.log(chalk_1.default.yellow(`Warning: Converting root path '/' to '${normalizedFilePath}'. File will be placed directly in the config directory.`)); } else if (path_1.default.isAbsolute(normalizedFilePath)) { // For absolute paths, we need to make them relative // Get the path parts const parsedPath = path_1.default.parse(normalizedFilePath); // On Windows, remove the drive letter if present if (parsedPath.root.includes(':')) { normalizedFilePath = normalizedFilePath.replace(/^[A-Za-z]:/, ''); } // Remove leading slashes to make it relative normalizedFilePath = normalizedFilePath.replace(/^[\/\\]+/, ''); // Log a warning about the absolute path console.log(chalk_1.default.yellow(`Warning: Converting absolute path '${file.filePath}' to relative path '${normalizedFilePath}'`)); } // Replace backslashes with forward slashes for consistency normalizedFilePath = normalizedFilePath.replace(/\\/g, '/'); debugLog(`Normalized file path: ${normalizedFilePath}`); // Resolve the file path relative to the config file location const absoluteFilePath = path_1.default.resolve(baseDir, normalizedFilePath); debugLog(`Resolved absolute file path: ${absoluteFilePath}`); debugLog(`Path.parse of resolved path:`, path_1.default.parse(absoluteFilePath)); // Create the directory if it doesn't exist const dir = path_1.default.dirname(absoluteFilePath); if (!fs_1.default.existsSync(dir)) { fs_1.default.mkdirSync(dir, { recursive: true }); debugLog(`Created directory: ${dir}`); } // Write the file fs_1.default.writeFileSync(absoluteFilePath, content); console.log(chalk_1.default.green(`✓ Synced ${file.fileName} to ${normalizedFilePath}`)); } catch (error) { console.error(chalk_1.default.red(`Error syncing ${file.fileName}:`), error); } } console.log(chalk_1.default.green('\nSecrets synced successfully!')); } catch (error) { spinner.fail('Failed to fetch credential files'); console.error(chalk_1.default.red('Error:'), error); debugLog('Error fetching credential files:', error); } }); }