import {existsSync} from "node:fs"; import {loadBuiltinProviders} from "./providers.mjs"; import {breakGlassActor, loadKeyFile, Vault} from "./vault.mjs"; const databasePath = process.env.DATABASE_PATH || "/data/vault.db"; const masterKeyFile = process.env.MASTER_KEY_FILE || "/run/secrets/vault_master_key"; const [command, ...args] = process.argv.slice(2); function usage() { console.log(`Usage: node cli.mjs list [owner-sub] node cli.mjs audit [limit] node cli.mjs verify node cli.mjs delete node cli.mjs reassign node cli.mjs rotate-master node cli.mjs backup `); } if (!command) { usage(); process.exit(1); } const vault = new Vault({ databasePath, masterKey: loadKeyFile(masterKeyFile), builtinProviders: loadBuiltinProviders(process.env.PROVIDER_CATALOG_FILE || "/app/providers.json") }); const actor = breakGlassActor(); try { if (command === "list") { const credentials = vault.listCredentials(actor, {all: true}); const filtered = args[0] ? credentials.filter((credential) => credential.owner.sub === args[0]) : credentials; console.table(filtered.map((credential) => ({ id: credential.id, owner: credential.owner.username, sub: credential.owner.sub, provider: credential.provider, name: credential.name, fingerprint: credential.fingerprint, status: credential.status }))); } else if (command === "audit") { console.table(vault.listAudit(actor, {all: true, limit: args[0] || 100})); } else if (command === "verify" && args[0]) { console.log(vault.verifyCredential(actor, args[0])); } else if (command === "delete" && args[0]) { console.log(vault.deleteCredential(actor, args[0])); } else if (command === "reassign" && args.length >= 4) { console.log(vault.reassignCredential(actor, args[0], { issuer: args[1], sub: args[2], username: args[3], type: "user" })); } else if (command === "rotate-master" && args[0]) { if (!existsSync(args[0])) { throw new Error(`New key file not found: ${args[0]}`); } console.log(vault.rotateMasterKey(actor, loadKeyFile(args[0]))); console.error("Rotation succeeded. Replace the mounted vault_master_key before restarting the service."); } else if (command === "backup" && args[0]) { if (existsSync(args[0])) { throw new Error(`Refusing to overwrite existing backup: ${args[0]}`); } console.log(vault.backup(args[0])); } else { usage(); process.exitCode = 1; } } finally { vault.close(); }