#!/usr/bin/env bash # # deploy-api-tf.sh — local Elastic Beanstalk publish for the Terraform POC. # Refuses live names. GitHub Actions is the real CD path once the branch is # pushed; this script exists only because GHA cannot run until then. # # Usage: # export AWS_PROFILE=seahaven-external-dev # bash scripts/deploy-api-tf.sh set -euo pipefail REGION="${AWS_REGION:-us-east-1}" APPLICATION_NAME="shoc-backend-tf-poc" ENVIRONMENT_NAME="shoc-backend-tf-poc" SMOKE_URL="https://tf-poc.api.dev.seahaven.com" S3_BUCKET="elasticbeanstalk-us-east-1-396287094661" log() { printf '\n\033[1m== %s ==\033[0m\n' "$1"; } die() { printf '\033[31mERR\033[0m %s\n' "$1" >&2; exit 1; } [[ "${APPLICATION_NAME}" != "shoc-backend" ]] \ || die "refusing live Elastic Beanstalk application shoc-backend" [[ "${ENVIRONMENT_NAME}" != "shoc-backend-dev" ]] \ || die "refusing live Elastic Beanstalk environment shoc-backend-dev" [[ "${SMOKE_URL}" != "https://api.dev.seahaven.com" ]] \ || die "refusing live hostname api.dev.seahaven.com" command -v aws >/dev/null 2>&1 || die "aws CLI is required" command -v curl >/dev/null 2>&1 || die "curl is required" ACCOUNT="$(aws sts get-caller-identity --query Account --output text)" [[ "${ACCOUNT}" == "396287094661" ]] \ || die "refusing to deploy outside seahaven-external-dev (caller account ${ACCOUNT})" REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" cd "$REPO_ROOT" log "package source bundle" bash scripts/package-elastic-beanstalk.sh VERSION_LABEL="local-$(date -u +%Y%m%d%H%M%S)-${USER:-unknown}" BUNDLE=".artifacts/elastic-beanstalk/site.zip" KEY="shoc-backend-tf-poc/${VERSION_LABEL}.zip" log "capture current environment version" prev="$(aws elasticbeanstalk describe-environments \ --environment-names "${ENVIRONMENT_NAME}" \ --region "${REGION}" \ --query 'Environments[0].VersionLabel' \ --output text)" echo "${prev}" > .artifacts/elastic-beanstalk/previous-version.txt echo "Previous version label: ${prev}" log "upload bundle ${KEY}" aws s3 cp "${BUNDLE}" "s3://${S3_BUCKET}/${KEY}" --region "${REGION}" log "create application version ${VERSION_LABEL}" aws elasticbeanstalk create-application-version \ --application-name "${APPLICATION_NAME}" \ --version-label "${VERSION_LABEL}" \ --source-bundle "S3Bucket=${S3_BUCKET},S3Key=${KEY}" \ --region "${REGION}" log "update environment ${ENVIRONMENT_NAME}" aws elasticbeanstalk update-environment \ --environment-name "${ENVIRONMENT_NAME}" \ --version-label "${VERSION_LABEL}" \ --region "${REGION}" log "wait until expected version is Ready" status="Unknown" current="Unknown" health="Unknown" for _ in $(seq 1 80); do read -r status current health < <( aws elasticbeanstalk describe-environments \ --environment-names "${ENVIRONMENT_NAME}" \ --region "${REGION}" \ --query 'Environments[0].[Status,VersionLabel,Health]' \ --output text ) echo "environment status: ${status}; version: ${current}; health: ${health}" if [ "${status}" = "Ready" ]; then if [ "${current}" = "${VERSION_LABEL}" ] && { [ "${health}" = "Green" ] || [ "${health}" = "Yellow" ]; }; then echo "Expected application version is Ready and healthy." break fi die "Environment became Ready without activating expected version ${VERSION_LABEL}." fi sleep 15 done [[ "${status}" = "Ready" ]] || die "Expected application version did not become Ready." log "smoke ${SMOKE_URL}" bash scripts/smoke-elastic-beanstalk.sh "${SMOKE_URL}" log "webhook secret source" response_file="$(mktemp)" trap 'rm -f "$response_file"' EXIT status_code="$(curl --silent --show-error \ --output "$response_file" \ --write-out '%{http_code}' \ --request POST \ --header 'Content-Type: application/json' \ --header "X-SH-Timestamp: $(date +%s)" \ --header 'X-SH-Key-Id: deployment-smoke-invalid-key' \ --header "X-SH-Signature: v1=$(printf '0%.0s' {1..64})" \ --data '{}' \ "${SMOKE_URL}/api/webhooks/work-orders")" if [ "${status_code}" != "401" ]; then die "Expected enabled webhook to reject the invalid probe with 401; received ${status_code}." fi echo "webhook HTTP 401"