Skip to content

Commit 5e24099

Browse files
authored
Merge pull request #110 from aligent/feature/DO-1953-Update-PWA-Deploy
DO-1953: Update the pwa deployment workflow
2 parents 3649b21 + a9798df commit 5e24099

2 files changed

Lines changed: 145 additions & 62 deletions

File tree

.github/workflows/pwa-deployment.yml

Lines changed: 101 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -12,18 +12,22 @@ on:
1212
s3-bucket:
1313
description: "S3 bucket name for deployment"
1414
type: string
15-
required: true
15+
required: false
1616
cloudfront-distribution-id:
1717
description: "CloudFront distribution ID for cache invalidation"
1818
type: string
19-
required: true
19+
required: false
20+
role-session-name:
21+
description: "AWS role session name for OIDC authentication (default: {repo}-{short-sha}-{run-number})"
22+
type: string
23+
required: false
24+
default: ""
2025

2126
# Environment Configuration
2227
environment:
23-
description: "Deployment environment (GitHub environment name for protection rules)"
28+
description: "GitHub Environment name for secrets/variables (e.g. Staging, Production)"
2429
type: string
25-
required: false
26-
default: "staging"
30+
required: true
2731

2832
# Build Configuration
2933
package-manager:
@@ -92,14 +96,6 @@ on:
9296
required: false
9397
default: false
9498

