#!/bin/bash set -euo pipefail # Database Gateway runtime setup: # 1. wait for the Cloudron postgresql addon (storage for profiles/bookmarks/ # query results) # 2. seed /app/data/config.json + /app/data/opa/ on first run # 3. apply the embedded schema migrations (migrate-up) # 4. exec the gateway (web UI + LRPC API on 0.0.0.0:8080) CONFIG_PATH="/app/data/config.json" OPA_DIR="/app/data/opa" COOKIE_SECRET_PATH="/app/data/.cookie_secret" # --- 1. wait for PostgreSQL ------------------------------------------------- DB_HOST=${CLOUDRON_POSTGRESQL_HOST:-127.0.0.1} DB_PORT=${CLOUDRON_POSTGRESQL_PORT:-5432} DB_NAME=${CLOUDRON_POSTGRESQL_DATABASE:-dbgw} DB_USER=${CLOUDRON_POSTGRESQL_USERNAME:-dbgw} DB_PASSWORD=${CLOUDRON_POSTGRESQL_PASSWORD} echo "Waiting for PostgreSQL at ${DB_HOST}:${DB_PORT} ..." until PGPASSWORD="${DB_PASSWORD}" psql -h "${DB_HOST}" -p "${DB_PORT}" -U "${DB_USER}" -d "${DB_NAME}" -c '\q' >/dev/null 2>&1; do echo "PostgreSQL is unavailable - sleeping" sleep 2 done echo "PostgreSQL is up" # --- 2. seed persistent configuration --------------------------------------- # Persistent cookie secret (rotating it would invalidate live sessions). if [[ ! -f "${COOKIE_SECRET_PATH}" ]]; then umask 077 openssl rand -hex 32 > "${COOKIE_SECRET_PATH}" echo "Generated new cookie secret" fi COOKIE_SECRET=$(cat "${COOKIE_SECRET_PATH}") # Default OPA policy: Cloudron "admins" see every target and may run any op; # everyone else is denied until an operator extends the policy. Edit with the # Cloudron file manager; changes apply on restart. mkdir -p "${OPA_DIR}" if [[ ! -f "${OPA_DIR}/simple.rego" ]]; then cat > "${OPA_DIR}/simple.rego" <<'EOF' package gateway # Default Cloudron policy: the admins group is unrestricted; everyone else # is denied until an operator edits this file (input.subjects contains # user: and role: principals). default allow_target := false default allow_query := false allow_target if { "role:admin" in input.subjects } allow_query if { "role:admin" in input.subjects } EOF echo "Seeded default OPA policy at ${OPA_DIR}/simple.rego" fi # Seed the app config once (jq handles escaping of secrets into JSON). OIDC # comes from the Cloudron platform identity provider; targets (the databases # this gateway may reach) are added by the operator by editing # ${CONFIG_PATH} with the Cloudron file manager. if [[ ! -f "${CONFIG_PATH}" ]]; then jq -n \ --arg db_host "${DB_HOST}" \ --arg db_name "${DB_NAME}" \ --arg db_user "${DB_USER}" \ --arg db_password "${DB_PASSWORD}" \ --argjson db_port "${DB_PORT}" \ --arg issuer "${CLOUDRON_OIDC_ISSUER}" \ --arg client_id "${CLOUDRON_OIDC_CLIENT_ID}" \ --arg client_secret "${CLOUDRON_OIDC_CLIENT_SECRET}" \ --arg origin "${CLOUDRON_APP_ORIGIN}" \ --arg cookie_secret "${COOKIE_SECRET}" \ --arg opa_dir "${OPA_DIR}" \ '{ targets: [], users: { client_id: $client_id, client_secret: $client_secret, issuer_url: $issuer, redirect_url: ($origin + "/auth/callback"), scopes: ["openid", "profile", "email", "groups"], role_claim: "groups", role_mapping: { admins: "admin", users: "user" } }, policy: { path: $opa_dir }, facade: { port: 8080, cookie_secret: $cookie_secret, unsafe_cors_allow_all: false }, storage: { host: $db_host, port: $db_port, database: $db_name, username: $db_user, password: $db_password, use_ssl: false, max_pool_size: 16 } }' > "${CONFIG_PATH}" chmod 600 "${CONFIG_PATH}" echo "Seeded config at ${CONFIG_PATH}" fi # --- 3. migrations ----------------------------------------------------------- echo "Applying database migrations ..." /usr/local/bin/database-gateway -c "${CONFIG_PATH}" migrate-up # --- 4. run -------------------------------------------------------------------- echo "Starting Database Gateway on :8080 ..." exec /usr/local/bin/database-gateway -c "${CONFIG_PATH}" run