fix: detect missing SECP384R1 early and fix community.crypto compatibility (#14970)

Add pre-flight check in main.yml that catches missing cryptography/SECP384R1
before deployment starts, replacing the cryptic error from community.crypto
internals with an actionable message pointing users to run ./algo or uv sync.

Root cause of the CI ipsec/both test failures: cryptography 46.0.5 wraps
the ec module with _ModuleWithDeprecations (for SECT curve deprecation),
which breaks community.crypto's ec.__dict__.get("SECP384R1") lookup.
The fix in community.crypto 3.1.1 uses getattr() instead.

Changes:
- Add SECP384R1 pre-flight check to main.yml (conditional on ipsec_enabled)
- Add cryptography>=42.0.0 as explicit dependency in pyproject.toml
- Upgrade community.crypto to >=3.1.1 (fixes __dict__ vs getattr bug)
- Add ansible-galaxy collection install step to CI
- Use venv Python interpreter for local deployments in add_host tasks

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Dan Guido
2026-02-22 02:40:17 -08:00
committed by GitHub
co-authored by Claude Opus 4.6
parent a79d73009f
commit de11b86060
8 changed files with 28 additions and 4 deletions
+3
View File
@@ -56,6 +56,9 @@ jobs:
- name: Install Python dependencies
run: uv sync
- name: Install Ansible collections
run: uv run ansible-galaxy collection install -r requirements.yml
- name: Create test configuration
run: |
cat > integration-test.cfg << EOF
+1 -1
View File
@@ -13,7 +13,7 @@
ansible_ssh_user: "{{ 'root' if client_ip == 'localhost' else ssh_user }}"
vpn_user: "{{ vpn_user }}"
IP_subject_alt_name: "{{ server_ip }}"
ansible_python_interpreter: /usr/bin/python3
ansible_python_interpreter: "{% if client_ip == 'localhost' %}{{ ansible_playbook_python }}{% else %}/usr/bin/python3{% endif %}"
- name: Configure the client and install required software
hosts: client-host
+18
View File
@@ -60,6 +60,24 @@
You must update the requirements to use this version of Algo.
Try to run: uv sync
- name: Check cryptography library SECP384R1 support
command: >
{{ ansible_playbook_python }} -c
"from cryptography.hazmat.primitives.asymmetric.ec import SECP384R1"
changed_when: false
failed_when: false
register: _crypto_check
when: ipsec_enabled | default(true) | bool
- name: Verify cryptography library supports IPsec requirements
assert:
that: _crypto_check.rc == 0
msg: >
The Python cryptography library is missing or does not support SECP384R1.
IPsec/IKEv2 requires the cryptography package with elliptic curve support.
Fix: Run ./algo (manages dependencies automatically) or: uv sync && uv run ansible-playbook main.yml
when: ipsec_enabled | default(true) | bool
- name: Include prompts playbook
import_playbook: input.yml
+1 -1
View File
@@ -10,7 +10,7 @@
ansible_connection: "{% if cloud_instance_ip == 'localhost' %}local{% else %}ssh{% endif %}"
ansible_ssh_user: "{{ ansible_ssh_user | default('root') }}"
ansible_ssh_port: "{{ ansible_ssh_port | default(22) }}"
ansible_python_interpreter: /usr/bin/python3
ansible_python_interpreter: "{% if cloud_instance_ip == 'localhost' %}{{ ansible_playbook_python }}{% else %}/usr/bin/python3{% endif %}"
algo_provider: "{{ algo_provider }}"
algo_server_name: "{{ algo_server_name }}"
algo_ondemand_cellular: "{{ algo_ondemand_cellular }}"
+1
View File
@@ -9,6 +9,7 @@ version = "2.0.0-beta"
requires-python = ">=3.11"
dependencies = [
"ansible==12.3.0",
"cryptography>=42.0.0",
"jinja2>=3.1.6",
"netaddr==1.3.0",
"pyyaml>=6.0.2",
+1 -1
View File
@@ -7,7 +7,7 @@ collections:
- name: community.general
version: "==11.1.0"
- name: community.crypto
version: "==3.0.3"
version: ">=3.1.1"
- name: openstack.cloud
version: "==2.4.1"
- name: linode.cloud
+1 -1
View File
@@ -142,7 +142,7 @@
groups: vpn-host
ansible_ssh_user: "{{ server_user | default('root') }}"
ansible_connection: "{% if algo_server == 'localhost' %}local{% else %}ssh{% endif %}"
ansible_python_interpreter: /usr/bin/python3
ansible_python_interpreter: "{% if algo_server == 'localhost' %}{{ ansible_playbook_python }}{% else %}/usr/bin/python3{% endif %}"
CA_password: "{{ CA_password | default(omit) }}"
rescue:
- include_tasks: playbooks/rescue.yml
Generated
+2
View File
@@ -27,6 +27,7 @@ version = "2.0.0b0"
source = { editable = "." }
dependencies = [
{ name = "ansible" },
{ name = "cryptography" },
{ name = "jinja2" },
{ name = "netaddr" },
{ name = "pyyaml" },
@@ -79,6 +80,7 @@ requires-dist = [
{ name = "azure-mgmt-network", marker = "extra == 'azure'", specifier = ">=25.0.0" },
{ name = "azure-mgmt-resource", marker = "extra == 'azure'", specifier = ">=23.0.0" },
{ name = "boto3", marker = "extra == 'aws'", specifier = ">=1.34.0" },
{ name = "cryptography", specifier = ">=42.0.0" },
{ name = "cs", marker = "extra == 'cloudstack'", specifier = ">=3.0.0" },
{ name = "google-auth", marker = "extra == 'gcp'", specifier = ">=2.28.0" },
{ name = "hcloud", marker = "extra == 'hetzner'", specifier = ">=1.33.0" },