Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 6 additions & 46 deletions .github/workflows/AdminWebpage-Deploy-WF.yml
Original file line number Diff line number Diff line change
@@ -1,22 +1,20 @@
name: AdminWebpage-Deploy-WF

# Provisions the Admin Web App App Service via Terraform, then builds and
# deploys the React SPA to it. Auth uses the same OIDC federated identity
# Phil configured for the BotNet API workflow, so no new secrets are needed.
# Builds and deploys the Admin Web App React SPA to Azure App Service.
# Infrastructure provisioning (App Service, etc.) is handled separately by
# .github/workflows/iac.yml — this workflow only builds and deploys the app.

on:
workflow_dispatch:
pull_request:
branches: [main]
paths:
- "admin-webapp/**"
- "Iac/admin-webapp/**"
- ".github/workflows/AdminWebpage-Deploy-WF.yml"
push:
branches: [main]
paths:
- "admin-webapp/**"
- "Iac/admin-webapp/**"
- ".github/workflows/AdminWebpage-Deploy-WF.yml"

permissions:
Expand All @@ -26,13 +24,11 @@ permissions:
env:
RESOURCE_GROUP: ewu-deliverybotsystem-rg
APP_SERVICE_NAME: WA-DeliveryBot-Admin-dev
TFSTATE_STORAGE_ACCOUNT: dbstfstate01
TFSTATE_CONTAINER: tfstate
BOTNET_API_URL: https://ewu-deliverybotsystem-api.mangocoast-332176b0.westus2.azurecontainerapps.io
SIMULATOR_API_URL: https://deliverybot-robot-simulator.mangocoast-332176b0.westus2.azurecontainerapps.io

jobs:
provision-and-deploy:
build-and-deploy:
runs-on: ubuntu-latest

steps:
Expand All @@ -47,43 +43,7 @@ jobs:
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}

# ── 2. Ensure the Terraform state container exists ────────────────────
# `az storage container create` is idempotent; safe to run every time.
- name: Ensure TF state container exists
run: |
az storage container create \
--name "$TFSTATE_CONTAINER" \
--account-name "$TFSTATE_STORAGE_ACCOUNT" \
--auth-mode login \
--only-show-errors

# ── 3. Provision App Service via Terraform ────────────────────────────
- name: Setup Terraform
uses: hashicorp/setup-terraform@v3
with:
terraform_version: "1.9.5"

- name: Terraform Init
working-directory: ./Iac/admin-webapp
env:
ARM_USE_OIDC: "true"
ARM_USE_AZUREAD: "true"
ARM_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}
ARM_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
ARM_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
run: terraform init -input=false

- name: Terraform Apply
working-directory: ./Iac/admin-webapp
env:
ARM_USE_OIDC: "true"
ARM_USE_AZUREAD: "true"
ARM_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}
ARM_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
ARM_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
run: terraform apply -input=false -auto-approve

# ── 4. Build the SPA with upstream URLs baked in ──────────────────────
# ── 2. Build the SPA with upstream URLs baked in ──────────────────────
- name: Setup Node.js
uses: actions/setup-node@v4
with:
Expand All @@ -106,7 +66,7 @@ jobs:
VITE_SIMULATOR_API_URL: ${{ env.SIMULATOR_API_URL }}
run: npm run build

# ── 5. Deploy the build to the App Service ────────────────────────────
# ── 3. Deploy the build to the App Service ────────────────────────────
- name: Deploy to Azure App Service
uses: azure/webapps-deploy@v3
with:
Expand Down
123 changes: 123 additions & 0 deletions .github/workflows/iac.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
name: Infrastructure — Apply All Services

# Single IaC workflow for the entire DeliveryBot platform.
# Implements the layered module pattern: Iac/main.tf composes all per-service
# modules (shared-infra, admin-webapp, order-service, bot-api, frontend,
# simulator) into one unified plan + apply.
#
# Strategy:
# - pull_request → plan only (lets reviewers see the diff before merge)
# - push to main → plan + apply
#
# Auth: OIDC federated identity — no client secrets stored in GitHub.
# State: single state file "deliverybot.tfstate" in dbstfstate01/tfstate.

on:
push:
branches: [main]
paths:
- "Iac/**"
- ".github/workflows/iac.yml"
pull_request:
branches: [main]
paths:
- "Iac/**"
- ".github/workflows/iac.yml"
workflow_dispatch:

permissions:
id-token: write
contents: read

