mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2025-09-09 03:37:37 +02:00
Implement filter checks: ensure all defined filters are used and remove dead code
Integration tests added/updated: - tests/integration/test_filters_usage.py: AST-based detection of filter definitions (FilterModule.filters), robust Jinja detection ({{ ... }}, {% ... %}, {% filter ... %}), plus Python call tracking; fails if a filter is used only under tests/. - tests/integration/test_filters_are_defined.py: inverse check — every filter used in .yml/.yaml/.j2/.jinja2/.tmpl must be defined locally. Scans only inside Jinja blocks and ignores pipes inside strings (e.g., lookup('pipe', "... | grep ... | awk ...")) to avoid false positives like trusted_hosts, woff/woff2, etc. Bug fixes & robustness: - Build regexes without %-string formatting to avoid ValueError from literal '%' in Jinja tags. - Strip quoted strings in usage analysis so sed/grep/awk pipes are not miscounted as filters. - Prevent self-matches in the defining file. Cleanup / removal of dead code: - Removed unused filter plugins and related unit tests: * filter_plugins/alias_domains_map.py * filter_plugins/get_application_id.py * filter_plugins/load_configuration.py * filter_plugins/safe.py * filter_plugins/safe_join.py * roles/svc-db-openldap/filter_plugins/build_ldap_nested_group_entries.py * roles/sys-ctl-bkp-docker-2-loc/filter_plugins/dict_to_cli_args.py * corresponding tests under tests/unit/* - roles/svc-db-postgres/filter_plugins/split_postgres_connections.py: dropped no-longer-needed list_postgres_roles API; adjusted tests. Misc: - sys-stk-front-proxy/defaults/main.yml: clarified valid vhost_flavour values (comma-separated). Ref: https://chatgpt.com/share/68b56bac-c4f8-800f-aeef-6708dbb44199
This commit is contained in:
@@ -1,77 +0,0 @@
|
||||
def build_ldap_nested_group_entries(applications, users, ldap):
|
||||
"""
|
||||
Builds structured LDAP role entries using the global `ldap` configuration.
|
||||
Supports objectClasses: posixGroup (adds gidNumber, memberUid), groupOfNames (adds member).
|
||||
Now nests roles under an application-level OU: application-id/role.
|
||||
"""
|
||||
|
||||
result = {}
|
||||
|
||||
# Base DN components
|
||||
role_dn_base = ldap["DN"]["OU"]["ROLES"]
|
||||
user_dn_base = ldap["DN"]["OU"]["USERS"]
|
||||
ldap_user_attr = ldap["USER"]["ATTRIBUTES"]["ID"]
|
||||
|
||||
# Supported objectClass flavors
|
||||
flavors = ldap.get("RBAC").get("FLAVORS")
|
||||
|
||||
for application_id, app_config in applications.items():
|
||||
# Compute the DN for the application-level OU
|
||||
app_ou_dn = f"ou={application_id},{role_dn_base}"
|
||||
|
||||
ou_entry = {
|
||||
"dn": app_ou_dn,
|
||||
"objectClass": ["top", "organizationalUnit"],
|
||||
"ou": application_id,
|
||||
"description": f"Roles for application {application_id}"
|
||||
}
|
||||
result[app_ou_dn] = ou_entry
|
||||
|
||||
# Standard roles with an extra 'administrator'
|
||||
base_roles = app_config.get("rbac", {}).get("roles", {})
|
||||
roles = {
|
||||
**base_roles,
|
||||
"administrator": {
|
||||
"description": "Has full administrative access: manage themes, plugins, settings, and users"
|
||||
}
|
||||
}
|
||||
|
||||
group_id = app_config.get("group_id")
|
||||
|
||||
for role_name, role_conf in roles.items():
|
||||
# Build CN under the application OU
|
||||
cn = role_name
|
||||
dn = f"cn={cn},{app_ou_dn}"
|
||||
|
||||
entry = {
|
||||
"dn": dn,
|
||||
"cn": cn,
|
||||
"description": role_conf.get("description", ""),
|
||||
"objectClass": ["top"] + flavors,
|
||||
}
|
||||
|
||||
member_dns = []
|
||||
member_uids = []
|
||||
for username, user_conf in users.items():
|
||||
if role_name in user_conf.get("roles", []):
|
||||
member_dns.append(f"{ldap_user_attr}={username},{user_dn_base}")
|
||||
member_uids.append(username)
|
||||
|
||||
if "posixGroup" in flavors:
|
||||
entry["gidNumber"] = group_id
|
||||
if member_uids:
|
||||
entry["memberUid"] = member_uids
|
||||
|
||||
if "groupOfNames" in flavors and member_dns:
|
||||
entry["member"] = member_dns
|
||||
|
||||
result[dn] = entry
|
||||
|
||||
return result
|
||||
|
||||
|
||||
class FilterModule(object):
|
||||
def filters(self):
|
||||
return {
|
||||
"build_ldap_nested_group_entries": build_ldap_nested_group_entries
|
||||
}
|
@@ -37,22 +37,8 @@ def split_postgres_connections(total_connections, roles_dir="roles"):
|
||||
denom = max(count, 1)
|
||||
return max(1, total // denom)
|
||||
|
||||
def list_postgres_roles(roles_dir="roles"):
|
||||
"""
|
||||
Helper: return a list of role names that declare database_type: postgres in vars/main.yml.
|
||||
"""
|
||||
names = []
|
||||
if not os.path.isdir(roles_dir):
|
||||
return names
|
||||
for name in os.listdir(roles_dir):
|
||||
vars_main = os.path.join(roles_dir, name, "vars", "main.yml")
|
||||
if os.path.isfile(vars_main) and _is_postgres_role(vars_main):
|
||||
names.append(name)
|
||||
return names
|
||||
|
||||
class FilterModule(object):
|
||||
def filters(self):
|
||||
return {
|
||||
"split_postgres_connections": split_postgres_connections,
|
||||
"list_postgres_roles": list_postgres_roles,
|
||||
"split_postgres_connections": split_postgres_connections
|
||||
}
|
||||
|
@@ -1,36 +0,0 @@
|
||||
def dict_to_cli_args(data):
|
||||
"""
|
||||
Convert a dictionary into CLI argument string.
|
||||
Example:
|
||||
{
|
||||
"backup-dir": "/mnt/backups",
|
||||
"shutdown": True,
|
||||
"ignore-volumes": ["redis", "memcached"]
|
||||
}
|
||||
becomes:
|
||||
--backup-dir=/mnt/backups --shutdown --ignore-volumes="redis memcached"
|
||||
"""
|
||||
if not isinstance(data, dict):
|
||||
raise TypeError("Expected a dictionary for CLI argument conversion")
|
||||
|
||||
args = []
|
||||
|
||||
for key, value in data.items():
|
||||
cli_key = f"--{key}"
|
||||
|
||||
if isinstance(value, bool):
|
||||
if value:
|
||||
args.append(cli_key)
|
||||
elif isinstance(value, list):
|
||||
items = " ".join(map(str, value))
|
||||
args.append(f'{cli_key}="{items}"')
|
||||
elif value is not None:
|
||||
args.append(f'{cli_key}={value}')
|
||||
|
||||
return " ".join(args)
|
||||
|
||||
class FilterModule(object):
|
||||
def filters(self):
|
||||
return {
|
||||
'dict_to_cli_args': dict_to_cli_args
|
||||
}
|
@@ -1,5 +1,5 @@
|
||||
# default vhost flavour
|
||||
vhost_flavour: "basic" # valid: basic | ws_generic
|
||||
vhost_flavour: "basic" # valid: basic, ws_generic
|
||||
|
||||
# build the full template path from the flavour
|
||||
vhost_template_src: "roles/srv-proxy-core/templates/vhost/{{ vhost_flavour }}.conf.j2"
|
Reference in New Issue
Block a user