95-
secrets:
96-
aws-access-key-id:
97-
description: "AWS access key ID"
98-
required: true
99-
aws-secret-access-key:
100-
description: "AWS secret access key"
101-
required: true
102-
10399
outputs:
104100
deployment-url:
105101
description: "URL of the deployed application"
@@ -113,14 +109,83 @@ jobs:
113109
prepare:
114110
name: 🔍 Prepare Deployment
115111
runs-on: ubuntu-latest
112+
environment: ${{ inputs.environment }}
116113
outputs:
117114
cache-control-static: ${{ steps.cache-config.outputs.cache-control-static }}
118115
cache-control-html: ${{ steps.cache-config.outputs.cache-control-html }}
119116
s3-prefix: ${{ steps.deployment-config.outputs.s3-prefix }}
120117
deployment-url: ${{ steps.deployment-config.outputs.deployment-url }}
121118
brand-matrix: ${{ steps.brand-config.outputs.matrix }}
122119
invalidation-paths: ${{ steps.cache-config.outputs.invalidation-paths }}
120+
auth-mode: ${{ steps.validate-inputs.outputs.auth-mode }}
121+
role-session-name: ${{ steps.resolve-session-name.outputs.role-session-name }}
123122
steps:
123+
- name: Validate required inputs
124+
id: validate-inputs
125+
env:
126+
ENVIRONMENT: ${{ inputs.environment }}
127+
S3_BUCKET: ${{ vars.S3_BUCKET }} || ${{ inputs.s3-bucket }}
128+
CLOUDFRONT_DISTRIBUTION_ID: ${{ vars.CLOUDFRONT_DISTRIBUTION_ID }} || ${{ inputs.cloudfront-distribution-id }}
129+
VAR_AWS_ACCESS_KEY_ID: ${{ vars.AWS_ACCESS_KEY_ID }}
130+
SECRET_AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
131+
VAR_AWS_ROLE_ARN: ${{ vars.AWS_ROLE_ARN }}
132+
run: |
133+
echo "🔍 Validating deployment configuration..."
134+
echo "ℹ️ Using variables from $ENVIRONMENT environment"
135+
136+
if [ -z "$S3_BUCKET" ]; then
137+
echo "❌ Error: S3_BUCKET must be set as a variable in your $ENVIRONMENT environment"
138+
exit 1
139+
fi
140+
echo "✅ S3_BUCKET: $S3_BUCKET"
141+
142+
if [ -z "$CLOUDFRONT_DISTRIBUTION_ID" ]; then
143+
echo "❌ Error: CLOUDFRONT_DISTRIBUTION_ID must be set as a variable in your $ENVIRONMENT environment"
144+
exit 1
145+
fi
146+
echo "✅ CLOUDFRONT_DISTRIBUTION_ID: $CLOUDFRONT_DISTRIBUTION_ID"
147+
148+
if [ -n "$VAR_AWS_ACCESS_KEY_ID" ]; then
149+
echo "ℹ️ AWS_ACCESS_KEY_ID set from variable: $VAR_AWS_ACCESS_KEY_ID"
150+
if [ -z "$SECRET_AWS_SECRET_ACCESS_KEY" ]; then
151+
echo "❌ Error: AWS_SECRET_ACCESS_KEY is not defined as a secret in your $ENVIRONMENT environment"
152+
exit 1
153+
fi
154+
echo "✅ AWS_SECRET_ACCESS_KEY secret is configured"
155+
echo "✅ Using static credential authentication"
156+
echo "auth-mode=static" >> $GITHUB_OUTPUT
157+
elif [ -n "$VAR_AWS_ROLE_ARN" ]; then
158+
echo "ℹ️ AWS_ROLE_ARN set from variable: $VAR_AWS_ROLE_ARN"
159+
echo "✅ Using OIDC authentication"
160+
echo "auth-mode=oidc" >> $GITHUB_OUTPUT
161+
else
162+
echo "❌ Error: No AWS credentials configured in your $ENVIRONMENT environment."
163+
echo " Configure one of the following:"
164+
echo " - Static credentials: AWS_ACCESS_KEY_ID (variable) + AWS_SECRET_ACCESS_KEY (secret)"
165+
echo " - OIDC: AWS_ROLE_ARN (variable)"
166+
exit 1
167+
fi
168+
169+
echo "✅ All inputs validated successfully"
170+
171+
- name: Resolve role session name
172+
id: resolve-session-name
173+
if: steps.validate-inputs.outputs.auth-mode == 'oidc'
174+
env:
175+
ROLE_SESSION_NAME: ${{ inputs.role-session-name }}
176+
COMMIT_SHA: ${{ github.sha }}
177+
REPOSITORY_NAME: ${{ github.event.repository.name }}
178+
RUN_NUMBER: ${{ github.run_number }}
179+
run: |
180+
SESSION_NAME="$ROLE_SESSION_NAME"
181+
if [ -z "$SESSION_NAME" ]; then
182+
SHORT_SHA=$(echo "$COMMIT_SHA" | cut -c1-7)
183+
SESSION_NAME="${REPOSITORY_NAME}-${SHORT_SHA}-${RUN_NUMBER}"
184+
fi
185+
# AWS session names: max 64 chars, allowed [a-zA-Z0-9=,.@-]
186+
SESSION_NAME=$(echo "$SESSION_NAME" | tr -c '[:alnum:]=,.@-' '-' | cut -c1-64)
187+
echo "role-session-name=$SESSION_NAME" >> $GITHUB_OUTPUT
188+
124189
- name: Configure cache strategy
125190
id: cache-config
126191
run: |
@@ -196,7 +261,7 @@ jobs:
196261
fi
197262
env:
198263
INPUTS_PREVIEW_BASE_URL: ${{ inputs.preview-base-url }}
199-
INPUTS_S3_BUCKET: ${{ inputs.s3-bucket }}
264+
INPUTS_S3_BUCKET: ${{ vars.S3_BUCKET }} || ${{ inputs.s3-bucket }}
200265

201266
- name: Configure multi-brand matrix
202267
id: brand-config
@@ -212,11 +277,14 @@ jobs:
212277
env:
213278
INPUTS_BRAND_CONFIG: ${{ inputs.brand-config }}
214279

215-
# Build and test the application
280+
# Build and deploy the application
216281
build-and-deploy:
217282
name: 🚀 Build Application and Deploy to AWS
218283
runs-on: ubuntu-latest
219284
needs: [prepare]
285+
permissions:
286+
id-token: write
287+
contents: read
220288
environment:
221289
name: ${{ inputs.environment }}
222290
url: ${{ needs.prepare.outputs.deployment-url }}
@@ -301,9 +369,17 @@ jobs:
301369
- name: Configure AWS credentials
302370
uses: aws-actions/configure-aws-credentials@8df5847569e6427dd6c4fb1cf565c83acfa8afa7 #v6.0.0
303371
with:
304-
aws-access-key-id: ${{ secrets.aws-access-key-id }}
305-
aws-secret-access-key: ${{ secrets.aws-secret-access-key }}
306-
aws-region: ${{ inputs.aws-region }}
372+
aws-access-key-id: ${{ vars.AWS_ACCESS_KEY_ID }}
373+
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
374+
aws-region: ${{ vars.AWS_REGION || inputs.aws-region }}
375+
376+
- name: Configure AWS credentials (OIDC)
377+
if: needs.prepare.outputs.auth-mode == 'oidc'
378+
uses: aws-actions/configure-aws-credentials@8df5847569e6427dd6c4fb1cf565c83acfa8afa7 #v6.0.0
379+
with:
380+
role-to-assume: ${{ vars.AWS_ROLE_ARN }}
381+
role-session-name: ${{ needs.prepare.outputs.role-session-name }}
382+
aws-region: ${{ vars.AWS_REGION || inputs.aws-region }}
307383

