/** * Secret set command */ import { and, eq } from 'drizzle-orm'; import { getDb } from '../../db/client'; import { modules, secrets } from '../../db/schema'; import { encryptSecret } from '../../secrets/encryption'; import { getOrCreateMasterKey } from '../../secrets/master-key'; import { getArg, validateRequiredArgs } from '../parser'; import type { CommandResult } from '../types'; /** * Handle secret set command * * Usage: celilo secret set * * @param args - Command arguments * @returns Command result */ export async function handleSecretSet(args: string[]): Promise { // Validate arguments const error = validateRequiredArgs(args, 3); if (error) { return { success: false, error: `${error}\n\nUsage: celilo secret set `, }; } const moduleId = getArg(args, 0); const name = getArg(args, 1); const value = getArg(args, 2); if (!moduleId || !name || !value) { return { success: false, error: 'Module ID, secret name, and value are required', }; } const db = getDb(); // Check if module exists const module = db.select().from(modules).where(eq(modules.id, moduleId)).get(); if (!module) { return { success: false, error: `Module not found: ${moduleId}`, }; } // Validate secret name against manifest const manifest = module.manifestData as Record; const secretsSection = manifest.secrets as | { declares?: Array<{ name: string; type?: string; required?: boolean }> } | undefined; const declaredSecrets = secretsSection?.declares || []; // Check if secret is declared in manifest const declaredSecret = declaredSecrets.find((s) => s.name === name); if (!declaredSecret) { const validSecrets = declaredSecrets.map((s) => s.name).join(', '); return { success: false, error: `Invalid secret '${name}' for module ${moduleId}.\n\nValid secrets: ${validSecrets || '(none declared)'}`, }; } // Get or create master key let masterKey: Buffer; try { masterKey = await getOrCreateMasterKey(); } catch (err) { return { success: false, error: 'Failed to access master key', details: err, }; } // Encrypt secret let encrypted: { encryptedValue: string; iv: string; authTag: string }; try { encrypted = encryptSecret(value, masterKey); } catch (err) { return { success: false, error: 'Failed to encrypt secret', details: err, }; } // Check if secret already exists const existingSecret = db .select() .from(secrets) .where(and(eq(secrets.moduleId, moduleId), eq(secrets.name, name))) .get(); if (existingSecret) { // Update existing secret db.update(secrets) .set({ encryptedValue: encrypted.encryptedValue, iv: encrypted.iv, authTag: encrypted.authTag, updatedAt: new Date(), }) .where(eq(secrets.id, existingSecret.id)) .run(); return { success: true, message: `Updated secret for ${moduleId}: ${name}`, }; } // Insert new secret db.insert(secrets) .values({ moduleId, name, encryptedValue: encrypted.encryptedValue, iv: encrypted.iv, authTag: encrypted.authTag, }) .run(); return { success: true, message: `Set secret for ${moduleId}: ${name}`, }; }