diff --git a/changelogs/fragments/7994-bitwarden-session-arg.yaml b/changelogs/fragments/7994-bitwarden-session-arg.yaml new file mode 100644 index 0000000000..36f9622ac0 --- /dev/null +++ b/changelogs/fragments/7994-bitwarden-session-arg.yaml @@ -0,0 +1,2 @@ +minor_changes: + - "bitwarden lookup plugin - add ``bw_session`` option, to pass session key instead of reading from env (https://github.com/ansible-collections/community.general/pull/7994)." diff --git a/plugins/lookup/bitwarden.py b/plugins/lookup/bitwarden.py index ff7025999f..727a2bac4d 100644 --- a/plugins/lookup/bitwarden.py +++ b/plugins/lookup/bitwarden.py @@ -39,6 +39,10 @@ DOCUMENTATION = """ description: Collection ID to filter results by collection. Leave unset to skip filtering. type: str version_added: 6.3.0 + bw_session: + description: Pass session key instead of reading from env. + type: str + version_added: 8.4.0 """ EXAMPLES = """ @@ -66,6 +70,11 @@ EXAMPLES = """ ansible.builtin.debug: msg: >- {{ lookup('community.general.bitwarden', 'a_test', field='api_key') }} + +- name: "Get 'password' from all Bitwarden records named 'a_test', using given session key" + ansible.builtin.debug: + msg: >- + {{ lookup('community.general.bitwarden', 'a_test', field='password', bw_session='bXZ9B5TXi6...') }} """ RETURN = """ @@ -94,11 +103,20 @@ class Bitwarden(object): def __init__(self, path='bw'): self._cli_path = path + self._session = None @property def cli_path(self): return self._cli_path + @property + def session(self): + return self._session + + @session.setter + def session(self, value): + self._session = value + @property def unlocked(self): out, err = self._run(['status'], stdin="") @@ -106,6 +124,9 @@ class Bitwarden(object): return decoded['status'] == 'unlocked' def _run(self, args, stdin=None, expected_rc=0): + if self.session: + args += ['--session', self.session] + p = Popen([self.cli_path] + args, stdout=PIPE, stderr=PIPE, stdin=PIPE) out, err = p.communicate(to_bytes(stdin)) rc = p.wait() @@ -179,6 +200,8 @@ class LookupModule(LookupBase): field = self.get_option('field') search_field = self.get_option('search') collection_id = self.get_option('collection_id') + _bitwarden.session = self.get_option('bw_session') + if not _bitwarden.unlocked: raise AnsibleError("Bitwarden Vault locked. Run 'bw unlock'.") diff --git a/tests/unit/plugins/lookup/test_bitwarden.py b/tests/unit/plugins/lookup/test_bitwarden.py index d452639658..58f46f2cc7 100644 --- a/tests/unit/plugins/lookup/test_bitwarden.py +++ b/tests/unit/plugins/lookup/test_bitwarden.py @@ -158,3 +158,23 @@ class TestLookupModule(unittest.TestCase): record_name = record['name'] with self.assertRaises(AnsibleError): self.lookup.run([record_name], field='password') + + def test_bitwarden_plugin_without_session_option(self): + mock_bitwarden = MockBitwarden() + with patch("ansible_collections.community.general.plugins.lookup.bitwarden._bitwarden", mock_bitwarden): + record = MOCK_RECORDS[0] + record_name = record['name'] + session = 'session' + + self.lookup.run([record_name], field=None) + self.assertIsNone(mock_bitwarden.session) + + def test_bitwarden_plugin_session_option(self): + mock_bitwarden = MockBitwarden() + with patch("ansible_collections.community.general.plugins.lookup.bitwarden._bitwarden", mock_bitwarden): + record = MOCK_RECORDS[0] + record_name = record['name'] + session = 'session' + + self.lookup.run([record_name], field=None, bw_session=session) + self.assertEqual(mock_bitwarden.session, session)