308384
- name: Configure S3 deployment paths
309385
id: s3-config
@@ -319,7 +395,7 @@ jobs:
319395
env:
320396
NEEDS_PREPARE_OUTPUTS_S3_PREFIX: ${{ needs.prepare.outputs.s3-prefix }}
321397
MATRIX_BRAND: ${{ matrix.brand }}
322-
INPUTS_S3_BUCKET: ${{ inputs.s3-bucket }}
398+
INPUTS_S3_BUCKET: ${{ vars.S3_BUCKET }} || ${{ inputs.s3-bucket }}
323399

324400
- name: Deploy static assets to S3
325401
run: |
@@ -336,7 +412,7 @@ jobs:
336412
${INPUTS_EXTRA_SYNC_ARGS}
337413
env:
338414
INPUTS_BUILD_DIRECTORY: ${{ inputs.build-directory }}
339-
INPUTS_S3_BUCKET: ${{ inputs.s3-bucket }}
415+
INPUTS_S3_BUCKET: ${{ vars.S3_BUCKET }} || ${{ inputs.s3-bucket }}
340416
STEPS_S3_CONFIG_OUTPUTS_S3_PATH: ${{ steps.s3-config.outputs.s3-path }}
341417
NEEDS_PREPARE_OUTPUTS_CACHE_CONTROL_STATIC: ${{ needs.prepare.outputs.cache-control-static }}
342418
INPUTS_EXTRA_SYNC_ARGS: ${{ inputs.extra-sync-args }}
@@ -356,7 +432,7 @@ jobs:
356432
${INPUTS_EXTRA_SYNC_ARGS}
357433
env:
358434
INPUTS_BUILD_DIRECTORY: ${{ inputs.build-directory }}
359-
INPUTS_S3_BUCKET: ${{ inputs.s3-bucket }}
435+
INPUTS_S3_BUCKET: ${{ vars.S3_BUCKET }} || ${{ inputs.s3-bucket }}
360436
STEPS_S3_CONFIG_OUTPUTS_S3_PATH: ${{ steps.s3-config.outputs.s3-path }}
361437
NEEDS_PREPARE_OUTPUTS_CACHE_CONTROL_HTML: ${{ needs.prepare.outputs.cache-control-html }}
362438
INPUTS_EXTRA_SYNC_ARGS: ${{ inputs.extra-sync-args }}
@@ -384,7 +460,7 @@ jobs:
384460
echo "Invalidating paths: $PATHS"
385461
386462
INVALIDATION_ID=$(aws cloudfront create-invalidation \
387-
--distribution-id "${INPUTS_CLOUDFRONT_DISTRIBUTION_ID}" \
463+
--distribution-id "${CLOUDFRONT_DISTRIBUTION_ID}" \
388464
--paths $PATHS \
389465
--query 'Invalidation.Id' \
390466
--output text)
@@ -394,16 +470,15 @@ jobs:
394470
if [ "${{ inputs.debug }}" = "true" ]; then
395471
echo "🔍 Waiting for invalidation to complete..."
396472
aws cloudfront wait invalidation-completed \
397-
--distribution-id "${INPUTS_CLOUDFRONT_DISTRIBUTION_ID}" \
473+
--distribution-id "${CLOUDFRONT_DISTRIBUTION_ID}" \
398474
--id "$INVALIDATION_ID"
399475
echo "✅ CloudFront invalidation completed"
400476
fi
401477
env:
402478
NEEDS_PREPARE_OUTPUTS_INVALIDATION_PATHS: ${{ needs.prepare.outputs.invalidation-paths }}
403479
MATRIX_BRAND: ${{ matrix.brand }}
404480
STEPS_S3_CONFIG_OUTPUTS_S3_PATH: ${{ steps.s3-config.outputs.s3-path }}
405-
INPUTS_CLOUDFRONT_DISTRIBUTION_ID: ${{ inputs.cloudfront-distribution-id }}
406-
481+
CLOUDFRONT_DISTRIBUTION_ID: ${{ vars.CLOUDFRONT_DISTRIBUTION_ID }} || ${{ inputs.cloudfront-distribution-id }}
407482
- name: Generate deployment summary
408483
run: |
409484
echo "## 🚀 Deployment Summary" >> $GITHUB_STEP_SUMMARY
@@ -437,7 +512,7 @@ jobs:
437512
env:
438513
INPUTS_ENVIRONMENT: ${{ inputs.environment }}
439514
MATRIX_BRAND: ${{ matrix.brand }}
440-
INPUTS_S3_BUCKET: ${{ inputs.s3-bucket }}
515+
INPUTS_S3_BUCKET: ${{ vars.S3_BUCKET }} || ${{ inputs.s3-bucket }}
441516
STEPS_S3_CONFIG_OUTPUTS_S3_PATH: ${{ steps.s3-config.outputs.s3-path }}
442517
INPUTS_CACHE_STRATEGY: ${{ inputs.cache-strategy }}
443518
NEEDS_PREPARE_OUTPUTS_DEPLOYMENT_URL: ${{ needs.prepare.outputs.deployment-url }}

