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

> Discover how hostgator-setup-kit/install.sh validates environment variables individually. Learn about its recursive prompts and validation functions for robust setup.

- Repository: [Rafael Melgaço/DeskcommCRM](https://github.com/melgarafael/DeskcommCRM)
- Tags: how-to-guide
- Published: 2026-09-13

---

**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`](https://github.com/melgarafael/DeskcommCRM/blob/main/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`](https://github.com/melgarafael/DeskcommCRM/blob/main/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:

```bash
"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:

```bash

# 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:

```bash

# 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:

```bash

# 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`:

```bash
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`](https://github.com/melgarafael/DeskcommCRM/blob/main/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.