Skip to content

Feature/iac scaffolding : Foundational Network Module #7427

Feature/iac scaffolding : Foundational Network Module

Feature/iac scaffolding : Foundational Network Module #7427

Workflow file for this run

name: Run CI/CD
on:
merge_group:
pull_request:
branches:
- feature/**
- main
paths-ignore:
- backend/data/nest.json.gz
push:
branches:
- feature/**
- main
paths-ignore:
- backend/data/nest.json.gz
release:
types:
- published
workflow_dispatch:
permissions:
contents: read
concurrency:
cancel-in-progress: true
group: ${{ github.repository }}-${{ github.workflow }}-${{ github.ref }}
env:
FORCE_COLOR: 1
jobs:
pre-commit:
name: Run pre-commit checks
runs-on: ubuntu-latest
steps:
- name: Check out repository
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
- name: Install Poetry
run: pipx install poetry
- name: Set up Python
uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c
with:
cache: 'poetry'
cache-dependency-path: backend/poetry.lock
python-version: '3.13'
- name: Set up pre-commit cache
uses: actions/cache@v4
with:
path: ~/.cache/pre-commit
key: pre-commit-${{ runner.os }}-${{ hashFiles('.pre-commit-config.yaml') }}
restore-keys: |
pre-commit-${{ runner.os }}-
- name: Run pre-commit
uses: pre-commit/action@2c7b3805fd2a0fd8c1884dcaebf91fc102a13ecd
- name: Check for uncommitted changes
run: |
git diff --exit-code || (echo 'Unstaged changes detected. \
Run `make check` and use `git add` to address it.' && exit 1)
check-frontend:
name: Run frontend checks
runs-on: ubuntu-latest
steps:
- name: Check out repository
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
- name: Install pnpm
uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda
with:
version: 10
run_install: true
- name: Set up Node
uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444
with:
node-version: 22
cache: 'pnpm'
cache-dependency-path: frontend/pnpm-lock.yaml
- name: Run pnpm format
working-directory: frontend
run: pnpm run format
- name: Run pnpm lint check
working-directory: frontend
run: pnpm run lint:check
- name: Check for uncommitted changes
run: |
git diff --exit-code || (echo 'Unstaged changes detected. \
Run `make check` and use `git add` to address it.' && exit 1)
spellcheck:
name: Run spell check
runs-on: ubuntu-latest
steps:
- name: Check out repository
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
- name: Run cspell
run: |
make check-spelling
scan-code:
name: Run Code Scan
needs:
- check-frontend
- pre-commit
- spellcheck
runs-on: ubuntu-latest
steps:
- name: Check out repository
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
- name: Run Trivy Repository Scan
uses: aquasecurity/trivy-action@b6643a29fecd7f34b3597bc6acb0a98b03d33ff8
with:
scan-type: repo
trivy-config: trivy.yaml
trivyignores: trivyignore.yaml
version: latest
scan-ci-dependencies:
name: Run CI Denendencies Scan
needs:
- check-frontend
- pre-commit
- spellcheck
runs-on: ubuntu-latest
steps:
- name: Check out repository
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
- name: Run Trivy Filesystem Scan
uses: aquasecurity/trivy-action@b6643a29fecd7f34b3597bc6acb0a98b03d33ff8
with:
scan-type: fs
trivy-config: trivy.yaml
trivyignores: trivyignore.yaml
version: latest
run-backend-tests:
name: Run backend tests
needs:
- scan-code
- scan-ci-dependencies
runs-on: ubuntu-latest
steps:
- name: Check out repository
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
- name: Set up Docker buildx
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435
- name: Build backend test image
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83
with:
cache-from: |
type=gha
type=registry,ref=owasp/nest:test-backend-cache
cache-to: |
type=gha,compression=zstd
context: backend
file: backend/docker/Dockerfile.test
load: true
platforms: linux/amd64
tags: owasp/nest:test-backend-latest
- name: Run backend tests
run: |
docker run -e DJANGO_SETTINGS_MODULE=settings.test --env-file backend/.env.example owasp/nest:test-backend-latest pytest
run-frontend-unit-tests:
name: Run frontend unit tests
needs:
- scan-code
- scan-ci-dependencies
runs-on: ubuntu-latest
steps:
- name: Check out repository
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
- name: Set up Docker buildx
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435
- name: Build frontend unit-testing image
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83
with:
cache-from: |
type=gha
type=registry,ref=owasp/nest:test-frontend-unit-cache
cache-to: |
type=gha,compression=zstd
context: frontend
file: frontend/docker/Dockerfile.unit.test
load: true
platforms: linux/amd64
tags: owasp/nest:test-frontend-unit-latest
- name: Run frontend unit tests
run: |
docker run --env-file frontend/.env.example owasp/nest:test-frontend-unit-latest pnpm run test:unit
run-frontend-e2e-tests:
name: Run frontend e2e tests
needs:
- scan-code
- scan-ci-dependencies
runs-on: ubuntu-latest
steps:
- name: Check out repository
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
- name: Set up Docker buildx
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435
- name: Build frontend end-to-end testing image
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83
with:
cache-from: |
type=gha
type=registry,ref=owasp/nest:test-frontend-e2e-cache
context: frontend
file: frontend/docker/Dockerfile.e2e.test
load: true
platforms: linux/amd64
tags: owasp/nest:test-frontend-e2e-latest
- name: Run frontend end-to-end tests
run: |
docker run --env-file frontend/.env.example owasp/nest:test-frontend-e2e-latest pnpm run test:e2e
set-release-version:
name: Set release version
runs-on: ubuntu-latest
outputs:
release_version: ${{ steps.set.outputs.release_version }}
steps:
- name: Set release version
id: set
run: |
if [ -n "${{ github.event.release.tag_name }}" ]; then
echo "release_version=${{ github.event.release.tag_name }}" >> $GITHUB_OUTPUT
else
echo "release_version=$(date '+%y.%-m.%-d')-${GITHUB_SHA::7}" >> $GITHUB_OUTPUT
fi
build-staging-images:
name: Build Staging Images
env:
RELEASE_VERSION: ${{ needs.set-release-version.outputs.release_version }}
environment: staging
if: |
github.repository == 'OWASP/Nest' &&
github.ref == 'refs/heads/main'
needs:
- run-backend-tests
- run-frontend-e2e-tests
- run-frontend-unit-tests
- set-release-version
runs-on: ubuntu-latest
steps:
- name: Check out repository
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
- name: Set up QEMU
uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392
- name: Set up Docker buildx
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435
- name: Login to Docker Hub
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Build backend image
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83
with:
build-args: |
OWASP_GID=1001
OWASP_UID=1001
cache-from: |
type=gha
type=registry,ref=owasp/nest:backend-staging-cache
cache-to: |
type=registry,ref=owasp/nest:backend-staging-cache
context: backend
file: backend/docker/Dockerfile
load: true
platforms: linux/amd64
push: true
tags: owasp/nest:backend-staging
- name: Prepare frontend public environment
env:
NEXT_PUBLIC_API_URL: ${{ secrets.VITE_API_URL }}
NEXT_PUBLIC_CSRF_URL: ${{ secrets.VITE_CSRF_URL }}
NEXT_PUBLIC_ENVIRONMENT: ${{ secrets.VITE_ENVIRONMENT }}
NEXT_PUBLIC_GRAPHQL_URL: ${{ secrets.VITE_GRAPHQL_URL }}
NEXT_PUBLIC_GTM_ID: ${{ secrets.NEXT_PUBLIC_GTM_ID }}
NEXT_PUBLIC_IDX_URL: ${{ secrets.VITE_IDX_URL }}
NEXT_PUBLIC_IS_PROJECT_HEALTH_ENABLED: ${{ secrets.NEXT_PUBLIC_IS_PROJECT_HEALTH_ENABLED }}
NEXT_PUBLIC_RELEASE_VERSION: ${{ env.RELEASE_VERSION }}
NEXT_PUBLIC_SENTRY_DSN: ${{ secrets.VITE_SENTRY_DSN }}
run: |
umask 377
cat > frontend/.env <<EOF
NEXT_PUBLIC_API_URL=$NEXT_PUBLIC_API_URL
NEXT_PUBLIC_CSRF_URL=$NEXT_PUBLIC_CSRF_URL
NEXT_PUBLIC_ENVIRONMENT=$NEXT_PUBLIC_ENVIRONMENT
NEXT_PUBLIC_GRAPHQL_URL=$NEXT_PUBLIC_GRAPHQL_URL
NEXT_PUBLIC_GTM_ID=$NEXT_PUBLIC_GTM_ID
NEXT_PUBLIC_IDX_URL=$NEXT_PUBLIC_IDX_URL
NEXT_PUBLIC_IS_PROJECT_HEALTH_ENABLED=$NEXT_PUBLIC_IS_PROJECT_HEALTH_ENABLED
NEXT_PUBLIC_RELEASE_VERSION=$NEXT_PUBLIC_RELEASE_VERSION
NEXT_PUBLIC_SENTRY_DSN=$NEXT_PUBLIC_SENTRY_DSN
EOF
- name: Get backend image size
id: backend-size
run: |
IMAGE_NAME="owasp/nest:backend-staging"
RAW_SIZE=$(docker image inspect "$IMAGE_NAME" --format='{{.Size}}')
DISPLAY_SIZE=$(numfmt --to=iec --suffix=B "$RAW_SIZE")
echo "human_readable=$DISPLAY_SIZE" >> $GITHUB_OUTPUT
- name: Build frontend image
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83
with:
cache-from: |
type=gha
type=registry,ref=owasp/nest:frontend-staging-cache
cache-to: |
type=registry,ref=owasp/nest:frontend-staging-cache
context: frontend
file: frontend/docker/Dockerfile
load: true
platforms: linux/amd64
push: true
secrets: |
RELEASE_VERSION=${{ needs.set-release-version.outputs.release_version }}
SENTRY_AUTH_TOKEN=${{ secrets.SENTRY_AUTH_TOKEN }}
tags: owasp/nest:frontend-staging
- name: Get frontend image size
id: frontend-size
run: |
IMAGE_NAME="owasp/nest:frontend-staging"
RAW_SIZE=$(docker image inspect "$IMAGE_NAME" --format='{{.Size}}')
DISPLAY_SIZE=$(numfmt --to=iec --suffix=B "$RAW_SIZE")
echo "human_readable=$DISPLAY_SIZE" >> $GITHUB_OUTPUT
- name: Create Docker image size report
run: |
{
echo "## Docker Image Size Report"
echo ""
echo "**Backend:** ${{ steps.backend-size.outputs.human_readable }}"
echo "**Frontend:** ${{ steps.frontend-size.outputs.human_readable }}"
} >> $GITHUB_STEP_SUMMARY
scan-staging-images:
name: Scan Staging Images
needs:
- build-staging-images
runs-on: ubuntu-latest
steps:
- name: Check out repository
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
- name: Scan backend image
continue-on-error: true
uses: aquasecurity/trivy-action@b6643a29fecd7f34b3597bc6acb0a98b03d33ff8
with:
exit-code: 1
image-ref: owasp/nest:backend-staging
scan-type: image
trivy-config: trivy.yaml
trivyignores: trivyignore.yaml
version: latest
- name: Scan frontend image
continue-on-error: true
uses: aquasecurity/trivy-action@b6643a29fecd7f34b3597bc6acb0a98b03d33ff8
with:
exit-code: 1
image-ref: owasp/nest:frontend-staging
scan-type: image
trivy-config: trivy.yaml
trivyignores: trivyignore.yaml
version: latest
deploy-staging-nest:
name: Deploy Nest Staging
env:
ANSIBLE_HOST_KEY_CHECKING: false
NEST_HOST_IP_ADDRESS: ${{ secrets.NEST_HOST_IP_ADDRESS }}
NEST_SSH_PRIVATE_KEY_PATH: ${{ vars.NEST_SSH_PRIVATE_KEY_PATH }}
RELEASE_VERSION: ${{ needs.set-release-version.outputs.release_version }}
environment: staging
if: |
github.repository == 'OWASP/Nest' &&
github.ref == 'refs/heads/main'
needs:
- scan-staging-images
- set-release-version
runs-on: ubuntu-latest
steps:
- name: Check out repository
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
- name: Prepare SSH key
env:
NEST_SSH_PRIVATE_KEY: ${{ secrets.NEST_SSH_PRIVATE_KEY }}
NEST_SSH_PRIVATE_KEY_PATH: ${{ env.NEST_SSH_PRIVATE_KEY_PATH }}
run: |
SSH_KEY_PATH="${NEST_SSH_PRIVATE_KEY_PATH/#\~/$HOME}"
mkdir -p -m 700 "$(dirname "$SSH_KEY_PATH")"
umask 377
cat > "$SSH_KEY_PATH" <<EOF
$NEST_SSH_PRIVATE_KEY
EOF
- name: Prepare secrets
env:
DJANGO_ALGOLIA_APPLICATION_ID: ${{ secrets.DJANGO_ALGOLIA_APPLICATION_ID }}
DJANGO_ALGOLIA_WRITE_API_KEY: ${{ secrets.DJANGO_ALGOLIA_WRITE_API_KEY }}
DJANGO_ALLOWED_HOSTS: ${{ secrets.DJANGO_ALLOWED_HOSTS }}
DJANGO_AWS_ACCESS_KEY_ID: ${{ secrets.DJANGO_AWS_ACCESS_KEY_ID }}
DJANGO_AWS_SECRET_ACCESS_KEY: ${{ secrets.DJANGO_AWS_SECRET_ACCESS_KEY }}
DJANGO_CONFIGURATION: ${{ secrets.DJANGO_CONFIGURATION }}
DJANGO_DB_HOST: ${{ secrets.DJANGO_DB_HOST }}
DJANGO_DB_NAME: ${{ secrets.DJANGO_DB_NAME }}
DJANGO_DB_PASSWORD: ${{ secrets.DJANGO_DB_PASSWORD }}
DJANGO_DB_PORT: ${{ secrets.DJANGO_DB_PORT }}
DJANGO_DB_USER: ${{ secrets.DJANGO_DB_USER }}
DJANGO_OPEN_AI_SECRET_KEY: ${{ secrets.DJANGO_OPEN_AI_SECRET_KEY }}
DJANGO_REDIS_HOST: ${{ secrets.DJANGO_REDIS_HOST }}
DJANGO_REDIS_PASSWORD: ${{ secrets.DJANGO_REDIS_PASSWORD }}
DJANGO_RELEASE_VERSION: ${{ secrets.DJANGO_RELEASE_VERSION }}
DJANGO_SECRET_KEY: ${{ secrets.DJANGO_SECRET_KEY }}
DJANGO_SENTRY_DSN: ${{ secrets.DJANGO_SENTRY_DSN }}
DJANGO_SETTINGS_MODULE: ${{ secrets.DJANGO_SETTINGS_MODULE }}
DJANGO_SLACK_BOT_TOKEN: ${{ secrets.DJANGO_SLACK_BOT_TOKEN }}
DJANGO_SLACK_SIGNING_SECRET: ${{ secrets.DJANGO_SLACK_SIGNING_SECRET }}
NEXT_SERVER_CSRF_URL: ${{ secrets.NEXT_SERVER_CSRF_URL }}
NEXT_SERVER_GITHUB_CLIENT_ID: ${{ secrets.NEST_GITHUB_CLIENT_ID }}
NEXT_SERVER_GITHUB_CLIENT_SECRET: ${{ secrets.NEST_GITHUB_CLIENT_SECRET }}
NEXT_SERVER_GRAPHQL_URL: ${{ secrets.NEXT_SERVER_GRAPHQL_URL }}
NEXTAUTH_SECRET: ${{ secrets.NEXTAUTH_SECRET }}
NEXTAUTH_URL: ${{ secrets.VITE_API_URL }}
SLACK_BOT_TOKEN_T04T40NHX: ${{ secrets.SLACK_BOT_TOKEN_T04T40NHX }}
run: |
# Backend
umask 377
cat > .env.backend <<EOF
DJANGO_ALGOLIA_APPLICATION_ID=$DJANGO_ALGOLIA_APPLICATION_ID
DJANGO_ALGOLIA_WRITE_API_KEY=$DJANGO_ALGOLIA_WRITE_API_KEY
DJANGO_ALLOWED_HOSTS=$DJANGO_ALLOWED_HOSTS
DJANGO_AWS_ACCESS_KEY_ID=$DJANGO_AWS_ACCESS_KEY_ID
DJANGO_AWS_SECRET_ACCESS_KEY=$DJANGO_AWS_SECRET_ACCESS_KEY
DJANGO_CONFIGURATION=$DJANGO_CONFIGURATION
DJANGO_DB_HOST=$DJANGO_DB_HOST
DJANGO_DB_NAME=$DJANGO_DB_NAME
DJANGO_DB_PASSWORD=$DJANGO_DB_PASSWORD
DJANGO_DB_PORT=$DJANGO_DB_PORT
DJANGO_DB_USER=$DJANGO_DB_USER
DJANGO_OPEN_AI_SECRET_KEY=$DJANGO_OPEN_AI_SECRET_KEY
DJANGO_REDIS_HOST=$DJANGO_REDIS_HOST
DJANGO_REDIS_PASSWORD=$DJANGO_REDIS_PASSWORD
DJANGO_RELEASE_VERSION=$DJANGO_RELEASE_VERSION
DJANGO_SECRET_KEY=$DJANGO_SECRET_KEY
DJANGO_SENTRY_DSN=$DJANGO_SENTRY_DSN
DJANGO_SETTINGS_MODULE=$DJANGO_SETTINGS_MODULE
DJANGO_SLACK_BOT_TOKEN=$DJANGO_SLACK_BOT_TOKEN
DJANGO_SLACK_SIGNING_SECRET=$DJANGO_SLACK_SIGNING_SECRET
SLACK_BOT_TOKEN_T04T40NHX=$SLACK_BOT_TOKEN_T04T40NHX
EOF
# Cache
umask 377
cat > .env.cache <<EOF
REDIS_PASSWORD=$DJANGO_REDIS_PASSWORD
EOF
# Database
umask 377
cat > .env.db <<EOF
POSTGRES_DB=$DJANGO_DB_NAME
POSTGRES_PASSWORD=$DJANGO_DB_PASSWORD
POSTGRES_USER=$DJANGO_DB_USER
EOF
# Frontend
umask 377
cat > .env.frontend <<EOF
NEXT_SERVER_CSRF_URL=$NEXT_SERVER_CSRF_URL
NEXT_SERVER_GITHUB_CLIENT_ID=$NEXT_SERVER_GITHUB_CLIENT_ID
NEXT_SERVER_GITHUB_CLIENT_SECRET=$NEXT_SERVER_GITHUB_CLIENT_SECRET
NEXT_SERVER_GRAPHQL_URL=$NEXT_SERVER_GRAPHQL_URL
NEXTAUTH_SECRET=$NEXTAUTH_SECRET
NEXTAUTH_URL=$NEXTAUTH_URL
EOF
- name: Run Nest deploy
working-directory: .github/ansible
run: ansible-playbook -i inventory.yaml staging/nest.yaml -e "github_workspace=$GITHUB_WORKSPACE"
deploy-staging-nest-proxy:
name: Deploy Staging Nest Proxy
env:
ANSIBLE_HOST_KEY_CHECKING: false
PROXY_HOST_IP_ADDRESS: ${{ secrets.PROXY_HOST_IP_ADDRESS }}
PROXY_SSH_PRIVATE_KEY_PATH: ${{ vars.PROXY_SSH_PRIVATE_KEY_PATH }}
environment: staging
if: |
github.repository == 'OWASP/Nest' &&
github.ref == 'refs/heads/main'
needs:
- deploy-staging-nest
runs-on: ubuntu-latest
steps:
- name: Check out repository
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
- name: Prepare SSH key
env:
PROXY_SSH_PRIVATE_KEY: ${{ secrets.PROXY_SSH_PRIVATE_KEY }}
PROXY_SSH_PRIVATE_KEY_PATH: ${{ env.PROXY_SSH_PRIVATE_KEY_PATH }}
run: |
SSH_KEY_PATH="${PROXY_SSH_PRIVATE_KEY_PATH/#\~/$HOME}"
mkdir -p -m 700 "$(dirname "$SSH_KEY_PATH")"
umask 377
cat > "$SSH_KEY_PATH" <<EOF
$PROXY_SSH_PRIVATE_KEY
EOF
- name: Run proxy deploy
working-directory: .github/ansible
run: ansible-playbook -i inventory.yaml staging/proxy.yaml -e "github_workspace=$GITHUB_WORKSPACE"
run-lighthouse-ci:
name: Run Lighthouse CI
needs:
- deploy-staging-nest-proxy
runs-on: ubuntu-latest
steps:
- name: Check out repository
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
- name: Install pnpm
uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda
with:
run_install: true
version: 10
- name: Set up Node
uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444
with:
cache-dependency-path: frontend/pnpm-lock.yaml
cache: 'pnpm'
node-version: 22
- name: Run lighthouse-ci
env:
LHCI_BASE_URL: 'https://nest.owasp.dev'
run: |
pnpm run lighthouse-ci
timeout-minutes: 15
working-directory: frontend
build-production-images:
name: Build Production Images
env:
RELEASE_VERSION: ${{ needs.set-release-version.outputs.release_version }}
environment: production
if: |
github.event_name == 'release' &&
github.event.action == 'published'
needs:
- run-backend-tests
- run-frontend-e2e-tests
- run-frontend-unit-tests
- set-release-version
runs-on: ubuntu-latest
steps:
- name: Check out repository
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
- name: Set up QEMU
uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392
- name: Set up Docker buildx
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435
- name: Login to Docker Hub
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Build backend image
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83
with:
build-args: |
OWASP_GID=1002
OWASP_UID=1002
cache-from: |
type=gha
type=registry,ref=owasp/nest:backend-staging-cache
context: backend
file: backend/docker/Dockerfile
load: true
platforms: linux/amd64
push: true
tags: owasp/nest:backend-production
- name: Get backend image size
id: backend-size
run: |
IMAGE_NAME="owasp/nest:backend-production"
RAW_SIZE=$(docker image inspect "$IMAGE_NAME" --format='{{.Size}}')
DISPLAY_SIZE=$(numfmt --to=iec --suffix=B "$RAW_SIZE")
echo "human_readable=$DISPLAY_SIZE" >> $GITHUB_OUTPUT
- name: Prepare frontend public environment
env:
NEXT_PUBLIC_API_URL: ${{ secrets.VITE_API_URL }}
NEXT_PUBLIC_CSRF_URL: ${{ secrets.VITE_CSRF_URL }}
NEXT_PUBLIC_ENVIRONMENT: ${{ secrets.VITE_ENVIRONMENT }}
NEXT_PUBLIC_GRAPHQL_URL: ${{ secrets.VITE_GRAPHQL_URL }}
NEXT_PUBLIC_GTM_ID: ${{ secrets.NEXT_PUBLIC_GTM_ID }}
NEXT_PUBLIC_IDX_URL: ${{ secrets.VITE_IDX_URL }}
NEXT_PUBLIC_IS_PROJECT_HEALTH_ENABLED: ${{ secrets.NEXT_PUBLIC_IS_PROJECT_HEALTH_ENABLED }}
NEXT_PUBLIC_RELEASE_VERSION: ${{ env.RELEASE_VERSION }}
NEXT_PUBLIC_SENTRY_DSN: ${{ secrets.VITE_SENTRY_DSN }}
run: |
umask 377
cat > frontend/.env <<EOF
NEXT_PUBLIC_API_URL=$NEXT_PUBLIC_API_URL
NEXT_PUBLIC_CSRF_URL=$NEXT_PUBLIC_CSRF_URL
NEXT_PUBLIC_ENVIRONMENT=$NEXT_PUBLIC_ENVIRONMENT
NEXT_PUBLIC_GRAPHQL_URL=$NEXT_PUBLIC_GRAPHQL_URL
NEXT_PUBLIC_GTM_ID=$NEXT_PUBLIC_GTM_ID
NEXT_PUBLIC_IDX_URL=$NEXT_PUBLIC_IDX_URL
NEXT_PUBLIC_IS_PROJECT_HEALTH_ENABLED=$NEXT_PUBLIC_IS_PROJECT_HEALTH_ENABLED
NEXT_PUBLIC_RELEASE_VERSION=$NEXT_PUBLIC_RELEASE_VERSION
NEXT_PUBLIC_SENTRY_DSN=$NEXT_PUBLIC_SENTRY_DSN
EOF
- name: Build frontend image
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83
with:
cache-from: |
type=gha
type=registry,ref=owasp/nest:frontend-staging-cache
context: frontend
file: frontend/docker/Dockerfile
load: true
platforms: linux/amd64
push: true
secrets: |
RELEASE_VERSION=${{ needs.set-release-version.outputs.release_version }}
SENTRY_AUTH_TOKEN=${{ secrets.SENTRY_AUTH_TOKEN }}
tags: owasp/nest:frontend-production
- name: Get frontend image size
id: frontend-size
run: |
IMAGE_NAME="owasp/nest:frontend-production"
RAW_SIZE=$(docker image inspect "$IMAGE_NAME" --format='{{.Size}}')
DISPLAY_SIZE=$(numfmt --to=iec --suffix=B "$RAW_SIZE")
echo "human_readable=$DISPLAY_SIZE" >> $GITHUB_OUTPUT
- name: Create Docker image size report
run: |
{
echo "## Docker Image Size Report"
echo ""
echo "**Backend:** ${{ steps.backend-size.outputs.human_readable }}"
echo "**Frontend:** ${{ steps.frontend-size.outputs.human_readable }}"
} >> $GITHUB_STEP_SUMMARY
scan-production-images:
name: Scan Production Images
needs:
- build-production-images
runs-on: ubuntu-latest
steps:
- name: Check out repository
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
- name: Setup Trivy
uses: aquasecurity/setup-trivy@e6c2c5e321ed9123bda567646e2f96565e34abe1
with:
cache: true
version: v0.62.1
- name: Scan backend image
continue-on-error: true
uses: aquasecurity/trivy-action@b6643a29fecd7f34b3597bc6acb0a98b03d33ff8
with:
exit-code: 1
image-ref: owasp/nest:backend-production
skip-setup-trivy: true
trivy-config: trivy.yaml
trivyignores: trivyignore.yaml
- name: Scan frontend image
continue-on-error: true
uses: aquasecurity/trivy-action@b6643a29fecd7f34b3597bc6acb0a98b03d33ff8
with:
exit-code: 1
image-ref: owasp/nest:frontend-production
skip-setup-trivy: true
trivy-config: trivy.yaml
trivyignores: trivyignore.yaml
deploy-production-nest:
name: Deploy Nest to Production
env:
ANSIBLE_HOST_KEY_CHECKING: false
NEST_HOST_IP_ADDRESS: ${{ secrets.NEST_HOST_IP_ADDRESS }}
NEST_SSH_PRIVATE_KEY_PATH: ${{ vars.NEST_SSH_PRIVATE_KEY_PATH }}
RELEASE_VERSION: ${{ needs.set-release-version.outputs.release_version }}
environment: production
if: |
github.event_name == 'release' &&
github.event.action == 'published'
needs:
- scan-production-images
- set-release-version
runs-on: ubuntu-latest
steps:
- name: Check out repository
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
- name: Prepare SSH key
env:
NEST_SSH_PRIVATE_KEY: ${{ secrets.NEST_SSH_PRIVATE_KEY }}
NEST_SSH_PRIVATE_KEY_PATH: ${{ env.NEST_SSH_PRIVATE_KEY_PATH }}
run: |
SSH_KEY_PATH="${NEST_SSH_PRIVATE_KEY_PATH/#\~/$HOME}"
mkdir -p -m 700 "$(dirname "$SSH_KEY_PATH")"
umask 377
cat > "$SSH_KEY_PATH" <<EOF
$NEST_SSH_PRIVATE_KEY
EOF
- name: Prepare secrets
env:
DJANGO_ALGOLIA_APPLICATION_ID: ${{ secrets.DJANGO_ALGOLIA_APPLICATION_ID }}
DJANGO_ALGOLIA_WRITE_API_KEY: ${{ secrets.DJANGO_ALGOLIA_WRITE_API_KEY }}
DJANGO_ALLOWED_HOSTS: ${{ secrets.DJANGO_ALLOWED_HOSTS }}
DJANGO_AWS_ACCESS_KEY_ID: ${{ secrets.DJANGO_AWS_ACCESS_KEY_ID }}
DJANGO_AWS_SECRET_ACCESS_KEY: ${{ secrets.DJANGO_AWS_SECRET_ACCESS_KEY }}
DJANGO_CONFIGURATION: ${{ secrets.DJANGO_CONFIGURATION }}
DJANGO_DB_HOST: ${{ secrets.DJANGO_DB_HOST }}
DJANGO_DB_NAME: ${{ secrets.DJANGO_DB_NAME }}
DJANGO_DB_PASSWORD: ${{ secrets.DJANGO_DB_PASSWORD }}
DJANGO_DB_PORT: ${{ secrets.DJANGO_DB_PORT }}
DJANGO_DB_USER: ${{ secrets.DJANGO_DB_USER }}
DJANGO_GITHUB_APP_ID: ${{ secrets.DJANGO_GITHUB_APP_ID }}
DJANGO_GITHUB_APP_INSTALLATION_ID: ${{ secrets.DJANGO_GITHUB_APP_INSTALLATION_ID }}
DJANGO_OPEN_AI_SECRET_KEY: ${{ secrets.DJANGO_OPEN_AI_SECRET_KEY }}
DJANGO_REDIS_HOST: ${{ secrets.DJANGO_REDIS_HOST }}
DJANGO_REDIS_PASSWORD: ${{ secrets.DJANGO_REDIS_PASSWORD }}
DJANGO_RELEASE_VERSION: ${{ env.RELEASE_VERSION }}
DJANGO_SECRET_KEY: ${{ secrets.DJANGO_SECRET_KEY }}
DJANGO_SENTRY_DSN: ${{ secrets.DJANGO_SENTRY_DSN }}
DJANGO_SETTINGS_MODULE: ${{ secrets.DJANGO_SETTINGS_MODULE }}
DJANGO_SLACK_BOT_TOKEN: ${{ secrets.DJANGO_SLACK_BOT_TOKEN }}
DJANGO_SLACK_SIGNING_SECRET: ${{ secrets.DJANGO_SLACK_SIGNING_SECRET }}
NEST_GITHUB_APP_PRIVATE_KEY: ${{ secrets.NEST_GITHUB_APP_PRIVATE_KEY }}
NEXT_SERVER_CSRF_URL: ${{ secrets.NEXT_SERVER_CSRF_URL }}
NEXT_SERVER_GITHUB_CLIENT_ID: ${{ secrets.NEST_GITHUB_CLIENT_ID }}
NEXT_SERVER_GITHUB_CLIENT_SECRET: ${{ secrets.NEST_GITHUB_CLIENT_SECRET }}
NEXT_SERVER_GRAPHQL_URL: ${{ secrets.NEXT_SERVER_GRAPHQL_URL }}
NEXTAUTH_SECRET: ${{ secrets.NEXTAUTH_SECRET }}
NEXTAUTH_URL: ${{ secrets.VITE_API_URL }}
SLACK_BOT_TOKEN_T04T40NHX: ${{ secrets.SLACK_BOT_TOKEN_T04T40NHX }}
run: |
# Backend
umask 377
cat > .env.backend <<EOF
DJANGO_ALGOLIA_APPLICATION_ID=$DJANGO_ALGOLIA_APPLICATION_ID
DJANGO_ALGOLIA_WRITE_API_KEY=$DJANGO_ALGOLIA_WRITE_API_KEY
DJANGO_ALLOWED_HOSTS=$DJANGO_ALLOWED_HOSTS
DJANGO_AWS_ACCESS_KEY_ID=$DJANGO_AWS_ACCESS_KEY_ID
DJANGO_AWS_SECRET_ACCESS_KEY=$DJANGO_AWS_SECRET_ACCESS_KEY
DJANGO_CONFIGURATION=$DJANGO_CONFIGURATION
DJANGO_DB_HOST=$DJANGO_DB_HOST
DJANGO_DB_NAME=$DJANGO_DB_NAME
DJANGO_DB_PASSWORD=$DJANGO_DB_PASSWORD
DJANGO_DB_PORT=$DJANGO_DB_PORT
DJANGO_DB_USER=$DJANGO_DB_USER
DJANGO_GITHUB_APP_ID=$DJANGO_GITHUB_APP_ID
DJANGO_GITHUB_APP_INSTALLATION_ID=$DJANGO_GITHUB_APP_INSTALLATION_ID
DJANGO_OPEN_AI_SECRET_KEY=$DJANGO_OPEN_AI_SECRET_KEY
DJANGO_REDIS_HOST=$DJANGO_REDIS_HOST
DJANGO_REDIS_PASSWORD=$DJANGO_REDIS_PASSWORD
DJANGO_RELEASE_VERSION=$DJANGO_RELEASE_VERSION
DJANGO_SECRET_KEY=$DJANGO_SECRET_KEY
DJANGO_SENTRY_DSN=$DJANGO_SENTRY_DSN
DJANGO_SETTINGS_MODULE=$DJANGO_SETTINGS_MODULE
DJANGO_SLACK_BOT_TOKEN=$DJANGO_SLACK_BOT_TOKEN
DJANGO_SLACK_SIGNING_SECRET=$DJANGO_SLACK_SIGNING_SECRET
SLACK_BOT_TOKEN_T04T40NHX=$SLACK_BOT_TOKEN_T04T40NHX
EOF
# Cache
umask 377
cat > .env.cache <<EOF
REDIS_PASSWORD=$DJANGO_REDIS_PASSWORD
EOF
# Database
umask 377
cat > .env.db <<EOF
POSTGRES_DB=$DJANGO_DB_NAME
POSTGRES_PASSWORD=$DJANGO_DB_PASSWORD
POSTGRES_USER=$DJANGO_DB_USER
EOF
# Frontend
umask 377
cat > .env.frontend <<EOF
NEXT_SERVER_CSRF_URL=$NEXT_SERVER_CSRF_URL
NEXT_SERVER_GITHUB_CLIENT_ID=$NEXT_SERVER_GITHUB_CLIENT_ID
NEXT_SERVER_GITHUB_CLIENT_SECRET=$NEXT_SERVER_GITHUB_CLIENT_SECRET
NEXT_SERVER_GRAPHQL_URL=$NEXT_SERVER_GRAPHQL_URL
NEXTAUTH_SECRET=$NEXTAUTH_SECRET
NEXTAUTH_URL=$NEXTAUTH_URL
EOF
# GitHub App private key
umask 377
cat > .github.pem <<EOF
"$NEST_GITHUB_APP_PRIVATE_KEY"
EOF
- name: Run Nest deploy
working-directory: .github/ansible
run: ansible-playbook -i inventory.yaml production/nest.yaml -e "github_workspace=$GITHUB_WORKSPACE"
deploy-production-nest-proxy:
name: Deploy Production Nest Proxy
env:
ANSIBLE_HOST_KEY_CHECKING: false
PROXY_HOST_IP_ADDRESS: ${{ secrets.PROXY_HOST_IP_ADDRESS }}
PROXY_SSH_PRIVATE_KEY_PATH: ${{ vars.PROXY_SSH_PRIVATE_KEY_PATH }}
environment: production
if: |
github.event_name == 'release' &&
github.event.action == 'published'
needs:
- deploy-production-nest
runs-on: ubuntu-latest
steps:
- name: Check out repository
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
- name: Prepare SSH key
env:
PROXY_SSH_PRIVATE_KEY: ${{ secrets.PROXY_SSH_PRIVATE_KEY }}
PROXY_SSH_PRIVATE_KEY_PATH: ${{ env.PROXY_SSH_PRIVATE_KEY_PATH }}
run: |
SSH_KEY_PATH="${PROXY_SSH_PRIVATE_KEY_PATH/#\~/$HOME}"
mkdir -p -m 700 "$(dirname "$SSH_KEY_PATH")"
umask 377
cat > "$SSH_KEY_PATH" <<EOF
$PROXY_SSH_PRIVATE_KEY
EOF
- name: Run proxy deploy
working-directory: .github/ansible
run: ansible-playbook -i inventory.yaml production/proxy.yaml -e "github_workspace=$GITHUB_WORKSPACE"