Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,6 @@ civiform_config.sh
tmp/
nuke.yaml # this file is created by developers when working on the deployment system. see https://docs.civiform.us/contributor-guide/developer-guide/deploy-system/prerequisites#setup-aws-nuke
checkout/

# Generated per-sandbox configs (contain secrets)
configs/sandbox-*.sh
95 changes: 95 additions & 0 deletions bin/create-sandbox
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
#!/usr/bin/env bash
# bin/create-sandbox
#
# Generates a per-sandbox civiform_config.sh from sandbox_civiform_config.sh.template,
# then invokes bin/setup to provision the CiviForm instance on AWS.
#
# Usage:
# bin/create-sandbox \
# --city-short="Burlington" \
# --city-full="Burlington, Vermont" \
# --slug="burlington-vt" \
# --version="v1.55.0" \
# --ssl-arn="arn:aws:acm:us-east-1:123456789:certificate/..." \
# --account-id="123456789012"
#
# Called by EcsFargateSandboxService (Sprint 2) or manually for testing.

set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(dirname "$SCRIPT_DIR")"
TEMPLATE="$REPO_ROOT/sandbox_civiform_config.sh.template"
CONFIGS_DIR="$REPO_ROOT/configs"

# ── Parse arguments ───────────────────────────────────────────────────────────

CITY_SHORT=""
CITY_FULL=""
SLUG=""
VERSION=""
SSL_ARN=""
ACCOUNT_ID=""

for arg in "$@"; do
case $arg in
--city-short=*) CITY_SHORT="${arg#*=}" ;;
--city-full=*) CITY_FULL="${arg#*=}" ;;
--slug=*) SLUG="${arg#*=}" ;;
--version=*) VERSION="${arg#*=}" ;;
--ssl-arn=*) SSL_ARN="${arg#*=}" ;;
--account-id=*) ACCOUNT_ID="${arg#*=}" ;;
*) echo "Unknown argument: $arg" >&2; exit 1 ;;
esac
done

# ── Validate ──────────────────────────────────────────────────────────────────

MISSING=()
[[ -z "$CITY_SHORT" ]] && MISSING+=("--city-short")
[[ -z "$CITY_FULL" ]] && MISSING+=("--city-full")
[[ -z "$SLUG" ]] && MISSING+=("--slug")
[[ -z "$VERSION" ]] && MISSING+=("--version")
[[ -z "$SSL_ARN" ]] && MISSING+=("--ssl-arn")
[[ -z "$ACCOUNT_ID" ]] && MISSING+=("--account-id")

