Skip to content

chore(deps): update dependency pytest to v9 [security] #1325

chore(deps): update dependency pytest to v9 [security]

chore(deps): update dependency pytest to v9 [security] #1325

Workflow file for this run

name: Phoenix VC Deployment Pipeline
on:
push:
branches: [ "main", "release/*", "staging/*" ]
pull_request:
branches: [ "main", "release/*", "staging/*" ]
workflow_dispatch:
inputs:
notifyOnFailure:
description: 'Send Teams notification if deployment fails'
type: boolean
default: true
deployToProd:
description: 'Also deploy to production after staging succeeds'
type: boolean
default: false
env:
LOCATION_CODE: 'euw' # Default to Europe West
permissions:
contents: write
pages: write
id-token: write
actions: read
concurrency:
group: ${{ github.workflow }}-staging
cancel-in-progress: false
jobs:
log_debug_information:
runs-on: ubuntu-latest
steps:
- name: Show Workflow Inputs
run: |
echo "==========================="
echo "✅ Logging Deployment Variables"
echo "==========================="
echo "GitHub Event Name: ${{ github.event_name }}"
echo "Ref: ${{ github.ref }}"
echo "Base Ref: ${{ github.event.pull_request.base.ref || 'N/A' }}"
echo "Location Code: ${LOCATION_CODE}"
echo "Resource Group Name: [env]-${LOCATION_CODE}-rg-phoenixvc-website"
echo "Static Web App Name: [env]-${LOCATION_CODE}-swa-phoenixvc-website"
echo "Log repository: ${{ github.repository }}"
echo "Azure Subscription ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }}"
echo "Prod deployment token: ${{ secrets.PROD_DEPLOYMENT_TOKEN }}"
if [[ -n "${{ secrets.GITHUB_TOKEN }}" ]]; then
echo "✅ GITHUB_TOKEN is set."
else
echo "⚠️ GITHUB_TOKEN is missing!"
fi
if [[ "${{ secrets.AZURE_CREDENTIALS }}" ]]; then
echo "✅ AZURE_CREDENTIALS is set."
else
echo "⚠️ AZURE_CREDENTIALS is missing!"
fi
if [[ -n "${{ secrets.AZURE_SUBSCRIPTION_ID }}" ]]; then
echo "✅ AZURE_SUBSCRIPTION_ID is set."
else
echo "⚠️ AZURE_SUBSCRIPTION_ID is missing!"
fi
if [[ -n "${{ secrets.PROD_DEPLOYMENT_TOKEN }}" ]]; then
echo "✅ PROD_DEPLOYMENT_TOKEN is set."
else
echo "⚠️ PROD_DEPLOYMENT_TOKEN is missing!"
fi
echo "==========================="
check_relevant_changes:
runs-on: ubuntu-latest
needs: [log_debug_information]
outputs:
resources_changed: ${{ steps.check_changes.outputs.resources_changed }}
change_summary: ${{ steps.get_changes.outputs.summary }}
steps:
- name: Checkout Repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Check for Relevant Changes
id: check_changes
run: |
# Get the list of changed files
if [[ "${{ github.event_name }}" == "pull_request" ]]; then
CHANGED_FILES=$(git diff --name-only ${{ github.event.pull_request.base.sha }} ${{ github.event.pull_request.head.sha }})
else
CHANGED_FILES=$(git diff --name-only HEAD^ HEAD)
fi
# Check if any relevant files changed (excluding .github/workflows/)
RESOURCES_CHANGED=false
while IFS= read -r file; do
if [[ ! "$file" =~ ^\.github/workflows/ ]]; then
RESOURCES_CHANGED=true
break
fi
done <<< "$CHANGED_FILES"
echo "resources_changed=${RESOURCES_CHANGED}" >> $GITHUB_OUTPUT
echo "Changed files:"
echo "$CHANGED_FILES"
- name: Get Change Summary
id: get_changes
env:
PR_TITLE: ${{ github.event.pull_request.title }}
PR_BODY: ${{ github.event.pull_request.body }}
EVENT_NAME: ${{ github.event_name }}
run: |
if [[ "$EVENT_NAME" == "pull_request" ]]; then
# For PR events, capture the title and body while replacing newlines with spaces
TITLE=$(echo "$PR_TITLE" | tr '\n' ' ')
BODY=$(echo "$PR_BODY" | tr '\n' ' ')
SUMMARY="${TITLE} - ${BODY}"
else
# For push events, use commit messages
SUMMARY=$(git log -1 --pretty=format:"%s%n%b")
fi
# Sanitize and truncate summary (remove any remaining carriage returns/newlines)
SUMMARY=$(echo "$SUMMARY" | tr -d '\r\n' | cut -c1-500)
echo "summary=${SUMMARY}" >> $GITHUB_OUTPUT
# ───────────────────────────────────────────────
# ✅ BUILD APPS WITH Vite
# ───────────────────────────────────────────────
build_apps:
runs-on: ubuntu-latest
needs: [log_debug_information, check_relevant_changes]
if: >
(github.event_name == 'workflow_dispatch' || needs.check_relevant_changes.outputs.resources_changed == 'true')
outputs:
web_artifact_id: ${{ steps.upload_web.outputs.artifact-id }}
web_artifact_name: web-dist-${{ steps.set_timestamp.outputs.timestamp }}
design_system_artifact_id: ${{ steps.upload_design.outputs.artifact-id }}
build_timestamp: ${{ steps.set_timestamp.outputs.timestamp }}
web_app_version: ${{ steps.build_web.outputs.version }}
web_app_author: ${{ steps.build_web.outputs.author }}
web_app_repository: ${{ format('https://github.com/{0}', github.repository) }}
steps:
- name: Checkout Repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Enable pnpm
run: |
corepack enable
corepack prepare pnpm@10.30.3 --activate
- name: Install Dependencies
run: pnpm install --frozen-lockfile
- name: Set Build Timestamp
id: set_timestamp
run: echo "timestamp=$(date +'%Y%m%d_%H%M%S')" >> $GITHUB_OUTPUT
- name: Build Web App
id: build_web
uses: ./.github/actions/build-vite
with:
app-name: 'web'
environment: ${{ github.ref == 'refs/heads/main' && 'production' || 'staging' }}
- name: Build Design System
id: build_design
uses: ./.github/actions/build-vite
with:
app-name: 'design-system'
environment: ${{ github.ref == 'refs/heads/main' && 'production' || 'staging' }}
- name: Upload Web App Artifact
id: upload_web
uses: actions/upload-artifact@v4
with:
name: web-dist-${{ steps.set_timestamp.outputs.timestamp }}
path: apps/web/dist
retention-days: 5
if-no-files-found: error
- name: Upload Design System Artifact
id: upload_design
uses: actions/upload-artifact@v4
with:
name: design-system-dist-${{ steps.set_timestamp.outputs.timestamp }}
path: apps/design-system/dist
retention-days: 5
if-no-files-found: error
# ───────────────────────────────────────────────
# ✅ SECURITY SCAN
# ───────────────────────────────────────────────
# security_scan:
# runs-on: ubuntu-latest
# needs: [build_apps]
# if: github.ref == 'refs/heads/main' || github.event_name == 'pull_request'
# steps:
# - name: Checkout code
# uses: actions/checkout@v4
# - name: Initialize CodeQL
# uses: github/codeql-action/init@v2
# with:
# languages: javascript, typescript
# - name: Run CodeQL Analysis
# uses: github/codeql-action/analyze@v2
# with:
# category: "/language:javascript"
# ───────────────────────────────────────────────
# ✅ STAGING RESOURCE CREATION (Run deploy.sh)
# ───────────────────────────────────────────────
deploy_resources_staging:
runs-on: ubuntu-latest
needs: [log_debug_information, check_relevant_changes, build_apps]
if: >
(github.event_name == 'workflow_dispatch' || needs.check_relevant_changes.outputs.resources_changed == 'true')
outputs:
staticSiteUrl: ${{ steps.deploy_staging_resources.outputs.staticSiteUrl }}
teamsLogicAppUrl: ${{ steps.deploy_staging_resources.outputs.teamsLogicAppUrl }}
githubLogicAppUrl: ${{ steps.deploy_staging_resources.outputs.githubLogicAppUrl }}
deployment_id: ${{ steps.get_deployment_info.outputs.deployment_id }}
run_id: ${{ github.run_id }}
steps:
- name: Checkout Repository for Staging Resources
uses: actions/checkout@v4
with:
fetch-depth: 0
# Add a delay to ensure artifacts are available via the GitHub API
- name: Wait for artifacts to be available
run: |
echo "Waiting for artifacts to be processed and available via GitHub API..."
sleep 30
echo "Continuing with deployment..."
- name: Deploy Staging Resources
id: deploy_staging_resources
uses: ./.github/actions/deploy-azure-resources
with:
environment: staging
azure_subscription_id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
azure_credentials: ${{ secrets.AZURE_CREDENTIALS }}
location_code: ${{ env.LOCATION_CODE }}
repository: ${{ github.repository }}
token: ${{ github.token }}
- name: Get Deployment Information
id: get_deployment_info
run: |
DEPLOYMENT_ID="${{ github.run_id }}_${{ github.sha }}"
# Generate a unique artifact ID based on timestamp and hash
ARTIFACT_ID="phoenixvc_$(date +%Y%m%d)_${{ github.sha }}_${{ github.run_number }}"
echo "deployment_id=${DEPLOYMENT_ID}" >> $GITHUB_OUTPUT
echo "artifact_id=${ARTIFACT_ID}" >> $GITHUB_OUTPUT
# ───────────────────────────────────────────────
# ✅ STAGING SITE DEPLOYMENT VIA SWA CLI
# ───────────────────────────────────────────────
swa_deploy_staging:
runs-on: ubuntu-latest
needs: [build_apps, deploy_resources_staging, check_relevant_changes]
continue-on-error: true
timeout-minutes: 15
environment:
name: staging
url: ${{ steps.swa_deploy.outputs.deployment_url }}
outputs:
staging_url: ${{ steps.swa_deploy.outputs.deployment_url }}
deployment_id: ${{ steps.swa_deploy.outputs.deployment_id }}
if: >
(github.event_name == 'workflow_dispatch' || needs.check_relevant_changes.outputs.resources_changed == 'true')
steps:
- name: Checkout Repository for Staging Resources
uses: actions/checkout@v4
with:
fetch-depth: 0
# Remove any steps that try to use a stored token from secrets
# Instead, let the swa-deploy action retrieve the token directly from Azure
- name: Use SWA Deploy Action for Staging
id: swa_deploy
uses: ./.github/actions/swa-deploy
with:
artifact-name: web-dist-${{ needs.build_apps.outputs.build_timestamp }}
run-id: ${{ github.run_id }}
app-name: staging-${{ env.LOCATION_CODE }}-swa-phoenixvc-website
resource-group: staging-${{ env.LOCATION_CODE }}-rg-phoenixvc-website
env: staging
azure_credentials: ${{ secrets.AZURE_CREDENTIALS }}
# Don't pass any deployment_token here - let the action retrieve it
github_token: ${{ github.token }}
# ───────────────────────────────────────────────
# NOTIFY DEPLOYMENT VIA TEAMS (Combined Notification)
# ───────────────────────────────────────────────
notify_deployment:
runs-on: ubuntu-latest
# Notify on success, or on failure if notifyOnFailure is enabled
# For production, always notify regardless of outcome.
needs: [build_apps, deploy_resources_staging, swa_deploy_staging, check_relevant_changes]
if: always()
steps:
- name: Log Required Variables
# Only validate when staging actually ran
if: needs.check_relevant_changes.outputs.resources_changed == 'true' || github.event_name == 'workflow_dispatch'
run: |
echo "Logging required variables for Teams Notification..."
echo "Deployment ID: ${{ needs.swa_deploy_staging.outputs.deployment_id }}"
echo "Artifact Name: ${{ needs.build_apps.outputs.web_artifact_name }}"
echo "Run ID: ${{ github.run_id }}"
if [[ -z "${{ needs.swa_deploy_staging.outputs.deployment_id }}" || -z "${{ needs.build_apps.outputs.web_artifact_name }}" || -z "${{ github.run_id }}" ]]; then
echo "❌ Missing required values for approval URL!"
exit 1
fi
- name: Skip notification - no changes
if: needs.check_relevant_changes.outputs.resources_changed == 'false' && github.event_name != 'workflow_dispatch'
run: |
echo "⏭️ Skipping notification - no relevant changes detected (only workflow files changed)"
- name: Checkout Repository for Notification
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Log Deployment Output Values
run: |
if [[ "${{ needs.check_relevant_changes.outputs.resources_changed }}" == "false" && "${{ github.event_name }}" != "workflow_dispatch" ]]; then
echo "Staging deployment was skipped - no relevant changes detected"
else
echo "Static Site URL: ${{ needs.deploy_resources_staging.outputs.staticSiteUrl }}"
echo "Teams Logic App URL: ${{ needs.deploy_resources_staging.outputs.teamsLogicAppUrl }}"
echo "GitHub Logic App URL: ${{ needs.deploy_resources_staging.outputs.githubLogicAppUrl }}"
fi
- name: Notify Staging via Teams
if: (needs.check_relevant_changes.outputs.resources_changed == 'true' || github.event_name == 'workflow_dispatch') && (needs.swa_deploy_staging.result == 'success' || inputs.notifyOnFailure == true)
uses: ./.github/actions/teams-notification
with:
webhook_url: "https://phoenixvc568.webhook.office.com/webhookb2/17b0291f-b70b-4bdd-9266-f212ae03a2bd@7edf4423-ccb3-4275-bc80-64dae3ef0148/IncomingWebhook/3174ffcca3804d34ae923ba2e131f82e/a41dbcc0-67a6-4a23-bdec-b780dcebefa9/V2MOPWeKY7ywC8-iGptxHlSIZpwHVxw2FLAOAMU2N0hmM1"
title: "Staging Deployment Complete"
message: "The deployment to the STAGING environment has completed successfully. Please review the deployment and take any necessary actions."
environment: "staging"
deployment_url: ${{ needs.swa_deploy_staging.outputs.staging_url }}
logic_app_url: ${{ needs.deploy_resources_staging.outputs.teamsLogicAppUrl }}
github_logic_app_url: ${{ needs.deploy_resources_staging.outputs.githubLogicAppUrl }}
branch: ${{ github.ref }}
location_code: ${{ env.LOCATION_CODE }}
resource_group: staging-${{ env.LOCATION_CODE }}-rg-phoenixvc-website
color: "0076D7"
approval_url: ${{ needs.deploy_resources_staging.outputs.githubLogicAppUrl }}
github_token: ${{ secrets.GITHUB_TOKEN }}
teams_token: ${{ secrets.TEAMS_TOKEN }}
change_summary: ${{ needs.check_relevant_changes.outputs.change_summary }}
deployment_id: ${{ needs.swa_deploy_staging.outputs.deployment_id }}
artifact_id: ${{ needs.build_apps.outputs.web_artifact_name }}
run_id: ${{ github.run_id }}
version: ${{ needs.build_apps.outputs.web_app_version }}
author: ${{ needs.build_apps.outputs.web_app_author }}
repository: ${{ needs.build_apps.outputs.web_app_repository }}
pr_description: ${{ github.event.pull_request.body || 'N/A' }}
# ───────────────────────────────────────────────
# ✅ PRODUCTION DEPLOYMENT (auto on main push, or manual with checkbox)
# ───────────────────────────────────────────────
deploy_production:
needs: [build_apps, swa_deploy_staging, check_relevant_changes]
# Trigger production when:
# 1. Auto: push to main + staging success + relevant changes, OR
# 2. Manual: workflow_dispatch + deployToProd checked + staging success
if: >
needs.swa_deploy_staging.result == 'success' &&
(
(github.ref == 'refs/heads/main' && github.event_name == 'push' && needs.check_relevant_changes.outputs.resources_changed == 'true') ||
(github.event_name == 'workflow_dispatch' && inputs.deployToProd == true)
)
uses: ./.github/workflows/production_deployment.yml
with:
artifactSource: 'specific'
artifactId: ${{ needs.build_apps.outputs.web_artifact_name }}
runID: ${{ github.run_id }}
includeDnsUpdate: false
secrets: inherit