-
-
Notifications
You must be signed in to change notification settings - Fork 10
256 lines (232 loc) · 10.7 KB
/
Copy pathdeploy-s3.yml
File metadata and controls
256 lines (232 loc) · 10.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
name: Deploy
on:
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@ab7a9404c0f3da075243ca237b5fac12c98deaa5 # v2.19.3
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 /*)"