Skip to content

feat: configurator landing page, inline editor flow, CI improvements #9

feat: configurator landing page, inline editor flow, CI improvements

feat: configurator landing page, inline editor flow, CI improvements #9

Workflow file for this run

name: E2E Integration Tests
on:
pull_request:
branches: [main]
paths:
- 'map2-auto-tagger-optimized.yaml'
- 'configurator.html'
# Cancel in-progress runs for the same PR
concurrency:
group: e2e-${{ github.ref }}
cancel-in-progress: true
# Default settings inherited by all jobs
defaults:
run:
working-directory: .github/scripts
env:
PR_NUMBER: ${{ github.event.pull_request.number }}
# MPE_ID drives the expected tag value. Stored as a secret so the real
# test MPE is not hard-coded here; falls back to migTEST0000001 for forks.
MPE_ID: ${{ secrets.TEST_MPE_ID || 'migTEST0000001' }}
STACK_NAME: map-auto-tagger-e2e-pr${{ github.event.pull_request.number }}
# ---------------------------------------------------------------------------
# Reusable step fragments — referenced by name in jobs below
# ---------------------------------------------------------------------------
# ── AWS credentials helper ─────────────────────────────────────────────────
# Every job includes these three steps at the top.
# Multi-account jobs override role-to-assume.
jobs:
# ══════════════════════════════════════════════════════════════════════════
# Phase 1 — Deploy the auto-tagger itself (runs in parallel)
# ══════════════════════════════════════════════════════════════════════════
deploy-single:
name: Deploy single-account stack
runs-on: ubuntu-latest
permissions:
id-token: write
contents: read
steps:
- uses: actions/checkout@v4
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::${{ secrets.AWS_SINGLE_ACCOUNT_ID }}:role/GitHubActionsE2ERole
aws-region: ap-northeast-2
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- run: pip install boto3
- name: Deploy auto-tagger CloudFormation stack
working-directory: .
run: |
# Template is >51KB — stage in S3 per region (buckets must be co-located)
ACCOUNT=$(aws sts get-caller-identity --query Account --output text)
for REGION in ap-northeast-2 us-east-1 us-west-2; do
S3_BUCKET="cfn-e2e-${ACCOUNT}-${PR_NUMBER}-${REGION}"
# us-east-1 does not accept LocationConstraint
if [ "$REGION" = "us-east-1" ]; then
aws s3api create-bucket --bucket "$S3_BUCKET" --region us-east-1 2>/dev/null || true
else
aws s3api create-bucket \
--bucket "$S3_BUCKET" \
--region "$REGION" \
--create-bucket-configuration LocationConstraint="$REGION" \
2>/dev/null || true
fi
aws cloudformation deploy \
--stack-name "${STACK_NAME}" \
--template-file map2-auto-tagger-optimized.yaml \
--parameter-overrides \
MpeId="$MPE_ID" \
AgreementStartDate="2024-01-01" \
--capabilities CAPABILITY_NAMED_IAM \
--s3-bucket "$S3_BUCKET" \
--s3-prefix "e2e" \
--region "$REGION" \
--no-fail-on-empty-changeset
done
- name: Verify stack is deployed
working-directory: .
run: |
STATUS=$(aws cloudformation describe-stacks \
--stack-name "$STACK_NAME" \
--query 'Stacks[0].StackStatus' --output text)
echo "Stack status: $STATUS"
if [[ "$STATUS" != *"COMPLETE"* ]]; then
echo "Stack not in a successful state: $STATUS"
exit 1
fi
deploy-stackset:
name: Deploy multi-account StackSet
runs-on: ubuntu-latest
permissions:
id-token: write
contents: read
steps:
- uses: actions/checkout@v4
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::${{ secrets.AWS_MGMT_ACCOUNT_ID }}:role/GitHubActionsE2ERole
aws-region: ap-northeast-2
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- run: pip install boto3
- name: Deploy StackSet to linked accounts
run: |
python3 deploy_stackset.py \
--stack-set-name "$STACK_NAME-stackset" \
--template ../../map2-auto-tagger-optimized.yaml \
--mpe-id "$MPE_ID" \
--agreement-date "2024-01-01" \
--accounts "${{ secrets.E2E_LINKED_ACCOUNT_IDS }}" \
--org-unit-ids "${{ secrets.AWS_SANDBOX_OU_ID }}" \
--region ap-northeast-2
# ══════════════════════════════════════════════════════════════════════════
# Phase 2 — Create test resources (all parallel, each group independent)
# ══════════════════════════════════════════════════════════════════════════
create-networking:
name: Create networking resources
runs-on: ubuntu-latest
needs: [deploy-single]
permissions:
id-token: write
contents: read
outputs:
vpc-id: ${{ steps.create.outputs.vpc-id }}
subnet-ids: ${{ steps.create.outputs.subnet-ids }}
sg-id: ${{ steps.create.outputs.sg-id }}
steps:
- uses: actions/checkout@v4
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::${{ secrets.AWS_SINGLE_ACCOUNT_ID }}:role/GitHubActionsE2ERole
aws-region: ap-northeast-2
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- run: pip install boto3
- name: Create networking resources
id: create
run: |
python3 create_resources.py \
--group networking \
--region ap-northeast-2
- uses: actions/upload-artifact@v4
if: always()
with:
name: arns-networking
path: .github/scripts/created-arns-networking.json
if-no-files-found: warn
create-core:
name: Create core compute resources
runs-on: ubuntu-latest
needs: [deploy-single]
permissions:
id-token: write
contents: read
steps:
- uses: actions/checkout@v4
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::${{ secrets.AWS_SINGLE_ACCOUNT_ID }}:role/GitHubActionsE2ERole
aws-region: ap-northeast-2
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- run: pip install boto3
- name: Create core resources
run: |
python3 create_resources.py --group core --region ap-northeast-2
- uses: actions/upload-artifact@v4
if: always()
with:
name: arns-core
path: .github/scripts/created-arns-core.json
if-no-files-found: warn
create-databases:
name: Create database resources
runs-on: ubuntu-latest
needs: [deploy-single, create-networking]
permissions:
id-token: write
contents: read
steps:
- uses: actions/checkout@v4
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::${{ secrets.AWS_SINGLE_ACCOUNT_ID }}:role/GitHubActionsE2ERole
aws-region: ap-northeast-2
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- run: pip install boto3
- name: Create database resources
run: |
python3 create_resources.py \
--group databases \
--region ap-northeast-2 \
--vpc-id "${{ needs.create-networking.outputs.vpc-id }}" \
--subnet-ids "${{ needs.create-networking.outputs.subnet-ids }}" \
--sg-id "${{ needs.create-networking.outputs.sg-id }}"
- uses: actions/upload-artifact@v4
if: always()
with:
name: arns-databases
path: .github/scripts/created-arns-databases.json
if-no-files-found: warn
create-analytics:
name: Create analytics resources
runs-on: ubuntu-latest
needs: [deploy-single]
permissions:
id-token: write
contents: read
steps:
- uses: actions/checkout@v4
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::${{ secrets.AWS_SINGLE_ACCOUNT_ID }}:role/GitHubActionsE2ERole
aws-region: ap-northeast-2
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- run: pip install boto3
- name: Create analytics resources
run: |
python3 create_resources.py --group analytics --region ap-northeast-2
- uses: actions/upload-artifact@v4
if: always()
with:
name: arns-analytics
path: .github/scripts/created-arns-analytics.json
if-no-files-found: warn
create-integration:
name: Create integration resources
runs-on: ubuntu-latest
needs: [deploy-single]
permissions:
id-token: write
contents: read
steps:
- uses: actions/checkout@v4
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::${{ secrets.AWS_SINGLE_ACCOUNT_ID }}:role/GitHubActionsE2ERole
aws-region: ap-northeast-2
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- run: pip install boto3
- name: Create integration resources
run: |
python3 create_resources.py --group integration --region ap-northeast-2
- uses: actions/upload-artifact@v4
if: always()
with:
name: arns-integration
path: .github/scripts/created-arns-integration.json
if-no-files-found: warn
create-security:
name: Create security resources
runs-on: ubuntu-latest
needs: [deploy-single]
permissions:
id-token: write
contents: read
steps:
- uses: actions/checkout@v4
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::${{ secrets.AWS_SINGLE_ACCOUNT_ID }}:role/GitHubActionsE2ERole
aws-region: ap-northeast-2
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- run: pip install boto3
- name: Create security resources
run: |
python3 create_resources.py --group security --region ap-northeast-2
- uses: actions/upload-artifact@v4
if: always()
with:
name: arns-security
path: .github/scripts/created-arns-security.json
if-no-files-found: warn
create-devtools:
name: Create devtools resources
runs-on: ubuntu-latest
needs: [deploy-single]
permissions:
id-token: write
contents: read
steps:
- uses: actions/checkout@v4
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::${{ secrets.AWS_SINGLE_ACCOUNT_ID }}:role/GitHubActionsE2ERole
aws-region: ap-northeast-2
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- run: pip install boto3
- name: Create devtools resources
run: |
python3 create_resources.py --group devtools --region ap-northeast-2
- uses: actions/upload-artifact@v4
if: always()
with:
name: arns-devtools
path: .github/scripts/created-arns-devtools.json
if-no-files-found: warn
create-ml:
name: Create ML/AI resources
runs-on: ubuntu-latest
needs: [deploy-single]
permissions:
id-token: write
contents: read
steps:
- uses: actions/checkout@v4
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::${{ secrets.AWS_SINGLE_ACCOUNT_ID }}:role/GitHubActionsE2ERole
aws-region: ap-northeast-2
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- run: pip install boto3
- name: Create ML resources
run: |
python3 create_resources.py --group ml --region ap-northeast-2
- uses: actions/upload-artifact@v4
if: always()
with:
name: arns-ml
path: .github/scripts/created-arns-ml.json
if-no-files-found: warn
create-media-iot:
name: Create media and IoT resources
runs-on: ubuntu-latest
needs: [deploy-single]
permissions:
id-token: write
contents: read
steps:
- uses: actions/checkout@v4
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::${{ secrets.AWS_SINGLE_ACCOUNT_ID }}:role/GitHubActionsE2ERole
aws-region: ap-northeast-2
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- run: pip install boto3
- name: Create media and IoT resources
run: |
python3 create_resources.py --group media-iot --region ap-northeast-2
- uses: actions/upload-artifact@v4
if: always()
with:
name: arns-media-iot
path: .github/scripts/created-arns-media-iot.json
if-no-files-found: warn
create-misc:
name: Create miscellaneous resources
runs-on: ubuntu-latest
needs: [deploy-single]
permissions:
id-token: write
contents: read
steps:
- uses: actions/checkout@v4
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::${{ secrets.AWS_SINGLE_ACCOUNT_ID }}:role/GitHubActionsE2ERole
aws-region: ap-northeast-2
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- run: pip install boto3
- name: Create miscellaneous resources
run: |
python3 create_resources.py --group misc --region ap-northeast-2
- uses: actions/upload-artifact@v4
if: always()
with:
name: arns-misc
path: .github/scripts/created-arns-misc.json
if-no-files-found: warn
create-global-us-east-1:
name: Create global us-east-1 resources
runs-on: ubuntu-latest
needs: [deploy-single]
permissions:
id-token: write
contents: read
steps:
- uses: actions/checkout@v4
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::${{ secrets.AWS_SINGLE_ACCOUNT_ID }}:role/GitHubActionsE2ERole
aws-region: us-east-1
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- run: pip install boto3
- name: Create global us-east-1 resources
run: |
python3 create_resources.py --group global-us-east-1 --region us-east-1
- uses: actions/upload-artifact@v4
if: always()
with:
name: arns-global-us-east-1
path: .github/scripts/created-arns-global-us-east-1.json
if-no-files-found: warn
create-global-us-west-2:
name: Create global us-west-2 resources
runs-on: ubuntu-latest
needs: [deploy-single]
permissions:
id-token: write
contents: read
steps:
- uses: actions/checkout@v4
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::${{ secrets.AWS_SINGLE_ACCOUNT_ID }}:role/GitHubActionsE2ERole
aws-region: us-west-2
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- run: pip install boto3
- name: Create global us-west-2 resources
run: |
python3 create_resources.py --group global-us-west-2 --region us-west-2
- uses: actions/upload-artifact@v4
if: always()
with:
name: arns-global-us-west-2
path: .github/scripts/created-arns-global-us-west-2.json
if-no-files-found: warn
# ── Multi-account linked account resource creation ────────────────────────
# Each linked account job assumes a separate role specific to that account.
create-multiaccount-linked1:
name: Create resources in linked account 1
runs-on: ubuntu-latest
needs: [deploy-stackset]
permissions:
id-token: write
contents: read
steps:
- uses: actions/checkout@v4
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::${{ secrets.AWS_LINKED1_ACCOUNT_ID }}:role/GitHubActionsE2ERole
aws-region: ap-northeast-2
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- run: pip install boto3
- name: Create resources in linked account 1
run: |
python3 create_resources.py \
--group multiaccount-linked1 \
--account-index 1 \
--region ap-northeast-2
- uses: actions/upload-artifact@v4
if: always()
with:
name: arns-multiaccount-linked1
path: .github/scripts/created-arns-multiaccount-linked1.json
if-no-files-found: warn
create-multiaccount-linked2:
name: Create resources in linked account 2
runs-on: ubuntu-latest
needs: [deploy-stackset]
permissions:
id-token: write
contents: read
steps:
- uses: actions/checkout@v4
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::${{ secrets.AWS_LINKED2_ACCOUNT_ID }}:role/GitHubActionsE2ERole
aws-region: ap-northeast-2
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- run: pip install boto3
- name: Create resources in linked account 2
run: |
python3 create_resources.py \
--group multiaccount-linked2 \
--account-index 2 \
--region ap-northeast-2
- uses: actions/upload-artifact@v4
if: always()
with:
name: arns-multiaccount-linked2
path: .github/scripts/created-arns-multiaccount-linked2.json
if-no-files-found: warn
create-multiaccount-linked3:
name: Create resources in linked account 3
runs-on: ubuntu-latest
needs: [deploy-stackset]
permissions:
id-token: write
contents: read
steps:
- uses: actions/checkout@v4
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::${{ secrets.AWS_LINKED3_ACCOUNT_ID }}:role/GitHubActionsE2ERole
aws-region: ap-northeast-2
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- run: pip install boto3
- name: Create resources in linked account 3
run: |
python3 create_resources.py \
--group multiaccount-linked3 \
--account-index 3 \
--region ap-northeast-2
- uses: actions/upload-artifact@v4
if: always()
with:
name: arns-multiaccount-linked3
path: .github/scripts/created-arns-multiaccount-linked3.json
if-no-files-found: warn
create-multiaccount-linked4:
name: Create resources in linked account 4
runs-on: ubuntu-latest
needs: [deploy-stackset]
permissions:
id-token: write
contents: read
steps:
- uses: actions/checkout@v4
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::${{ secrets.AWS_LINKED4_ACCOUNT_ID }}:role/GitHubActionsE2ERole
aws-region: ap-northeast-2
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- run: pip install boto3
- name: Create resources in linked account 4
run: |
python3 create_resources.py \
--group multiaccount-linked4 \
--account-index 4 \
--region ap-northeast-2
- uses: actions/upload-artifact@v4
if: always()
with:
name: arns-multiaccount-linked4
path: .github/scripts/created-arns-multiaccount-linked4.json
if-no-files-found: warn
create-multiaccount-linked5:
name: Create resources in linked account 5
runs-on: ubuntu-latest
needs: [deploy-stackset]
permissions:
id-token: write
contents: read
steps:
- uses: actions/checkout@v4
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::${{ secrets.AWS_LINKED5_ACCOUNT_ID }}:role/GitHubActionsE2ERole
aws-region: ap-northeast-2
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- run: pip install boto3
- name: Create resources in linked account 5
run: |
python3 create_resources.py \
--group multiaccount-linked5 \
--account-index 5 \
--region ap-northeast-2
- uses: actions/upload-artifact@v4
if: always()
with:
name: arns-multiaccount-linked5
path: .github/scripts/created-arns-multiaccount-linked5.json
if-no-files-found: warn
# ══════════════════════════════════════════════════════════════════════════
# Phase 3 — Verify tags (runs after all create jobs)
# ══════════════════════════════════════════════════════════════════════════
verify:
name: Verify map-migrated tags
runs-on: ubuntu-latest
needs:
- create-networking
- create-core
- create-databases
- create-analytics
- create-integration
- create-security
- create-devtools
- create-ml
- create-media-iot
- create-misc
- create-global-us-east-1
- create-global-us-west-2
- create-multiaccount-linked1
- create-multiaccount-linked2
- create-multiaccount-linked3
- create-multiaccount-linked4
- create-multiaccount-linked5
permissions:
id-token: write
contents: read
steps:
- uses: actions/checkout@v4
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::${{ secrets.AWS_SINGLE_ACCOUNT_ID }}:role/GitHubActionsE2ERole
aws-region: ap-northeast-2
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- run: pip install boto3
# Download all ARN artifact files into a single directory
- uses: actions/download-artifact@v4
with:
pattern: arns-*
path: artifacts/
merge-multiple: true
- name: List downloaded ARN files
run: ls -la artifacts/ || echo "No artifacts directory"
working-directory: .
- name: Verify tags on all resources
run: |
python3 verify_tags.py \
--arns-dir ../../artifacts/ \
--tag-key map-migrated \
--tag-value "$MPE_ID" \
--max-wait 900 \
--poll-interval 30
- uses: actions/upload-artifact@v4
if: always()
with:
name: verification-report
path: .github/scripts/verification-report.json
if-no-files-found: warn
# ══════════════════════════════════════════════════════════════════════════
# Phase 3b — deploy.sh generation + execution test
# Tests that configurator.html generates a working deploy.sh (not just the YAML)
# ══════════════════════════════════════════════════════════════════════════
test-deploy-sh:
name: Test deploy.sh generation and execution
runs-on: ubuntu-latest
needs: [deploy-single]
permissions:
id-token: write
contents: read
steps:
- uses: actions/checkout@v4
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::${{ secrets.AWS_SINGLE_ACCOUNT_ID }}:role/GitHubActionsE2ERole
aws-region: ap-northeast-2
- uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install Playwright
working-directory: .
run: npm install playwright && npx playwright install chromium --with-deps
- name: Generate deploy.sh from configurator.html
working-directory: .
run: |
node .github/scripts/generate_deploy_sh.js \
--mpe-id "$MPE_ID" \
--agreement-date "2024-01-01" \
--agreement-end-date "2099-12-31" \
--region ap-northeast-2 \
--mode single \
--output /tmp/deploy-generated.sh
- name: Run generated deploy.sh (dry-run validation)
working-directory: .
run: |
# Verify key elements are present in the generated script
echo "Validating generated deploy.sh contents..."
grep -q "aws cloudformation deploy" /tmp/deploy-generated.sh && echo "✅ cloudformation deploy command present"
grep -q "$MPE_ID" /tmp/deploy-generated.sh && echo "✅ MPE ID present"
grep -q "ap-northeast-2" /tmp/deploy-generated.sh && echo "✅ region present"
grep -q "AgreementStartDate" /tmp/deploy-generated.sh && echo "✅ agreement date parameter present"
grep -q "CloudTrail" /tmp/deploy-generated.sh && echo "✅ CloudTrail preflight check present"
grep -q "map2-auto-tagger" /tmp/deploy-generated.sh && echo "✅ stack name present"
echo "All content checks passed."
- name: Execute generated deploy.sh
working-directory: .
run: |
ACCT=$(aws sts get-caller-identity --query Account --output text)
S3_BUCKET="cfn-e2e-${ACCT}-${PR_NUMBER}-ap-northeast-2"
aws s3api create-bucket --bucket "$S3_BUCKET" --region ap-northeast-2 --create-bucket-configuration LocationConstraint=ap-northeast-2 2>/dev/null || true
# Inject S3 bucket into the script (deploy.sh stages template to S3 itself,
# but needs a bucket to exist — the script creates one named after account ID)
bash /tmp/deploy-generated.sh
env:
AWS_DEFAULT_REGION: ap-northeast-2
# ══════════════════════════════════════════════════════════════════════════
# Phase 3c — Scoping tests
# Tests that account scope, VPC scope, and date filtering work correctly
# ══════════════════════════════════════════════════════════════════════════
# ── Account scope test ─────────────────────────────────────────────────────
deploy-scope-account:
name: "[Scope] Deploy account-scoped stack (linked1 only)"
runs-on: ubuntu-latest
needs: [deploy-stackset]
permissions:
id-token: write
contents: read
steps:
- uses: actions/checkout@v4
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::${{ secrets.AWS_SINGLE_ACCOUNT_ID }}:role/GitHubActionsE2ERole
aws-region: ap-northeast-2
- name: Deploy account-scoped stack
working-directory: .
run: |
ACCT=$(aws sts get-caller-identity --query Account --output text)
S3_BUCKET="cfn-e2e-${ACCT}-${PR_NUMBER}-ap-northeast-2"
aws s3api create-bucket --bucket "$S3_BUCKET" --region ap-northeast-2 --create-bucket-configuration LocationConstraint=ap-northeast-2 2>/dev/null || true
aws cloudformation deploy \
--stack-name "${STACK_NAME}-scope-acct" \
--template-file map2-auto-tagger-optimized.yaml \
--parameter-overrides \
MpeId="$MPE_ID" \
AgreementStartDate="2024-01-01" \
ScopeMode="account" \
ScopedAccountIds="${{ secrets.AWS_LINKED1_ACCOUNT_ID }}" \
--capabilities CAPABILITY_NAMED_IAM \
--s3-bucket "$S3_BUCKET" \
--s3-prefix "e2e-scope-acct" \
--region ap-northeast-2 \
--no-fail-on-empty-changeset
create-scope-account-inscope:
name: "[Scope] Create resource in-scope account (linked1)"
runs-on: ubuntu-latest
needs: [deploy-scope-account]
permissions:
id-token: write
contents: read
steps:
- uses: actions/checkout@v4
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::${{ secrets.AWS_LINKED1_ACCOUNT_ID }}:role/GitHubActionsE2ERole
aws-region: ap-northeast-2
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- run: pip install boto3
- name: Create S3 bucket in linked1 (should be tagged)
run: |
python3 - <<'EOF'
import boto3, json, os, time
s3 = boto3.client('s3', region_name='ap-northeast-2')
name = f"e2e-scope-acct-inscope-{os.environ['PR_NUMBER']}-{int(time.time())}"
s3.create_bucket(Bucket=name, CreateBucketConfiguration={'LocationConstraint': 'ap-northeast-2'})
record = {"arn": f"arn:aws:s3:::{name}", "service": "s3", "region": "ap-northeast-2",
"account": boto3.client('sts').get_caller_identity()['Account'],
"resource_id": name, "taggable": True,
"expected_tag_key": "map-migrated", "expected_tag_value": os.environ['MPE_ID']}
with open('created-arns-scope-acct-inscope.json', 'w') as f:
json.dump([record], f)
print(f"Created S3 bucket: {name}")
EOF
working-directory: .github/scripts
- uses: actions/upload-artifact@v4
if: always()
with:
name: arns-scope-acct-inscope
path: .github/scripts/created-arns-scope-acct-inscope.json
if-no-files-found: warn
create-scope-account-outscope:
name: "[Scope] Create resource out-of-scope account (linked2)"
runs-on: ubuntu-latest
needs: [deploy-scope-account]
permissions:
id-token: write
contents: read
steps:
- uses: actions/checkout@v4
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::${{ secrets.AWS_LINKED2_ACCOUNT_ID }}:role/GitHubActionsE2ERole
aws-region: ap-northeast-2
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- run: pip install boto3
- name: Create S3 bucket in linked2 (should NOT be tagged)
run: |
python3 - <<'EOF'
import boto3, json, os, time
s3 = boto3.client('s3', region_name='ap-northeast-2')
name = f"e2e-scope-acct-outscope-{os.environ['PR_NUMBER']}-{int(time.time())}"
s3.create_bucket(Bucket=name, CreateBucketConfiguration={'LocationConstraint': 'ap-northeast-2'})
record = {"arn": f"arn:aws:s3:::{name}", "service": "s3", "region": "ap-northeast-2",
"account": boto3.client('sts').get_caller_identity()['Account'],
"resource_id": name, "taggable": True,
"expected_tag_key": "map-migrated", "expected_tag_value": os.environ['MPE_ID']}
with open('created-arns-scope-acct-outscope.json', 'w') as f:
json.dump([record], f)
print(f"Created S3 bucket: {name}")
EOF
working-directory: .github/scripts
- uses: actions/upload-artifact@v4
if: always()
with:
name: arns-scope-acct-outscope
path: .github/scripts/created-arns-scope-acct-outscope.json
if-no-files-found: warn
verify-scope-account-positive:
name: "[Scope] Verify in-scope resource IS tagged"
runs-on: ubuntu-latest
needs: [create-scope-account-inscope]
permissions:
id-token: write
contents: read
steps:
- uses: actions/checkout@v4
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::${{ secrets.AWS_LINKED1_ACCOUNT_ID }}:role/GitHubActionsE2ERole
aws-region: ap-northeast-2
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- run: pip install boto3
- uses: actions/download-artifact@v4
with:
name: arns-scope-acct-inscope
path: artifacts/
- run: |
python3 verify_tags.py \
--arns-dir ../../artifacts/ \
--tag-key map-migrated \
--tag-value "$MPE_ID" \
--max-wait 300 \
--poll-interval 30
working-directory: .github/scripts
verify-scope-account-negative:
name: "[Scope] Verify out-of-scope resource is NOT tagged"
runs-on: ubuntu-latest
needs: [create-scope-account-outscope]
permissions:
id-token: write
contents: read
steps:
- uses: actions/checkout@v4
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::${{ secrets.AWS_LINKED2_ACCOUNT_ID }}:role/GitHubActionsE2ERole
aws-region: ap-northeast-2
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- run: pip install boto3
- uses: actions/download-artifact@v4
with:
name: arns-scope-acct-outscope
path: artifacts/
- run: |
python3 verify_tags.py \
--arns-dir ../../artifacts/ \
--tag-key map-migrated \
--tag-value "$MPE_ID" \
--expect-not-tagged \
--not-tagged-wait 120
working-directory: .github/scripts
# ── VPC scope test ──────────────────────────────────────────────────────────
deploy-scope-vpc:
name: "[Scope] Deploy VPC-scoped stack"
runs-on: ubuntu-latest
needs: [create-networking]
permissions:
id-token: write
contents: read
steps:
- uses: actions/checkout@v4
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::${{ secrets.AWS_SINGLE_ACCOUNT_ID }}:role/GitHubActionsE2ERole
aws-region: ap-northeast-2
- name: Deploy VPC-scoped stack
working-directory: .
run: |
ACCT=$(aws sts get-caller-identity --query Account --output text)
S3_BUCKET="cfn-e2e-${ACCT}-${PR_NUMBER}-ap-northeast-2"
aws cloudformation deploy \
--stack-name "${STACK_NAME}-scope-vpc" \
--template-file map2-auto-tagger-optimized.yaml \
--parameter-overrides \
MpeId="$MPE_ID" \
AgreementStartDate="2024-01-01" \
ScopeMode="vpc" \
ScopedVpcIds="${{ needs.create-networking.outputs.vpc-id }}" \
--capabilities CAPABILITY_NAMED_IAM \
--s3-bucket "$S3_BUCKET" \
--s3-prefix "e2e-scope-vpc" \
--region ap-northeast-2 \
--no-fail-on-empty-changeset
create-scope-vpc-inscope:
name: "[Scope] Create SG in scoped VPC (should be tagged)"
runs-on: ubuntu-latest
needs: [deploy-scope-vpc, create-networking]
permissions:
id-token: write
contents: read
steps:
- uses: actions/checkout@v4
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::${{ secrets.AWS_SINGLE_ACCOUNT_ID }}:role/GitHubActionsE2ERole
aws-region: ap-northeast-2
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- run: pip install boto3
- name: Create security group in scoped VPC
run: |
python3 - <<'EOF'
import boto3, json, os, time
ec2 = boto3.client('ec2', region_name='ap-northeast-2')
sts = boto3.client('sts')
account = sts.get_caller_identity()['Account']
vpc_id = os.environ['VPC_ID']
sg = ec2.create_security_group(
GroupName=f"e2e-scope-vpc-inscope-{os.environ['PR_NUMBER']}-{int(time.time())}",
Description="E2E scope test - in VPC scope",
VpcId=vpc_id
)
sg_id = sg['GroupId']
arn = f"arn:aws:ec2:ap-northeast-2:{account}:security-group/{sg_id}"
record = {"arn": arn, "service": "ec2", "region": "ap-northeast-2", "account": account,
"resource_id": sg_id, "taggable": True,
"expected_tag_key": "map-migrated", "expected_tag_value": os.environ['MPE_ID']}
with open('created-arns-scope-vpc-inscope.json', 'w') as f:
json.dump([record], f)
print(f"Created SG {sg_id} in VPC {vpc_id}")
EOF
working-directory: .github/scripts
env:
VPC_ID: ${{ needs.create-networking.outputs.vpc-id }}
- uses: actions/upload-artifact@v4
if: always()
with:
name: arns-scope-vpc-inscope
path: .github/scripts/created-arns-scope-vpc-inscope.json
if-no-files-found: warn
create-scope-vpc-outscope:
name: "[Scope] Create SG in default VPC (should NOT be tagged)"
runs-on: ubuntu-latest
needs: [deploy-scope-vpc]
permissions:
id-token: write
contents: read
steps:
- uses: actions/checkout@v4
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::${{ secrets.AWS_SINGLE_ACCOUNT_ID }}:role/GitHubActionsE2ERole
aws-region: ap-northeast-2
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- run: pip install boto3
- name: Create security group in default VPC (out of scope)
run: |
python3 - <<'EOF'
import boto3, json, os, time
ec2 = boto3.client('ec2', region_name='ap-northeast-2')
sts = boto3.client('sts')
account = sts.get_caller_identity()['Account']
# Get default VPC (different from scoped VPC)
vpcs = ec2.describe_vpcs(Filters=[{'Name': 'isDefault', 'Values': ['true']}])
default_vpc = vpcs['Vpcs'][0]['VpcId'] if vpcs['Vpcs'] else None
if not default_vpc:
print("No default VPC found — creating VPC for test")
default_vpc = ec2.create_vpc(CidrBlock='172.31.0.0/16')['Vpc']['VpcId']
sg = ec2.create_security_group(
GroupName=f"e2e-scope-vpc-outscope-{os.environ['PR_NUMBER']}-{int(time.time())}",
Description="E2E scope test - out of VPC scope",
VpcId=default_vpc
)
sg_id = sg['GroupId']
arn = f"arn:aws:ec2:ap-northeast-2:{account}:security-group/{sg_id}"
record = {"arn": arn, "service": "ec2", "region": "ap-northeast-2", "account": account,
"resource_id": sg_id, "taggable": True,
"expected_tag_key": "map-migrated", "expected_tag_value": os.environ['MPE_ID']}
with open('created-arns-scope-vpc-outscope.json', 'w') as f:
json.dump([record], f)
print(f"Created SG {sg_id} in default VPC {default_vpc}")
EOF
working-directory: .github/scripts
- uses: actions/upload-artifact@v4
if: always()
with:
name: arns-scope-vpc-outscope
path: .github/scripts/created-arns-scope-vpc-outscope.json
if-no-files-found: warn
verify-scope-vpc-positive:
name: "[Scope] Verify VPC-scoped SG IS tagged"
runs-on: ubuntu-latest
needs: [create-scope-vpc-inscope]
permissions:
id-token: write
contents: read
steps:
- uses: actions/checkout@v4
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::${{ secrets.AWS_SINGLE_ACCOUNT_ID }}:role/GitHubActionsE2ERole
aws-region: ap-northeast-2
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- run: pip install boto3
- uses: actions/download-artifact@v4
with:
name: arns-scope-vpc-inscope
path: artifacts/
- run: |
python3 verify_tags.py \
--arns-dir ../../artifacts/ \
--tag-key map-migrated \
--tag-value "$MPE_ID" \
--max-wait 300 \
--poll-interval 30
working-directory: .github/scripts
verify-scope-vpc-negative:
name: "[Scope] Verify out-of-VPC SG is NOT tagged"
runs-on: ubuntu-latest
needs: [create-scope-vpc-outscope]
permissions:
id-token: write
contents: read
steps:
- uses: actions/checkout@v4
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::${{ secrets.AWS_SINGLE_ACCOUNT_ID }}:role/GitHubActionsE2ERole
aws-region: ap-northeast-2
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- run: pip install boto3
- uses: actions/download-artifact@v4
with:
name: arns-scope-vpc-outscope
path: artifacts/
- run: |
python3 verify_tags.py \
--arns-dir ../../artifacts/ \
--tag-key map-migrated \
--tag-value "$MPE_ID" \
--expect-not-tagged \
--not-tagged-wait 120
working-directory: .github/scripts
# ── Date filter test ────────────────────────────────────────────────────────
deploy-scope-date:
name: "[Scope] Deploy future-dated stack"
runs-on: ubuntu-latest
needs: [deploy-single]
permissions:
id-token: write
contents: read
steps:
- uses: actions/checkout@v4
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::${{ secrets.AWS_SINGLE_ACCOUNT_ID }}:role/GitHubActionsE2ERole
aws-region: ap-northeast-2
- name: Deploy stack with future agreement start date
working-directory: .
run: |
TOMORROW=$(date -d '+1 day' '+%Y-%m-%d')
ACCT=$(aws sts get-caller-identity --query Account --output text)
S3_BUCKET="cfn-e2e-${ACCT}-${PR_NUMBER}-ap-northeast-2"
aws cloudformation deploy \
--stack-name "${STACK_NAME}-scope-date" \
--template-file map2-auto-tagger-optimized.yaml \
--parameter-overrides \
MpeId="$MPE_ID" \
AgreementStartDate="${TOMORROW}" \
--capabilities CAPABILITY_NAMED_IAM \
--s3-bucket "$S3_BUCKET" \
--s3-prefix "e2e-scope-date" \
--region ap-northeast-2 \
--no-fail-on-empty-changeset
create-scope-date:
name: "[Scope] Create resource before agreement start (should NOT be tagged)"
runs-on: ubuntu-latest
needs: [deploy-scope-date]
permissions:
id-token: write
contents: read
steps:
- uses: actions/checkout@v4
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::${{ secrets.AWS_SINGLE_ACCOUNT_ID }}:role/GitHubActionsE2ERole
aws-region: ap-northeast-2
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- run: pip install boto3
- name: Create S3 bucket (before agreement start date)
run: |
python3 - <<'EOF'
import boto3, json, os, time
s3 = boto3.client('s3', region_name='ap-northeast-2')
name = f"e2e-scope-date-{os.environ['PR_NUMBER']}-{int(time.time())}"
s3.create_bucket(Bucket=name, CreateBucketConfiguration={'LocationConstraint': 'ap-northeast-2'})
record = {"arn": f"arn:aws:s3:::{name}", "service": "s3", "region": "ap-northeast-2",
"account": boto3.client('sts').get_caller_identity()['Account'],
"resource_id": name, "taggable": True,
"expected_tag_key": "map-migrated", "expected_tag_value": os.environ['MPE_ID']}
with open('created-arns-scope-date.json', 'w') as f:
json.dump([record], f)
print(f"Created S3 bucket: {name} (should NOT be tagged — before agreement start)")
EOF
working-directory: .github/scripts
- uses: actions/upload-artifact@v4
if: always()
with:
name: arns-scope-date
path: .github/scripts/created-arns-scope-date.json
if-no-files-found: warn
verify-scope-date:
name: "[Scope] Verify pre-agreement resource is NOT tagged"
runs-on: ubuntu-latest
needs: [create-scope-date]
permissions:
id-token: write
contents: read
steps:
- uses: actions/checkout@v4
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::${{ secrets.AWS_SINGLE_ACCOUNT_ID }}:role/GitHubActionsE2ERole
aws-region: ap-northeast-2
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- run: pip install boto3
- uses: actions/download-artifact@v4
with:
name: arns-scope-date
path: artifacts/
- run: |
python3 verify_tags.py \
--arns-dir ../../artifacts/ \
--tag-key map-migrated \
--tag-value "$MPE_ID" \
--expect-not-tagged \
--not-tagged-wait 120
working-directory: .github/scripts
# ══════════════════════════════════════════════════════════════════════════
# Phase 4 — Teardown (always runs, even on failure)
# ══════════════════════════════════════════════════════════════════════════
teardown:
name: Teardown all E2E resources
runs-on: ubuntu-latest
if: always()
needs:
- verify
- test-deploy-sh
- verify-scope-account-positive
- verify-scope-account-negative
- verify-scope-vpc-positive
- verify-scope-vpc-negative
- verify-scope-date
- create-networking
- create-core
- create-databases
- create-analytics
- create-integration
- create-security
- create-devtools
- create-ml
- create-media-iot
- create-misc
- create-global-us-east-1
- create-global-us-west-2
- create-multiaccount-linked1
- create-multiaccount-linked2
- create-multiaccount-linked3
- create-multiaccount-linked4
- create-multiaccount-linked5
permissions:
id-token: write
contents: read
steps:
- uses: actions/checkout@v4
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::${{ secrets.AWS_SINGLE_ACCOUNT_ID }}:role/GitHubActionsE2ERole
aws-region: ap-northeast-2
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- run: pip install boto3
# Download all ARN records so teardown knows what to delete
- uses: actions/download-artifact@v4
with:
pattern: arns-*
path: artifacts/
merge-multiple: true
continue-on-error: true
- name: Delete test resources
run: |
python3 teardown.py \
--arns-dir ../../artifacts/ \
--pr "$PR_NUMBER" \
--tag-value "$MPE_ID"
continue-on-error: true
- name: Delete single-account CloudFormation stacks and S3 staging bucket
working-directory: .
run: |
for REGION in ap-northeast-2 us-east-1 us-west-2; do
aws cloudformation delete-stack --stack-name "$STACK_NAME" --region "$REGION" || true
done
# Delete scoped test stacks
for SUFFIX in scope-acct scope-vpc scope-date; do
aws cloudformation delete-stack --stack-name "${STACK_NAME}-${SUFFIX}" --region ap-northeast-2 || true
done
# Delete the stack deployed by deploy.sh test
aws cloudformation delete-stack --stack-name "map-auto-tagger-$MPE_ID" --region ap-northeast-2 || true
ACCOUNT=$(aws sts get-caller-identity --query Account --output text)
# Delete per-region staging buckets
for REGION in ap-northeast-2 us-east-1 us-west-2; do
aws s3 rb "s3://cfn-e2e-${ACCOUNT}-${PR_NUMBER}-${REGION}" --force 2>/dev/null || true
done
# Delete single ap-northeast-2 bucket used by scoped test deploys
aws s3 rb "s3://cfn-e2e-${ACCOUNT}-${PR_NUMBER}" --force 2>/dev/null || true
echo "Stack deletions initiated and S3 staging buckets removed"
continue-on-error: true
- name: Delete multi-account StackSet
run: |
python3 delete_stackset.py \
--name "$STACK_NAME-stackset" \
--accounts "${{ secrets.E2E_LINKED_ACCOUNT_IDS }}" \
--region ap-northeast-2
continue-on-error: true