if [[ ${#MISSING[@]} -gt 0 ]]; then
echo "Error: missing required arguments: ${MISSING[*]}" >&2
echo "Run: bin/create-sandbox --help" >&2
exit 1
fi

# Slug: lowercase, letters/numbers/hyphens only, max 15 chars for APP_PREFIX (sb- + 15 = 17 chars)
if [[ ! "$SLUG" =~ ^[a-z0-9-]{1,15}$ ]]; then
echo "Error: --slug must be lowercase letters, numbers, hyphens only, max 15 chars" >&2
exit 1
fi

# ── Generate config ───────────────────────────────────────────────────────────

CONFIG_FILE="$CONFIGS_DIR/sandbox-${SLUG}.sh"
mkdir -p "$CONFIGS_DIR"

sed \
-e "s|SANDBOX_SLUG|${SLUG}|g" \
-e "s|SANDBOX_CITY_SHORT|${CITY_SHORT}|g" \
-e "s|SANDBOX_CITY_FULL|${CITY_FULL}|g" \
-e "s|SANDBOX_VERSION|${VERSION}|g" \
-e "s|SANDBOX_SSL_ARN|${SSL_ARN}|g" \
-e "s|SANDBOX_ACCOUNT_ID|${ACCOUNT_ID}|g" \
"$TEMPLATE" > "$CONFIG_FILE"

chmod 600 "$CONFIG_FILE" # contains secrets, restrict permissions

echo "Generated config: $CONFIG_FILE"
echo ""
echo "Sandbox details:"
echo " URL: https://${SLUG}.sandbox.civiform.dev"
echo " City: ${CITY_FULL}"
echo " Version: ${VERSION}"
echo ""

# ── Run setup ─────────────────────────────────────────────────────────────────

echo "Running bin/setup --config=${CONFIG_FILE} ..."
exec "$SCRIPT_DIR/setup" --config="$CONFIG_FILE"
1 change: 1 addition & 0 deletions configs/.gitkeep
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Generated per-sandbox configs live here. Gitignored.
67 changes: 67 additions & 0 deletions sandbox_civiform_config.sh.template
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
#!/usr/bin/env bash
# sandbox_civiform_config.sh.template
#
# Template for a per-sandbox CiviForm deployment config.
# Do NOT edit this file directly. Instead, run:
#
# bin/create-sandbox --city="Burlington, VT" --slug="burlington-vt" --version="v1.55.0"
#
# That script fills in the SANDBOX_* placeholders and writes a
# generated civiform_config.sh to configs/sandbox-{slug}.sh, then
# calls bin/setup --config=configs/sandbox-{slug}.sh
#
# Generated configs are gitignored. The template is version-controlled.
#
# Required placeholders (filled in by bin/create-sandbox):
# SANDBOX_SLUG e.g. burlington-vt
# SANDBOX_CITY_SHORT e.g. Burlington
# SANDBOX_CITY_FULL e.g. Burlington, Vermont
# SANDBOX_VERSION e.g. v1.55.0 (pinned at creation time)
# SANDBOX_SSL_ARN ARN of *.sandbox.civiform.dev wildcard cert
# SANDBOX_ACCOUNT_ID AWS account ID for the sandbox account

# ── CiviForm version ──────────────────────────────────────────────────────────
# Pinned at sandbox creation time — never auto-upgrades mid-trial.
export CIVIFORM_VERSION="SANDBOX_VERSION"
export CIVIFORM_CLOUD_DEPLOYMENT_VERSION="${CIVIFORM_VERSION}"

# ── Cloud provider ────────────────────────────────────────────────────────────
export CIVIFORM_CLOUD_PROVIDER="aws"
export AWS_REGION="us-east-1"
export ACCOUNT_ID="SANDBOX_ACCOUNT_ID"

# ── Auth: FAKE_IDP (no real OIDC needed for sandbox demos) ───────────────────
# STAGING_DISABLE_DEMO_MODE_LOGINS=false enables the 1-click role switcher.
export CIVIFORM_APPLICANT_AUTH_PROTOCOL="oidc"
export STAGING_DISABLE_DEMO_MODE_LOGINS="false"
export CIVIFORM_MODE="staging"

# ── Domain + SSL ──────────────────────────────────────────────────────────────
# Wildcard cert *.sandbox.civiform.dev — pre-provisioned once, shared.
export BASE_URL="https://SANDBOX_SLUG.sandbox.civiform.dev"
export STAGING_HOSTNAME="SANDBOX_SLUG.sandbox.civiform.dev"
export SSL_CERTIFICATE_ARN="SANDBOX_SSL_ARN"

# ── App prefix — unique per sandbox ──────────────────────────────────────────
# Used for S3 bucket + DynamoDB lock table naming. Max 19 chars.
export APP_PREFIX="sb-SANDBOX_SLUG"

# ── City branding ─────────────────────────────────────────────────────────────
export WHITELABEL_CIVIC_ENTITY_SHORT_NAME="SANDBOX_CITY_SHORT"
export WHITELABEL_CIVIC_ENTITY_LONG_NAME="SANDBOX_CITY_FULL"

# ── Demo banner ───────────────────────────────────────────────────────────────
export SHOW_NOT_PRODUCTION_BANNER_ENABLED="true"

# ── Notifications — send to sandbox ops inbox, not real city addresses ────────
export SENDER_EMAIL_ADDRESS="civiform-sandbox@exygy.com"
export STAGING_PROGRAM_ADMIN_NOTIFICATION_MAILING_LIST="civiform-sandbox@exygy.com"
export STAGING_TI_NOTIFICATION_MAILING_LIST="civiform-sandbox@exygy.com"
export STAGING_APPLICANT_NOTIFICATION_MAILING_LIST="civiform-sandbox@exygy.com"

# ── OIDC secrets — fake values are fine for FAKE_IDP sandboxes ───────────────
# bin/setup will prompt for these; bin/create-sandbox passes them non-interactively.
export APPLICANT_OIDC_CLIENT_ID="generic-fake-oidc-client"
export APPLICANT_OIDC_CLIENT_SECRET="fake-secret"
export ADMIN_OIDC_CLIENT_ID="idcs-fake-oidc-client"
export ADMIN_OIDC_CLIENT_SECRET="fake-secret"