docs/pwa-deployment.md

Lines changed: 44 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,31 @@ A comprehensive Progressive Web Application deployment workflow supporting S3 st
1212
- **Manual production gates**: Environment-based deployment protection
1313
- **Comprehensive caching**: Build artifact optimisation and cleanup
1414

15+
#### **GitHub Environment Variables and Secrets**
16+
17+
Environment-specific values are read directly from the GitHub Environment (set via `github-environment`), rather than being passed as workflow inputs. Configure the following on each environment:
18+
19+
| Name | Type | Required | Description |
20+
|------|------|----------|-------------|
21+
| `S3_BUCKET` | variable | :white_check_mark: | S3 bucket name for deployment |
22+
| `CLOUDFRONT_DISTRIBUTION_ID` | variable | :white_check_mark: | CloudFront distribution ID for cache invalidation |
23+
| `AWS_REGION` | variable | :x: | AWS region (falls back to `aws-region` input) |
24+
| **Static credentials** | | | |
25+
| `AWS_ACCESS_KEY_ID` | variable | :white_check_mark: | AWS access key ID (required if not using OIDC) |
26+
| `AWS_SECRET_ACCESS_KEY` | secret | :white_check_mark: | AWS secret access key (required if not using OIDC) |
27+
| **OIDC** | | | |
28+
| `AWS_ROLE_ARN` | variable | :white_check_mark: | IAM role ARN to assume via OIDC (alternative to static credentials) |
29+
30+
Either `AWS_ACCESS_KEY_ID` + `AWS_SECRET_ACCESS_KEY` **or** `AWS_ROLE_ARN` must be configured. The workflow detects which to use automatically.
31+
1532
#### **Inputs**
1633
| Name | Required | Type | Default | Description |
1734
|------|----------|------|---------|-------------|
18-
| **AWS Configuration** |
19-
| aws-region | :x: | string | ap-southeast-2 | AWS region for deployment |
20-
| s3-bucket | :white_check_mark: | string | | S3 bucket name for deployment |
21-
| cloudfront-distribution-id | :white_check_mark: | string | | CloudFront distribution ID for cache invalidation |
2235
| **Environment Configuration** |
23-
| environment | :x: | string | staging | Deployment environment (GitHub environment name for protection rules) |
36+
| github-environment | :white_check_mark: | string | | GitHub Environment name for secrets/variables (e.g. Staging, Production) |
37+
| **AWS Configuration** |
38+
| aws-region | :x: | string | ap-southeast-2 | AWS region fallback (overridden by `AWS_REGION` environment variable if set) |
39+
| role-session-name | :x: | string | | AWS role session name for OIDC (default: `{repo}-{short-sha}-{run-number}`) |
2440
| **Build Configuration** |
2541
| package-manager | :x: | string | yarn | Node package manager (yarn/npm) |
2642
| is-yarn-classic | :x: | boolean | false | Use Yarn Classic (pre-Berry) instead of modern Yarn |
@@ -38,14 +54,6 @@ A comprehensive Progressive Web Application deployment workflow supporting S3 st
3854
| extra-sync-args | :x: | string | | Additional AWS S3 sync arguments |
3955
| **Debug and Control** |
4056
| debug | :x: | boolean | false | Enable verbose logging and debug output |
41-
| skip-build | :x: | boolean | false | Skip the build step (use pre-built assets) |
42-
| skip-tests | :x: | boolean | false | Skip test execution |
43-
44-
#### **Secrets**
45-
| Name | Required | Description |
46-
|------|----------|-------------|
47-
| aws-access-key-id | :white_check_mark: | AWS access key ID |
48-
| aws-secret-access-key | :white_check_mark: | AWS secret access key |
4957

