Commit Graph
1281 Commits
Author SHA1 Message Date
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
ae4b8b6cdf chore(deps): bump filelock from 3.19.1 to 3.20.3 (#14939)
Bumps [filelock](https://github.com/tox-dev/py-filelock) from 3.19.1 to 3.20.3.
- [Release notes](https://github.com/tox-dev/py-filelock/releases)
- [Changelog](https://github.com/tox-dev/filelock/blob/main/docs/changelog.rst)
- [Commits](https://github.com/tox-dev/py-filelock/compare/3.19.1...3.20.3)

---
updated-dependencies:
- dependency-name: filelock
  dependency-version: 3.20.3
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-16 15:18:30 -05:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
534412a1e2 chore(deps): bump urllib3 from 2.5.0 to 2.6.3 (#14940)
Bumps [urllib3](https://github.com/urllib3/urllib3) from 2.5.0 to 2.6.3.
- [Release notes](https://github.com/urllib3/urllib3/releases)
- [Changelog](https://github.com/urllib3/urllib3/blob/main/CHANGES.rst)
- [Commits](https://github.com/urllib3/urllib3/compare/2.5.0...2.6.3)

---
updated-dependencies:
- dependency-name: urllib3
  dependency-version: 2.6.3
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-16 15:11:04 -05:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
549fd0220a chore(deps): bump pyasn1 from 0.6.1 to 0.6.2 (#14938)
Bumps [pyasn1](https://github.com/pyasn1/pyasn1) from 0.6.1 to 0.6.2.
- [Release notes](https://github.com/pyasn1/pyasn1/releases)
- [Changelog](https://github.com/pyasn1/pyasn1/blob/main/CHANGES.rst)
- [Commits](https://github.com/pyasn1/pyasn1/compare/v0.6.1...v0.6.2)

---
updated-dependencies:
- dependency-name: pyasn1
  dependency-version: 0.6.2
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-16 15:07:54 -05:00
dependabot[bot]andGitHub 5c967ad35e chore(deps): bump the python group with 2 updates (#14937) 2026-01-14 11:36:37 -05:00
dependabot[bot]andGitHub e566fe467e chore(deps): bump boto3 from 1.42.16 to 1.42.19 in the python group (#14936) 2026-01-07 09:54:59 -05:00
dependabot[bot]andGitHub 38b609257a chore(deps): bump the python group with 2 updates (#14935) 2025-12-31 12:50:30 -05:00
dependabot[bot]andGitHub 7802c13ab7 chore(deps): bump the python group with 2 updates (#14934) 2025-12-24 10:36:40 -05:00
dependabot[bot]andGitHub b123e43c54 chore(deps): bump the github-actions group with 2 updates (#14933) 2025-12-24 10:36:19 -05:00
dependabot[bot]andGitHub 6682db90fd chore(deps): bump azure-mgmt-network in the python group (#14932) 2025-12-14 20:20:48 -05:00
0d314ea631 Add cooldown and grouping to Dependabot config (#14931)
- Add 7-day cooldown to protect against supply chain attacks
- Group updates by ecosystem to reduce PR noise
- Change schedule from daily to weekly
- Add Docker ecosystem for base image updates

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-14 19:58:02 -05:00
dependabot[bot]andGitHub fd0ab40421 chore(deps): bump boto3 from 1.42.7 to 1.42.8 (#14930) 2025-12-12 07:36:33 -05:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
aea4ac477a chore(deps): bump ansible from 12.2.0 to 12.3.0 (#14926)
Bumps [ansible](https://github.com/ansible-community/ansible-build-data) from 12.2.0 to 12.3.0.
- [Changelog](https://github.com/ansible-community/ansible-build-data/blob/main/docs/release-process.md)
- [Commits](https://github.com/ansible-community/ansible-build-data/compare/12.2.0...12.3.0)

---
updated-dependencies:
- dependency-name: ansible
  dependency-version: 12.3.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-11 11:02:33 -05:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
6e0810c359 chore(deps): bump hcloud from 2.11.1 to 2.12.0 (#14929)
Bumps [hcloud](https://github.com/hetznercloud/hcloud-python) from 2.11.1 to 2.12.0.
- [Release notes](https://github.com/hetznercloud/hcloud-python/releases)
- [Changelog](https://github.com/hetznercloud/hcloud-python/blob/main/CHANGELOG.md)
- [Commits](https://github.com/hetznercloud/hcloud-python/compare/v2.11.1...v2.12.0)

---
updated-dependencies:
- dependency-name: hcloud
  dependency-version: 2.12.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-11 11:02:22 -05:00
dependabot[bot]andGitHub ce365037e5 chore(deps): bump boto3 from 1.42.6 to 1.42.7 (#14928) 2025-12-11 08:26:52 -05:00
dependabot[bot]andGitHub 1d052f3f80 chore(deps): bump boto3 from 1.42.5 to 1.42.6 (#14927) 2025-12-10 08:41:06 -05:00
dependabot[bot]andGitHub 7b5e326fca chore(deps): bump boto3 from 1.42.4 to 1.42.5 (#14925) 2025-12-09 10:20:27 -05:00
6a9edfabc8 Auto-install Ansible Galaxy collections before deployment (#14924)
After PR #14908 migrated cloud providers to Ansible collections,
users deploying to Linode (and other providers using collections)
get errors because the collections aren't automatically installed.

This adds automatic collection installation to:
- The `algo` script (runs before playbook execution)
- The Dockerfile (baked into the image at build time)

Fixes #14923

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-08 10:03:19 -05:00
dependabot[bot]andGitHub a7babef704 chore(deps): bump boto3 from 1.42.3 to 1.42.4 (#14922) 2025-12-08 09:03:23 -05:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
e75e217061 chore(deps): bump boto3 from 1.42.2 to 1.42.3 (#14921)
Bumps [boto3](https://github.com/boto/boto3) from 1.42.2 to 1.42.3.
- [Release notes](https://github.com/boto/boto3/releases)
- [Commits](https://github.com/boto/boto3/compare/1.42.2...1.42.3)

---
updated-dependencies:
- dependency-name: boto3
  dependency-version: 1.42.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-07 16:43:32 -05:00
dependabot[bot]andGitHub 8eb7697a83 chore(deps): bump boto3 from 1.42.0 to 1.42.2 (#14920) 2025-12-04 09:07:01 -05:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2d3e97cf88 chore(deps): bump actions/checkout from 6.0.0 to 6.0.1 (#14919)
Bumps [actions/checkout](https://github.com/actions/checkout) from 6.0.0 to 6.0.1.
- [Release notes](https://github.com/actions/checkout/releases)
- [Commits](https://github.com/actions/checkout/compare/v6...v6.0.1)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: 6.0.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-03 10:32:18 -05:00
dependabot[bot]andGitHub 72a13aadef chore(deps): bump boto3 from 1.41.5 to 1.42.0 (#14917) 2025-12-01 08:50:37 -05:00
9268a78028 Add end-to-end VPN connectivity tests using network namespaces (#14914)
* Add end-to-end VPN connectivity tests using network namespaces

Addresses #14912

Current integration tests verify that VPN services start, but don't verify
they actually work. This adds true E2E tests using Linux network namespaces
to simulate a client connecting to the server.

New tests verify:
- WireGuard handshake completes and tunnel is functional
- IPsec/StrongSwan service is configured and listening
- DNS resolution works through VPN (172.16.0.1)
- mobileconfig XML files are valid
- CA certificate chain is correct

Changes:
- Add tests/e2e/test-vpn-connectivity.sh - main E2E test script
- Add tests/e2e/README.md - documentation for running tests
- Update integration-tests.yml to run E2E tests after deployment
- Delete tests/legacy-lxd/ - replaced by new E2E tests
- Update .ansible-lint to remove legacy-lxd from excludes
- Rewrite tests/README.md for clarity

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Fix WireGuard handshake timeout by allowing VPN traffic on veth

The namespace test was timing out because the firewall was blocking
UDP traffic on the veth interface. This adds explicit INPUT rules
to allow WireGuard (51820) and IPsec (500, 4500) traffic.

Also refines the MASQUERADE rule to not apply to bridge-local traffic.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Use -I instead of -A for iptables rules; add debug output

The firewall rules were being appended (-A) after existing DROP rules
and never matched. Changed to -I to insert at beginning of chain.

Also added debug output to show:
- Server WireGuard peers before client connects
- Server port listening status
- iptables INPUT chain on timeout (to verify rules)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Work around deployment bug where WireGuard handlers don't fire

The async role execution in server.yml causes handlers not to fire
properly. This workaround restarts WireGuard if no peers are found,
ensuring the peer configuration is loaded.

Root cause: import_role with async: 300, poll: 0 breaks handler
notification flow. The 'restart wireguard' handler is notified but
never executed because the async context loses track of handlers.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Add packet capture and rp_filter diagnostics to debug WireGuard handshake

- Disable reverse path filtering on veth interface (can drop packets)
- Add tcpdump capture to see if UDP packets are arriving
- Show host and namespace routing tables
- Add route debugging to error output

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Add PersistentKeepalive to trigger WireGuard handshake

WireGuard only initiates a handshake when there's outgoing traffic or
a keepalive timer fires. Without PersistentKeepalive, the test was
waiting forever because no traffic was being sent through the tunnel
(Table=off prevents route creation).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Clean up verbose debug output from WireGuard tests

Remove routing table and rp_filter debug output that was printed on every
run. Keep the packet capture and detailed error diagnostics that are only
shown on failure.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Document configuration assumptions in E2E test README

Add explicit documentation about the hardcoded IP addresses and test user
requirements as suggested in code review. This helps users understand what
default values are expected and why tests might fail on custom configurations.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Remove unused pip cache from integration tests workflow

We use uv for dependency management, not pip, so the pip cache setting
was causing warnings about missing cache folders.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
2025-11-29 02:16:33 -05:00
11e4dcae22 Reduce friction for bug reporting (#14911)
- Update error message to present troubleshooting and issue filing equally
- Remove dead GitHub Discussions link from troubleshooting page
- Simplify bug report template from 6 sections to 3
- Add config.yml to show troubleshooting link in issue chooser
- Lead CONTRIBUTING.md with "We welcome bug reports!"

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude <noreply@anthropic.com>
2025-11-28 23:45:29 -05:00
56cd17b21a Add AF_UNIX to SystemD RestrictAddressFamilies for future VICI support (#14910)
Preparatory work for issue #14810 (stroke to swanctl migration).

This change adds AF_UNIX to the allowed socket address families in the
StrongSwan SystemD service hardening configuration. This is required for
the VICI socket (/var/run/charon.vici) that swanctl uses to communicate
with the charon daemon.

The change is:
- Backward-compatible (doesn't affect current stroke interface)
- Zero-risk (additive change only)
- Future-proof (enables eventual swanctl migration)

Full migration is deferred until Ubuntu 26.04 approaches, per research
findings documented in #14810.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude <noreply@anthropic.com>
2025-11-28 18:30:38 -05:00
39bdcc122c Migrate Azure module to azure.azcollection (#14909)
* Migrate Azure module to azure.azcollection

Replace deprecated azure_rm_deployment module with FQCN:
- azure_rm_deployment → azure.azcollection.azure_rm_deployment

Changes:
- Add azure.azcollection (>=3.0.0) to requirements.yml
- Update roles/cloud-azure/tasks/main.yml to use FQCN

No parameter changes needed - the collection module supports all
existing parameters via aliases (deployment_name, resource_group_name,
client_id, secret, tenant, subscription_id).

Closes #14904

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Fix trailing comma in Azure deployment template

Remove invalid trailing comma in outputs section (line 222).
This was a pre-existing JSON syntax error.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
2025-11-28 17:50:49 -05:00
42aa65da00 Migrate Linode and DigitalOcean modules to Ansible collections (#14908)
Replace custom modules with official Ansible collection equivalents:
- linode_v4 → linode.cloud.instance
- linode_stackscript_v4 → linode.cloud.stackscript
- digital_ocean_floating_ip → community.digitalocean.digital_ocean_floating_ip

Changes:
- Add linode.cloud and community.digitalocean to requirements.yml
- Update roles/cloud-linode/tasks/main.yml (FQCN + api_token param)
- Update roles/cloud-digitalocean/tasks/main.yml (FQCN)
- Remove 3 entries from .ansible-lint mock_modules
- Delete 3 custom modules (519 lines removed)

Modules kept (no collection equivalent or deferred):
- x25519_pubkey.py - crypto-specific, no equivalent
- scaleway_compute.py - complex state machine, deferred
- lightsail_region_facts.py - no collection equivalent
- gcp_compute_location_info.py - no equivalent, google.cloud deprecated

Closes #14902

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude <noreply@anthropic.com>
2025-11-28 17:39:11 -05:00
f4e2b8c9e7 Phase 1: Quick wins for code quality and test infrastructure (#14907)
- Replace ignore_errors: true with failed_when: false in 5 files
  (main.yml, users.yml, ubuntu.yml, umount.yml, test-wireguard-real-async.yml)
- Add pytest.ini configuration for test discovery
- Add tests/conftest.py with shared fixtures and mock helpers

The failed_when: false pattern is preferred by ansible-lint as it
explicitly indicates expected failure handling rather than silently
ignoring all errors.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude <noreply@anthropic.com>
2025-11-28 17:02:17 -05:00
ff4b853fa8 Refactor CLAUDE.md: add quality gates, reduce redundancy (#14901)
* Refactor CLAUDE.md: add quality gates, reduce redundancy

Analyzed the last 25 PRs to identify patterns where better guidance
could have prevented iteration. Key findings:
- PRs had lint failures caught after submission
- with_items→loop conversions broke list flattening
- Missing input validation and explicit file modes
- Duplicate DNS documentation in 3 places

Changes:
- Add Quality Gates section with mandatory pre-submission checks
- Add Design Requirements checklist (validate inputs, explicit modes)
- Add Ansible Pitfalls section (with_items vs loop, path variables)
- Add Self-Review Checklist
- Consolidate DNS architecture from 3 sections into 1
- Remove redundant sections (Final Notes, User Profiles, duplicate philosophy)
- Condense linting rules into table format

Result: 496 → 307 lines (-38%) while adding actionable new guidance

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Add Jinja2 native mode guidance (Ansible 12 compatibility)

Analysis of PRs 26-50 revealed that 28% (7 PRs) were fixing Ansible 12
compatibility issues caused by jinja2_native mode being always enabled.

Added guidance for:
- Boolean conditionals requiring actual booleans
- No nested templates in lookup()
- JSON files needing explicit | from_json parsing
- default() not triggering on empty strings (need true param)
- Complex Jinja loops breaking in set_fact

Also added "Undocumented workarounds" to What to Avoid section based on
Scaleway/Vultr upstream module bug patterns.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Fix Ansible version and add OpenSSL explanation

- Update Ansible version from "v9.x" to "v12+" for consistency
  with Jinja2 native mode guidance
- Add one-line explanation to OpenSSL snippet for clarity

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Soften language and add troubleshooting cross-reference

- Remove "CRITICAL" and "Critical Gotcha" labels
- Change "90% of routing issues are DNS" to "Many routing issues"
- Add link to docs/troubleshooting.md for comprehensive diagnostics

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Clarify 'verify before encoding' philosophy statement

Change ambiguous "Verify before encoding" (encoding could mean data
encoding) to clearer "Test assumptions - run the code before committing"

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
2025-11-28 16:35:48 -05:00
10de344c5c Fix Docker --cap-drop=all and add multi-arch support (#14900)
* Fix Docker --cap-drop=all and add multi-arch support

Fixes #14899

## Bug Fix: CAP_DROP_ALL Permission Denied

The `chown -R algo:algo /algo` line added in commit 2ab57c3 broke
`--cap-drop=all` functionality. When running as root with all
capabilities dropped, root loses CAP_DAC_OVERRIDE and cannot write
to files owned by other users.

The fix removes the unnecessary chown since:
- Container runs as USER root
- algo-docker.sh writes to /algo/config.cfg at runtime
- /algo must be root-owned for --cap-drop=all to work

## Multi-arch Support

The Docker image was only built for linux/amd64. Added:
- QEMU setup for ARM emulation
- Docker Buildx for multi-platform builds
- platforms: linux/amd64,linux/arm64

This enables native support for Apple Silicon Macs.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Update Docker actions to latest versions

- setup-qemu-action: v3.6.0 → v3.7.0
- setup-buildx-action: v3.10.0 → v3.11.1

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
2025-11-28 15:21:53 -05:00
a30df0c7eb Add explicit confirmation for local installation (#14897)
Enhance the local installation warning to require typing 'yes' to
proceed, making risks impossible to miss. Users following external
tutorials often don't see the documentation warning until after
their server is already modified.

Changes:
- Replace press-ENTER prompt with explicit 'yes' confirmation
- List specific consequences (firewall, DNS, no uninstall)
- Add local_install_confirmed variable for automation
- Document skip method in deploy-to-ubuntu.md

Closes #14362

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude <noreply@anthropic.com>
2025-11-28 05:27:29 -05:00
a6bd2a215e Remove obsolete troubleshooting entries (#14896)
* Remove obsolete troubleshooting entries

Remove 3 troubleshooting entries that are no longer relevant:

1. DigitalOcean: error tagging resource
   - Fixed in 2018 when tagging was moved to droplet creation
   - The separate tagging step that caused this error no longer exists

2. Docker: Failed to connect to the host via ssh
   - 6+ years old workaround for control_path_dir
   - Modern Docker deployments don't exhibit this issue
   - The workaround was never added to ansible.cfg

3. Ubuntu Error: unable to write 'random state'
   - OpenSSL 3.x (Ubuntu 22.04) doesn't use .rnd files
   - Algo now uses Ansible community.crypto modules instead of
     shell openssl commands

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Reorganize Installation Problems section by category

Group related troubleshooting entries for easier navigation:

- General Setup: Python, Ansible, SSL certs, SSH permissions
- Cloud Providers: Region availability, AWS (3), Azure (2), Linode (1)
- Windows: WSL keyData issue, VPN connection error
- Local Deployment: Symlinks, WireGuard configs
- Network: Firewall timeout

Moves Linode stackscript issue to be grouped with other cloud providers
instead of at the end of the section.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
2025-11-28 05:18:20 -05:00
59ee7585ec Add diagnostic commands section to troubleshooting guide (#14895)
Add a new 'Diagnostic Commands' section to help users investigate issues
themselves. Includes:

- Config options to enable verbose logging (algo_no_log, strongswan_log_level,
  privacy_enhancements_enabled)
- Server-side diagnostics for WireGuard, IPsec/StrongSwan, and DNS
- Log viewing commands (journalctl, dmesg)
- Network and firewall diagnostic commands
- Client-side diagnostics for macOS, Linux, and Windows

Closes #514

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude <noreply@anthropic.com>
2025-11-28 05:02:14 -05:00
cfda275a20 Simplify codebase: modernize loops, split templates, improve CI (#14891)
* Simplify codebase: remove dead venv files, consolidate loops, modernize patterns

- Delete 8 empty venv.yml files that were remnants of pyproject.toml migration
- Remove corresponding import_tasks references from cloud provider main.yml files
- Consolidate server.yml async polling from 4 copy-paste blocks to 1 loop
- Wrap sequential VPN service imports in a block with single when condition
- Replace deprecated with_indexed_items with modern loop/loop_control syntax

These changes reduce maintenance burden by:
- Eliminating 8 files that served no purpose
- Reducing server.yml by ~20 lines while improving readability
- Removing Ansible deprecation warnings for with_indexed_items
- Making the parallel/sequential execution paths easier to maintain

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Fix template variable and undefined job variable bugs

- Fix client.conf.j2 to use `item` instead of `item.1` to match modern
  loop syntax (loop with index_var instead of with_indexed_items)
- Fix server.yml _vpn_jobs to use `| default({})` for job variables
  that may be undefined when running with tags (e.g., IPsec-only)
- Update test_template_rendering.py to pass item as string instead of
  tuple, matching the new loop behavior

Fixes CI failures from PR #14891 that were correctly identified by the
Claude Code bot review.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
2025-11-28 04:57:06 -05:00
ba7297268a Simplify codebase: modernize loops, split templates, improve CI (#14889)
* Simplify codebase: modernize loops, split templates, improve CI

This PR consolidates several simplification phases:

## Ansible Modernization
- Modernize `with_items` to `loop` across ~50 task files
- Add OS detection facts (is_ubuntu, os_family_lowercase)
- Condense inline YAML syntax where appropriate

## Template Splitting
- Split 568-line dnscrypt-proxy.toml.j2 into focused partials:
  - global.toml.j2 (core settings)
  - sources.toml.j2 (resolver sources)
  - filters.toml.j2 (blocking rules)
  - cache.toml.j2 (caching config)

## CI Workflow Improvements
- Create setup-algo composite action for shared CI setup
- Re-enable integration tests with health checks
- Fix smart-tests.yml silent lint failures (remove || true)
- Use env variables for GitHub SHAs (security)

## server.yml Async Simplification
- Reorganize VPN service configuration with clear sections
- Add performance_parallel_services toggle
- Simplify status display from json_query to inline conditionals
- Keep services explicit for readability

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Fix with_items to loop conversion: preserve list flattening

with_items automatically flattens nested lists, but loop does NOT.
The mechanical conversion broke iteration over list variables.

Wrong:
  loop:
    - "{{ users }}"  # ['alice', 'bob'] treated as ONE item

Fixed:
  loop: "{{ users }}"  # Iterates over alice, bob correctly

For combined lists (users + server):
  loop: "{{ users + [IP_subject_alt_name] }}"

Fixes IPsec certificate generation creating files named literally
'['alice', 'bob'].key' instead of separate alice.key and bob.key.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Fix integration test: use strongswan-starter service name on Ubuntu 20.04+

The StrongSwan service is named 'strongswan-starter' on Ubuntu 20.04+,
not 'strongswan'. The test was checking the wrong service name, causing
false failures even when StrongSwan was actually running.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Fix IPsec path issues: remove trailing slashes and fix test paths

1. Remove trailing slashes from ipsec_config_path and ipsec_pki_path
   in roles/strongswan/defaults/main.yml (causes double slashes)

2. Fix integration test to check correct subdirectories:
   - .p12 files are in ipsec/manual/
   - .mobileconfig files are in ipsec/apple/

3. Fix strongswan service name check (strongswan-starter on Ubuntu 20.04+)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
2025-11-28 04:28:59 -05:00
0d5793d05d Add FAQ about migrating clients to a new Algo server (#14890)
Addresses a long-standing user question about whether existing VPN
clients can be migrated when deploying a new Algo server. The answer:
technically possible but rarely worth it, since servers auto-update
their VPN software anyway.

Closes #1538

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude <noreply@anthropic.com>
2025-11-28 04:25:05 -05:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
4dad4cfd9a chore(deps): bump docker/metadata-action from 5.9.0 to 5.10.0 (#14887)
Bumps [docker/metadata-action](https://github.com/docker/metadata-action) from 5.9.0 to 5.10.0.
- [Release notes](https://github.com/docker/metadata-action/releases)
- [Commits](https://github.com/docker/metadata-action/compare/318604b99e75e41977312d83839a89be02ca4893...c299e40c65443455700f0fdfc63efafe5b349051)

---
updated-dependencies:
- dependency-name: docker/metadata-action
  dependency-version: 5.10.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-28 03:41:05 -05:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
fa40d7e611 chore(deps): bump actions/checkout from 4.3.1 to 6.0.0 (#14888)
Bumps [actions/checkout](https://github.com/actions/checkout) from 4.3.1 to 6.0.0.
- [Release notes](https://github.com/actions/checkout/releases)
- [Commits](https://github.com/actions/checkout/compare/v4.3.1...v6)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: 6.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-28 03:40:22 -05:00
2bbb750f1b Skip wait_for_connection for local deployments (#14886)
The wait_for_connection task hangs in certain Docker environments when
using the local provider because Ansible's local connection plugin
doesn't implement the reset method, causing the warning "Reset is not
implemented for this connection" and potential indefinite hangs.

This change adds a condition to skip the task for localhost connections,
following the same pattern used elsewhere in the codebase (e.g., the SSH
wait task on line 40 and the wait_for_connection in ubuntu.yml).

The task is unnecessary for localhost since it always completes instantly
(elapsed: 0) - localhost is always reachable.

Fixes #14627

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude <noreply@anthropic.com>
2025-11-28 02:25:37 -05:00
60f1cca03b Fix ansible-lint failures and code review sticky comments (#14885)
* Fix ansible-lint failures and improve linting configuration

This PR eliminates all ansible-lint failures (9 → 0) and reduces warnings
(25 → 20). The remaining warnings are yaml[line-length] which are
intentionally in the warn_list.

Changes:

1. GitHub workflow YAML compliance
   - Add document start markers (---)
   - Quote 'on:' key (YAML truthy value)

2. Replace ignore_errors with failed_when
   - privacy/clear_history.yml: Use failed_when: false instead of
     ignore_errors for tasks that may fail on clean systems

3. Use apt module instead of shell
   - privacy/auto_cleanup.yml: Replace apt-get shell command with
     proper apt module (autoclean: true)

4. Add changed_when to handlers and tasks
   - Handlers always run due to notifications, so changed_when: false
     is appropriate for read-only operations
   - Check commands that only read state get changed_when: false
   - Reboot task gets changed_when: true (it actually changes state)

5. Configure ansible-lint for project structure
   - Exclude CloudFormation templates (roles/cloud-*/files/) which use
     AWS-specific YAML tags (!Equals, !GetAtt) that ansible-lint
     cannot parse
   - Add mock_modules for custom modules in library/ directory that
     ansible-lint cannot auto-discover during static analysis
     See: https://github.com/ansible/ansible-lint/discussions/1353

6. Fix Jinja2 spacing
   - Remove extraneous whitespace in multi-line Jinja expressions
   - Fix spacing before closing parentheses

References:
- ansible-lint mock_modules: https://ansible.readthedocs.io/projects/lint/configuring/
- Custom module discovery issue: https://github.com/ansible/ansible-lint/discussions/1353
- Ansible local modules: https://docs.ansible.com/ansible/latest/dev_guide/developing_locally.html

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Workaround sticky comment bug in claude-code-action

The use_sticky_comment feature is broken in claude-code-action v1.
This adds instructions for Claude to minimize its old comments as
OUTDATED before posting new reviews, preventing comment clutter.

Also adds gh api to allowed tools for the GraphQL mutation.

See: https://github.com/anthropics/claude-code-action/issues/419

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
2025-11-28 02:06:59 -05:00
9515e7ee3a Remove unused FreeBSD/BSD support code (#14884)
Algo focuses exclusively on Ubuntu LTS. Remove dead code for BSD support
that was never fully implemented:

- Remove roles/common/tasks/bsd_ipv6_facts.yml (unused file)
- Remove BSD handlers (restart ipfw, restart loopback bsd)
- Remove FreeBSD compatibility claim from privacy README
- Remove BSD loopback mock from integration tests

The FAQ entries about OpenBSD are kept as they explain why BSD is NOT
supported (historical context about IPSEC).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude <noreply@anthropic.com>
2025-11-28 01:27:16 -05:00
a7b9b61265 Fix update-users: DNS IP, reboots, key regeneration, and local permissions (#14883)
* Fix DNS IP changing after running update-users

The local_service_ip variable is generated using a deterministic random
formula seeded by algo_server_name + ansible_fqdn. While algo_server_name
is persisted in .config.yml, ansible_fqdn is a runtime fact gathered from
the target host that can change if:

- Server's hostname configuration changes
- DNS resolution changes
- User runs ansible from a different control machine

When ansible_fqdn differs between initial deployment and users.yml, a
different local_service_ip is generated, causing new client configs to
point to a DNS IP that doesn't exist on the server.

This fix persists local_service_ip and local_service_ipv6 in .config.yml
during initial deployment, ensuring users.yml uses the correct DNS IP.

Fixes #14614

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Skip apt upgrade and reboot during update-users

Previously, running `./algo update-users` would trigger a full apt upgrade
and potentially reboot the server because ubuntu.yml was tagged with
`update-users`. This caused unexpected disconnections for all VPN clients
(gaming, downloads, etc.) during what should be a simple user management
operation.

Now only facts.yml runs during update-users, which provides the necessary
password facts for IPsec certificate generation without running apt upgrade
or triggering reboots.

Fixes #14518

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Add keys_clean_all support to WireGuard (parity with IPsec)

Previously, WireGuard had no option to force credential regeneration for
existing users. The keys_clean_all option only affected IPsec certificates.

Now WireGuard respects keys_clean_all the same way IPsec does:
- keys_clean_all: false (default) - preserve existing keys, only generate
  for new users
- keys_clean_all: true - delete all keys and regenerate for all users

Also improved the config.cfg documentation to clarify this option affects
both WireGuard and IPsec credentials.

Fixes #14610

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Add permission check for local deployment update-users

For local deployments, file ownership must be consistent between initial
deployment and subsequent update-users runs. When there's a mismatch
(e.g., initial deployment without sudo, update with sudo), files get
mixed ownership causing permission errors.

This adds a pre-flight check that:
- Detects local deployments (localhost or algo_provider: local)
- Compares config directory owner with current user
- Displays a warning with guidance if there's a mismatch
- Provides the exact chown command to fix permissions

Addresses #14551

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Address review feedback: explicit directory modes and clearer docs

- Add explicit mode to WireGuard directory creation in main.yml:
  - PKI directories (preshared, private, public): 0700
  - Config directories (apple/ios, apple/macos): 0755

- Enhance config.cfg keys_clean_all comment to clarify:
  - When false: new users added (not just preserved)
  - When true: ALL CLIENTS MUST RECONFIGURE (explicit impact warning)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Address review: fail on permission mismatch, clean up directory creation

1. Permission check now FAILS instead of warning
   - Prevents continuing with mismatched permissions
   - Provides clear fix command: sudo chown -R <user> configs/<server>/
   - Simpler condition: just compare owner with current user

2. Clean separation of directory creation
   - main.yml: Only config directories (apple/ios, apple/macos) with 0755
   - keys.yml: Only PKI directories (preshared, private, public) with 0700
   - Eliminates duplication and clarifies responsibility

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Address review: add empty users validation and improve docs

1. Add empty users list validation
   - Fails early with clear message if no users defined in config.cfg
   - Prevents confusing downstream errors

2. Improve config.cfg keys_clean_all documentation
   - Add example use cases: key compromise, removing untrusted users, security audit

3. Rename block for clarity
   - "Check local deployment permissions" → "Local deployment permission validation"

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Fix jinja2 spacing lint warning

Remove extra spaces inside brackets in Jinja2 expression per ansible-lint
jinja[spacing] rule.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
2025-11-28 01:19:36 -05:00
152440ff3c Remove unused pyopenssl and boto dependencies (#14882)
- Remove pyopenssl from core dependencies: community.crypto 3.0.3
  removed pyopenssl backend from ALL modules, now uses only
  cryptography library
- Remove boto from AWS optional dependencies: Algo only uses
  boto3/botocore (library/lightsail_region_facts.py confirms this),
  and amazon.aws collection requires only boto3>=1.34.0

Verified by:
- Code search confirming no imports of pyopenssl or old boto
- Runtime tests in isolated environments without these packages
- All 101 unit tests passing
- Ansible playbook syntax checks passing

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude <noreply@anthropic.com>
v2.0.1
2025-11-27 14:50:38 -05:00
2662c5efc3 Add pre-flight SSH connectivity check before update-users (#14881)
When running ./algo update-users, if the server is unreachable, users
previously saw cryptic Ansible SSH retry errors like:

    ssh_retry: attempt: 3, ssh return code is 255

This adds a pre-flight check that tests SSH connectivity before running
the full playbook. If the connection fails, it provides a helpful error
message with:
- Clear explanation of what failed
- Possible causes (server not running, IP changed, firewall blocking)
- Diagnostic commands to run (nc, ssh -vvv)

Fixes #14878

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude <noreply@anthropic.com>
2025-11-27 14:49:45 -05:00
3e62871e6c Add missing ansible.utils collection to requirements.yml (#14880)
The ansible.utils.ipmath filter is used in config.cfg and WireGuard
templates but the collection was not listed in requirements.yml.
This causes 'No filter named ipmath' errors for users who install
ansible-core separately rather than the full ansible package.

Fixes #14879

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude <noreply@anthropic.com>
2025-11-27 14:34:04 -05:00
Florian KinderandGitHub 38e87c2f5a Fix Vultr startup script JSON serialization issues (#14853)
* Fix Vultr startup script JSON serialization error

The startup_script module was failing with "Object of type 'bytes' is not
JSON serializable" because the lookup('template', ...) was returning bytes
instead of a string.

Added | string filter to explicitly convert the template result to a
string, matching the pattern used by the DigitalOcean cloud provider.

Also simplified from multiline block format to inline format for
consistency with other cloud providers.

Fixes the error: "Object of type 'bytes' is not JSON serializable by the
'tagless' profile."

* Add string filters to template lookups in cloud-init base template

Added | string filters to lookup() calls in the cloud-init base template
to ensure consistent string handling across all cloud providers.

The Vultr startup_script module requires all values to be JSON-serializable
strings, and lookup() can return bytes in some contexts. This change ensures
that both the SSH config template lookup and the SSH public key file lookup
explicitly return strings.

This is a defensive fix that improves compatibility with strict JSON
serialization requirements in some Ansible modules, while remaining
backward compatible with existing cloud providers.

Related to: vultr.cloud.startup_script JSON serialization requirements

* Use two-step fact assignment for Vultr startup script

Changed to set the cloud-init script as a fact first, then reference
that fact in the startup_script module. This follows the pattern used
by the Linode provider and avoids JSON serialization issues with nested
template lookups.

This approach ensures the template is fully evaluated and stored as a
string before being passed to the vultr.cloud.startup_script module,
which then base64-encodes it for the API.

Related to: JSON serialization with "tagless" profile in Ansible 2.19+
2025-11-27 13:42:26 -05:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
5655bcda75 chore(deps): bump boto3 from 1.40.3 to 1.41.5 (#14876)
Bumps [boto3](https://github.com/boto/boto3) from 1.40.3 to 1.41.5.
- [Release notes](https://github.com/boto/boto3/releases)
- [Commits](https://github.com/boto/boto3/compare/1.40.3...1.41.5)

---
updated-dependencies:
- dependency-name: boto3
  dependency-version: 1.41.5
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-27 13:37:07 -05:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
7148faaa8a chore(deps): bump azure-identity from 1.23.1 to 1.25.1 (#14877)
Bumps [azure-identity](https://github.com/Azure/azure-sdk-for-python) from 1.23.1 to 1.25.1.
- [Release notes](https://github.com/Azure/azure-sdk-for-python/releases)
- [Changelog](https://github.com/Azure/azure-sdk-for-python/blob/main/doc/esrp_release.md)
- [Commits](https://github.com/Azure/azure-sdk-for-python/compare/azure-identity_1.23.1...azure-identity_1.25.1)

---
updated-dependencies:
- dependency-name: azure-identity
  dependency-version: 1.25.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-27 13:36:52 -05:00
dependabot[bot]andGitHub e0b5cf8608 chore(deps): bump actions/checkout from 4 to 6 (#14875) 2025-11-27 13:06:23 -05:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
44d9c4ab56 chore(deps): bump hcloud from 2.5.4 to 2.11.1 (#14870)
Bumps [hcloud](https://github.com/hetznercloud/hcloud-python) from 2.5.4 to 2.11.1.
- [Release notes](https://github.com/hetznercloud/hcloud-python/releases)
- [Changelog](https://github.com/hetznercloud/hcloud-python/blob/main/CHANGELOG.md)
- [Commits](https://github.com/hetznercloud/hcloud-python/compare/v2.5.4...v2.11.1)

---
updated-dependencies:
- dependency-name: hcloud
  dependency-version: 2.11.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-26 13:30:19 -05:00