Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

unsafe strings in molecule.yml cause stackdump. #4348

Open
7 tasks done
r-pufky opened this issue Dec 28, 2024 · 2 comments
Open
7 tasks done

unsafe strings in molecule.yml cause stackdump. #4348

r-pufky opened this issue Dec 28, 2024 · 2 comments
Labels

Comments

@r-pufky
Copy link

r-pufky commented Dec 28, 2024

Prerequisites

  • This was not already reported in the past (duplicate check)
  • It does reproduce it with code from main branch (latest unreleased version)
  • I include a minimal example for reproducing the bug
  • The bug is not trivial, as for those a direct pull-request is preferred
  • Running pip check does not report any conflicts
  • I was able to reproduce the issue on a different machine
  • The issue is not specific to any driver other than 'default' one

Environment

$ pip check
No broken requirements found.

$ molecule --version
molecule 24.12.0 using python 3.12 
    ansible:2.18.1
    podman:23.6.0 from molecule_plugins requiring collections: containers.podman>=1.7.0 ansible.posix>=1.3.0
    vagrant:23.6.0 from molecule_plugins
    azure:23.6.0 from molecule_plugins
    containers:23.6.0 from molecule_plugins requiring collections: ansible.posix>=1.3.0 community.docker>=1.9.1 containers.podman>=1.8.1
    docker:23.6.0 from molecule_plugins requiring collections: community.docker>=3.4.11 ansible.posix>=1.4.0
    openstack:23.6.0 from molecule_plugins requiring collections: openstack.cloud>=2.1.0
    default:24.12.0 from molecule
    ec2:23.6.0 from molecule_plugins
    gce:23.6.0 from molecule_plugins requiring collections: google.cloud>=1.0.2 community.crypto>=1.8.0

