Merge pull request #1422 from acidtib/feat/secrets-add-passbolt-adapter
feat(secrets): add Passbolt adapter
This commit is contained in:
130
lib/kamal/secrets/adapters/passbolt.rb
Normal file
130
lib/kamal/secrets/adapters/passbolt.rb
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
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)
|
||||||
|
raise ArgumentError, "No secrets given to fetch" if secrets.empty?
|
||||||
|
|
||||||
|
secret_names = secrets.collect { |s| s.split("/").last }
|
||||||
|
folders = secrets_get_folders(secrets)
|
||||||
|
|
||||||
|
# build filter conditions for each secret with its corresponding folder
|
||||||
|
filter_conditions = []
|
||||||
|
secrets.each do |secret|
|
||||||
|
parts = secret.split("/")
|
||||||
|
secret_name = parts.last
|
||||||
|
|
||||||
|
if parts.size > 1
|
||||||
|
# get the folder path without the secret name
|
||||||
|
folder_path = parts[0..-2]
|
||||||
|
|
||||||
|
# find the most nested folder for this path
|
||||||
|
current_folder = nil
|
||||||
|
current_path = []
|
||||||
|
|
||||||
|
folder_path.each do |folder_name|
|
||||||
|
current_path << folder_name
|
||||||
|
matching_folders = folders.select { |f| get_folder_path(f, folders) == current_path.join("/") }
|
||||||
|
current_folder = matching_folders.first if matching_folders.any?
|
||||||
|
end
|
||||||
|
|
||||||
|
if current_folder
|
||||||
|
filter_conditions << "(Name == #{secret_name.shellescape.inspect} && FolderParentID == #{current_folder["id"].shellescape.inspect})"
|
||||||
|
end
|
||||||
|
else
|
||||||
|
# for root level secrets (no folders)
|
||||||
|
filter_conditions << "Name == #{secret_name.shellescape.inspect}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
filter_condition = filter_conditions.any? ? "--filter '#{filter_conditions.join(" || ")}'" : ""
|
||||||
|
items = `passbolt list resources #{filter_condition} #{folders.map { |item| "--folder #{item["id"]}" }.join(" ")} --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_folders(secrets)
|
||||||
|
# extract all folder paths (both parent and nested)
|
||||||
|
folder_paths = secrets
|
||||||
|
.select { |s| s.include?("/") }
|
||||||
|
.map { |s| s.split("/")[0..-2] } # get all parts except the secret name
|
||||||
|
.uniq
|
||||||
|
|
||||||
|
return [] if folder_paths.empty?
|
||||||
|
|
||||||
|
all_folders = []
|
||||||
|
|
||||||
|
# first get all top-level folders
|
||||||
|
parent_folders = folder_paths.map(&:first).uniq
|
||||||
|
filter_condition = "--filter '#{parent_folders.map { |name| "Name == #{name.shellescape.inspect}" }.join(" || ")}'"
|
||||||
|
fetch_folders = `passbolt list folders #{filter_condition} --json`
|
||||||
|
raise RuntimeError, "Could not read folders from Passbolt" unless $?.success?
|
||||||
|
|
||||||
|
parent_folder_items = JSON.parse(fetch_folders)
|
||||||
|
all_folders.concat(parent_folder_items)
|
||||||
|
|
||||||
|
# get nested folders for each parent
|
||||||
|
folder_paths.each do |path|
|
||||||
|
next if path.size <= 1 # skip non-nested folders
|
||||||
|
|
||||||
|
parent = path[0]
|
||||||
|
parent_folder = parent_folder_items.find { |f| f["name"] == parent }
|
||||||
|
next unless parent_folder
|
||||||
|
|
||||||
|
# for each nested level, get the folders using the parent's ID
|
||||||
|
current_parent = parent_folder
|
||||||
|
path[1..-1].each do |folder_name|
|
||||||
|
filter_condition = "--filter 'Name == #{folder_name.shellescape.inspect} && FolderParentID == #{current_parent["id"].shellescape.inspect}'"
|
||||||
|
fetch_nested = `passbolt list folders #{filter_condition} --json`
|
||||||
|
next unless $?.success?
|
||||||
|
|
||||||
|
nested_folders = JSON.parse(fetch_nested)
|
||||||
|
break if nested_folders.empty?
|
||||||
|
|
||||||
|
all_folders.concat(nested_folders)
|
||||||
|
current_parent = nested_folders.first
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# check if we found all required folders
|
||||||
|
found_paths = all_folders.map { |f| get_folder_path(f, all_folders) }
|
||||||
|
missing_paths = folder_paths.map { |path| path.join("/") } - found_paths
|
||||||
|
raise RuntimeError, "Could not find the following folders in Passbolt: #{missing_paths.join(", ")}" if missing_paths.any?
|
||||||
|
|
||||||
|
all_folders
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_folder_path(folder, all_folders, path = [])
|
||||||
|
path.unshift(folder["name"])
|
||||||
|
return path.join("/") if folder["folder_parent_id"].to_s.empty?
|
||||||
|
|
||||||
|
parent = all_folders.find { |f| f["id"] == folder["folder_parent_id"] }
|
||||||
|
return path.join("/") unless parent
|
||||||
|
|
||||||
|
get_folder_path(parent, all_folders, path)
|
||||||
|
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
|
||||||
474
test/secrets/passbolt_adapter.rb
Normal file
474
test/secrets/passbolt_adapter.rb
Normal file
@@ -0,0 +1,474 @@
|
|||||||
|
require "test_helper"
|
||||||
|
|
||||||
|
class PassboltAdapterTest < SecretAdapterTestCase
|
||||||
|
setup do
|
||||||
|
`true` # Ensure $? is 0
|
||||||
|
end
|
||||||
|
|
||||||
|
test "fetch" do
|
||||||
|
stub_ticks_with("passbolt --version 2> /dev/null", succeed: true)
|
||||||
|
stub_ticks.with("passbolt verify 2> /dev/null", succeed: true)
|
||||||
|
|
||||||
|
stub_ticks
|
||||||
|
.with("passbolt list resources --filter 'Name == \"SECRET1\" || Name == \"FSECRET1\" || Name == \"FSECRET2\"' --json")
|
||||||
|
.returns(<<~JSON)
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"id": "4c116996-f6d0-4342-9572-0d676f75b3ac",
|
||||||
|
"folder_parent_id": "",
|
||||||
|
"name": "FSECRET1",
|
||||||
|
"username": "",
|
||||||
|
"uri": "",
|
||||||
|
"password": "fsecret1",
|
||||||
|
"description": "",
|
||||||
|
"created_timestamp": "2025-02-21T06:04:29Z",
|
||||||
|
"modified_timestamp": "2025-02-21T06:04:29Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "62949b26-4957-43fe-9523-294d66861499",
|
||||||
|
"folder_parent_id": "",
|
||||||
|
"name": "FSECRET2",
|
||||||
|
"username": "",
|
||||||
|
"uri": "",
|
||||||
|
"password": "fsecret2",
|
||||||
|
"description": "",
|
||||||
|
"created_timestamp": "2025-02-21T06:04:34Z",
|
||||||
|
"modified_timestamp": "2025-02-21T06:04:34Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "dd32963c-0db5-4303-a6fc-22c5229dabef",
|
||||||
|
"folder_parent_id": "",
|
||||||
|
"name": "SECRET1",
|
||||||
|
"username": "",
|
||||||
|
"uri": "",
|
||||||
|
"password": "secret1",
|
||||||
|
"description": "",
|
||||||
|
"created_timestamp": "2025-02-21T06:04:23Z",
|
||||||
|
"modified_timestamp": "2025-02-21T06:04:23Z"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
JSON
|
||||||
|
|
||||||
|
json = JSON.parse(
|
||||||
|
shellunescape run_command("fetch", "SECRET1", "FSECRET1", "FSECRET2")
|
||||||
|
)
|
||||||
|
|
||||||
|
expected_json = {
|
||||||
|
"SECRET1"=>"secret1",
|
||||||
|
"FSECRET1"=>"fsecret1",
|
||||||
|
"FSECRET2"=>"fsecret2"
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_equal expected_json, json
|
||||||
|
end
|
||||||
|
|
||||||
|
test "fetch with --from" do
|
||||||
|
stub_ticks_with("passbolt --version 2> /dev/null", succeed: true)
|
||||||
|
stub_ticks.with("passbolt verify 2> /dev/null", succeed: true)
|
||||||
|
|
||||||
|
stub_ticks
|
||||||
|
.with("passbolt list folders --filter 'Name == \"my-project\"' --json")
|
||||||
|
.returns(<<~JSON)
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"id": "dcbe0e39-42d8-42db-9637-8256b9f2f8e3",
|
||||||
|
"folder_parent_id": "",
|
||||||
|
"name": "my-project",
|
||||||
|
"created_timestamp": "2025-02-21T19:52:50Z",
|
||||||
|
"modified_timestamp": "2025-02-21T19:52:50Z"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
JSON
|
||||||
|
|
||||||
|
stub_ticks
|
||||||
|
.with("passbolt list resources --filter '(Name == \"SECRET1\" && FolderParentID == \"dcbe0e39-42d8-42db-9637-8256b9f2f8e3\") || (Name == \"FSECRET1\" && FolderParentID == \"dcbe0e39-42d8-42db-9637-8256b9f2f8e3\") || (Name == \"FSECRET2\" && FolderParentID == \"dcbe0e39-42d8-42db-9637-8256b9f2f8e3\")' --folder dcbe0e39-42d8-42db-9637-8256b9f2f8e3 --json")
|
||||||
|
.returns(<<~JSON)
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"id": "4c116996-f6d0-4342-9572-0d676f75b3ac",
|
||||||
|
"folder_parent_id": "dcbe0e39-42d8-42db-9637-8256b9f2f8e3",
|
||||||
|
"name": "FSECRET1",
|
||||||
|
"username": "",
|
||||||
|
"uri": "",
|
||||||
|
"password": "fsecret1",
|
||||||
|
"description": "",
|
||||||
|
"created_timestamp": "2025-02-21T06:04:29Z",
|
||||||
|
"modified_timestamp": "2025-02-21T06:04:29Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "62949b26-4957-43fe-9523-294d66861499",
|
||||||
|
"folder_parent_id": "dcbe0e39-42d8-42db-9637-8256b9f2f8e3",
|
||||||
|
"name": "FSECRET2",
|
||||||
|
"username": "",
|
||||||
|
"uri": "",
|
||||||
|
"password": "fsecret2",
|
||||||
|
"description": "",
|
||||||
|
"created_timestamp": "2025-02-21T06:04:34Z",
|
||||||
|
"modified_timestamp": "2025-02-21T06:04:34Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "dd32963c-0db5-4303-a6fc-22c5229dabef",
|
||||||
|
"folder_parent_id": "dcbe0e39-42d8-42db-9637-8256b9f2f8e3",
|
||||||
|
"name": "SECRET1",
|
||||||
|
"username": "",
|
||||||
|
"uri": "",
|
||||||
|
"password": "secret1",
|
||||||
|
"description": "",
|
||||||
|
"created_timestamp": "2025-02-21T06:04:23Z",
|
||||||
|
"modified_timestamp": "2025-02-21T06:04:23Z"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
JSON
|
||||||
|
|
||||||
|
json = JSON.parse(
|
||||||
|
shellunescape run_command("fetch", "--from", "my-project", "SECRET1", "FSECRET1", "FSECRET2")
|
||||||
|
)
|
||||||
|
|
||||||
|
expected_json = {
|
||||||
|
"SECRET1"=>"secret1",
|
||||||
|
"FSECRET1"=>"fsecret1",
|
||||||
|
"FSECRET2"=>"fsecret2"
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_equal expected_json, json
|
||||||
|
end
|
||||||
|
|
||||||
|
test "fetch with folder in secret" do
|
||||||
|
stub_ticks_with("passbolt --version 2> /dev/null", succeed: true)
|
||||||
|
stub_ticks.with("passbolt verify 2> /dev/null", succeed: true)
|
||||||
|
|
||||||
|
stub_ticks
|
||||||
|
.with("passbolt list folders --filter 'Name == \"my-project\"' --json")
|
||||||
|
.returns(<<~JSON)
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"id": "dcbe0e39-42d8-42db-9637-8256b9f2f8e3",
|
||||||
|
"folder_parent_id": "",
|
||||||
|
"name": "my-project",
|
||||||
|
"created_timestamp": "2025-02-21T19:52:50Z",
|
||||||
|
"modified_timestamp": "2025-02-21T19:52:50Z"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
JSON
|
||||||
|
|
||||||
|
stub_ticks
|
||||||
|
.with("passbolt list resources --filter '(Name == \"SECRET1\" && FolderParentID == \"dcbe0e39-42d8-42db-9637-8256b9f2f8e3\") || (Name == \"FSECRET1\" && FolderParentID == \"dcbe0e39-42d8-42db-9637-8256b9f2f8e3\") || (Name == \"FSECRET2\" && FolderParentID == \"dcbe0e39-42d8-42db-9637-8256b9f2f8e3\")' --folder dcbe0e39-42d8-42db-9637-8256b9f2f8e3 --json")
|
||||||
|
.returns(<<~JSON)
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"id": "4c116996-f6d0-4342-9572-0d676f75b3ac",
|
||||||
|
"folder_parent_id": "dcbe0e39-42d8-42db-9637-8256b9f2f8e3",
|
||||||
|
"name": "FSECRET1",
|
||||||
|
"username": "",
|
||||||
|
"uri": "",
|
||||||
|
"password": "fsecret1",
|
||||||
|
"description": "",
|
||||||
|
"created_timestamp": "2025-02-21T06:04:29Z",
|
||||||
|
"modified_timestamp": "2025-02-21T06:04:29Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "62949b26-4957-43fe-9523-294d66861499",
|
||||||
|
"folder_parent_id": "dcbe0e39-42d8-42db-9637-8256b9f2f8e3",
|
||||||
|
"name": "FSECRET2",
|
||||||
|
"username": "",
|
||||||
|
"uri": "",
|
||||||
|
"password": "fsecret2",
|
||||||
|
"description": "",
|
||||||
|
"created_timestamp": "2025-02-21T06:04:34Z",
|
||||||
|
"modified_timestamp": "2025-02-21T06:04:34Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "dd32963c-0db5-4303-a6fc-22c5229dabef",
|
||||||
|
"folder_parent_id": "dcbe0e39-42d8-42db-9637-8256b9f2f8e3",
|
||||||
|
"name": "SECRET1",
|
||||||
|
"username": "",
|
||||||
|
"uri": "",
|
||||||
|
"password": "secret1",
|
||||||
|
"description": "",
|
||||||
|
"created_timestamp": "2025-02-21T06:04:23Z",
|
||||||
|
"modified_timestamp": "2025-02-21T06:04:23Z"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
JSON
|
||||||
|
|
||||||
|
json = JSON.parse(
|
||||||
|
shellunescape run_command("fetch", "my-project/SECRET1", "my-project/FSECRET1", "my-project/FSECRET2")
|
||||||
|
)
|
||||||
|
|
||||||
|
expected_json = {
|
||||||
|
"SECRET1"=>"secret1",
|
||||||
|
"FSECRET1"=>"fsecret1",
|
||||||
|
"FSECRET2"=>"fsecret2"
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_equal expected_json, json
|
||||||
|
end
|
||||||
|
|
||||||
|
test "fetch from multiple folders" do
|
||||||
|
stub_ticks_with("passbolt --version 2> /dev/null", succeed: true)
|
||||||
|
stub_ticks.with("passbolt verify 2> /dev/null", succeed: true)
|
||||||
|
|
||||||
|
stub_ticks
|
||||||
|
.with("passbolt list folders --filter 'Name == \"my-project\" || Name == \"other-project\"' --json")
|
||||||
|
.returns(<<~JSON)
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"id": "dcbe0e39-42d8-42db-9637-8256b9f2f8e3",
|
||||||
|
"folder_parent_id": "",
|
||||||
|
"name": "my-project",
|
||||||
|
"created_timestamp": "2025-02-21T19:52:50Z",
|
||||||
|
"modified_timestamp": "2025-02-21T19:52:50Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "14e11dd8-b279-4689-8bd9-fa33ebb527da",
|
||||||
|
"folder_parent_id": "",
|
||||||
|
"name": "other-project",
|
||||||
|
"created_timestamp": "2025-02-21T20:00:29Z",
|
||||||
|
"modified_timestamp": "2025-02-21T20:00:29Z"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
JSON
|
||||||
|
|
||||||
|
stub_ticks
|
||||||
|
.with("passbolt list resources --filter '(Name == \"SECRET1\" && FolderParentID == \"dcbe0e39-42d8-42db-9637-8256b9f2f8e3\") || (Name == \"FSECRET1\" && FolderParentID == \"dcbe0e39-42d8-42db-9637-8256b9f2f8e3\") || (Name == \"FSECRET2\" && FolderParentID == \"14e11dd8-b279-4689-8bd9-fa33ebb527da\")' --folder dcbe0e39-42d8-42db-9637-8256b9f2f8e3 --folder 14e11dd8-b279-4689-8bd9-fa33ebb527da --json")
|
||||||
|
.returns(<<~JSON)
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"id": "4c116996-f6d0-4342-9572-0d676f75b3ac",
|
||||||
|
"folder_parent_id": "dcbe0e39-42d8-42db-9637-8256b9f2f8e3",
|
||||||
|
"name": "FSECRET1",
|
||||||
|
"username": "",
|
||||||
|
"uri": "",
|
||||||
|
"password": "fsecret1",
|
||||||
|
"description": "",
|
||||||
|
"created_timestamp": "2025-02-21T06:04:29Z",
|
||||||
|
"modified_timestamp": "2025-02-21T06:04:29Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "62949b26-4957-43fe-9523-294d66861499",
|
||||||
|
"folder_parent_id": "14e11dd8-b279-4689-8bd9-fa33ebb527da",
|
||||||
|
"name": "FSECRET2",
|
||||||
|
"username": "",
|
||||||
|
"uri": "",
|
||||||
|
"password": "fsecret2",
|
||||||
|
"description": "",
|
||||||
|
"created_timestamp": "2025-02-21T06:04:34Z",
|
||||||
|
"modified_timestamp": "2025-02-21T06:04:34Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "dd32963c-0db5-4303-a6fc-22c5229dabef",
|
||||||
|
"folder_parent_id": "dcbe0e39-42d8-42db-9637-8256b9f2f8e3",
|
||||||
|
"name": "SECRET1",
|
||||||
|
"username": "",
|
||||||
|
"uri": "",
|
||||||
|
"password": "secret1",
|
||||||
|
"description": "",
|
||||||
|
"created_timestamp": "2025-02-21T06:04:23Z",
|
||||||
|
"modified_timestamp": "2025-02-21T06:04:23Z"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
JSON
|
||||||
|
|
||||||
|
json = JSON.parse(
|
||||||
|
shellunescape run_command("fetch", "my-project/SECRET1", "my-project/FSECRET1", "other-project/FSECRET2")
|
||||||
|
)
|
||||||
|
|
||||||
|
expected_json = {
|
||||||
|
"SECRET1"=>"secret1",
|
||||||
|
"FSECRET1"=>"fsecret1",
|
||||||
|
"FSECRET2"=>"fsecret2"
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_equal expected_json, json
|
||||||
|
end
|
||||||
|
|
||||||
|
test "fetch from nested folder" do
|
||||||
|
stub_ticks_with("passbolt --version 2> /dev/null", succeed: true)
|
||||||
|
stub_ticks.with("passbolt verify 2> /dev/null", succeed: true)
|
||||||
|
|
||||||
|
stub_ticks
|
||||||
|
.with("passbolt list folders --filter 'Name == \"my-project\"' --json")
|
||||||
|
.returns(<<~JSON)
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"id": "dcbe0e39-42d8-42db-9637-8256b9f2f8e3",
|
||||||
|
"folder_parent_id": "",
|
||||||
|
"name": "my-project",
|
||||||
|
"created_timestamp": "2025-02-21T19:52:50Z",
|
||||||
|
"modified_timestamp": "2025-02-21T19:52:50Z"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
JSON
|
||||||
|
|
||||||
|
stub_ticks
|
||||||
|
.with("passbolt list folders --filter 'Name == \"subfolder\" && FolderParentID == \"dcbe0e39-42d8-42db-9637-8256b9f2f8e3\"' --json")
|
||||||
|
.returns(<<~JSON)
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"id": "6a3f21fc-aa40-4ba9-852c-7477fdd0310d",
|
||||||
|
"folder_parent_id": "dcbe0e39-42d8-42db-9637-8256b9f2f8e3",
|
||||||
|
"name": "subfolder",
|
||||||
|
"created_timestamp": "2025-02-21T19:52:50Z",
|
||||||
|
"modified_timestamp": "2025-02-21T19:52:50Z"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
JSON
|
||||||
|
|
||||||
|
stub_ticks
|
||||||
|
.with("passbolt list resources --filter '(Name == \"SECRET1\" && FolderParentID == \"6a3f21fc-aa40-4ba9-852c-7477fdd0310d\") || (Name == \"FSECRET1\" && FolderParentID == \"6a3f21fc-aa40-4ba9-852c-7477fdd0310d\") || (Name == \"FSECRET2\" && FolderParentID == \"6a3f21fc-aa40-4ba9-852c-7477fdd0310d\")' --folder dcbe0e39-42d8-42db-9637-8256b9f2f8e3 --folder 6a3f21fc-aa40-4ba9-852c-7477fdd0310d --json")
|
||||||
|
.returns(<<~JSON)
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"id": "4c116996-f6d0-4342-9572-0d676f75b3ac",
|
||||||
|
"folder_parent_id": "6a3f21fc-aa40-4ba9-852c-7477fdd0310d",
|
||||||
|
"name": "FSECRET1",
|
||||||
|
"username": "",
|
||||||
|
"uri": "",
|
||||||
|
"password": "fsecret1",
|
||||||
|
"description": "",
|
||||||
|
"created_timestamp": "2025-02-21T06:04:29Z",
|
||||||
|
"modified_timestamp": "2025-02-21T06:04:29Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "62949b26-4957-43fe-9523-294d66861499",
|
||||||
|
"folder_parent_id": "6a3f21fc-aa40-4ba9-852c-7477fdd0310d",
|
||||||
|
"name": "FSECRET2",
|
||||||
|
"username": "",
|
||||||
|
"uri": "",
|
||||||
|
"password": "fsecret2",
|
||||||
|
"description": "",
|
||||||
|
"created_timestamp": "2025-02-21T06:04:34Z",
|
||||||
|
"modified_timestamp": "2025-02-21T06:04:34Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "dd32963c-0db5-4303-a6fc-22c5229dabef",
|
||||||
|
"folder_parent_id": "6a3f21fc-aa40-4ba9-852c-7477fdd0310d",
|
||||||
|
"name": "SECRET1",
|
||||||
|
"username": "",
|
||||||
|
"uri": "",
|
||||||
|
"password": "secret1",
|
||||||
|
"description": "",
|
||||||
|
"created_timestamp": "2025-02-21T06:04:23Z",
|
||||||
|
"modified_timestamp": "2025-02-21T06:04:23Z"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
JSON
|
||||||
|
|
||||||
|
json = JSON.parse(
|
||||||
|
shellunescape run_command("fetch", "--from", "my-project/subfolder", "SECRET1", "FSECRET1", "FSECRET2")
|
||||||
|
)
|
||||||
|
|
||||||
|
expected_json = {
|
||||||
|
"SECRET1"=>"secret1",
|
||||||
|
"FSECRET1"=>"fsecret1",
|
||||||
|
"FSECRET2"=>"fsecret2"
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_equal expected_json, json
|
||||||
|
end
|
||||||
|
|
||||||
|
test "fetch from nested folder in secret" do
|
||||||
|
stub_ticks_with("passbolt --version 2> /dev/null", succeed: true)
|
||||||
|
stub_ticks.with("passbolt verify 2> /dev/null", succeed: true)
|
||||||
|
|
||||||
|
stub_ticks
|
||||||
|
.with("passbolt list folders --filter 'Name == \"my-project\"' --json")
|
||||||
|
.returns(<<~JSON)
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"id": "dcbe0e39-42d8-42db-9637-8256b9f2f8e3",
|
||||||
|
"folder_parent_id": "",
|
||||||
|
"name": "my-project",
|
||||||
|
"created_timestamp": "2025-02-21T19:52:50Z",
|
||||||
|
"modified_timestamp": "2025-02-21T19:52:50Z"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
JSON
|
||||||
|
|
||||||
|
stub_ticks
|
||||||
|
.with("passbolt list folders --filter 'Name == \"subfolder\" && FolderParentID == \"dcbe0e39-42d8-42db-9637-8256b9f2f8e3\"' --json")
|
||||||
|
.returns(<<~JSON)
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"id": "6a3f21fc-aa40-4ba9-852c-7477fdd0310d",
|
||||||
|
"folder_parent_id": "dcbe0e39-42d8-42db-9637-8256b9f2f8e3",
|
||||||
|
"name": "subfolder",
|
||||||
|
"created_timestamp": "2025-02-21T19:52:50Z",
|
||||||
|
"modified_timestamp": "2025-02-21T19:52:50Z"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
JSON
|
||||||
|
|
||||||
|
stub_ticks
|
||||||
|
.with("passbolt list resources --filter '(Name == \"SECRET1\" && FolderParentID == \"6a3f21fc-aa40-4ba9-852c-7477fdd0310d\") || (Name == \"FSECRET1\" && FolderParentID == \"6a3f21fc-aa40-4ba9-852c-7477fdd0310d\") || (Name == \"FSECRET2\" && FolderParentID == \"6a3f21fc-aa40-4ba9-852c-7477fdd0310d\")' --folder dcbe0e39-42d8-42db-9637-8256b9f2f8e3 --folder 6a3f21fc-aa40-4ba9-852c-7477fdd0310d --json")
|
||||||
|
.returns(<<~JSON)
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"id": "4c116996-f6d0-4342-9572-0d676f75b3ac",
|
||||||
|
"folder_parent_id": "6a3f21fc-aa40-4ba9-852c-7477fdd0310d",
|
||||||
|
"name": "FSECRET1",
|
||||||
|
"username": "",
|
||||||
|
"uri": "",
|
||||||
|
"password": "fsecret1",
|
||||||
|
"description": "",
|
||||||
|
"created_timestamp": "2025-02-21T06:04:29Z",
|
||||||
|
"modified_timestamp": "2025-02-21T06:04:29Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "62949b26-4957-43fe-9523-294d66861499",
|
||||||
|
"folder_parent_id": "6a3f21fc-aa40-4ba9-852c-7477fdd0310d",
|
||||||
|
"name": "FSECRET2",
|
||||||
|
"username": "",
|
||||||
|
"uri": "",
|
||||||
|
"password": "fsecret2",
|
||||||
|
"description": "",
|
||||||
|
"created_timestamp": "2025-02-21T06:04:34Z",
|
||||||
|
"modified_timestamp": "2025-02-21T06:04:34Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "dd32963c-0db5-4303-a6fc-22c5229dabef",
|
||||||
|
"folder_parent_id": "6a3f21fc-aa40-4ba9-852c-7477fdd0310d",
|
||||||
|
"name": "SECRET1",
|
||||||
|
"username": "",
|
||||||
|
"uri": "",
|
||||||
|
"password": "secret1",
|
||||||
|
"description": "",
|
||||||
|
"created_timestamp": "2025-02-21T06:04:23Z",
|
||||||
|
"modified_timestamp": "2025-02-21T06:04:23Z"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
JSON
|
||||||
|
|
||||||
|
json = JSON.parse(
|
||||||
|
shellunescape run_command("fetch", "my-project/subfolder/SECRET1", "my-project/subfolder/FSECRET1", "my-project/subfolder/FSECRET2")
|
||||||
|
)
|
||||||
|
|
||||||
|
expected_json = {
|
||||||
|
"SECRET1"=>"secret1",
|
||||||
|
"FSECRET1"=>"fsecret1",
|
||||||
|
"FSECRET2"=>"fsecret2"
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_equal expected_json, json
|
||||||
|
end
|
||||||
|
|
||||||
|
test "fetch without CLI installed" do
|
||||||
|
stub_ticks_with("passbolt --version 2> /dev/null", succeed: false)
|
||||||
|
|
||||||
|
error = assert_raises RuntimeError do
|
||||||
|
JSON.parse(shellunescape(run_command("fetch", "HOST", "PORT")))
|
||||||
|
end
|
||||||
|
|
||||||
|
assert_equal "Passbolt CLI is not installed", error.message
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
def run_command(*command)
|
||||||
|
stdouted do
|
||||||
|
Kamal::Cli::Secrets.start \
|
||||||
|
[ *command,
|
||||||
|
"-c", "test/fixtures/deploy_with_accessories.yml",
|
||||||
|
"--adapter", "passbolt" ]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
Reference in New Issue
Block a user