5058
#### **Outputs**
5159
| Name | Description |
@@ -55,37 +63,42 @@ A comprehensive Progressive Web Application deployment workflow supporting S3 st
5563

5664
#### **Example Usage**
5765

58-
**Basic Production Deployment:**
66+
**Basic Deployment (Static Credentials):**
67+
```yaml
68+
jobs:
69+
deploy-staging:
70+
uses: aligent/workflows/.github/workflows/pwa-deployment.yml@main
71+
with:
72+
github-environment: Staging
73+
secrets: inherit
74+
```
75+
76+
The `Staging` GitHub Environment must have `S3_BUCKET`, `CLOUDFRONT_DISTRIBUTION_ID`, `AWS_ACCESS_KEY_ID`, and `AWS_SECRET_ACCESS_KEY` configured.
77+
78+
**Basic Deployment (OIDC):**
5979
```yaml
6080
jobs:
6181
deploy-production:
6282
uses: aligent/workflows/.github/workflows/pwa-deployment.yml@main
6383
with:
64-
s3-bucket: my-production-bucket
65-
cloudfront-distribution-id: E1234567890ABC
66-
environment: production
67-
cache-strategy: immutable
68-
secrets:
69-
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
70-
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
84+
github-environment: Production
85+
secrets: inherit
7186
```
7287

88+
The `Production` GitHub Environment must have `S3_BUCKET`, `CLOUDFRONT_DISTRIBUTION_ID`, and `AWS_ROLE_ARN` configured.
89+
7390
**Preview Environment for Pull Requests:**
7491
```yaml
7592
jobs:
7693
deploy-preview:
7794
if: github.event_name == 'pull_request'
7895
uses: aligent/workflows/.github/workflows/pwa-deployment.yml@main
7996
with:
80-
s3-bucket: my-preview-bucket
81-
cloudfront-distribution-id: E1234567890ABC
82-
environment: preview
97+
github-environment: Preview
8398
preview-mode: true
8499
preview-base-url: https://preview.example.com
85100
cache-strategy: no-cache
86-
secrets:
87-
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
88-
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
101+
secrets: inherit
89102
```
90103

91104
**Multi-brand Deployment:**
@@ -94,14 +107,10 @@ jobs:
94107
deploy-multi-brand:
95108
uses: aligent/workflows/.github/workflows/pwa-deployment.yml@main
96109
with:
97-
s3-bucket: my-multi-brand-bucket
98-
cloudfront-distribution-id: E1234567890ABC
99-
environment: production
110+
github-environment: Production
100111
brand-config: '{"brand":["brand-a","brand-b","brand-c"]}'
101112
build-command: build:brands
102-
secrets:
103-
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
104-
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
113+
secrets: inherit
105114
```
106115

107116
**Custom Build Configuration:**
@@ -110,13 +119,12 @@ jobs:
110119
deploy-custom:
111120
uses: aligent/workflows/.github/workflows/pwa-deployment.yml@main
112121
with:
113-
s3-bucket: my-custom-bucket
114-
cloudfront-distribution-id: E1234567890ABC
115-
environment: staging
122+
github-environment: Staging
116123
package-manager: npm
117124
build-command: build:staging
118125
build-directory: build
119126
cloudfront-invalidation-paths: '["/*", "/api/*"]'
120127
extra-sync-args: --exclude "*.map"
121128
debug: true
129+
secrets: inherit
122130
```

0 commit comments

Comments
 (0)