$ ansible --version
ansible [core 2.18.1]
  config file = None
  configured module search path = ['/home/{REDACTED}/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /run/venv/ansible_collection_srv/lib/python3.12/site-packages/ansible
  ansible collection location = /home/{REDACTED}/.ansible/collections:/usr/share/ansible/collections
  executable location = /run/venv/ansible_collection_srv/bin/ansible
  python version = 3.12.7 (main, Oct  1 2024, 11:15:50) [GCC 14.2.1 20240910] (/run/venv/ansible_collection_srv/bin/python3)
  jinja version = 3.1.5
  libyaml = True

$ cat /etc/lsb-release
DISTRIB_ID="ManjaroLinux"
DISTRIB_RELEASE="24.2.1"
DISTRIB_CODENAME="Yonada"
DISTRIB_DESCRIPTION="Manjaro Linux"

What happened

Specifying unsafe for an unsafe yaml string in molecule.yml causes stackdump. This is unexpected as unsafe is used without error with general ansible use.

Failure Setup (unsafe specified, causing stackdump)

molecule.yml

...
provisioner:
  inventory:
    group_vars:
      all:
        ssh_client_security_key_provider: !unsafe '$FIDO-TEST'
...

Results in the following trace when run:

$ molecule create --scenario-name=ssh_config_all_values
Traceback (most recent call last):
  File "/run/venv/ansible_collection_srv/bin/molecule", line 8, in <module>
    sys.exit(main())
             ^^^^^^
  File "/run/venv/ansible_collection_srv/lib/python3.12/site-packages/click/core.py", line 1161, in __call__
    return self.main(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/run/venv/ansible_collection_srv/lib/python3.12/site-packages/click/core.py", line 1082, in main
    rv = self.invoke(ctx)
         ^^^^^^^^^^^^^^^^
  File "/run/venv/ansible_collection_srv/lib/python3.12/site-packages/click/core.py", line 1697, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/run/venv/ansible_collection_srv/lib/python3.12/site-packages/click/core.py", line 1443, in invoke
    return ctx.invoke(self.callback, **ctx.params)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/run/venv/ansible_collection_srv/lib/python3.12/site-packages/click/core.py", line 788, in invoke
    return __callback(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/run/venv/ansible_collection_srv/lib/python3.12/site-packages/click/decorators.py", line 33, in new_func
    return f(get_current_context(), *args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/run/venv/ansible_collection_srv/lib/python3.12/site-packages/molecule/command/create.py", line 93, in create
    base.execute_cmdline_scenarios(scenario_name, args, command_args)
  File "/run/venv/ansible_collection_srv/lib/python3.12/site-packages/molecule/command/base.py", line 127, in execute_cmdline_scenarios
    get_configs(args, command_args, ansible_args, glob_str),
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/run/venv/ansible_collection_srv/lib/python3.12/site-packages/molecule/command/base.py", line 270, in get_configs
    config.Config(
  File "/run/venv/ansible_collection_srv/lib/python3.12/site-packages/molecule/config.py", line 117, in __init__
    self.config = self._get_config()
                  ^^^^^^^^^^^^^^^^^^
  File "/run/venv/ansible_collection_srv/lib/python3.12/site-packages/molecule/config.py", line 425, in _get_config
    return self._combine(keep_string=MOLECULE_KEEP_STRING)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/run/venv/ansible_collection_srv/lib/python3.12/site-packages/molecule/config.py", line 480, in _combine
    util.safe_load(interpolated_config),
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/run/venv/ansible_collection_srv/lib/python3.12/site-packages/molecule/util.py", line 323, in safe_load
    return yaml.safe_load(string) or {}
           ^^^^^^^^^^^^^^^^^^^^^^
  File "/run/venv/ansible_collection_srv/lib/python3.12/site-packages/yaml/__init__.py", line 125, in safe_load
    return load(stream, SafeLoader)
           ^^^^^^^^^^^^^^^^^^^^^^^^
  File "/run/venv/ansible_collection_srv/lib/python3.12/site-packages/yaml/__init__.py", line 81, in load
    return loader.get_single_data()
           ^^^^^^^^^^^^^^^^^^^^^^^^
  File "/run/venv/ansible_collection_srv/lib/python3.12/site-packages/yaml/constructor.py", line 51, in get_single_data
    return self.construct_document(node)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/run/venv/ansible_collection_srv/lib/python3.12/site-packages/yaml/constructor.py", line 60, in construct_document
    for dummy in generator:
                 ^^^^^^^^^
  File "/run/venv/ansible_collection_srv/lib/python3.12/site-packages/yaml/constructor.py", line 413, in construct_yaml_map
    value = self.construct_mapping(node)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/run/venv/ansible_collection_srv/lib/python3.12/site-packages/yaml/constructor.py", line 218, in construct_mapping
    return super().construct_mapping(node, deep=deep)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/run/venv/ansible_collection_srv/lib/python3.12/site-packages/yaml/constructor.py", line 143, in construct_mapping
    value = self.construct_object(value_node, deep=deep)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/run/venv/ansible_collection_srv/lib/python3.12/site-packages/yaml/constructor.py", line 100, in construct_object
    data = constructor(self, node)
           ^^^^^^^^^^^^^^^^^^^^^^^
  File "/run/venv/ansible_collection_srv/lib/python3.12/site-packages/yaml/constructor.py", line 427, in construct_undefined
    raise ConstructorError(None, None,
yaml.constructor.ConstructorError: could not determine a constructor for the tag '!unsafe'
  in "<unicode string>", line 74, column 43:
     ... h_client_security_key_provider: !unsafe 'TEST'

Test failure (due to unsafe string being used without unsafe specifier)

molecule.yml

...
provisioner:
  inventory:
    group_vars:
      all:
        ssh_client_security_key_provider: '$FIDO-TEST'
...

ssh_config (incorrect)

  SecurityKeyProvider TEST

ssh_config (expected)

  SecurityKeyProvider $FIDO-TEST

Temporary workaround

Migrating test setup to override the variable in converge with interpret unsafe correctly and result in the correct output (assumption is that ansible is interpreting the variable in converge instead of molecule).

molecule.yml

...
provisioner:
  inventory:
    group_vars:
      all:
        ...
...

converge.yml

---
- name: 'SSH config all values | converge'
  hosts: all
  gather_facts: false
  tasks:
    - name: 'SSH config all values | converge | apply SSH role'
      ansible.builtin.include_role:
        name: 'r_pufky.srv.ssh'
      vars:
        ssh_client_security_key_provider: !unsafe '$FIDO-TEST'

ssh_config (correct)

  SecurityKeyProvider $FIDO-TEST

Essentially, this boils down to consistency and expectations around yaml variable interpretation in molecule. If it is different than ansible, it must be explicitly stated in documentation. This is definitely a 'gotcha'.

Reproducing example

I've created a complete example role which demonstrates this error as concisely as possible.

It is linked here [unsafe_poc_molecule.tar.gz](https://drive.google.com/file/d/1wyoNuDVZ4UxpcDMKdGP8t2OZvjH5CVaM/view?usp=drive_link).

You may need to modify the role name for your testing environment.

tests:
* stackdump (`molecule test --scenario-name=stackdump`). This will express the stackdump with the `unsafe` keyword usage in `molecule.yml`.
* unsafe_used_with_error (`molecule test --scenario-name=unsafe_used_with_error`). This will render the unsafe string incorrectly to the templated file. The test will fail the expected result.
* workaround (`molecule test --scenario-name=workaround`). This will use the `unsafe` keyword in the converge step to workaround the incorrect interpretation in `molecule.yml`. The tests will pass correctly.
@ssbarnea
Copy link
Member

ssbarnea commented Jan 8, 2025

@r-pufky Is it a bug only because it is causing a stacktrace, but reality is that we do not support loading these YAML extensions with molecule, even if ansible does. A fix for this should produce a nice error message about not being able to load the molecule.yml file.

Can you make a PR to do this?

@r-pufky
Copy link
Author

r-pufky commented Jan 8, 2025

I can give it a go, sure.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
Status: No status
Development

No branches or pull requests

2 participants