18 cloud lib/common.sh files had identical 7-line get_server_name()
functions (get_resource_name + validate_server_name + echo). Added a
shared get_validated_server_name helper to shared/common.sh and replaced
all duplicates with one-line delegations. Net -110 lines.
Agent: complexity-hunter
Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
~1500 progress messages across 481 files were using log_warn (yellow)
for normal status updates like "Installing...", "Setting up...",
"Creating server...", etc. This made users think something was wrong
when everything was proceeding normally.
Changes:
- Replace log_warn with log_step for all progress/status messages
- Keep log_warn only for actual warnings (errors, remediation hints)
- Remove emoji from 3 sprite completion messages
Agent: ux-engineer
Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Add a generic ensure_multi_credentials() helper to shared/common.sh that
handles the env-var/config-file/prompt/test/save flow for providers needing
multiple credentials. This eliminates ~270 lines of duplicated logic across
contabo, netcup, ramnode, ionos, and upcloud, replacing it with single
function calls.
Each provider's ensure_*_credentials() function is now 3-8 lines instead
of 30-65 lines.
Agent: complexity-hunter
Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
IONOS: Replace hand-rolled curl calls with generic_cloud_api_custom_auth,
eliminating the duplicated GET/DELETE vs POST branch and adding retry
logic that was previously missing.
Scaleway: Extract duplicated Python image-lookup into _scaleway_pick_ubuntu_image
helper and consolidate the two-pass search into a loop, reducing
get_ubuntu_image_id from 47 to 18 lines.
Agent: complexity-hunter
Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Haiku 4.5 <noreply@anthropic.com>
Extract focused helpers from the most complex functions in ionos/lib/common.sh
and upcloud/lib/common.sh to reduce line count and nesting depth.
IONOS (3 functions refactored):
- _ionos_create_boot_volume: 60 -> 24 lines (extracted _ionos_build_volume_body and _ionos_wait_for_volume)
- ensure_datacenter: 56 -> 18 lines (extracted _ionos_find_existing_datacenter and _ionos_create_datacenter)
- ensure_ionos_credentials: 47 -> 24 lines, max nesting 16 -> 8 (extracted _ionos_load_config_credentials and _ionos_prompt_credentials)
UpCloud (1 function refactored):
- ensure_upcloud_credentials: 57 -> 27 lines, max nesting 12 -> 8 (extracted _upcloud_load_config_credentials and _upcloud_prompt_credentials)
No behavior changes - pure refactoring with helper extraction and early returns.
Agent: complexity-hunter
Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Haiku 4.5 <noreply@anthropic.com>
Add ssh_run_server, ssh_upload_file, ssh_interactive_session, and
ssh_verify_connectivity to shared/common.sh. These four functions
were copy-pasted identically across 21 cloud provider lib files,
differing only in SSH username (root vs ubuntu).
Providers now set SSH_USER and delegate to the shared helpers via
one-line wrappers, reducing each provider's lib by ~20 lines.
Agent: complexity-hunter
Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The IONOS provider interpolated $IONOS_USERNAME and $IONOS_PASSWORD
directly into Python string literals when saving credentials, allowing
arbitrary code execution via crafted credential values containing
single quotes. Use json_escape + printf instead (matching the pattern
used by all other providers). Also validate IONOS_LOCATION format and
numeric env vars (IONOS_CORES, IONOS_RAM, IONOS_DISK_SIZE).
Agent: security-auditor
Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Budget European provider starting at $2/month for 1 vCore/1GB RAM
- REST API via CloudAPI v6 with Basic Auth (username + password)
- Datacenter-based resource organization (auto-creates if needed)
- Volume-based boot disks with cloud-init support
- Implemented 3 agents: claude, aider, goose
- 11 agents marked as missing for future implementation
Agent: cloud-scout-1
Co-authored-by: B <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>