#!/usr/bin/env bash DEPLOY_CONTRACT_KEYS=( REMOTE_DIR REMOTE_ENV_FILE COMPOSE_FILE COMPOSE_PROJECT_NAME POSTGRES_DATA_DIR STORAGE_HOST_DIR ) deployment_contract_safe_ssh_target() { [[ "${1:-}" =~ ^([A-Za-z0-9._-]+@)?[A-Za-z0-9._-]+$ ]] } deployment_contract_safe_service() { [[ "${1:-}" =~ ^[A-Za-z0-9_.@-]+\.service$ ]] } deployment_contract_safe_absolute_path() { local value="${1:-}" [[ -n "$value" && "$value" == /* && "$value" =~ ^/[A-Za-z0-9._/-]+$ \ && "$value" != "/" && "$value" != */ && "$value" != *"//"* \ && "/$value/" != *"/../"* && "/$value/" != *"/./"* ]] } deployment_contract_safe_compose_file() { local value="${1:-}" [[ -n "$value" && "$value" != /* && "$value" =~ ^[A-Za-z0-9._/-]+$ \ && "/$value/" != *"/../"* && "/$value/" != *"/./"* ]] } deployment_contract_safe_project() { [[ "${1:-}" =~ ^[a-z0-9][a-z0-9_-]*$ ]] } deployment_contract_load() { local target="$1" local unit="$2" local destination_name="$3" local unit_environment key value local -n destination="$destination_name" destination=() deployment_contract_safe_ssh_target "$target" || return 1 deployment_contract_safe_service "$unit" || return 1 unit_environment="$(ssh "$target" "systemctl show '${unit}' -p Environment --value" 2>/dev/null)" \ || return 1 [[ -n "$unit_environment" ]] || return 1 for entry in $unit_environment; do key="${entry%%=*}" value="${entry#*=}" case "$key" in REMOTE_DIR|REMOTE_ENV_FILE|COMPOSE_FILE|COMPOSE_PROJECT_NAME|POSTGRES_DATA_DIR|STORAGE_HOST_DIR) destination["$key"]="$value" ;; esac done for key in "${DEPLOY_CONTRACT_KEYS[@]}"; do [[ -n "${destination[$key]:-}" ]] || return 1 done deployment_contract_safe_absolute_path "${destination[REMOTE_DIR]}" || return 1 deployment_contract_safe_absolute_path "${destination[REMOTE_ENV_FILE]}" || return 1 deployment_contract_safe_absolute_path "${destination[POSTGRES_DATA_DIR]}" || return 1 deployment_contract_safe_absolute_path "${destination[STORAGE_HOST_DIR]}" || return 1 deployment_contract_safe_compose_file "${destination[COMPOSE_FILE]}" || return 1 deployment_contract_safe_project "${destination[COMPOSE_PROJECT_NAME]}" || return 1 } deployment_contract_refresh_category() { local status="${1:-1}" local output="${2:-}" if [[ "$status" == "0" \ && "$output" == "[deployment-contract-refresh][PASS] refreshed" ]]; then printf 'success' return 0 fi case "$status" in 255) printf 'root_identity_unavailable' ;; 126|127) printf 'refresh_program_unavailable' ;; 43) printf 'timer_not_active' ;; 44) printf 'backup_mode_invalid' ;; 45) printf 'backup_timer_not_disabled' ;; *) printf 'unit_build_not_refreshed' ;; esac }