Skip to content
Merged
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
78 changes: 45 additions & 33 deletions .github/workflows/backend-cd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -90,23 +90,31 @@ jobs:
IMAGE_URI="${{ steps.cf.outputs.ecr_repo_uri }}:${{ github.sha }}"
docker push "$IMAGE_URI"

- name: Write MongoDB URI to SSM (SecureString)
- name: Sync all secrets to SSM Parameter Store
shell: bash
env:
MONGO_URI: ${{ secrets.MongoURI }}
run: |
set -euo pipefail

if [ -z "${MONGO_URI:-}" ]; then
echo "MongoURI secret is missing/empty"
exit 1
fi

aws ssm put-parameter \
--name "${{ steps.cf.outputs.mongo_param_name }}" \
--type "SecureString" \
--value "$MONGO_URI" \
--overwrite
PARAM_PREFIX="/comptaleyes/dev"

write_secret() {
local name=$1
local value=$2
if [ -n "${value}" ] && [ "${value}" != "" ]; then
echo "✓ $name"
aws ssm put-parameter --name "${PARAM_PREFIX}/${name}" --type "SecureString" --value "${value}" --overwrite >/dev/null
fi
}

echo "📤 Syncing secrets to SSM..."
write_secret "mongodbUri" "${{ secrets.MONGO_URI }}"
write_secret "jwtSecret" "${{ secrets.JWT_SECRET }}"
write_secret "smtpHost" "${{ secrets.SMTP_HOST }}"
write_secret "smtpPort" "${{ secrets.SMTP_PORT }}"
write_secret "smtpUser" "${{ secrets.SMTP_USER }}"
write_secret "smtpPassword" "${{ secrets.SMTP_PASSWORD }}"
write_secret "smtpFrom" "${{ secrets.SMTP_FROM }}"
# Add any new secret here - just add to GitHub Secrets UI
echo "✅ Done"

- name: Deploy on EC2 via SSM RunCommand (pull + restart container)
shell: bash
Expand All @@ -116,9 +124,6 @@ jobs:
INSTANCE_ID="${{ steps.cf.outputs.instance_id }}"
IMAGE_URI="${{ steps.cf.outputs.ecr_repo_uri }}:${{ github.sha }}"
REGION="us-east-1"
MONGO_PARAM="${{ steps.cf.outputs.mongo_param_name }}"

# <= 100 chars
COMMENT="Deploy backend ${GITHUB_SHA::7}"

SCRIPT=$(cat <<'EOF'
Expand All @@ -129,38 +134,45 @@ jobs:
HOST_PORT="3000"
CONTAINER_PORT="3000"
IMAGE_URI="__IMAGE_URI__"
MONGO_PARAM="__MONGO_PARAM__"
NODE_ENV_VALUE="production"
PARAM_PREFIX="/comptaleyes/dev"

echo "[1/7] Fetch ALL parameters from SSM"
PARAMS_JSON=$(aws ssm get-parameters-by-path --path "$PARAM_PREFIX" --with-decryption --region "$REGION" --query 'Parameters[*].[Name,Value]' --output json)

echo "[1/7] Fetch Mongo URI from SSM"
MONGO_URI="$(aws ssm get-parameter --name "$MONGO_PARAM" --with-decryption --query 'Parameter.Value' --output text)"
if [ -z "$MONGO_URI" ] || [ "$MONGO_URI" = "None" ]; then
echo "Mongo URI is empty; aborting deploy"
if [ "$(echo "$PARAMS_JSON" | jq 'length')" -eq 0 ]; then
echo "❌ No parameters found"
exit 1
fi

echo "✅ Found $(echo "$PARAMS_JSON" | jq 'length') parameters"

echo "[2/7] Ensure docker is running"
sudo systemctl start docker || true

echo "[3/7] Login to ECR"
echo "[3/7] Login to ECR"
aws ecr get-login-password --region "$REGION" | sudo docker login --username AWS --password-stdin "$(echo "$IMAGE_URI" | cut -d/ -f1)"

echo "[4/7] Pull image"
echo "[4/7] Pull image"
sudo docker pull "$IMAGE_URI"

echo "[5/7] Stop/remove old container if exists"
echo "[5/7] Stop/remove old container"
sudo docker rm -f "$APP_NAME" || true

echo "[6/7] Run new container"
sudo docker run -d \
--name "$APP_NAME" \
--restart unless-stopped \
-p "${HOST_PORT}:${CONTAINER_PORT}" \
-e MONGO_URI="$MONGO_URI" \
-e NODE_ENV="$NODE_ENV_VALUE" \
"$IMAGE_URI"
echo "[6/7] Run container with ALL SSM env vars"
ENV_FLAGS="-e PORT=$CONTAINER_PORT -e SERVICE_NAME=comptaleyes-backend"

while IFS= read -r line; do
PARAM_NAME=$(echo "$line" | jq -r '.[0]' | sed 's|.*/||')
PARAM_VALUE=$(echo "$line" | jq -r '.[1]')
ENV_VAR=$(echo "$PARAM_NAME" | sed 's/Uri$/URI/' | sed 's/\([a-z]\)\([A-Z]\)/\1_\2/g' | tr '[:lower:]' '[:upper:]')
ENV_FLAGS="$ENV_FLAGS -e ${ENV_VAR}=\"${PARAM_VALUE}\""
done < <(echo "$PARAMS_JSON" | jq -c '.[]')

eval sudo docker run -d --name "$APP_NAME" --restart unless-stopped -p "${HOST_PORT}:${CONTAINER_PORT}" $ENV_FLAGS "$IMAGE_URI"

echo "[7/7] Show running container"
echo "[7/7] Container status"
sudo docker ps --filter "name=$APP_NAME" --format "table {{.Names}}\t{{.Image}}\t{{.Status}}\t{{.Ports}}"
EOF
)
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ cdk.out/
.env.*
.DS_Store

scripts/
3 changes: 3 additions & 0 deletions backend/src/core/config/env.schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ export const envSchema = z.object({
NODE_ENV: z.enum(['development', 'test', 'production']).default('development'),
PORT: z.coerce.number().int().positive().default(3000),

// Database
MONGO_URI: z.string().url().optional(),

// Optional but common; just a placeholder for later
SERVICE_NAME: z.string().min(1).default('nest-backend-service'),
});
Expand Down