From 03db141316680f69061e63d0311746bf52bc649d Mon Sep 17 00:00:00 2001 From: Kevin Veen-Birkenbach Date: Wed, 2 Jul 2025 18:29:53 +0200 Subject: [PATCH] Updated user logic --- Makefile | 10 ++- cli/generate-applications-defaults.py | 39 +++++++++-- cli/generate_users.py | 8 +-- .../{04_maintenace.yml => 05_maintenace.yml} | 0 group_vars/all/{05_nginx.yml => 06_nginx.yml} | 0 group_vars/all/{06_paths.yml => 07_paths.yml} | 0 .../all/{07_calendar.yml => 08_calendar.yml} | 0 group_vars/all/{08_ports.yml => 09_ports.yml} | 0 .../all/{09_networks.yml => 10_networks.yml} | 0 roles/docker-bluesky/meta/users.yml | 3 + roles/docker-bluesky/vars/configuration.yml | 3 - .../configuration.yml => meta/users.yml} | 0 roles/docker-espocrm/meta/users.yml | 6 ++ roles/docker-espocrm/vars/configuration.yml | 6 -- roles/docker-keycloak/meta/users.yml | 3 + roles/docker-keycloak/vars/configuration.yml | 3 - roles/docker-ldap/meta/users.yml | 3 + roles/docker-ldap/vars/configuration.yml | 3 - roles/docker-listmonk/meta/users.yml | 7 ++ roles/docker-listmonk/vars/configuration.yml | 7 -- roles/docker-mailu/meta/users.yml | 3 + roles/docker-mailu/vars/configuration.yml | 3 - roles/docker-matrix/meta/users.yml | 3 + roles/docker-matrix/vars/configuration.yml | 3 - roles/docker-moodle/meta/users.yml | 3 + roles/docker-moodle/vars/configuration.yml | 3 - roles/docker-nextcloud/meta/users.yml | 5 ++ roles/docker-nextcloud/vars/configuration.yml | 5 -- roles/docker-pgadmin/meta/users.yml | 3 + roles/docker-pgadmin/vars/configuration.yml | 3 - roles/docker-wordpress/meta/users.yml | 4 ++ roles/docker-wordpress/vars/configuration.yml | 4 -- roles/docker-yourls/meta/users.yml | 3 + roles/docker-yourls/vars/configuration.yml | 3 - roles/nginx/vars/configuration.yml | 7 -- .../configuration.yml => meta/users.yml} | 0 .../configuration.yml => meta/users.yml} | 6 ++ tests/integration/test_domain_uniqueness.py | 2 +- tests/integration/test_oauth2_proxy_ports.py | 4 +- ...st_generate_applications_defaults_users.py | 65 +++++++++++++++++++ .../test_generate_default_applications.py | 2 +- tests/unit/test_generate_users.py | 10 +-- 42 files changed, 166 insertions(+), 79 deletions(-) rename group_vars/all/{04_maintenace.yml => 05_maintenace.yml} (100%) rename group_vars/all/{05_nginx.yml => 06_nginx.yml} (100%) rename group_vars/all/{06_paths.yml => 07_paths.yml} (100%) rename group_vars/all/{07_calendar.yml => 08_calendar.yml} (100%) rename group_vars/all/{08_ports.yml => 09_ports.yml} (100%) rename group_vars/all/{09_networks.yml => 10_networks.yml} (100%) create mode 100644 roles/docker-bluesky/meta/users.yml rename roles/docker-compose/{vars/configuration.yml => meta/users.yml} (100%) create mode 100644 roles/docker-espocrm/meta/users.yml create mode 100644 roles/docker-keycloak/meta/users.yml create mode 100644 roles/docker-ldap/meta/users.yml create mode 100644 roles/docker-listmonk/meta/users.yml create mode 100644 roles/docker-mailu/meta/users.yml create mode 100644 roles/docker-matrix/meta/users.yml create mode 100644 roles/docker-moodle/meta/users.yml create mode 100644 roles/docker-nextcloud/meta/users.yml create mode 100644 roles/docker-pgadmin/meta/users.yml create mode 100644 roles/docker-wordpress/meta/users.yml create mode 100644 roles/docker-yourls/meta/users.yml delete mode 100644 roles/nginx/vars/configuration.yml rename roles/user-administrator/{vars/configuration.yml => meta/users.yml} (100%) rename roles/user/{vars/configuration.yml => meta/users.yml} (92%) create mode 100644 tests/unit/test_generate_applications_defaults_users.py diff --git a/Makefile b/Makefile index 23792179..76369ddf 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ ROLES_DIR := ./roles -APPLICATIONS_OUT := ./group_vars/all/03_applications.yml +APPLICATIONS_OUT := ./group_vars/all/04_applications.yml APPLICATIONS_SCRIPT := ./cli/generate-applications-defaults.py -USERS_OUT := ./group_vars/all/10_users.yml +USERS_OUT := ./group_vars/all/03_users.yml USERS_SCRIPT := ./cli/generate_users.py INCLUDES_OUT := ./tasks/utils/docker-roles.yml INCLUDES_SCRIPT := ./cli/generate_playbook.py @@ -16,13 +16,11 @@ EXTRA_USERS := $(shell \ build: @echo "🔧 Generating applications defaults → $(APPLICATIONS_OUT) from roles in $(ROLES_DIR)…" - @mkdir -p $(dir $(APPLICATIONS_OUT)) + python3 $(USERS_SCRIPT) --roles-dir $(ROLES_DIR) --output $(USERS_OUT) --extra-users "$(EXTRA_USERS)" + @echo "✅ Users defaults written to $(USERS_OUT)\n" python3 $(APPLICATIONS_SCRIPT) --roles-dir $(ROLES_DIR) --output-file $(APPLICATIONS_OUT) @echo "✅ Applications defaults written to $(APPLICATIONS_OUT)\n" @echo "🔧 Generating users defaults → $(USERS_OUT) from roles in $(ROLES_DIR)…" - @mkdir -p $(dir $(USERS_OUT)) - python3 $(USERS_SCRIPT) --roles-dir $(ROLES_DIR) --output $(USERS_OUT) --extra-users "$(EXTRA_USERS)" - @echo "✅ Users defaults written to $(USERS_OUT)\n" @echo "🔧 Generating Docker role includes → $(INCLUDES_OUT)…" @mkdir -p $(dir $(INCLUDES_OUT)) python3 $(INCLUDES_SCRIPT) $(ROLES_DIR) -o $(INCLUDES_OUT) -p docker- diff --git a/cli/generate-applications-defaults.py b/cli/generate-applications-defaults.py index df96c439..4693e5bb 100644 --- a/cli/generate-applications-defaults.py +++ b/cli/generate-applications-defaults.py @@ -13,20 +13,31 @@ def load_yaml_file(path): with path.open("r", encoding="utf-8") as f: return yaml.safe_load(f) or {} + def main(): - parser = argparse.ArgumentParser(description="Generate defaults_applications YAML from docker roles.") - parser.add_argument("--roles-dir", default="roles", help="Path to the roles directory (default: roles)") - parser.add_argument("--output-file", default="group_vars/all/03_applications.yml", help="Path to output YAML file") + parser = argparse.ArgumentParser( + description="Generate defaults_applications YAML from docker roles and include users meta data for each role." + ) + parser.add_argument( + "--roles-dir", + help="Path to the roles directory (default: roles)" + ) + parser.add_argument( + "--output-file", + help="Path to output YAML file" + ) args = parser.parse_args() cwd = Path.cwd() roles_dir = (cwd / args.roles_dir).resolve() output_file = (cwd / args.output_file).resolve() - + # Ensure output directory exists output_file.parent.mkdir(parents=True, exist_ok=True) + # Initialize result structure result = {"defaults_applications": {}} + # Process each role for application configs for role_dir in sorted(roles_dir.iterdir()): role_name = role_dir.name vars_main = role_dir / "vars" / "main.yml" @@ -40,9 +51,10 @@ def main(): try: application_id = vars_data.get("application_id") except Exception as e: - # print the exception message - print(f"Warning: failed to read application_id from {vars_data} in {vars_main}.\nException: {e}", file=sys.stderr) - # exit with status 0 + print( + f"Warning: failed to read application_id from {vars_main}\nException: {e}", + file=sys.stderr + ) sys.exit(1) if not application_id: @@ -56,7 +68,19 @@ def main(): config_data = load_yaml_file(config_file) if config_data: result["defaults_applications"][application_id] = config_data + users_meta_file = role_dir / "meta" / "users.yml" + transformed_users = {} + if users_meta_file.exists(): + users_meta = load_yaml_file(users_meta_file) + users_data = users_meta.get("users", {}) + for user, role_user_attrs in users_data.items(): + transformed_users[user] = f"{{{{ users[\"{user}\"] }}}}" + # Attach transformed users under each application + if transformed_users: + result["defaults_applications"][application_id]["users"] = transformed_users + + # Write out result YAML with output_file.open("w", encoding="utf-8") as f: yaml.dump(result, f, sort_keys=False) @@ -65,5 +89,6 @@ def main(): except ValueError: print(f"✅ Generated: {output_file}") + if __name__ == "__main__": main() diff --git a/cli/generate_users.py b/cli/generate_users.py index 7c60e631..3df8e6f9 100644 --- a/cli/generate_users.py +++ b/cli/generate_users.py @@ -93,7 +93,7 @@ def build_users(defs, primary_domain, start_id, become_pwd): def load_user_defs(roles_dir): """ - Scan all roles/*/vars/configuration.yml files and extract 'users:' sections. + Scan all roles/*/meta/users.yml files and extract 'users:' sections. Raises an exception if conflicting definitions are found. @@ -106,7 +106,7 @@ def load_user_defs(roles_dir): Raises: ValueError: On invalid format or conflicting field values. """ - pattern = os.path.join(roles_dir, '*/vars/configuration.yml') + pattern = os.path.join(roles_dir, '*/meta/users.yml') files = sorted(glob.glob(pattern)) merged = OrderedDict() @@ -151,11 +151,11 @@ def dictify(data): def parse_args(): parser = argparse.ArgumentParser( - description='Generate a users.yml by merging all roles/*/vars/configuration.yml users sections.' + description='Generate a users.yml by merging all roles/*/meta/users.yml users sections.' ) parser.add_argument( '--roles-dir', '-r', required=True, - help='Directory containing roles (e.g., roles/*/vars/configuration.yml).' + help='Directory containing roles (e.g., roles/*/meta/users.yml).' ) parser.add_argument( '--output', '-o', required=True, diff --git a/group_vars/all/04_maintenace.yml b/group_vars/all/05_maintenace.yml similarity index 100% rename from group_vars/all/04_maintenace.yml rename to group_vars/all/05_maintenace.yml diff --git a/group_vars/all/05_nginx.yml b/group_vars/all/06_nginx.yml similarity index 100% rename from group_vars/all/05_nginx.yml rename to group_vars/all/06_nginx.yml diff --git a/group_vars/all/06_paths.yml b/group_vars/all/07_paths.yml similarity index 100% rename from group_vars/all/06_paths.yml rename to group_vars/all/07_paths.yml diff --git a/group_vars/all/07_calendar.yml b/group_vars/all/08_calendar.yml similarity index 100% rename from group_vars/all/07_calendar.yml rename to group_vars/all/08_calendar.yml diff --git a/group_vars/all/08_ports.yml b/group_vars/all/09_ports.yml similarity index 100% rename from group_vars/all/08_ports.yml rename to group_vars/all/09_ports.yml diff --git a/group_vars/all/09_networks.yml b/group_vars/all/10_networks.yml similarity index 100% rename from group_vars/all/09_networks.yml rename to group_vars/all/10_networks.yml diff --git a/roles/docker-bluesky/meta/users.yml b/roles/docker-bluesky/meta/users.yml new file mode 100644 index 00000000..386ff356 --- /dev/null +++ b/roles/docker-bluesky/meta/users.yml @@ -0,0 +1,3 @@ +users: + administrator: + email: "administrator@{{ primary_domain }}" \ No newline at end of file diff --git a/roles/docker-bluesky/vars/configuration.yml b/roles/docker-bluesky/vars/configuration.yml index a25d6c80..913bc228 100644 --- a/roles/docker-bluesky/vars/configuration.yml +++ b/roles/docker-bluesky/vars/configuration.yml @@ -1,6 +1,3 @@ -users: - administrator: - email: "administrator@{{ primary_domain }}" images: pds: "ghcr.io/bluesky-social/pds:latest" pds: diff --git a/roles/docker-compose/vars/configuration.yml b/roles/docker-compose/meta/users.yml similarity index 100% rename from roles/docker-compose/vars/configuration.yml rename to roles/docker-compose/meta/users.yml diff --git a/roles/docker-espocrm/meta/users.yml b/roles/docker-espocrm/meta/users.yml new file mode 100644 index 00000000..ed75b4ba --- /dev/null +++ b/roles/docker-espocrm/meta/users.yml @@ -0,0 +1,6 @@ +users: + administrator: + username: "administrator" + contact: + description: "General contact account" + username: "contact" \ No newline at end of file diff --git a/roles/docker-espocrm/vars/configuration.yml b/roles/docker-espocrm/vars/configuration.yml index c4d68af3..b90fcbcf 100644 --- a/roles/docker-espocrm/vars/configuration.yml +++ b/roles/docker-espocrm/vars/configuration.yml @@ -1,11 +1,5 @@ images: espocrm: "espocrm/espocrm:latest" -users: - administrator: - username: "administrator" - contact: - description: "General contact account" - username: "contact" features: matomo: true css: false diff --git a/roles/docker-keycloak/meta/users.yml b/roles/docker-keycloak/meta/users.yml new file mode 100644 index 00000000..74bc191e --- /dev/null +++ b/roles/docker-keycloak/meta/users.yml @@ -0,0 +1,3 @@ +users: + administrator: + username: "administrator" \ No newline at end of file diff --git a/roles/docker-keycloak/vars/configuration.yml b/roles/docker-keycloak/vars/configuration.yml index 1a866210..9ae4f208 100644 --- a/roles/docker-keycloak/vars/configuration.yml +++ b/roles/docker-keycloak/vars/configuration.yml @@ -1,8 +1,5 @@ images: keycloak: "quay.io/keycloak/keycloak:latest" -users: - administrator: - username: "administrator" import_realm: True # If True realm will be imported. If false skip. credentials: features: diff --git a/roles/docker-ldap/meta/users.yml b/roles/docker-ldap/meta/users.yml new file mode 100644 index 00000000..5e013004 --- /dev/null +++ b/roles/docker-ldap/meta/users.yml @@ -0,0 +1,3 @@ +users: + administrator: + username: "administrator" \ No newline at end of file diff --git a/roles/docker-ldap/vars/configuration.yml b/roles/docker-ldap/vars/configuration.yml index bc092154..2081e759 100644 --- a/roles/docker-ldap/vars/configuration.yml +++ b/roles/docker-ldap/vars/configuration.yml @@ -6,9 +6,6 @@ network: public: False # Set to true in inventory file if you want to expose the LDAP port to the internet hostname: "ldap" # Hostname of the LDAP Server in the central_ldap network webinterface: "lam" # The webinterface which should be used. Possible: lam and phpldapadmin -users: - administrator: - username: "administrator" credentials: features: ldap: true \ No newline at end of file diff --git a/roles/docker-listmonk/meta/users.yml b/roles/docker-listmonk/meta/users.yml new file mode 100644 index 00000000..650e1f70 --- /dev/null +++ b/roles/docker-listmonk/meta/users.yml @@ -0,0 +1,7 @@ +users: + administrator: + username: "administrator" + bounce: + username: "bounce" + newsletter: + username: "newsletter" \ No newline at end of file diff --git a/roles/docker-listmonk/vars/configuration.yml b/roles/docker-listmonk/vars/configuration.yml index 25b8d1a2..d1dbf75d 100644 --- a/roles/docker-listmonk/vars/configuration.yml +++ b/roles/docker-listmonk/vars/configuration.yml @@ -1,12 +1,5 @@ images: listmonk: "listmonk/listmonk:latest" -users: - administrator: - username: "administrator" - bounce: - username: "bounce" - newsletter: - username: "newsletter" public_api_activated: False # Security hole. Can be used for spaming version: "latest" # Docker Image version features: diff --git a/roles/docker-mailu/meta/users.yml b/roles/docker-mailu/meta/users.yml new file mode 100644 index 00000000..a69907d6 --- /dev/null +++ b/roles/docker-mailu/meta/users.yml @@ -0,0 +1,3 @@ +users: + administrator: + email: "administrator@{{ primary_domain }}" # Administrator Email for DNS Records \ No newline at end of file diff --git a/roles/docker-mailu/vars/configuration.yml b/roles/docker-mailu/vars/configuration.yml index 96be3397..71351e75 100644 --- a/roles/docker-mailu/vars/configuration.yml +++ b/roles/docker-mailu/vars/configuration.yml @@ -1,7 +1,4 @@ version: "2024.06" # Docker Image Version -users: - administrator: - email: "administrator@{{ primary_domain }}" # Administrator Email for DNS Records oidc: email_by_username: true # If true, then the mail is set by the username. If wrong then the OIDC user email is used enable_user_creation: true # Users will be created if not existing diff --git a/roles/docker-matrix/meta/users.yml b/roles/docker-matrix/meta/users.yml new file mode 100644 index 00000000..74bc191e --- /dev/null +++ b/roles/docker-matrix/meta/users.yml @@ -0,0 +1,3 @@ +users: + administrator: + username: "administrator" \ No newline at end of file diff --git a/roles/docker-matrix/vars/configuration.yml b/roles/docker-matrix/vars/configuration.yml index 8847f054..8fa487e7 100644 --- a/roles/docker-matrix/vars/configuration.yml +++ b/roles/docker-matrix/vars/configuration.yml @@ -1,9 +1,6 @@ images: synapse: "matrixdotorg/synapse:latest" element: "vectorim/element-web:latest" -users: - administrator: - username: "administrator" playbook_tags: "setup-all,start" # For the initial update use: install-all,ensure-matrix-users-created,start server_name: "{{primary_domain}}" # Adress for the account names etc. synapse: diff --git a/roles/docker-moodle/meta/users.yml b/roles/docker-moodle/meta/users.yml new file mode 100644 index 00000000..74bc191e --- /dev/null +++ b/roles/docker-moodle/meta/users.yml @@ -0,0 +1,3 @@ +users: + administrator: + username: "administrator" \ No newline at end of file diff --git a/roles/docker-moodle/vars/configuration.yml b/roles/docker-moodle/vars/configuration.yml index dc02b2be..1255a316 100644 --- a/roles/docker-moodle/vars/configuration.yml +++ b/roles/docker-moodle/vars/configuration.yml @@ -1,7 +1,4 @@ site_titel: "Academy on {{primary_domain}}" -users: - administrator: - username: "administrator" version: "4.5" # Latest LTS - Necessary for OIDC features: matomo: true diff --git a/roles/docker-nextcloud/meta/users.yml b/roles/docker-nextcloud/meta/users.yml new file mode 100644 index 00000000..5cd86d54 --- /dev/null +++ b/roles/docker-nextcloud/meta/users.yml @@ -0,0 +1,5 @@ +users: + administrator: + username: "administrator" + no-reply: + username: "no-reply" \ No newline at end of file diff --git a/roles/docker-nextcloud/vars/configuration.yml b/roles/docker-nextcloud/vars/configuration.yml index 6fc109f2..0eda8e1b 100644 --- a/roles/docker-nextcloud/vars/configuration.yml +++ b/roles/docker-nextcloud/vars/configuration.yml @@ -27,11 +27,6 @@ features: ldap: true oidc: true central_database: true -users: - administrator: - username: "administrator" - no-reply: - username: "no-reply" default_quota: '1000000000' # Quota to assign if no quota is specified in the OIDC response (bytes) legacy_login_mask: enabled: False # If true, then legacy login mask is shown. Otherwise just SSO diff --git a/roles/docker-pgadmin/meta/users.yml b/roles/docker-pgadmin/meta/users.yml new file mode 100644 index 00000000..0e8e6748 --- /dev/null +++ b/roles/docker-pgadmin/meta/users.yml @@ -0,0 +1,3 @@ +users: + administrator: + email: "administrator@{{ primary_domain }}" \ No newline at end of file diff --git a/roles/docker-pgadmin/vars/configuration.yml b/roles/docker-pgadmin/vars/configuration.yml index 4cfafda2..28cc13fa 100644 --- a/roles/docker-pgadmin/vars/configuration.yml +++ b/roles/docker-pgadmin/vars/configuration.yml @@ -1,9 +1,6 @@ version: "latest" server_mode: False # If true then the preconfigured database file is loaded. Recommended False. True is a security risk. master_password_required: True # Master password is required. Recommended True. False is a security risk. -users: - administrator: - email: "administrator@{{ primary_domain }}" oauth2_proxy: application: "application" port: "80" diff --git a/roles/docker-wordpress/meta/users.yml b/roles/docker-wordpress/meta/users.yml new file mode 100644 index 00000000..f33c641d --- /dev/null +++ b/roles/docker-wordpress/meta/users.yml @@ -0,0 +1,4 @@ +users: # Credentials + administrator: # Wordpress administrator + username: "administrator" + email: "administrator@{{ primary_domain }}" \ No newline at end of file diff --git a/roles/docker-wordpress/vars/configuration.yml b/roles/docker-wordpress/vars/configuration.yml index 7699f832..dd7af1e6 100644 --- a/roles/docker-wordpress/vars/configuration.yml +++ b/roles/docker-wordpress/vars/configuration.yml @@ -1,8 +1,4 @@ title: "Blog" # Wordpress titel -users: # Credentials - administrator: # Wordpress administrator - username: "administrator" - email: "administrator@{{ primary_domain }}" plugins: wp-discourse: enabled: "{{ 'discourse' in group_names | lower }}" diff --git a/roles/docker-yourls/meta/users.yml b/roles/docker-yourls/meta/users.yml new file mode 100644 index 00000000..74bc191e --- /dev/null +++ b/roles/docker-yourls/meta/users.yml @@ -0,0 +1,3 @@ +users: + administrator: + username: "administrator" \ No newline at end of file diff --git a/roles/docker-yourls/vars/configuration.yml b/roles/docker-yourls/vars/configuration.yml index 22d9aa3f..6541fafb 100644 --- a/roles/docker-yourls/vars/configuration.yml +++ b/roles/docker-yourls/vars/configuration.yml @@ -1,6 +1,3 @@ -users: - administrator: - username: "administrator" version: "latest" oauth2_proxy: application: "application" diff --git a/roles/nginx/vars/configuration.yml b/roles/nginx/vars/configuration.yml deleted file mode 100644 index d4ff6ce1..00000000 --- a/roles/nginx/vars/configuration.yml +++ /dev/null @@ -1,7 +0,0 @@ -users: - sld: - description: "Auto Generated Account to reserve the SLD" - username: "{{ primary_domain.split('.')[0] }}" - tld: - description: "Auto Generated Account to reserve the TLD" - username: "{{ primary_domain.split('.')[1] }}" \ No newline at end of file diff --git a/roles/user-administrator/vars/configuration.yml b/roles/user-administrator/meta/users.yml similarity index 100% rename from roles/user-administrator/vars/configuration.yml rename to roles/user-administrator/meta/users.yml diff --git a/roles/user/vars/configuration.yml b/roles/user/meta/users.yml similarity index 92% rename from roles/user/vars/configuration.yml rename to roles/user/meta/users.yml index c44464a1..84d371a4 100644 --- a/roles/user/vars/configuration.yml +++ b/roles/user/meta/users.yml @@ -1,5 +1,11 @@ # Reserved usernames users: + sld: + description: "Auto Generated Account to reserve the SLD" + username: "{{ primary_domain.split('.')[0] }}" + tld: + description: "Auto Generated Account to reserve the TLD" + username: "{{ primary_domain.split('.')[1] }}" root: username: root uid: 0 diff --git a/tests/integration/test_domain_uniqueness.py b/tests/integration/test_domain_uniqueness.py index 9b0b46f1..ea3a80de 100644 --- a/tests/integration/test_domain_uniqueness.py +++ b/tests/integration/test_domain_uniqueness.py @@ -12,7 +12,7 @@ class TestDomainUniqueness(unittest.TestCase): and assert that no domain appears more than once. """ repo_root = Path(__file__).resolve().parents[2] - yaml_file = repo_root / 'group_vars' / 'all' / '03_applications.yml' + yaml_file = repo_root / 'group_vars' / 'all' / '04_applications.yml' # Generate the file if it doesn't exist if not yaml_file.exists(): diff --git a/tests/integration/test_oauth2_proxy_ports.py b/tests/integration/test_oauth2_proxy_ports.py index 2d4c5000..b65af545 100644 --- a/tests/integration/test_oauth2_proxy_ports.py +++ b/tests/integration/test_oauth2_proxy_ports.py @@ -8,7 +8,7 @@ class TestOAuth2ProxyPorts(unittest.TestCase): def setUpClass(cls): # Set up root paths and load oauth2_proxy ports mapping cls.ROOT = Path(__file__).parent.parent.parent.resolve() - cls.PORTS_FILE = cls.ROOT / 'group_vars' / 'all' / '08_ports.yml' + cls.PORTS_FILE = cls.ROOT / 'group_vars' / 'all' / '09_ports.yml' with cls.PORTS_FILE.open() as f: data = yaml.safe_load(f) cls.oauth2_ports = ( @@ -50,7 +50,7 @@ class TestOAuth2ProxyPorts(unittest.TestCase): if app_id not in self.oauth2_ports: self.fail( f"Missing oauth2_proxy port mapping for application '{app_id}' " - f"in group_vars/all/08_ports.yml" + f"in group_vars/all/09_ports.yml" ) diff --git a/tests/unit/test_generate_applications_defaults_users.py b/tests/unit/test_generate_applications_defaults_users.py new file mode 100644 index 00000000..b05a3f68 --- /dev/null +++ b/tests/unit/test_generate_applications_defaults_users.py @@ -0,0 +1,65 @@ +import os +import unittest +import tempfile +import shutil +import yaml +from pathlib import Path +import subprocess + +class TestGenerateDefaultApplicationsUsers(unittest.TestCase): + def setUp(self): + # Setup temporary roles directory + self.temp_dir = Path(tempfile.mkdtemp()) + self.roles_dir = self.temp_dir / "roles" + self.roles_dir.mkdir() + + # Sample role with users meta + self.role = self.roles_dir / "docker-app-with-users" + (self.role / "vars").mkdir(parents=True) + (self.role / "meta").mkdir(parents=True) + + # Write application_id and configuration + (self.role / "vars" / "main.yml").write_text("application_id: app_with_users\n") + (self.role / "vars" / "configuration.yml").write_text("setting: value\n") + + # Write users meta + users_meta = { + 'users': { + 'alice': {'uid': 2001, 'gid': 2001}, + 'bob': {'uid': 2002, 'gid': 2002} + } + } + with (self.role / "meta" / "users.yml").open('w', encoding='utf-8') as f: + yaml.dump(users_meta, f) + + # Output file path + self.output_file = self.temp_dir / "output.yml" + + def tearDown(self): + shutil.rmtree(self.temp_dir) + + def test_users_injection(self): + """ + When a users.yml exists with defined users, the script should inject a 'users' + mapping in the generated YAML, mapping each username to a Jinja2 reference. + """ + script_path = Path(__file__).resolve().parents[2] / "cli" / "generate-applications-defaults.py" + result = subprocess.run([ + "python3", str(script_path), + "--roles-dir", str(self.roles_dir), + "--output-file", str(self.output_file) + ], capture_output=True, text=True) + self.assertEqual(result.returncode, 0, msg=result.stderr) + data = yaml.safe_load(self.output_file.read_text()) + + apps = data.get('defaults_applications', {}) + # Only the app with users should be present + self.assertIn('app_with_users', apps) + + # 'users' section should be present and correct + users_map = apps['app_with_users']['users'] + expected = {'alice': '{{ users["alice"] }}', 'bob': '{{ users["bob"] }}'} + self.assertEqual(users_map, expected) + +if __name__ == '__main__': + unittest.main() diff --git a/tests/unit/test_generate_default_applications.py b/tests/unit/test_generate_default_applications.py index 92c7186d..9b5cce3d 100644 --- a/tests/unit/test_generate_default_applications.py +++ b/tests/unit/test_generate_default_applications.py @@ -23,7 +23,7 @@ class TestGenerateDefaultApplications(unittest.TestCase): (self.sample_role / "vars" / "configuration.yml").write_text("foo: bar\nbaz: 123\n") # Output file path - self.output_file = self.temp_dir / "group_vars" / "all" / "03_applications.yml" + self.output_file = self.temp_dir / "group_vars" / "all" / "04_applications.yml" def tearDown(self): shutil.rmtree(self.temp_dir) diff --git a/tests/unit/test_generate_users.py b/tests/unit/test_generate_users.py index efaf488d..e5ec9b2f 100644 --- a/tests/unit/test_generate_users.py +++ b/tests/unit/test_generate_users.py @@ -114,18 +114,18 @@ class TestGenerateUsers(unittest.TestCase): # create temp roles structure tmp = tempfile.mkdtemp() try: - os.makedirs(os.path.join(tmp, 'role1/vars')) - os.makedirs(os.path.join(tmp, 'role2/vars')) + os.makedirs(os.path.join(tmp, 'role1/meta')) + os.makedirs(os.path.join(tmp, 'role2/meta')) # role1 defines user x - with open(os.path.join(tmp, 'role1/vars/configuration.yml'), 'w') as f: + with open(os.path.join(tmp, 'role1/meta/users.yml'), 'w') as f: yaml.safe_dump({'users': {'x': {'email': 'x@a'}}}, f) # role2 defines same user x with same value - with open(os.path.join(tmp, 'role2/vars/configuration.yml'), 'w') as f: + with open(os.path.join(tmp, 'role2/meta/users.yml'), 'w') as f: yaml.safe_dump({'users': {'x': {'email': 'x@a'}}}, f) defs = generate_users.load_user_defs(tmp) self.assertIn('x', defs) # now conflict definition - with open(os.path.join(tmp, 'role2/vars/configuration.yml'), 'w') as f: + with open(os.path.join(tmp, 'role2/meta/users.yml'), 'w') as f: yaml.safe_dump({'users': {'x': {'email': 'x@b'}}}, f) with self.assertRaises(ValueError): generate_users.load_user_defs(tmp)