Skip to content

add postgres to dependencies #2916

add postgres to dependencies

add postgres to dependencies #2916

name: staging-pipeline
on:
push:
branches:
- staging
# Security: Set minimal default permissions for all jobs
permissions:
contents: read # All jobs can read code, but can't write by default
jobs:
linters-and-build:
name: Run linters and build
runs-on: ubuntu-latest
permissions:
contents: read # Read code
pull-requests: write # Post lint comments
statuses: write # Update check status
steps:
- name: Check out Git repository
uses: actions/checkout@v5
with:
fetch-depth: 1
- name: Set up Node.js
uses: actions/setup-node@v6
with:
node-version: 22.18.0
cache: 'npm'
# ESLint and Prettier must be in `package.json`
- name: Install Node.js dependencies
run: npm ci
- name: Run linters
uses: wearerequired/lint-action@v2.3.0
with:
eslint: true
#prettier: true
continue_on_error: true
- name: Build project
run: |
echo "🔨 Building TypeScript..."
npm run build
echo "✅ Build complete"
publish:
needs: linters-and-build
runs-on: ubuntu-latest
permissions:
contents: read # Read code
packages: write # Push to GHCR
id-token: write # Cosign signing
outputs:
image-digest: ${{ steps.build.outputs.digest }}
steps:
- name: Check out the repo
uses: actions/checkout@v5
with:
fetch-depth: 1
- name: Login to GitHub Container Registry
uses: docker/login-action@v3.6.0
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3.11.1
# Performance: Build with cache for faster builds
- name: Build image and push to GitHub Packages
id: build
uses: docker/build-push-action@v6.18.0
with:
context: .
push: true
tags: |
ghcr.io/giveth/impact-graph:staging
ghcr.io/giveth/impact-graph:${{ github.sha }}
cache-from: type=gha
cache-to: type=gha,mode=max
provenance: true
sbom: true
# Security: Sign container image with Cosign
- name: Install Cosign
uses: sigstore/cosign-installer@v4.0.0
- name: Sign container image
run: |
cosign sign --yes ghcr.io/giveth/impact-graph@${{ steps.build.outputs.digest }}
deploy:
needs: publish
runs-on: ubuntu-latest
permissions:
contents: read # Read code for actions
id-token: write # Cosign signature verification
steps:
# Security: Verify image signature before deployment
- name: Install Cosign
uses: sigstore/cosign-installer@v4.0.0
- name: Verify Image Signature
run: |
echo "🔐 Verifying image signature..."
cosign verify ghcr.io/giveth/impact-graph@${{ needs.publish.outputs.image-digest }} \
--certificate-identity "${{ github.server_url }}/${{ github.repository }}/.github/workflows/staging-pipeline.yml@${{ github.ref }}" \
--certificate-oidc-issuer="https://token.actions.githubusercontent.com"
echo "✅ Image signature verified successfully! Image is authentic and untampered."
# Only deploys if signature verification passes
- name: SSH and Pull Verified Image
uses: appleboy/ssh-action@v1.2.2
with:
host: ${{ secrets.STAGING_HOST_ALL }}
username: ${{ secrets.STAGING_USERNAME_ALL }}
key: ${{ secrets.STAGING_PRIVATE_KEY_ALL }}
port: ${{ secrets.SSH_PORT }}
script: |
cd giveth-all
# Pull the verified image by its immutable SHA
docker pull ghcr.io/giveth/impact-graph@${{ needs.publish.outputs.image-digest }}
# Export the verified SHA for docker-compose to use
echo "IMPACT_GRAPH_IMAGE=ghcr.io/giveth/impact-graph@${{ needs.publish.outputs.image-digest }}" > .env.impact-graph
echo "✅ Verified image pulled: ghcr.io/giveth/impact-graph@${{ needs.publish.outputs.image-digest }}"
migrate:
needs: deploy
runs-on: ubuntu-latest
permissions:
contents: none # Minimal - only for actions to work
steps:
- name: SSH and Run DB Migrations (one-shot)
uses: appleboy/ssh-action@v1.2.2
with:
host: ${{ secrets.STAGING_HOST_ALL }}
username: ${{ secrets.STAGING_USERNAME_ALL }}
key: ${{ secrets.STAGING_PRIVATE_KEY_ALL }}
port: ${{ secrets.SSH_PORT }}
script: |
set -e
cd giveth-all
# Load the verified image SHA so migrations run on the exact image being deployed
export $(cat .env.impact-graph | xargs)
echo "🗃️ Running database migrations using verified image: $IMPACT_GRAPH_IMAGE"
# One-shot container: runs migrations, then exits. Non-zero exit fails the deploy.
docker compose run --rm impact-graph-migrations
echo "✅ Migrations complete"
rollout-deploy-1:
needs: migrate
runs-on: ubuntu-latest
permissions:
contents: none # Minimal - only for actions to work
steps:
- name: SSH and Redeploy
uses: appleboy/ssh-action@v1.2.2
with:
host: ${{ secrets.STAGING_HOST_ALL }}
username: ${{ secrets.STAGING_USERNAME_ALL }}
key: ${{ secrets.STAGING_PRIVATE_KEY_ALL }}
port: ${{ secrets.SSH_PORT }}
script: |
cd giveth-all
# Load the verified image SHA from environment
export $(cat .env.impact-graph | xargs)
## Update each backend service one by one
## First Deployment - uses IMPACT_GRAPH_IMAGE with verified SHA
docker compose up -d --no-deps --force-recreate impact-graph-ql1
docker compose up -d --no-deps --force-recreate impact-graph-jobs
echo "First deployment phase triggered using verified image: $IMPACT_GRAPH_IMAGE"
rollout-deploy-2:
needs: rollout-deploy-1
runs-on: ubuntu-latest
permissions:
contents: none # Minimal - only for actions to work
steps:
- name: SSH and Redeploy
uses: appleboy/ssh-action@v1.2.2
with:
host: ${{ secrets.STAGING_HOST_ALL }}
username: ${{ secrets.STAGING_USERNAME_ALL }}
key: ${{ secrets.STAGING_PRIVATE_KEY_ALL }}
port: ${{ secrets.SSH_PORT }}
script: |
cd giveth-all
# Load the verified image SHA from environment
export $(cat .env.impact-graph | xargs)
## Update each backend service one by one
## Second Deployment - uses IMPACT_GRAPH_IMAGE with verified SHA
docker compose up -d --no-deps --force-recreate impact-graph-ql2
echo "Second deployment phase triggered using verified image: $IMPACT_GRAPH_IMAGE"
rollout-deploy-3:
needs: rollout-deploy-2
runs-on: ubuntu-latest
permissions:
contents: none # Minimal - only for actions to work
steps:
- name: SSH and Redeploy
uses: appleboy/ssh-action@v1.2.2
with:
host: ${{ secrets.STAGING_HOST_ALL }}
username: ${{ secrets.STAGING_USERNAME_ALL }}
key: ${{ secrets.STAGING_PRIVATE_KEY_ALL }}
port: ${{ secrets.SSH_PORT }}
script: |
cd giveth-all
# Load the verified image SHA from environment
export $(cat .env.impact-graph | xargs)
## Update each backend service one by one
## Third Deployment - uses IMPACT_GRAPH_IMAGE with verified SHA
docker compose up -d --no-deps --force-recreate impact-graph-ql3
echo "Third deployment phase triggered using verified image: $IMPACT_GRAPH_IMAGE"
rollout-deploy-4:
needs: rollout-deploy-3
runs-on: ubuntu-latest
permissions:
contents: none # Minimal - only for actions to work
steps:
- name: SSH and Redeploy
uses: appleboy/ssh-action@v1.2.2
with:
host: ${{ secrets.STAGING_HOST_ALL }}
username: ${{ secrets.STAGING_USERNAME_ALL }}
key: ${{ secrets.STAGING_PRIVATE_KEY_ALL }}
port: ${{ secrets.SSH_PORT }}
script: |
set -e
cd giveth-all
# Load the verified image SHA from environment
export $(cat .env.impact-graph | xargs)
## Update each backend service one by one
## Fourth Deployment - uses IMPACT_GRAPH_IMAGE with verified SHA
docker compose up -d --no-deps --force-recreate impact-graph-ql4
echo "Fourth deployment phase triggered using verified image: $IMPACT_GRAPH_IMAGE"
verify-health:
needs:
- rollout-deploy-1
- rollout-deploy-2
- rollout-deploy-3
- rollout-deploy-4
runs-on: ubuntu-latest
permissions:
contents: none # Minimal - only for actions to work
steps:
- name: Wait for services to stabilize
run: sleep 60
- name: SSH and Verify Health
uses: appleboy/ssh-action@v1.2.2
with:
host: ${{ secrets.STAGING_HOST_ALL }}
username: ${{ secrets.STAGING_USERNAME_ALL }}
key: ${{ secrets.STAGING_PRIVATE_KEY_ALL }}
port: ${{ secrets.SSH_PORT }}
script: |
set -e
cd giveth-all
services=("impact-graph-ql1" "impact-graph-ql2" "impact-graph-ql3" "impact-graph-ql4")
echo "=== Final Health Check for All Services ==="
for svc in "${services[@]}"; do
echo "Checking health for $svc ..."
ok=0
for i in {1..12}; do # up to ~2 minutes
status=$(docker inspect --format='{{json .State.Health.Status}}' "$svc" 2>/dev/null || echo '""')
if [ "$status" = "\"healthy\"" ]; then
echo "✓ $svc is healthy"
ok=1
break
fi
echo "Current health: $status; waiting..."
sleep 10
done
if [ $ok -ne 1 ]; then
echo "::error::$svc did not reach healthy status"
# Get container logs for debugging
docker logs --tail 100 "$svc" || true
exit 1
fi
done
echo "Checking impact-graph-jobs is running ..."
job_status=$(docker inspect --format='{{json .State.Status}}' impact-graph-jobs 2>/dev/null || echo '""')
if [ "$job_status" != "\"running\"" ]; then
echo "::error::impact-graph-jobs is not running (status: $job_status)"
exit 1
fi
echo "All services healthy."
docker image prune -f