#!/usr/bin/env bash set -euo pipefail # Runtime dependency checker for selective-vpn-api. # Note: go.mod tracks only Go modules. External services/binaries are checked here. strict=0 if [[ "${1:-}" == "--strict" ]]; then strict=1 fi missing_required=0 warnings=0 ok() { printf 'OK %s\n' "$1"; } warn() { printf 'WARN %s\n' "$1"; warnings=$((warnings + 1)); } fail() { printf 'MISS %s\n' "$1"; missing_required=$((missing_required + 1)); } check_cmd_required() { local name="$1" if command -v "$name" >/dev/null 2>&1; then ok "cmd:$name" else fail "cmd:$name (required)" fi } check_cmd_optional() { local name="$1" if command -v "$name" >/dev/null 2>&1; then ok "cmd:$name" else warn "cmd:$name (optional)" fi } check_bin_required() { local path="$1" if [[ -x "$path" ]]; then ok "bin:$path" else fail "bin:$path (required)" fi } check_bin_optional_any() { local title="$1"; shift local found="" local p for p in "$@"; do if [[ -x "$p" ]]; then found="$p" break fi done if [[ -n "$found" ]]; then ok "bin:$title -> $found" else warn "bin:$title (optional)" fi } check_unit_required() { local unit="$1" if ! command -v systemctl >/dev/null 2>&1; then fail "unit:$unit (required, systemctl missing)" return fi if systemctl list-unit-files "$unit" --no-legend 2>/dev/null | grep -q "$unit"; then ok "unit:$unit" else fail "unit:$unit (required, not installed)" fi } check_unit_optional() { local unit="$1" if ! command -v systemctl >/dev/null 2>&1; then warn "unit:$unit (systemctl missing)" return fi if systemctl list-unit-files "$unit" --no-legend 2>/dev/null | grep -q "$unit"; then ok "unit:$unit" else warn "unit:$unit (optional, not installed)" fi } printf '== Core required ==\n' check_cmd_required systemctl check_cmd_required nft check_cmd_required ip check_cmd_required curl check_bin_required /usr/local/bin/adguardvpn-cli-root printf '\n== Core optional/recommended ==\n' check_cmd_optional nsenter check_cmd_optional wget check_cmd_optional ps check_cmd_optional ipset printf '\n== Transport binaries (optional by enabled client kind) ==\n' check_bin_optional_any sing-box /usr/local/bin/sing-box /usr/bin/sing-box check_bin_optional_any dnstt-client /usr/local/bin/dnstt-client /usr/bin/dnstt-client check_bin_optional_any phoenix-client /usr/local/bin/phoenix-client /usr/bin/phoenix-client printf '\n== Service units required for current production path ==\n' check_unit_required singbox@.service printf '\n== Service units optional by deployment profile ==\n' check_unit_optional adguardvpn-autoconnect.service check_unit_optional smartdns-local.service check_unit_optional selective-vpn2@.service check_unit_optional dnstt-client.service check_unit_optional phoenix-client.service check_unit_optional sing-box.service printf '\n== Summary ==\n' printf 'missing_required=%d warnings=%d\n' "$missing_required" "$warnings" if (( strict == 1 )); then if (( missing_required > 0 || warnings > 0 )); then exit 1 fi exit 0 fi if (( missing_required > 0 )); then exit 2 fi exit 0