From ef23ef6e6519d9bd9914897250040c82aba5b98d Mon Sep 17 00:00:00 2001 From: Rich Megginson Date: Fri, 23 Oct 2026 09:00:20 -0600 Subject: [PATCH] refactor: delegate PostgreSQL certificate validation to certificate role Declare postgresql_certificates as raw and remove its sub-options from the argument spec. Remove local certificate assertions and invalid-input tests so the certificate role validates certificate requests. --- meta/argument_specs.yml | 134 +--------------------------------- tasks/assert_role_vars.yml | 77 ------------------- tests/tests_invalid_input.yml | 50 ------------- 3 files changed, 1 insertion(+), 260 deletions(-) diff --git a/meta/argument_specs.yml b/meta/argument_specs.yml index 8de797c18d..97809e85cb 100644 --- a/meta/argument_specs.yml +++ b/meta/argument_specs.yml @@ -49,144 +49,12 @@ argument_specs: Whether to enable SSL/TLS for PostgreSQL connections by setting `ssl = on` in the server configuration. postgresql_certificates: - type: list - elements: dict + type: raw default: [] description: > A list of certificate request specifications passed to the certificate role for generating TLS certificates used by PostgreSQL. - options: - name: - type: str - required: true - description: > - The name of the certificate. A full path can be used to - choose the directory where files will be stored. - ca: - type: str - required: true - description: > - The CA that will issue the certificate (for example - `self-sign` or `ipa`). - dns: - type: raw - description: > - A domain name or list of domain names to include in the - certificate Subject Alternative Name (SAN). - email: - type: raw - description: > - An email address or list of email addresses to include in - the certificate Subject Alternative Name (SAN). - ip: - type: raw - description: > - An IP address or list of IP addresses to include in the - certificate Subject Alternative Name (SAN). - auto_renew: - type: bool - default: true - description: > - Whether the certificate should be renewed automatically - before it expires. - owner: - type: str - description: > - The user name or user id for the certificate and key - files. - group: - type: str - description: > - The group name or group id for the certificate and key - files. - mode: - type: raw - description: > - The file system permissions for the certificate and key - files. Accepts a string (for example `0644`) or an - integer. - key_size: - type: int - description: > - The key size in bits. - common_name: - type: str - description: > - The Common Name requested for the certificate subject. - country: - type: str - description: > - The country code requested for the certificate subject. - state: - type: str - description: > - The state requested for the certificate subject. - locality: - type: str - description: > - The locality requested for the certificate subject. - organization: - type: str - description: > - The organization requested for the certificate subject. - organizational_unit: - type: str - description: > - The organizational unit requested for the certificate - subject. - contact_email: - type: str - description: > - The contact email requested for the certificate subject. - key_usage: - type: list - elements: str - choices: - - digitalSignature - - nonRepudiation - - keyEncipherment - - dataEncipherment - - keyAgreement - - keyCertSign - - cRLSign - - encipherOnly - - decipherOnly - default: - - digitalSignature - - keyEncipherment - description: > - The allowed Key Usage extensions for the certificate. - extended_key_usage: - type: list - elements: str - default: - - id-kp-serverAuth - - id-kp-clientAuth - description: > - The Extended Key Usage attributes for the certificate. - run_before: - type: str - description: > - A command to run before saving the certificate. - run_after: - type: str - description: > - A command to run after saving the certificate. - principal: - type: raw - description: > - A Kerberos principal or list of Kerberos principals. - provider: - type: str - default: certmonger - description: > - The underlying method used to request and manage the - certificate. - issuer: - type: str - description: > - The issuer certificate nickname or template name. postgresql_secure_logging: type: bool default: true diff --git a/tasks/assert_role_vars.yml b/tasks/assert_role_vars.yml index f47f10f4d4..e69919ce22 100644 --- a/tasks/assert_role_vars.yml +++ b/tasks/assert_role_vars.yml @@ -44,83 +44,6 @@ postgresql_server_tuning must be null or a boolean, got {{ postgresql_server_tuning | type_debug }} -- name: Assert dns in postgresql_certificates is a string or list of strings - ansible.builtin.assert: - that: - - >- - item.dns is string - or (item.dns is sequence and item.dns is not mapping - and item.dns | reject('string') | list | length == 0) - fail_msg: >- - postgresql_certificates[{{ idx }}].dns must be a string or list of - strings, got {{ item.dns | type_debug }} - loop: "{{ postgresql_certificates }}" - loop_control: - index_var: idx - label: "{{ item.name | d('unnamed') }}" - when: item.dns is defined - -- name: Assert email in postgresql_certificates is a string or list of strings - ansible.builtin.assert: - that: - - >- - item.email is string - or (item.email is sequence and item.email is not mapping - and item.email | reject('string') | list | length == 0) - fail_msg: >- - postgresql_certificates[{{ idx }}].email must be a string or list of - strings, got {{ item.email | type_debug }} - loop: "{{ postgresql_certificates }}" - loop_control: - index_var: idx - label: "{{ item.name | d('unnamed') }}" - when: item.email is defined - -- name: Assert ip in postgresql_certificates is a string or list of strings - ansible.builtin.assert: - that: - - >- - item.ip is string - or (item.ip is sequence and item.ip is not mapping - and item.ip | reject('string') | list | length == 0) - fail_msg: >- - postgresql_certificates[{{ idx }}].ip must be a string or list of - strings, got {{ item.ip | type_debug }} - loop: "{{ postgresql_certificates }}" - loop_control: - index_var: idx - label: "{{ item.name | d('unnamed') }}" - when: item.ip is defined - -- name: Assert principal in postgresql_certificates is a string or list of strings - ansible.builtin.assert: - that: - - >- - item.principal is string - or (item.principal is sequence and item.principal is not mapping - and item.principal | reject('string') | list | length == 0) - fail_msg: >- - postgresql_certificates[{{ idx }}].principal must be a string or list of - strings, got {{ item.principal | type_debug }} - loop: "{{ postgresql_certificates }}" - loop_control: - index_var: idx - label: "{{ item.name | d('unnamed') }}" - when: item.principal is defined - -- name: Assert mode in postgresql_certificates is a string or integer - ansible.builtin.assert: - that: - - (item.mode | type_debug) in ['str', 'int', 'unicode'] - fail_msg: >- - postgresql_certificates[{{ idx }}].mode must be a string or integer, - got {{ item.mode | type_debug }} - loop: "{{ postgresql_certificates }}" - loop_control: - index_var: idx - label: "{{ item.name | d('unnamed') }}" - when: item.mode is defined - - name: Assert postgresql_transactional_update_reboot_ok is null or a boolean ansible.builtin.assert: that: diff --git a/tests/tests_invalid_input.yml b/tests/tests_invalid_input.yml index 0894b184ae..9d57aeff71 100644 --- a/tests/tests_invalid_input.yml +++ b/tests/tests_invalid_input.yml @@ -18,29 +18,6 @@ - name: Run argument specs validation tests when: ansible_version.full is version('2.11', '>=') block: - - name: Argument specs reject missing required ca in postgresql_certificates - block: - - name: Run role without required ca in postgresql_certificates - ansible.builtin.include_tasks: tasks/run_role_with_clear_facts.yml - vars: - postgresql_certificates: - - name: test_cert - rescue: - - name: Mark missing ca rejected - ansible.builtin.set_fact: - __invalid_input_missing_ca_failed: true - when: >- - 'missing required arguments: ca found in postgresql_certificates' - in __invalid_input_failure_messages - - - name: Assert missing ca was rejected - ansible.builtin.assert: - that: - - __invalid_input_missing_ca_failed | default(false) - fail_msg: >- - argument_specs should reject postgresql_certificates - entries missing the required ca field - - name: Argument specs reject non-boolean postgresql_ssl_enable block: - name: Run role with non-boolean postgresql_ssl_enable @@ -182,31 +159,6 @@ assert_role_vars should reject postgresql_server_tuning when given an integer value - - name: Assert rejects postgresql_certificates dns as an integer - block: - - name: Run role with postgresql_certificates dns as an integer - ansible.builtin.include_tasks: tasks/run_role_with_clear_facts.yml - vars: - postgresql_certificates: - - name: test_cert - ca: self-sign - dns: 123 - rescue: - - name: Mark postgresql_certificates dns integer rejected - ansible.builtin.set_fact: - __invalid_input_cert_dns_int_failed: true - when: >- - 'postgresql_certificates[0].dns must be a string or list of strings, got int' - in __invalid_input_failure_messages - - - name: Assert postgresql_certificates dns as integer was rejected - ansible.builtin.assert: - that: - - __invalid_input_cert_dns_int_failed | default(false) - fail_msg: >- - assert_role_vars should reject postgresql_certificates - entries where dns is an integer - - name: Assert repeated role invocations resolve current inputs block: - name: Run role set_vars with postgresql_version 13 @@ -288,12 +240,10 @@ - name: Clear test facts ansible.builtin.set_fact: - __invalid_input_missing_ca_failed: __invalid_input_ssl_enable_type_failed: __invalid_input_secure_logging_type_failed: __invalid_input_version_dict_failed: __invalid_input_password_int_failed: __invalid_input_cert_name_int_failed: __invalid_input_server_tuning_int_failed: - __invalid_input_cert_dns_int_failed: tags: tests::cleanup