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