How hostgator-setup-kit/install.sh Validates Environment Variables One at a Time

The script validates every environment variable individually using dedicated v_* validator functions wrapped in a recursive ask_one helper that repeats prompts until inputs pass strict format checks, API health tests, or database connectivity verification.

The hostgator-setup-kit/install.sh script in the melgarafael/DeskcommCRM repository implements a sequential, fail-fast validation pipeline for CRM configuration values. Rather than bulk-validating a .env file, it interrogates each variable—from domain names to Supabase credentials—through specialized Bash functions that enforce business rules and verify external connectivity before writing values to disk.

The Validation Architecture

Dedicated Validator Functions

Each configuration category defines a v_* function in hostgator-setup-kit/install.sh that receives raw user input, outputs localized Portuguese error messages on failure, and returns a non-zero exit code when validation fails. These functions act as atomic guards for specific data types:

  • v_domain (lines 73‑79) — Rejects URLs containing protocols or paths, accepting only bare hostnames (e.g., crm.suaempresa.com.br).
  • v_email (lines 82‑86) — Requires both an "@" symbol and a dot-separated domain.
  • v_hex (lines 2‑4) — Accepts empty strings or hash-prefixed six-digit hexadecimal codes for brand colors.
  • v_locale (lines 18‑24) — Restricts input to pt-BR, es, or their numeric aliases 1 and 2.
  • v_supabase_url (lines 27‑44) — Verifies the https:// scheme and performs a live HTTP request to the /auth/v1/health endpoint.
  • v_sb_key (lines 48‑65) — Parses JWT claims or the newer sb_* format, ensuring the key’s role matches expectations and belongs to the specified Supabase project.
  • v_db_url (lines 90‑41) — Validates the connection string scheme, removes placeholder passwords, confirms the host belongs to the same Supabase project, and executes a real psql check inside a temporary container.
  • v_anthropic (lines 43‑54) — Enforces the sk-ant- prefix and makes a test request to the Anthropic API.
  • v_openrouter (lines 56‑73) — Requires the sk-or- prefix and pings the OpenRouter endpoint.
  • v_openai (lines 76‑88) — Optional validation requiring the sk- prefix and live API verification.
  • v_password (lines 90‑94) — Enforces a minimum length of eight characters.

The ask_one Control Loop

The core interaction logic resides in the ask_one function (lines 96‑100). This helper accepts a prompt string and a validator function name, then implements a repeat-until-valid loop:

  1. Displays the prompt and captures user input.
  2. Invokes the specified v_* validator with the raw value.
  3. If the validator returns non-zero, prints the error message and recurses.
  4. If the user types voltar (Portuguese for "back"), returns exit code 2 to signal navigation to a previous step.
  5. On success, returns 0 and stores the cleaned value.

Validator Implementation Details

Domain and Format Validators

Simple format validators perform pattern matching without external network calls. For example, v_domain explicitly rejects strings containing http or forward slashes, printing:

"Dige só o domínio, sem https:// — ex.: crm.suaempresa.com.br"

Similarly, v_hex uses regex to ensure color codes match ^#[0-9a-fA-F]{6}$ or are empty, preventing invalid CSS values from entering the configuration.

Supabase Ecosystem Validation

The script performs deep validation on Supabase credentials to prevent runtime connection failures:

v_supabase_url validates the URL format and performs a synchronous HTTP health check:


# Conceptual implementation based on lines 27-44

