Moved duplicate get_cloud_init_userdata() function from all 4 cloud
provider common.sh files to shared/common.sh. This eliminates 60+ lines
of duplication and centralizes cloud-init configuration.
Changes:
- Added get_cloud_init_userdata() to shared/common.sh with detailed comments
- Removed duplicate function from hetzner/lib/common.sh
- Removed duplicate function from digitalocean/lib/common.sh
- Removed duplicate function from vultr/lib/common.sh
- Removed duplicate function from linode/lib/common.sh
- Added comment that clouds can override if needed
All tests pass (42 passed, 0 failed).
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Moved duplicate SSH_OPTS constant from all 4 cloud provider common.sh
files to shared/common.sh. This removes 4 lines of duplication and
centralizes SSH configuration.
Changes:
- Added SSH_OPTS to shared/common.sh with comment explaining clouds can override
- Removed SSH_OPTS from hetzner/lib/common.sh
- Removed SSH_OPTS from digitalocean/lib/common.sh
- Removed SSH_OPTS from vultr/lib/common.sh
- Removed SSH_OPTS from linode/lib/common.sh
All tests pass (42 passed, 0 failed).
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Created helper functions in shared/common.sh to simplify ensure_ssh_key():
- generate_ssh_key_if_missing(key_path): Generate SSH key if needed
- get_ssh_fingerprint(pub_path): Get MD5 fingerprint
- json_escape(string): JSON-escape strings for API bodies
Refactored ensure_ssh_key() in all cloud providers to use these helpers:
- Reduced function length from 35-52 lines to 24-28 lines
- Eliminated nested conditionals
- Made the code flow more linear and readable
- Centralized SSH key generation and fingerprint logic
Benefits:
- Single source of truth for SSH key operations
- Reduced code duplication (~40 lines per provider → 3 helper functions)
- Easier to maintain and test
- More consistent error handling
All tests pass (42/42).
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Created generic_ssh_wait() in shared/common.sh to eliminate ~100 lines
of duplicated waiting logic across all cloud providers.
Changes:
- Added generic_ssh_wait(ip, ssh_opts, test_cmd, description, max_attempts, interval)
to shared/common.sh
- Refactored verify_server_connectivity() in all clouds to use generic_ssh_wait
- Refactored wait_for_cloud_init() in all clouds to use generic_ssh_wait
Benefits:
- Single source of truth for SSH polling logic
- Consistent error messages across providers
- Reduced code duplication (~20 lines per provider → 2 lines)
- Easier to maintain and test
All tests pass (42/42).
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Improved bash safety by quoting numeric comparison variables:
- $elapsed and $timeout in OAuth timeout loop
- $server_pid in process cleanup (kill and wait)
This prevents potential word splitting and follows bash best practices
for variable quoting in numeric contexts.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Added validate_model_id() function to all common.sh files to prevent
command injection via user-supplied MODEL_ID values. MODEL_ID is used
in JSON configs, shell commands, and exported to remote systems, so
validation is critical.
Validation enforces that MODEL_ID contains only safe characters:
- Letters (a-z, A-Z)
- Numbers (0-9)
- Separators: / - _ : .
Rejects dangerous characters like backticks, $(), quotes, semicolons
that could be used for command injection.
Changes:
- Added validate_model_id() to all lib/common.sh files
- Added validation calls after MODEL_ID input in all agent scripts
- Tests pass for all sprite scripts
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>