[bitwarden] ability to fetch all fields from an item
Sometimes a projects has a lot of secrets (more than 10). And its cumbersome to write $(kama secrets fetch ...) with a lot of field names. I want to be able to just fetch all the fields from a given item and then just use these with $(kamal extract NAME)
This commit is contained in:
@@ -25,18 +25,15 @@ class Kamal::Secrets::Adapters::Bitwarden < Kamal::Secrets::Adapters::Base
|
|||||||
{}.tap do |results|
|
{}.tap do |results|
|
||||||
items_fields(secrets).each do |item, fields|
|
items_fields(secrets).each do |item, fields|
|
||||||
item_json = run_command("get item #{item.shellescape}", session: session, raw: true)
|
item_json = run_command("get item #{item.shellescape}", session: session, raw: true)
|
||||||
raise RuntimeError, "Could not read #{secret} from Bitwarden" unless $?.success?
|
raise RuntimeError, "Could not read #{item} from Bitwarden" unless $?.success?
|
||||||
item_json = JSON.parse(item_json)
|
item_json = JSON.parse(item_json)
|
||||||
|
|
||||||
if fields.any?
|
if fields.any?
|
||||||
fields.each do |field|
|
results.merge! fetch_secrets_from_fields(fields, item, item_json)
|
||||||
item_field = item_json["fields"].find { |f| f["name"] == field }
|
|
||||||
raise RuntimeError, "Could not find field #{field} in item #{item} in Bitwarden" unless item_field
|
|
||||||
value = item_field["value"]
|
|
||||||
results["#{item}/#{field}"] = value
|
|
||||||
end
|
|
||||||
elsif item_json.dig("login", "password")
|
elsif item_json.dig("login", "password")
|
||||||
results[item] = item_json.dig("login", "password")
|
results[item] = item_json.dig("login", "password")
|
||||||
|
elsif item_json["fields"]&.any?
|
||||||
|
fields = item_json["fields"].pluck("name")
|
||||||
|
results.merge! fetch_secrets_from_fields(fields, item, item_json)
|
||||||
else
|
else
|
||||||
raise RuntimeError, "Item #{item} is not a login type item and no fields were specified"
|
raise RuntimeError, "Item #{item} is not a login type item and no fields were specified"
|
||||||
end
|
end
|
||||||
@@ -44,6 +41,15 @@ class Kamal::Secrets::Adapters::Bitwarden < Kamal::Secrets::Adapters::Base
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def fetch_secrets_from_fields(fields, item, item_json)
|
||||||
|
fields.to_h do |field|
|
||||||
|
item_field = item_json["fields"].find { |f| f["name"] == field }
|
||||||
|
raise RuntimeError, "Could not find field #{field} in item #{item} in Bitwarden" unless item_field
|
||||||
|
value = item_field["value"]
|
||||||
|
[ "#{item}/#{field}", value ]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def items_fields(secrets)
|
def items_fields(secrets)
|
||||||
{}.tap do |items|
|
{}.tap do |items|
|
||||||
secrets.each do |secret|
|
secrets.each do |secret|
|
||||||
|
|||||||
@@ -44,6 +44,23 @@ class BitwardenAdapterTest < SecretAdapterTestCase
|
|||||||
assert_equal expected_json, json
|
assert_equal expected_json, json
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "fetch all with from" do
|
||||||
|
stub_ticks.with("bw --version 2> /dev/null")
|
||||||
|
|
||||||
|
stub_unlocked
|
||||||
|
stub_ticks.with("bw sync").returns("")
|
||||||
|
stub_noteitem_with_fields
|
||||||
|
|
||||||
|
json = JSON.parse(shellunescape(run_command("fetch", "mynotefields")))
|
||||||
|
|
||||||
|
expected_json = {
|
||||||
|
"mynotefields/field1"=>"secret1", "mynotefields/field2"=>"blam", "mynotefields/field3"=>"fewgrwjgk",
|
||||||
|
"mynotefields/field4"=>"auto"
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_equal expected_json, json
|
||||||
|
end
|
||||||
|
|
||||||
test "fetch with multiple items" do
|
test "fetch with multiple items" do
|
||||||
stub_ticks.with("bw --version 2> /dev/null")
|
stub_ticks.with("bw --version 2> /dev/null")
|
||||||
|
|
||||||
@@ -239,6 +256,36 @@ class BitwardenAdapterTest < SecretAdapterTestCase
|
|||||||
JSON
|
JSON
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def stub_noteitem_with_fields(session: nil)
|
||||||
|
stub_ticks
|
||||||
|
.with("#{"BW_SESSION=#{session} " if session}bw get item mynotefields")
|
||||||
|
.returns(<<~JSON)
|
||||||
|
{
|
||||||
|
"passwordHistory":null,
|
||||||
|
"revisionDate":"2024-09-28T09:07:27.461Z",
|
||||||
|
"creationDate":"2024-09-28T09:07:00.740Z",
|
||||||
|
"deletedDate":null,
|
||||||
|
"object":"item",
|
||||||
|
"id":"aaaaaaaa-cccc-eeee-0000-222222222222",
|
||||||
|
"organizationId":null,
|
||||||
|
"folderId":null,
|
||||||
|
"type":2,
|
||||||
|
"reprompt":0,
|
||||||
|
"name":"noteitem",
|
||||||
|
"notes":"NOTES",
|
||||||
|
"favorite":false,
|
||||||
|
"fields":[
|
||||||
|
{"name":"field1","value":"secret1","type":1,"linkedId":null},
|
||||||
|
{"name":"field2","value":"blam","type":1,"linkedId":null},
|
||||||
|
{"name":"field3","value":"fewgrwjgk","type":1,"linkedId":null},
|
||||||
|
{"name":"field4","value":"auto","type":1,"linkedId":null}
|
||||||
|
],
|
||||||
|
"secureNote":{"type":0},
|
||||||
|
"collectionIds":[]
|
||||||
|
}
|
||||||
|
JSON
|
||||||
|
end
|
||||||
|
|
||||||
def stub_myitem
|
def stub_myitem
|
||||||
stub_ticks
|
stub_ticks
|
||||||
.with("bw get item myitem")
|
.with("bw get item myitem")
|
||||||
@@ -260,7 +307,8 @@ class BitwardenAdapterTest < SecretAdapterTestCase
|
|||||||
"fields":[
|
"fields":[
|
||||||
{"name":"field1","value":"secret1","type":1,"linkedId":null},
|
{"name":"field1","value":"secret1","type":1,"linkedId":null},
|
||||||
{"name":"field2","value":"blam","type":1,"linkedId":null},
|
{"name":"field2","value":"blam","type":1,"linkedId":null},
|
||||||
{"name":"field3","value":"fewgrwjgk","type":1,"linkedId":null}
|
{"name":"field3","value":"fewgrwjgk","type":1,"linkedId":null},
|
||||||
|
{"name":"field4","value":"auto","type":1,"linkedId":null}
|
||||||
],
|
],
|
||||||
"login":{"fido2Credentials":[],"uris":[],"username":null,"password":null,"totp":null,"passwordRevisionDate":null},"collectionIds":[]
|
"login":{"fido2Credentials":[],"uris":[],"username":null,"password":null,"totp":null,"passwordRevisionDate":null},"collectionIds":[]
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user