v_supabase_url() {
  local url="$1"
  [[ "$url" =~ ^https:// ]] || { echo "URL deve começar com https://"; return 1; }
  curl -sf "${url}/auth/v1/health" >/dev/null || { echo "Supabase não responde"; return 1; }
}

v_sb_key (lines 48‑65) goes further by decoding the JWT payload to verify the role claim (e.g., anon or service_role) matches the expected key type, ensuring the user pasted the correct key for the intended permission level.

Database and Third-Party API Checks

High-risk variables like database URLs and paid API keys undergo live verification:

v_db_url (lines 90‑41) parses the PostgreSQL connection string, extracts the host, validates it belongs to the same Supabase project referenced earlier, and spawns a temporary container to execute psql -c "SELECT 1". This confirms both network reachability and credential validity before the installer proceeds.

API key validators follow a consistent pattern: prefix validation followed by authenticated ping. For instance, v_anthropic (lines 43‑54) checks for the sk-ant- prefix, then submits a minimal request to the Anthropic API to verify quota and key validity.

Interactive vs Non-Interactive Modes

When executed with the --yes flag, the script enters non-interactive mode and reads an existing .env file. Rather than prompting, it iterates over the same v_* validators automatically:


# Non-interactive validation pattern from the source

for var in DOMAIN EMAIL SUPABASE_URL ANON_KEY DB_URL; do
  validator="v_${var,,}"
  value="${!var}"
  if ! "$validator" "$value"; then
    die "Valor inválido para $var – corrija o .env e rode novamente."
  fi
done

If any validator fails, the script aborts immediately with a clear error message, forcing the operator to correct the .env file before retrying. This guarantees that the same strict validation applies in both interactive and automated deployments.

Practical Usage Examples

Interactive Setup

During normal installation, each variable is collected individually:


# From hostgator-setup-kit/install.sh

ask_one "Qual domínio (ex.: crm.suaempresa.com.br)?" v_domain
ask_one "E-mail do admin?" v_email
ask_one "Cor da marca (ex.: #7a5cd6)?" v_hex
ask_one "URL do Supabase (ex.: https://abcd.supabase.co)?" v_supabase_url
ask_one "Chave anon do Supabase?" v_anon
ask_one "Chave service_role do Supabase?" v_service
ask_one "Connection string do Postgres?" v_db_url
ask_one "Chave Anthropic?" v_anthropic
ask_one "Chave OpenRouter?" v_openrouter
ask_one "Chave OpenAI (opcional)?" v_openai
ask_one "Senha do admin (mínimo 8 caracteres)?" v_password

If a user enters https://example.com for the domain, v_domain returns 1, prints the protocol error, and ask_one repeats the prompt until a bare hostname is provided.

Extending Validation

To add a validator for a new variable, define a v_* function returning 0 for success or 1 for failure, then invoke it via ask_one:

v_slack_webhook() {
  local url="$1"
  [[ "$url" =~ ^https://hooks.slack.com/ ]] || { echo "URL do Slack inválida"; return 1; }
  curl -sf "$url" -X POST -d '{"text":"test"}' >/dev/null || { echo "Webhook não responde"; return 1; }
}

ask_one "Webhook do Slack?" v_slack_webhook

Summary

  • Atomic validators: Each environment variable has a dedicated v_* function in hostgator-setup-kit/install.sh (lines 2‑94) enforcing type-specific rules, from regex patterns to live API health checks.
  • Recursive prompting: The ask_one helper (lines 96‑100) isolates validation logic from user interaction, looping until inputs pass or the user triggers the back navigation (voltar).
  • Dual-mode operation: The same validation suite runs in both interactive mode (prompting) and non-interactive mode (--yes flag reading existing .env files), ensuring consistency across manual and automated deployments.
  • External verification: High-value credentials (Supabase URLs, database connections, Anthropic/OpenAI keys) undergo real network validation to catch typos and permission errors before deployment.

Frequently Asked Questions

How does the script handle invalid input during interactive setup?

When a v_* validator returns a non-zero exit code, ask_one prints the validator’s Portuguese error message and recursively calls itself with the same prompt. This loop continues indefinitely until the user provides a valid value or types voltar to return to the previous question.

Can I run the installer without interactive prompts?

Yes. Executing install.sh --yes enables non-interactive mode, where the script reads an existing .env file and validates each value against the same v_* functions. If any validation fails, the script aborts with a descriptive error, requiring you to fix the .env before re-running.

What happens if I enter a valid-looking Supabase URL that is unreachable?

The v_supabase_url function (lines 27‑44) performs a live curl request to the /auth/v1/health endpoint. If the host is down, returns a non-200 status, or the SSL handshake fails, the validator prints an error and ask_one repeats the prompt, preventing you from proceeding with a broken configuration.

How do the validators distinguish between the anon and service_role Supabase keys?

The v_sb_key function (lines 48‑65) decodes the JWT payload to inspect the role claim. It validates that the key’s embedded role matches the expected type (e.g., anon vs service_role) and verifies the project identifier within the key matches the previously validated SUPABASE_URL, ensuring cryptographic isolation between environments.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →