Skip to content

Rollout workload identity federation to all environments #9978

Rollout workload identity federation to all environments

Rollout workload identity federation to all environments #9978

name: Build and Deploy
concurrency: build_and_deploy_${{ github.ref_name }}
on:
push:
branches:
- main
pull_request:
types: [opened, reopened, synchronize, labeled]
permissions:
contents: write
deployments: write
packages: write
pull-requests: write
jobs:
build:
name: Build
outputs:
docker_image: ${{ env.DOCKER_IMAGE }}
image_tag: ${{ env.DOCKER_IMAGE_TAG }}
runs-on: ubuntu-latest
env:
DOCKER_IMAGE: ghcr.io/dfe-digital/publish-teacher-training
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Get values for current commit (Push)
if: github.event_name == 'push'
run: |
GIT_REF=${{github.ref}}
GIT_BRANCH=${GIT_REF##*/}
echo "BRANCH_TAG=$GIT_BRANCH" >> $GITHUB_ENV
echo "DOCKER_IMAGE_TAG=$GITHUB_SHA" >> $GITHUB_ENV
- name: Get values for current commit (Pull request)
if: github.event_name == 'pull_request'
run: |
# This is the actual PR branch
GIT_REF=${{ github.head_ref }}
GIT_BRANCH=${GIT_REF##*/}
echo "BRANCH_TAG=$GIT_BRANCH" >> $GITHUB_ENV
# This is the latest commit on the actual PR branch
echo "DOCKER_IMAGE_TAG=${{ github.event.pull_request.head.sha }}" >> $GITHUB_ENV
- name: Set KV environment variables
run: |
# tag build to the review env for vars and secrets
tf_vars_file=terraform/aks/workspace_variables/review_aks.tfvars.json
echo "KEY_VAULT_NAME=$(jq -r '.key_vault_name' ${tf_vars_file})" >> $GITHUB_ENV
echo "KEY_VAULT_INFRA_SECRET_NAME=$(jq -r '.key_vault_infra_secret_name' ${tf_vars_file})" >> $GITHUB_ENV
- name: Login to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- uses: azure/login@v2
with:
creds: ${{ secrets.AZURE_CREDENTIALS_REVIEW_AKS }}
- uses: DFE-Digital/keyvault-yaml-secret@v1
id: get-secret
with:
keyvault: ${{ env.KEY_VAULT_NAME }}
secret: ${{ env.KEY_VAULT_INFRA_SECRET_NAME }}
key: SNYK_TOKEN
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build Publish-Teacher-Training-Middleman
uses: docker/build-push-action@v6
with:
tags: ${{ env.DOCKER_IMAGE}}-middleman:${{ env.BRANCH_TAG }}
push: true
target: middleman
cache-from: |
type=registry,ref=${{ env.DOCKER_IMAGE}}-middleman:main
type=registry,ref=${{ env.DOCKER_IMAGE}}-middleman:${{ env.BRANCH_TAG }}
build-args: BUILDKIT_INLINE_CACHE=1
- name: Build Publish-Teacher-Training
uses: docker/build-push-action@v6
with:
tags: |
${{ env.DOCKER_IMAGE}}:${{ env.BRANCH_TAG }}
${{ env.DOCKER_IMAGE}}:${{ env.DOCKER_IMAGE_TAG }}
push: false
load: true
cache-from: |
type=registry,ref=${{ env.DOCKER_IMAGE}}:main
type=registry,ref=${{ env.DOCKER_IMAGE}}:${{ env.BRANCH_TAG }}
type=registry,ref=${{ env.DOCKER_IMAGE}}-middleman:main
type=registry,ref=${{ env.DOCKER_IMAGE}}-middleman:${{ env.BRANCH_TAG }}
build-args: |
BUILDKIT_INLINE_CACHE=1
COMMIT_SHA=${{ env.DOCKER_IMAGE_TAG }}
- name: Push ${{ env.DOCKER_IMAGE }} images for review
if: ${{ github.event_name == 'pull_request' && contains(github.event.pull_request.labels.*.name, 'deploy_v2') }}
run: docker image push --all-tags ${{ env.DOCKER_IMAGE }}
- name: Run Snyk to check Docker image for vulnerabilities
uses: snyk/actions/docker@master
env:
SNYK_TOKEN: ${{ steps.get-secret.outputs.snyk_token }}
with:
image: ${{ env.DOCKER_IMAGE }}:${{ env.DOCKER_IMAGE_TAG }}
args: --file=Dockerfile --severity-threshold=high --exclude-app-vulns
- name: Push ${{ env.DOCKER_IMAGE }} images
if: ${{ success() && !contains(github.event.pull_request.labels.*.name, 'deploy_v2') }}
run: docker image push --all-tags ${{ env.DOCKER_IMAGE }}
- name: Alert Build Failures
if: ${{ failure() && github.ref == 'refs/heads/main' }}
uses: rtCamp/action-slack-notify@master
env:
SLACK_CHANNEL: twd_findpub_tech
SLACK_COLOR: '#ef5343'
SLACK_ICON_EMOJI: ':github-logo:'
SLACK_USERNAME: Publish Teacher Training
SLACK_TITLE: Build failure
SLACK_MESSAGE: ':alert: <!channel> Publish Teacher Training Build failure :sadparrot:'
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
lint:
name: Lint
needs: [build]
runs-on: ubuntu-latest
outputs:
image_tag: ${{ needs.build.outputs.image_tag }}
strategy:
fail-fast: false
matrix:
tests: [rubocop, erblint, dfe_analytics, yarn_lint_and_test]
include:
- tests: rubocop
command: docker compose exec -T web /bin/sh -c 'bundle exec rubocop --format clang'
- tests: erblint
command: docker compose exec -T web /bin/sh -c 'bundle exec erblint app'
- tests: dfe_analytics
command: |
docker compose exec -T web /bin/sh -c "bundle exec rails db:setup"
docker compose exec -T web /bin/sh -c 'bundle exec rake dfe:analytics:check'
- tests: yarn_lint_and_test
command: |
docker compose exec -T web /bin/sh -c "yarn add [email protected]"
docker compose exec -T web /bin/sh -c "yarn run standard $(git ls-files '**.js' | tr '\n' ' ')"
docker compose exec -T web /bin/sh -c 'yarn run test'
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set environment variables
run: |
echo "IMAGE_TAG=${{ needs.build.outputs.image_tag }}" >> $GITHUB_ENV
- name: Pull docker images
run: docker pull ${{ needs.build.outputs.docker_image }}:$IMAGE_TAG
- name: Setup container
run: |
docker compose up --no-build -d
docker compose exec -T web /bin/sh -c "./wait-for-command.sh -c 'nc -z db 5432' -s 0 -t 20"
docker compose exec -T web /bin/sh -c 'bundle config --local disable_exec_load true'
- name: ${{ matrix.tests }}
run: ${{ env.COMMAND }}
env:
COMMAND: ${{ matrix.command }}
- name: Notify Slack channel on job failure
if: ${{ failure() && github.ref == 'refs/heads/main' }}
uses: rtCamp/action-slack-notify@master
env:
SLACK_CHANNEL: twd_findpub_tech
SLACK_USERNAME: Publish Teacher Training CI
SLACK_TITLE: Lint failure
SLACK_MESSAGE: ':alert: <!channel> Publish Teacher Training ${{ matrix.tests }} lint failure on branch ${{ needs.build.outputs.GIT_BRANCH }} :sadparrot:'
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
SLACK_COLOR: failure
SLACK_FOOTER: Sent from lint job in build workflow
test:
name: Test
needs: [build]
outputs:
image_tag: ${{ needs.build.outputs.image_tag }}
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
tests: [ unit_models, unit_services, unit_forms, unit_components, unit_other, integration_auth, integration_find, integration_publish, integration_support, integration_other ]
include:
- tests: unit_models
include-pattern: spec/models/.*_spec.rb
- tests: unit_services
include-pattern: spec/services/.*_spec.rb
- tests: unit_forms
include-pattern: spec/forms/.*_spec.rb
- tests: unit_components
include-pattern: spec/components/.*_spec.rb
- tests: unit_other
include-pattern: spec/.*_spec.rb
exclude-pattern: spec/(features|smoke|models|services|forms|components)/.*_spec.rb
- tests: integration_auth
include-pattern: spec/features/auth/.*_spec.rb
- tests: integration_find
include-pattern: spec/features/find/.*_spec.rb
- tests: integration_publish
include-pattern: spec/features/publish/.*_spec.rb
- tests: integration_support
include-pattern: spec/features/support/.*_spec.rb
- tests: integration_other
include-pattern: spec/features/.*_spec.rb
exclude-pattern: spec/features/(auth|find|publish|support)/.*_spec.rb
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set environment variables
run: |
echo "IMAGE_TAG=${{ needs.build.outputs.image_tag }}" >> $GITHUB_ENV
- name: Pull docker images
run: docker pull ${{ needs.build.outputs.docker_image }}:$IMAGE_TAG
- name: Setup tests
run: |
docker compose up --no-build -d
docker compose exec -T web /bin/sh -c "./wait-for-command.sh -c 'nc -z db 5432' -s 0 -t 20"
docker compose exec -T web /bin/sh -c 'bundle config --local disable_exec_load true'
docker compose exec -T web /bin/sh -c 'bundle exec rake parallel:setup'
- name: ${{ matrix.tests }} tests
run: |
docker compose exec -T web /bin/sh -c 'bundle exec --verbose parallel_rspec --pattern "${{ env.INCLUDE_PATTERN }}" --exclude-pattern "${{ env.EXCLUDE_PATTERN }}"'
env:
IMAGE_TAG: ${{ env.DOCKER_IMAGE_TAG }}
INCLUDE_PATTERN: ${{ matrix.include-pattern }}
EXCLUDE_PATTERN: ${{ matrix.exclude-pattern || ' ' }}
TEST_MATRIX_NODE_NAME: ${{ matrix.tests }}
- name: Upload coverage results
if: always()
uses: actions/upload-artifact@v4
with:
name: Coverage_report
path: ${{ github.workspace }}/out/*
- name: Alert Test Failures
if: ${{ failure() && github.ref == 'refs/heads/main' }}
uses: rtCamp/action-slack-notify@master
env:
SLACK_CHANNEL: twd_findpub_tech
SLACK_COLOR: '#ef5343'
SLACK_ICON_EMOJI: ':github-logo:'
SLACK_USERNAME: Publish Teacher Training CI
SLACK_TITLE: Test failure
SLACK_MESSAGE: ':alert: <!channel> Publish Teacher Training Test failure :sadparrot:'
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
deploy-v2-review-app:
name: Deployment To Review v2
concurrency: deploy_v2_review_${{ github.event.pull_request.number }}
if: ${{ github.event_name == 'pull_request' && contains(github.event.pull_request.labels.*.name, 'deploy_v2') }}
needs: [build]
runs-on: ubuntu-latest
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
- name: Start review_aks-${{ github.event.pull_request.number }} Deployment
uses: bobheadxi/deployments@v1
id: deployment
with:
step: start
token: ${{ secrets.GITHUB_TOKEN }}
env: review_aks-${{ github.event.pull_request.number }}
ref: ${{ github.head_ref }}
- name: Checkout
uses: actions/checkout@v4
- name: Deploy App to Review v2
id: deploy_v2_review
uses: ./.github/actions/deploy_v2/
with:
azure-credentials: ${{ secrets.AZURE_CREDENTIALS_REVIEW_AKS }}
environment: review_aks
pr-number: ${{ github.event.pull_request.number }}
sha: ${{ needs.build.outputs.image_tag }}
slack-webhook: ${{ secrets.SLACK_WEBHOOK }}
- name: Update review_aks-${{ github.event.pull_request.number }} status
if: always()
uses: bobheadxi/deployments@v1
with:
step: finish
token: ${{ secrets.GITHUB_TOKEN }}
env: review_aks-${{ github.event.pull_request.number }}
status: ${{ job.status }}
deployment_id: ${{ steps.deployment.outputs.deployment_id }}
env_url: ${{ steps.deploy_v2_review.outputs.deploy-url }}
ref: ${{ github.head_ref }}
deploy-aks-before-production:
name: Parallel deployment before production v2
environment:
name: ${{ matrix.environment }}
url: ${{ steps.deploy_app_before_production_v2.outputs.deploy-url }}
if: ${{ success() && github.ref == 'refs/heads/main' }}
needs: [test]
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
environment: [qa_aks,staging_aks]
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Deploy App to ${{ matrix.environment }} v2
id: deploy_app_before_production_v2
uses: ./.github/actions/deploy_v2/
with:
azure-credentials: ${{ secrets[format('AZURE_CREDENTIALS_{0}', matrix.environment)] }}
environment: ${{ matrix.environment }}
sha: ${{ github.sha }}
slack-webhook: ${{ secrets.SLACK_WEBHOOK }}
deploy-aks-production:
name: Production deployment v2
environment:
name: production_aks
url: ${{ steps.deploy_app_v2.outputs.deploy-url }}
if: ${{ success() && github.ref == 'refs/heads/main' }}
needs: [deploy-aks-before-production]
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Deploy App to production v2
id: deploy_app_v2
uses: ./.github/actions/deploy_v2/
with:
azure-credentials: ${{ secrets.AZURE_CREDENTIALS_PRODUCTION_AKS }}
environment: production_aks
sha: ${{ github.sha }}
slack-webhook: ${{ secrets.SLACK_WEBHOOK }}
deploy-aks-sandbox:
name: Sandbox deployment v2
environment:
name: sandbox_aks
url: ${{ steps.deploy_sandbox_v2.outputs.deploy-url }}
if: ${{ success() && github.ref == 'refs/heads/main' }}
needs: [deploy-aks-production]
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Deploy App to sandbox v2
id: deploy_sandbox_v2
uses: ./.github/actions/deploy_v2/
with:
azure-credentials: ${{ secrets.AZURE_CREDENTIALS_SANDBOX_AKS }}
environment: sandbox_aks
sha: ${{ github.sha }}
slack-webhook: ${{ secrets.SLACK_WEBHOOK }}