Skip to content
This repository was archived by the owner on Aug 10, 2026. It is now read-only.

Destroy URL Bookmark Saver #3

Destroy URL Bookmark Saver

Destroy URL Bookmark Saver #3

name: Destroy URL Bookmark Saver
# Pipeline stages:
# preflight ──→ teardown
#
# preflight validates identity and the safety confirmation.
# teardown only runs if preflight passes.
# Only runs when manually triggered — no push/PR trigger intentionally.
on:
workflow_dispatch:
inputs:
student_name:
description: 'Deployment name prefix used when the stack was deployed (e.g. john-smith)'
required: true
aws_region:
description: 'AWS region where the stack lives'
required: false
default: 'us-east-1'
aws_access_key_id:
description: 'AWS Access Key ID — leave blank to use repo secret AWS_ACCESS_KEY_ID'
required: false
default: ''
aws_secret_access_key:
description: 'AWS Secret Access Key — leave blank to use repo secret AWS_SECRET_ACCESS_KEY'
required: false
default: ''
confirm_destroy:
description: 'Type "destroy" to confirm you want to tear down all resources'
required: true
env:
PROJECT_DIR: projects/03-url-bookmark-saver
AWS_REGION: ${{ inputs.aws_region || 'us-east-1' }}
STUDENT_NAME: ${{ inputs.student_name }}
# ── Stage 1: Preflight ────────────────────────────────────────────────────────
jobs:
preflight:
name: Preflight
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write
steps:
- name: Confirm destruction intent
shell: bash
run: |
if [ "${{ inputs.confirm_destroy }}" != "destroy" ]; then
echo "::error::Safety check failed. Set confirm_destroy to the word \"destroy\" to proceed."
exit 1
fi
echo "Confirmation accepted. Will destroy stack: ${STUDENT_NAME} in ${AWS_REGION}"
- uses: actions/checkout@v4
- uses: hashicorp/setup-terraform@v3
with:
terraform_wrapper: false
# Priority 1: workflow inputs
- name: Configure AWS credentials (workflow inputs)
if: ${{ inputs.aws_access_key_id != '' }}
uses: aws-actions/configure-aws-credentials@v4
with:
aws-region: ${{ env.AWS_REGION }}
aws-access-key-id: ${{ inputs.aws_access_key_id }}
aws-secret-access-key: ${{ inputs.aws_secret_access_key }}
# Priority 2: OIDC role
- name: Configure AWS credentials (OIDC role)
if: ${{ inputs.aws_access_key_id == '' && vars.URL_BOOKMARK_SAVER_AWS_ROLE_ARN != '' }}
uses: aws-actions/configure-aws-credentials@v4
with:
aws-region: ${{ env.AWS_REGION }}
role-to-assume: ${{ vars.URL_BOOKMARK_SAVER_AWS_ROLE_ARN }}
role-session-name: github-actions-stash-destroy
# Priority 3: repo secrets
- name: Configure AWS credentials (repo secrets)
if: ${{ inputs.aws_access_key_id == '' && vars.URL_BOOKMARK_SAVER_AWS_ROLE_ARN == '' }}
uses: aws-actions/configure-aws-credentials@v4
with:
aws-region: ${{ env.AWS_REGION }}
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
- name: Verify AWS identity
run: aws sts get-caller-identity
- name: Create placeholder lambda.zip
run: |
echo "placeholder" | zip -q ${{ env.PROJECT_DIR }}/backend/lambda.zip -
- name: Terraform init (dry-run validate)
working-directory: ${{ env.PROJECT_DIR }}/terraform
run: |
terraform init -input=false
terraform plan \
-destroy \
-input=false \
-var="student_name=${STUDENT_NAME}" \
-var="aws_region=${AWS_REGION}" \
-out=destroy.tfplan
# Surface what will be destroyed before teardown runs
- name: Upload destroy plan
uses: actions/upload-artifact@v4
with:
name: destroy-tfplan
path: ${{ env.PROJECT_DIR }}/terraform/destroy.tfplan
retention-days: 1
# ── Stage 2: Teardown ─────────────────────────────────────────────────────────
teardown:
name: Teardown
runs-on: ubuntu-latest
needs: preflight
permissions:
contents: read
id-token: write
steps:
- uses: actions/checkout@v4
- uses: hashicorp/setup-terraform@v3
with:
terraform_wrapper: false
# Same credential priority as preflight
- name: Configure AWS credentials (workflow inputs)
if: ${{ inputs.aws_access_key_id != '' }}
uses: aws-actions/configure-aws-credentials@v4
with:
aws-region: ${{ env.AWS_REGION }}
aws-access-key-id: ${{ inputs.aws_access_key_id }}
aws-secret-access-key: ${{ inputs.aws_secret_access_key }}
- name: Configure AWS credentials (OIDC role)
if: ${{ inputs.aws_access_key_id == '' && vars.URL_BOOKMARK_SAVER_AWS_ROLE_ARN != '' }}
uses: aws-actions/configure-aws-credentials@v4
with:
aws-region: ${{ env.AWS_REGION }}
role-to-assume: ${{ vars.URL_BOOKMARK_SAVER_AWS_ROLE_ARN }}
role-session-name: github-actions-stash-destroy
- name: Configure AWS credentials (repo secrets)
if: ${{ inputs.aws_access_key_id == '' && vars.URL_BOOKMARK_SAVER_AWS_ROLE_ARN == '' }}
uses: aws-actions/configure-aws-credentials@v4
with:
aws-region: ${{ env.AWS_REGION }}
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
- name: Create placeholder lambda.zip
run: |
echo "placeholder" | zip -q ${{ env.PROJECT_DIR }}/backend/lambda.zip -
- name: Terraform init
working-directory: ${{ env.PROJECT_DIR }}/terraform
run: terraform init -input=false
- name: Empty S3 frontend bucket
working-directory: ${{ env.PROJECT_DIR }}/terraform
shell: bash
run: |
set -euo pipefail
terraform refresh \
-input=false \
-var="student_name=${STUDENT_NAME}" \
-var="aws_region=${AWS_REGION}" 2>/dev/null || true
BUCKET=$(terraform output -raw frontend_bucket 2>/dev/null || echo "")
if [ -n "$BUCKET" ]; then
echo "Emptying bucket: $BUCKET"
aws s3 rm "s3://${BUCKET}" --recursive --region "${AWS_REGION}" || true
else
echo "No frontend bucket found in state — skipping."
fi
- name: Terraform destroy
working-directory: ${{ env.PROJECT_DIR }}/terraform
run: |
terraform destroy \
-auto-approve \
-input=false \
-var="student_name=${STUDENT_NAME}" \
-var="aws_region=${AWS_REGION}"
- name: Publish destroy summary
if: always()
shell: bash
run: |
{
echo "## URL Bookmark Saver — Destroyed"
echo ""
echo "| | |"
echo "|---|---|"
echo "| **Region** | ${AWS_REGION} |"
echo "| **Name** | ${STUDENT_NAME} |"
echo "| **Triggered by** | ${{ github.actor }} |"
echo "| **Status** | ${{ job.status }} |"
} >> "$GITHUB_STEP_SUMMARY"