env:
TFSTATE_STORAGE_ACCOUNT: dbstfstate01
TFSTATE_CONTAINER: tfstate

jobs:
terraform:
name: Terraform Plan / Apply
runs-on: ubuntu-latest
defaults:
run:
working-directory: ./Iac
env:
ARM_USE_OIDC: "true"
ARM_USE_AZUREAD: "true"
ARM_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}
ARM_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
ARM_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }}

# ── Sensitive variable injection ─────────────────────────────────────
# Connection strings and secrets are injected as TF_VAR_* so they never
# appear in .tf files or terraform.tfvars.

# Order Service — uses Managed Identity; the string contains no password.
TF_VAR_order_service_sql_connection_string: "Server=tcp:jacob-orderservice-sql2.database.windows.net,1433;Initial Catalog=OrderServiceDb;Authentication=Active Directory Managed Identity;"

# Bot API — uses Managed Identity; the string contains no password.
TF_VAR_bot_api_sql_connection_string: "Server=tcp:deliverybotsystem-sql.database.windows.net,1433;Initial Catalog=BotNetApiDb;Authentication=Active Directory Managed Identity;"

# Event Hub — shared by Order Service and Robot Simulator.
TF_VAR_eventhub_connection_string: ${{ secrets.AZURE_EVENTHUB_CONNECTION_STRING }}

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Azure Login (OIDC)
uses: azure/login@v2
with:
client-id: ${{ secrets.AZURE_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}

# Idempotent — creates the container if it doesn't already exist.
- name: Ensure TF state container exists
run: |
az storage container create \
--name "$TFSTATE_CONTAINER" \
--account-name "$TFSTATE_STORAGE_ACCOUNT" \
--auth-mode login \
--only-show-errors

# ── One-time state decommission ───────────────────────────────────────
# This repo previously used six isolated per-service Terraform stacks,
# each writing to its own *.tfstate blob. Those blobs are now orphaned
# (the unified root uses deliverybot.tfstate). Delete them so no one
# accidentally runs terraform against stale state.
#
# `az storage blob delete` is a no-op when the blob doesn't exist, so
# this step is safe to leave in permanently.
- name: Remove orphaned per-service state blobs
run: |
for key in \
admin-webapp.tfstate \
order-service.tfstate \
bot-api.tfstate \
frontend.tfstate \
shared-infra.tfstate \
simulator.tfstate; do
az storage blob delete \
--container-name "$TFSTATE_CONTAINER" \
--name "$key" \
--account-name "$TFSTATE_STORAGE_ACCOUNT" \
--auth-mode login \
--only-show-errors \
2>/dev/null || true
done

- name: Setup Terraform
uses: hashicorp/setup-terraform@v3
with:
terraform_version: "1.9.5"

- name: Terraform Init
run: terraform init -input=false

- name: Terraform Plan
run: terraform plan -input=false -out=tfplan

# Apply only on merge to main — PRs stop at plan for review.
- name: Terraform Apply
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
run: terraform apply -input=false tfplan
76 changes: 0 additions & 76 deletions .github/workflows/orderservice-iac.yml

This file was deleted.

8 changes: 0 additions & 8 deletions Iac/admin-webapp/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,3 @@ module "admin_webapp" {
simulator_api_url = var.simulator_api_url
tags = var.tags
}

# The App Service was originally declared at the root before the module
# refactor. Tell Terraform it simply moved addresses so the existing live
# resource is preserved instead of destroyed and recreated.
moved {
from = azurerm_linux_web_app.admin
to = module.admin_webapp.azurerm_linux_web_app.admin
}
37 changes: 0 additions & 37 deletions Iac/admin-webapp/providers.tf

This file was deleted.

23 changes: 23 additions & 0 deletions Iac/backend.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Terraform remote state backend.
#
# State is stored in the pre-existing Azure Blob Storage account:
# Storage account : dbstfstate01
# Resource group : ewu-deliverybotsystem-rg
# Container : tfstate
# Blob key : deliverybot.tfstate
#
# Auth uses OIDC + Azure AD (no SAS tokens or storage keys).
# The storage account and container were verified via:
# az storage account show --name dbstfstate01
# az storage container list --account-name dbstfstate01 --auth-mode login

terraform {
backend "azurerm" {
resource_group_name = "ewu-deliverybotsystem-rg"
storage_account_name = "dbstfstate01"
container_name = "tfstate"
key = "deliverybot.tfstate"
use_oidc = true
use_azuread_auth = true
}
}
Loading
Loading