From 9b63ad5cb8eb648c2a2d4669e889ff5683711dea Mon Sep 17 00:00:00 2001 From: acidtib Date: Thu, 20 Feb 2025 22:38:07 -0700 Subject: [PATCH] feat: add Passbolt adapter --- lib/kamal/secrets/adapters/passbolt.rb | 60 ++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 lib/kamal/secrets/adapters/passbolt.rb diff --git a/lib/kamal/secrets/adapters/passbolt.rb b/lib/kamal/secrets/adapters/passbolt.rb new file mode 100644 index 00000000..b0eb1b10 --- /dev/null +++ b/lib/kamal/secrets/adapters/passbolt.rb @@ -0,0 +1,60 @@ +class Kamal::Secrets::Adapters::Passbolt < Kamal::Secrets::Adapters::Base + def requires_account? + false + end + + private + + def login(*) + `passbolt verify` + raise RuntimeError, "Failed to login to Passbolt" unless $?.success? + end + + def fetch_secrets(secrets, from:, **) + secrets = prefixed_secrets(secrets, from: from) + flags = secrets_get_flags(secrets) + secret_names = secrets.collect { |s| s.split("/").last } + + filter_condition = secret_names.any? ? "--filter '#{secret_names.map { |name| "Name == #{name.shellescape.inspect}" }.join(" || ")}'" : "" + items = `passbolt list resources #{filter_condition} #{flags} --json` + raise RuntimeError, "Could not read #{secrets} from Passbolt" unless $?.success? + + items = JSON.parse(items) + found_names = items.map { |item| item["name"] } + missing_secrets = secret_names - found_names + raise RuntimeError, "Could not find the following secrets in Passbolt: #{missing_secrets.join(", ")}" if missing_secrets.any? + + items.to_h { |item| [item["name"], item["password"]] } + end + + def secrets_get_flags(secrets) + folders = secrets + .select { |s| s.include?("/") } + .map { |s| s.split("/").first } + .uniq + + if folders.any? + folder_ids = folders.map do |folder| + fetch_folder = `passbolt list folders --filter 'Name == \"#{folder.shellescape}\"' --json` + raise RuntimeError, "Could not read folder #{folder} from Passbolt" unless $?.success? + + folder_items = JSON.parse(fetch_folder) + folder_item = folder_items.find { |item| item["name"] == folder } + folder_item["id"] + end + + "--folder #{folder_ids.join(" --folder ")}" + else + "" + end + end + + def check_dependencies! + raise RuntimeError, "Passbolt CLI is not installed" unless cli_installed? + end + + def cli_installed? + `passbolt --version 2> /dev/null` + $?.success? + end +end \ No newline at end of file