Skip to content

Commit cc41d9d

Browse files
gdrososrussoz
andauthored
gem: fix soundness issue when uninstalling default gems on Ubuntu (#10689)
* Attempt to fix gem soundness issue * Return command execution * Fix value error * Attempt to fix failling tests * Fix minor issues * Update changelog * Update tests/integration/targets/gem/tasks/main.yml Co-authored-by: Alexei Znamensky <[email protected]> * Update changelogs/fragments/10689-gem-prevent-soundness-issue.yml Co-authored-by: Alexei Znamensky <[email protected]> * Remove state and name from gem error message * Improve gem uninstall check * Make unit tests pass * Fix linting issues * gem: Remove length chenck and adapt unit tests * Adapt gem unit tests * gem: improve error msg * Fix sanity error * Fix linting issue --------- Co-authored-by: Alexei Znamensky <[email protected]>
1 parent 750adb4 commit cc41d9d

File tree

4 files changed

+38
-8
lines changed

4 files changed

+38
-8
lines changed
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
bugfixes:
2+
- "gem - fix soundness issue when uninstalling default gems on Ubuntu (https://github.com/ansible-collections/community.general/issues/10451, https://github.com/ansible-collections/community.general/pull/10689)."

plugins/modules/gem.py

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,7 @@ def uninstall(module):
243243
if module.params['force']:
244244
cmd.append('--force')
245245
cmd.append(module.params['name'])
246-
module.run_command(cmd, environ_update=environ, check_rc=True)
246+
return module.run_command(cmd, environ_update=environ, check_rc=True)
247247

248248

249249
def install(module):
@@ -334,9 +334,21 @@ def main():
334334
changed = True
335335
elif module.params['state'] == 'absent':
336336
if exists(module):
337-
uninstall(module)
338-
changed = True
339-
337+
command_output = uninstall(module)
338+
if command_output is not None and exists(module):
339+
rc, out, err = command_output
340+
module.fail_json(
341+
msg=(
342+
"Failed to uninstall gem '%s': it is still present after 'gem uninstall'. "
343+
"This usually happens with default or system gems provided by the OS, "
344+
"which cannot be removed with the gem command."
345+
) % module.params['name'],
346+
rc=rc,
347+
stdout=out,
348+
stderr=err
349+
)
350+
else:
351+
changed = True
340352
result = {}
341353
result['name'] = module.params['name']
342354
result['state'] = module.params['state']

tests/integration/targets/gem/tasks/main.yml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,3 +212,18 @@
212212
that:
213213
- install_gem_result is changed
214214
- not gem_bindir_stat.stat.exists
215+
216+
- name: Attempt to uninstall default gem 'json'
217+
community.general.gem:
218+
name: json
219+
state: absent
220+
when: ansible_distribution == "Ubuntu"
221+
register: gem_result
222+
ignore_errors: true
223+
224+
- name: Assert gem uninstall failed as expected
225+
when: ansible_distribution == "Ubuntu"
226+
assert:
227+
that:
228+
- gem_result is failed
229+
- gem_result.msg.startswith("Failed to uninstall gem 'json'")

tests/unit/plugins/modules/test_gem.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,9 @@ def new(module):
5252

5353
def patch_run_command(self):
5454
target = 'ansible.module_utils.basic.AnsibleModule.run_command'
55-
return self.mocker.patch(target)
55+
mock = self.mocker.patch(target)
56+
mock.return_value = (0, '', '')
57+
return mock
5658

5759
def test_fails_when_user_install_and_install_dir_are_combined(self):
5860
with set_module_args({
@@ -107,12 +109,11 @@ def test_passes_install_dir_and_gem_home_when_uninstall_gem(self):
107109

108110
run_command = self.patch_run_command()
109111

110-
with pytest.raises(AnsibleExitJson) as exc:
112+
with pytest.raises(AnsibleFailJson) as exc:
111113
gem.main()
112114

113115
result = exc.value.args[0]
114-
115-
assert result['changed']
116+
assert result['failed']
116117
assert run_command.called
117118

118119
assert '--install-dir /opt/dummy' in get_command(run_command)

0 commit comments

Comments
 (0)