Skip to content

Update strawberry_django decorators (#3404) #10557

Update strawberry_django decorators (#3404)

Update strawberry_django decorators (#3404) #10557

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: {}
env:
FORCE_COLOR: 1
jobs:
pre-commit:
name: Run pre-commit checks
permissions:
contents: read
runs-on: ubuntu-latest
steps:
- name: Check out repository
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8
- name: Install Poetry
run: pipx install poetry
- name: Set up Python
uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548
with:
cache: 'poetry'
cache-dependency-path: backend/poetry.lock
python-version: '3.13'
- name: Set up pre-commit cache
uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb
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
permissions:
contents: read
runs-on: ubuntu-latest
steps:
- name: Check out repository
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8
- name: Install pnpm
uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061
with:
version: 10
run_install: true
- name: Set up Node
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238
with:
node-version: 24
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
permissions:
contents: read
runs-on: ubuntu-latest
steps:
- name: Check out repository
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8
- name: Set up Docker buildx
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f
- name: Build cspell image
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83
with:
cache-from: type=gha,scope=cspell
cache-to: type=gha,scope=cspell,mode=max
context: cspell
file: cspell/Dockerfile
load: true
tags: cspell:ci
- name: Run cspell
run: |
make check-spelling
scan-code:
name: Run Code Scan
needs:
- check-frontend
- pre-commit
- spellcheck
permissions:
contents: read
runs-on: ubuntu-latest
steps:
- name: Check out repository
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8
- name: Setup Trivy
uses: aquasecurity/setup-trivy@3fb12ec12f41e471780db15c232d5dd185dcb514
with:
cache: true
- name: Run Trivy Repository Scan
uses: aquasecurity/trivy-action@b6643a29fecd7f34b3597bc6acb0a98b03d33ff8
with:
scan-type: repo
skip-setup-trivy: true
trivy-config: trivy.yaml
timeout-minutes: 5
scan-ci-dependencies:
name: Run CI Dependencies Scan
needs:
- check-frontend
- pre-commit
- spellcheck
permissions:
contents: read
runs-on: ubuntu-latest
steps:
- name: Check out repository
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8
- name: Setup Trivy
uses: aquasecurity/setup-trivy@3fb12ec12f41e471780db15c232d5dd185dcb514
with:
cache: true
- name: Run Trivy Filesystem Scan
uses: aquasecurity/trivy-action@b6643a29fecd7f34b3597bc6acb0a98b03d33ff8
with:
scan-type: fs
skip-setup-trivy: true
trivy-config: trivy.yaml
timeout-minutes: 5
run-backend-tests:
name: Run backend tests
needs:
- scan-code
- scan-ci-dependencies
permissions:
contents: read
runs-on: ubuntu-latest
steps:
- name: Check out repository
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8
- name: Set up Docker buildx
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f
- 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: docker/backend/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
timeout-minutes: 5
run-frontend-unit-tests:
name: Run frontend unit tests
needs:
- scan-code
- scan-ci-dependencies
permissions:
contents: read
runs-on: ubuntu-latest
steps:
- name: Check out repository
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8
- name: Set up Docker buildx
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f
- 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: docker/frontend/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
timeout-minutes: 5
run-frontend-e2e-tests:
name: Run frontend e2e tests
needs:
- scan-code
- scan-ci-dependencies
permissions:
contents: read
runs-on: ubuntu-latest
services:
db:
image: pgvector/pgvector:pg16
env:
POSTGRES_DB: nest_db_e2e
POSTGRES_PASSWORD: nest_user_e2e_password
POSTGRES_USER: nest_user_e2e
options: >-
--health-cmd="pg_isready -U nest_user_e2e -d nest_db_e2e -h localhost -p 5432"
--health-interval=5s
--health-timeout=5s
--health-retries=5
ports:
- 5432:5432
cache:
image: redis:8.0.5-alpine3.21
options: >-
--health-cmd="redis-cli ping"
--health-interval=5s
--health-retries=5
--health-timeout=5s
ports:
- 6379:6379
steps:
- name: Check out repository
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8
- name: Set up Docker buildx
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f
- name: Setup Backend environment
uses: ./.github/workflows/setup-backend-environment
with:
db_username: nest_user_e2e
db_name: nest_db_e2e
- name: Start Backend in the background
run: |
docker run -d --rm --name e2e-nest-backend \
--env-file backend/.env.e2e.example \
--network host \
-e DJANGO_DB_HOST=localhost \
-e DJANGO_REDIS_AUTH_ENABLED=False \
-e DJANGO_REDIS_HOST=localhost \
-p 9000:9000 \
owasp/nest:test-backend-latest \
sh -c '
python manage.py migrate &&
gunicorn wsgi:application --bind 0.0.0.0:9000
'
- name: Waiting for the backend to be ready
run: |
timeout 5m bash -c '
until wget --spider http://localhost:9000/a; do
echo "Waiting for backend..."
sleep 5
done
'
echo "Backend is up!"
- name: Load Postgres data
env:
PGPASSWORD: nest_user_e2e_password
run: |
pg_restore -h localhost -U nest_user_e2e -d nest_db_e2e < backend/data/nest.dump
- 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: docker/frontend/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.e2e.example owasp/nest:test-frontend-e2e-latest pnpm run test:e2e
timeout-minutes: 10
run-frontend-a11y-tests:
name: Run frontend accessibility tests
needs:
- scan-code
- scan-ci-dependencies
permissions:
contents: read
runs-on: ubuntu-latest
steps:
- name: Check out repository
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8
- name: Set up Docker buildx
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f
- name: Build frontend a11y-testing image
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83
with:
cache-from: |
type=gha
type=registry,ref=owasp/nest:test-frontend-a11y-cache
cache-to: |
type=gha,compression=zstd
context: frontend
file: docker/frontend/Dockerfile.a11y.test
load: true
platforms: linux/amd64
tags: owasp/nest:test-frontend-a11y-latest
- name: Run frontend a11y tests
run: |
docker run --env-file frontend/.env.example owasp/nest:test-frontend-a11y-latest pnpm run test:a11y
timeout-minutes: 5
set-release-version:
name: Set release version
outputs:
release_version: ${{ steps.set.outputs.release_version }}
permissions: {}
runs-on: ubuntu-latest
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
timeout-minutes: 5
run-graphql-fuzz-tests:
name: Run GraphQL fuzz tests
needs:
- scan-code
- scan-ci-dependencies
uses: ./.github/workflows/run-fuzz-tests.yaml
with:
test-file: graphql_test.py
run-rest-fuzz-tests:
name: Run REST fuzz tests
needs:
- scan-code
- scan-ci-dependencies
uses: ./.github/workflows/run-fuzz-tests.yaml
with:
test-file: rest_test.py
rest-url: http://localhost:9500/api/v0
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-a11y-tests
- run-frontend-e2e-tests
- run-frontend-unit-tests
- set-release-version
permissions:
contents: read
runs-on: ubuntu-latest
steps:
- name: Check out repository
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8
- name: Set up QEMU
uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130
- name: Set up Docker buildx
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f
- 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: docker/backend/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: docker/frontend/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
timeout-minutes: 5
scan-staging-images:
name: Scan Staging Images
needs:
- build-staging-images
permissions:
contents: read
runs-on: ubuntu-latest
steps:
- name: Check out repository
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8
- name: Setup Trivy
uses: aquasecurity/setup-trivy@3fb12ec12f41e471780db15c232d5dd185dcb514
with:
cache: true
- name: Scan backend image
uses: aquasecurity/trivy-action@b6643a29fecd7f34b3597bc6acb0a98b03d33ff8
with:
exit-code: 1
image-ref: owasp/nest:backend-staging
scan-type: image
skip-setup-trivy: true
trivy-config: trivy.yaml
- name: Scan frontend image
uses: aquasecurity/trivy-action@b6643a29fecd7f34b3597bc6acb0a98b03d33ff8
with:
exit-code: 1
image-ref: owasp/nest:frontend-staging
scan-type: image
skip-setup-trivy: true
trivy-config: trivy.yaml
timeout-minutes: 5
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
permissions:
contents: read
runs-on: ubuntu-latest
steps:
- name: Check out repository
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8
- 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"
timeout-minutes: 5
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
permissions:
contents: read
runs-on: ubuntu-latest
steps:
- name: Check out repository
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8
- 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"
timeout-minutes: 5
run-staging-lighthouse-ci:
name: Run Lighthouse CI
needs:
- deploy-staging-nest-proxy
permissions:
contents: read
runs-on: ubuntu-latest
steps:
- name: Check out repository
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8
- name: Install pnpm
uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061
with:
run_install: true
version: 10
- name: Set up Node
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238
with:
cache-dependency-path: frontend/pnpm-lock.yaml
cache: 'pnpm'
node-version: 24
- name: Run lighthouse-ci
env:
LHCI_BASE_URL: 'https://nest.owasp.dev'
run: |
pnpm run lighthouse-ci
working-directory: frontend
timeout-minutes: 5
run-staging-zap-baseline-scan:
name: Run staging ZAP baseline scan
needs:
- deploy-staging-nest-proxy
permissions:
contents: read
runs-on: ubuntu-latest
steps:
- name: Check out repository
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8
- name: Run baseline scan
uses: zaproxy/action-baseline@de8ad967d3548d44ef623df22cf95c3b0baf8b25
with:
token: ${{ secrets.GITHUB_TOKEN }}
target: 'https://nest.owasp.dev'
allow_issue_writing: false
fail_action: true
cmd_options: '-a -c .zapconfig -r report_html.html'
- name: Upload report
if: always()
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f
with:
name: zap-baseline-scan-report-${{ github.run_id }}
path: report_html.html
timeout-minutes: 5
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-a11y-tests
- run-frontend-e2e-tests
- run-frontend-unit-tests
- set-release-version
permissions:
contents: read
runs-on: ubuntu-latest
steps:
- name: Check out repository
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8
- name: Set up QEMU
uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130
- name: Set up Docker buildx
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f
- 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: docker/backend/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: docker/frontend/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
timeout-minutes: 5
scan-production-images:
name: Scan Production Images
needs:
- build-production-images
permissions:
contents: read
runs-on: ubuntu-latest
steps:
- name: Check out repository
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8
- name: Setup Trivy
uses: aquasecurity/setup-trivy@3fb12ec12f41e471780db15c232d5dd185dcb514
with:
cache: true
- name: Scan backend image
uses: aquasecurity/trivy-action@b6643a29fecd7f34b3597bc6acb0a98b03d33ff8
with:
exit-code: 1
image-ref: owasp/nest:backend-production
scan-type: image
skip-setup-trivy: true
trivy-config: trivy.yaml
- name: Scan frontend image
uses: aquasecurity/trivy-action@b6643a29fecd7f34b3597bc6acb0a98b03d33ff8
with:
exit-code: 1
image-ref: owasp/nest:frontend-production
scan-type: image
skip-setup-trivy: true
trivy-config: trivy.yaml
timeout-minutes: 5
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
permissions:
contents: read
runs-on: ubuntu-latest
steps:
- name: Check out repository
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8
- 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"
timeout-minutes: 5
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
permissions:
contents: read
runs-on: ubuntu-latest
steps:
- name: Check out repository
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8
- 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"
timeout-minutes: 5
run-production-zap-baseline-scan:
name: Run production ZAP baseline scan
needs:
- deploy-production-nest-proxy
permissions:
contents: read
runs-on: ubuntu-latest
steps:
- name: Check out repository
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8
- name: Run baseline scan
uses: zaproxy/action-baseline@de8ad967d3548d44ef623df22cf95c3b0baf8b25
with:
token: ${{ secrets.GITHUB_TOKEN }}
target: 'https://nest.owasp.org'
allow_issue_writing: false
fail_action: true
cmd_options: '-a -c .zapconfig -r report_html.html'
- name: Upload report
if: always()
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f
with:
name: zap-baseline-scan-report-${{ github.run_id }}
path: report_html.html
timeout-minutes: 5