Add role-scoped-variables ansible-lint rule - #729
Conversation
|
I expect this to fail and will then need to apply a commit on top that fixes those. As I have kept seeing these in PRs and having to comment on them, I decided to create a rule instead. Right now there is only one exception |
ca3b687 to
05f99dc
Compare
| """Check if a variable reference is allowed inside this role.""" | ||
| if var.startswith(role_prefix) or var.lstrip("_").startswith(role_prefix): | ||
| return True | ||
| if var.startswith("_"): |
There was a problem hiding this comment.
Why do we allow any _ prefix var? The line before seems to say we only want _role_prefix to be allowed
There was a problem hiding this comment.
Because I was torn between whether we want to allow "internal" (_ prefixed) variables to exist however without convention other than being prefixed to allow potentially shorter names or if we want to enforce prefixing of the role name in all cases.
| "lookup", | ||
| "query", | ||
| "q", |
There was a problem hiding this comment.
those aren't variables, but functions.
There was a problem hiding this comment.
As in -- split the functions out to their own list and constant? I think the tricky part was how to only identify variables by the lint rule.
Should it instead only consider the first "token" before a pipe | ?
There was a problem hiding this comment.
Yeah, maybe not looking at the rest of a pipe is a good idea. There still can be some {{ a | combine(b) }} and we'd not notice the b being bad, but we probably also don't in the current code
|
I said elsewhere that I like the rule, but dislike the code. I think it boils down to:
I wonder if there is a better way to obtain this information from Ansible (instead of Jinja). Also, we might have the same problem in template files, which are uncovered today too. (Not saying it belongs into this PR!). |
05f99dc to
2875952
Compare
Co-Authored-By: Claude <noreply@anthropic.com>
2875952 to
53a9cfa
Compare
I think this is unavoidable as that's what Ansible lint rules do, but I did include updates to make how it interacts more clean with the standard ansible lint rules.
Across the board I think this should be better relying on more builtin methods from Ansibles python code.
|
Map shared variables to role-prefixed names at playbook invocation sites and pass them through parent roles. Use leading underscore convention for role-internal variables (loop vars, include_tasks vars). Co-Authored-By: Claude <noreply@anthropic.com>
53a9cfa to
5c4061d
Compare
Why are you introducing these changes? (Problem description, related links)
Roles currently reference shared variables (e.g.
database_host,ca_certificate) directly, coupling them to the playbook's variable namespace. This makes it hard to tell which variables a role actually needs, creates implicit dependencies between roles, and means renaming a shared variable silently breaks every role that uses it.This PR adds a custom ansible-lint rule that enforces role-scoped variables and fixes the existing violations in addressed roles.
What are the changes introduced in this pull request?
New custom ansible-lint rule
role-scoped-variablesthat flags variables inside role tasks not prefixed with the role namenested_items_pathto walk all task values — no manual key enumerationlookup,query,now) from variable references — no function allowlist neededansible_*facts, Ansible builtins (item,omit,inventory_hostname, etc.),_-prefixed internal variables, and project globalsMap shared variables to role-prefixed names at playbook invocation sites:
deploy.yaml,deploy-proxy.yaml,checks.yaml,backup.yaml,deploy-dev.yamlcheckspasseschecks_database_*tocheck_database_index)Rename role-internal variables (loop vars, include_tasks vars) to use leading underscore convention:
db_itemto_db_itemincheck_database_connectionfeature_name/feature_enabledto_feature_name/_feature_enabledinforeman_proxytuning_varsto_tuning_varsincheck_system_requirementsRemaining violations to address in follow-up:
certificates(6),restore(26), and 7 dynamically-included check roles whereexecute_check.ymlusesinclude_role: name: "{{ item }}"with no way to pass per-role varsHow to test this pull request
Steps to reproduce:
python -m pytest tests/ansible_lint/test_role_scoped_variables.py -vvANSIBLE_COLLECTIONS_PATH="$PWD/build/collections/foremanctl" ANSIBLE_COLLECTIONS_SCAN_SYS_PATH=false bash -c '(cd src && ansible-lint)'ANSIBLE_COLLECTIONS_PATH="$PWD/build/collections/forge" ANSIBLE_COLLECTIONS_SCAN_SYS_PATH=false bash -c '(cd development && ansible-lint --exclude ../build/collections)'./foremanctl deploy --foreman-initial-admin-password=changeme --tuning developmentChecklist