Skip to content

Deploy

Deploy #273

Workflow file for this run

name: Deploy
on:
push:
branches:
- main
workflow_dispatch:
permissions:
contents: read
id-token: write
env:
AWS_REGION : "us-east-1"
AWS_REGION_ZONE : "us-east-1"
S3_BUCKET_NAME: "ciacompliancemanager-frontend-us-east-1-172017021075"
CLOUDFRONT_STACK_NAME: "ciacompliancemanager-frontend"
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Harden Runner
uses: step-security/harden-runner@9ca718d3bf646d6534007c269a635b3e54cadf99 # v2.19.2
with:
egress-policy: block
allowed-endpoints: >
accounts.google.com:443
amazon-cloudfront-secure-static-site-s3bucketroot-14oliw5cmta06.s3.us-east-1.amazonaws.com:443
api.github.com:443
api.securityscorecards.dev:443
app.fossa.io:443
auth.docker.io:443
bestpractices.coreinfrastructure.org:443
cfu.zaproxy.org:443
cla-assistant.io:443
cla-assistant.io:80
clients2.google.com:80
cloudformation.us-east-1.amazonaws.com:443
cloudfront.amazonaws.com:443
content-signature-2.cdn.mozilla.net:443
deb.debian.org:80
firefox-settings-attachments.cdn.mozilla.net:443
firefox.settings.services.mozilla.com:443
fonts.googleapis.com:443
fonts.gstatic.com:443
ghcr.io:443
github.com:443
hack23.com:443
hack23.com:80
hack23.comnull:443
img.shields.io:443
isitmaintained.com:443
isitmaintained.com:80
location.services.mozilla.com:443
news.zaproxy.org:443
objects.githubusercontent.com:443
pkg-containers.githubusercontent.com:443
production.cloudflare.docker.com:443
r10.o.lencr.org:443
r11.o.lencr.org:80
raw.githubusercontent.com:443
registry-1.docker.io:443
registry.npmjs.org:443
safebrowsingohttpgateway.googleapis.com:443
shavar.services.mozilla.com:443
slsa.dev:443
sonarcloud.io:443
storage.googleapis.com:443
sts.us-east-1.amazonaws.com:443
tel.zaproxy.org:443
tracking-protection.cdn.mozilla.net:443
us-central1-lighthouse-infrastructure.cloudfunctions.net:443
www.google.com:443
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: configure aws credentials
uses: aws-actions/configure-aws-credentials@d979d5b3a71173a29b74b5b88418bfda9437d885 # v6.1.1
with:
role-to-assume: arn:aws:iam::172017021075:role/GithubWorkFlowRole
role-session-name: githubworkflowrolesessiont2
aws-region: ${{ env.AWS_REGION }}
- name: Deploy to S3 with optimized sync
run: |
# Cost-optimized deployment: minimizes S3 API calls and CloudTrail events
# - Uses --size-only for immutable content-hashed assets only
# - Uses default sync (size+mtime) for mutable files (HTML, metadata)
# - Consolidates multiple syncs into minimal commands per cache tier
# - Deploys to both / and /docs/ paths to support all current and legacy URLs
echo "🚀 Starting cost-optimized deployment (minimal API calls)"
# --- Deploy to root (/) ---
# 1. Immutable assets: JS, CSS, fonts, images (all content-hashed)
echo "⚡ [root] Syncing immutable assets (JS, CSS, fonts, images)..."
aws s3 sync docs/. s3://${{ env.S3_BUCKET_NAME }}/ \
--size-only \
--exclude "*" \
--include "*.js" \
--include "*.css" \
--include "*.woff" \
--include "*.woff2" \
--include "*.ttf" \
--include "*.eot" \
--include "*.otf" \
--include "*.webp" \
--include "*.png" \
--include "*.jpg" \
--include "*.jpeg" \
--include "*.gif" \
--include "*.svg" \
--include "*.ico" \
--cache-control "public, max-age=31536000, immutable" \
--exclude ".git/*" \
--exclude "screenshots/*"
# 2. Source map files with explicit content-type (immutable, content-hashed)
echo "🗺️ [root] Syncing source maps with correct content-type..."
aws s3 sync docs/. s3://${{ env.S3_BUCKET_NAME }}/ \
--size-only \
--exclude "*" \
--include "*.js.map" \
--include "*.css.map" \
--cache-control "public, max-age=31536000, immutable" \
--content-type "application/json" \
--exclude ".git/*"
# 3. HTML files (not content-hashed, short cache, use size+mtime for correctness)
echo "📄 [root] Syncing HTML files..."
aws s3 sync docs/. s3://${{ env.S3_BUCKET_NAME }}/ \
--exclude "*" \
--include "*.html" \
--cache-control "public, max-age=3600, must-revalidate" \
--content-type "text/html; charset=utf-8" \
--exclude ".git/*"
# 4. Metadata and text files (medium cache, use size+mtime for correctness)
echo "📋 [root] Syncing metadata files..."
aws s3 sync docs/. s3://${{ env.S3_BUCKET_NAME }}/ \
--exclude "*" \
--include "*.xml" \
--include "*.json" \
--include "*.txt" \
--include "*.md" \
--cache-control "public, max-age=86400" \
--exclude ".git/*"
# 5. Extensionless files (CNAME, .nojekyll, etc.)
echo "📎 [root] Syncing extensionless/dotfiles..."
aws s3 sync docs/. s3://${{ env.S3_BUCKET_NAME }}/ \
--exclude "*.*" \
--exclude ".git/*" \
--cache-control "public, max-age=86400"
# --- Deploy to /docs/ (legacy URL support) ---
# 6. Immutable assets to /docs/
echo "⚡ [/docs/] Syncing immutable assets..."
aws s3 sync docs/. s3://${{ env.S3_BUCKET_NAME }}/docs/ \
--size-only \
--exclude "*" \
--include "*.js" \
--include "*.css" \
--include "*.woff" \
--include "*.woff2" \
--include "*.ttf" \
--include "*.eot" \
--include "*.otf" \
--include "*.webp" \
--include "*.png" \
--include "*.jpg" \
--include "*.jpeg" \
--include "*.gif" \
--include "*.svg" \
--include "*.ico" \
--cache-control "public, max-age=31536000, immutable" \
--exclude ".git/*" \
--exclude "screenshots/*"
# 7. Source map files to /docs/ with explicit content-type
echo "🗺️ [/docs/] Syncing source maps with correct content-type..."
aws s3 sync docs/. s3://${{ env.S3_BUCKET_NAME }}/docs/ \
--size-only \
--exclude "*" \
--include "*.js.map" \
--include "*.css.map" \
--cache-control "public, max-age=31536000, immutable" \
--content-type "application/json" \
--exclude ".git/*"
# 8. HTML files to /docs/
echo "📄 [/docs/] Syncing HTML files..."
aws s3 sync docs/. s3://${{ env.S3_BUCKET_NAME }}/docs/ \
--exclude "*" \
--include "*.html" \
--cache-control "public, max-age=3600, must-revalidate" \
--content-type "text/html; charset=utf-8" \
--exclude ".git/*"
# 9. Metadata and text files to /docs/
echo "📋 [/docs/] Syncing metadata files..."
aws s3 sync docs/. s3://${{ env.S3_BUCKET_NAME }}/docs/ \
--exclude "*" \
--include "*.xml" \
--include "*.json" \
--include "*.txt" \
--include "*.md" \
--cache-control "public, max-age=86400" \
--exclude ".git/*"
# 10. Extensionless files to /docs/
echo "📎 [/docs/] Syncing extensionless/dotfiles..."
aws s3 sync docs/. s3://${{ env.S3_BUCKET_NAME }}/docs/ \
--exclude "*.*" \
--exclude ".git/*" \
--cache-control "public, max-age=86400"
# --- Screenshots (if directory exists) ---
if [ -d "docs/screenshots" ]; then
echo "📸 Syncing screenshots to both paths..."
aws s3 sync docs/screenshots/. s3://${{ env.S3_BUCKET_NAME }}/screenshots/ \
--size-only
aws s3 sync docs/screenshots/. s3://${{ env.S3_BUCKET_NAME }}/docs/screenshots/ \
--size-only
fi
echo "✅ Deployment completed (10 sync commands vs 16 previously)"
# Invalidate CloudFront cache for HTML and metadata only (immutable assets don't need invalidation)
- name: Invalidate CloudFront
run: |
echo "🔍 Discovering CloudFront distribution ID from stack: ${{ env.CLOUDFRONT_STACK_NAME }}"
CloudFrontDistId=$(aws cloudformation describe-stacks \
--stack-name ${{ env.CLOUDFRONT_STACK_NAME }} \
--query "Stacks[0].Outputs[?OutputKey=='CloudFrontDistributionId'].OutputValue" \
--output text 2>/dev/null || echo "")
if [ -z "$CloudFrontDistId" ]; then
echo "⚠️ Warning: CloudFront distribution ID not found in stack outputs"
echo "Attempting to find distribution by S3 origin domain..."
CloudFrontDistId=$(aws cloudfront list-distributions \
--output json 2>/dev/null | \
jq -r ".DistributionList.Items[] | select(.Origins.Items[].DomainName | contains(\"${{ env.S3_BUCKET_NAME }}\")) | .Id" | \
head -n 1 || echo "")
fi
if [ -z "$CloudFrontDistId" ] || [ "$CloudFrontDistId" = "None" ]; then
echo "❌ Error: Could not discover CloudFront distribution ID"
exit 1
fi
echo "✅ Found CloudFront distribution: $CloudFrontDistId"
echo "🔄 Invalidating HTML and metadata paths (immutable assets use cache-busting hashes)..."
aws cloudfront create-invalidation \
--distribution-id $CloudFrontDistId \
--paths "/index.html" "/docs/index.html" "/*.html" "/docs/*.html" "/*/index.html" "/docs/*/index.html" "/sitemap.xml" "/docs/sitemap.xml" "/manifest.json" "/docs/manifest.json" "/robots.txt" "/docs/robots.txt" "/version.txt" "/docs/version.txt"
echo "✅ CloudFront invalidation completed (targeted paths only, reduces cost vs /*)"