diff --git a/q2-postmortem/q3-cicd/workflow.yml b/q2-postmortem/q3-cicd/workflow.yml new file mode 100644 index 0000000..923b9c2 --- /dev/null +++ b/q2-postmortem/q3-cicd/workflow.yml @@ -0,0 +1,126 @@ +# .github/workflows/workflow.yml +# +# CI/CD pipeline: build Docker image -> push to ghaymah Container Registry -> +# auto-deploy to staging -> manual approval gate -> deploy to production. +# +name: Build and Deploy to Ghaymah + +on: + push: + branches: [main, develop] + pull_request: + branches: [main] + +env: + GHAYMAH_REGISTRY: registry.ghaymah.systems + IMAGE_NAME: ${{ github.repository }} + +jobs: + # --------------------------------------------------------------------- + # 1) Build & push image (runs on every push to main/develop, and on PRs + # for build validation only — PRs never push or deploy). + # --------------------------------------------------------------------- + build: + name: Build & Push Image + runs-on: ubuntu-latest + permissions: + contents: read + outputs: + image_tag: ${{ steps.meta.outputs.tag }} + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set image tag + id: meta + run: echo "tag=${GITHUB_SHA::12}" >> "$GITHUB_OUTPUT" + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to Ghaymah Container Registry + if: github.event_name == 'push' + uses: docker/login-action@v3 + with: + registry: ${{ env.GHAYMAH_REGISTRY }} + username: ${{ secrets.GHAYMAH_REGISTRY_USER }} + password: ${{ secrets.GHAYMAH_REGISTRY_TOKEN }} + + - name: Build image + uses: docker/build-push-action@v6 + with: + context: ./q1-deploy-monitor + push: ${{ github.event_name == 'push' }} + tags: | + ${{ env.GHAYMAH_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.meta.outputs.tag }} + ${{ env.GHAYMAH_REGISTRY }}/${{ env.IMAGE_NAME }}:latest + cache-from: type=gha + cache-to: type=gha,mode=max + + - name: Scan image for vulnerabilities + if: github.event_name == 'push' + uses: aquasecurity/trivy-action@0.24.0 + with: + image-ref: ${{ env.GHAYMAH_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.meta.outputs.tag }} + severity: CRITICAL,HIGH + exit-code: "1" + + # --------------------------------------------------------------------- + # 2) Auto-deploy to STAGING — no approval needed, fast feedback loop. + # Only runs on pushes to `develop`. + # --------------------------------------------------------------------- + deploy-staging: + name: Deploy to Staging + needs: build + if: github.ref == 'refs/heads/develop' && github.event_name == 'push' + runs-on: ubuntu-latest + environment: + name: staging + url: https://myapp-staging.ghaymah.systems + steps: + - name: Install Ghaymah CLI + run: curl -fsSL https://ghaymah.systems/cli/install.sh | sh + + - name: Authenticate CLI + run: ghaymah auth login --token "${{ secrets.GHAYMAH_API_TOKEN }}" + + - name: Deploy image to staging app + run: | + ghaymah deploy \ + --app myapp-staging \ + --image "${{ env.GHAYMAH_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ needs.build.outputs.image_tag }}" \ + --plan g3.small + + # --------------------------------------------------------------------- + # 3) Deploy to PRODUCTION — gated behind a manual approval. + # GitHub Environments with required reviewers = the approval gate. + # Only triggers on pushes to `main` (protected branch, PR-merge only). + # --------------------------------------------------------------------- + deploy-production: + name: Deploy to Production (manual approval required) + needs: build + if: github.ref == 'refs/heads/main' && github.event_name == 'push' + runs-on: ubuntu-latest + environment: + name: production # configure this environment in GitHub repo settings + # Settings -> Environments -> production -> Required reviewers + url: https://myapp.ghaymah.systems + steps: + - name: Install Ghaymah CLI + run: curl -fsSL https://ghaymah.systems/cli/install.sh | sh + + - name: Authenticate CLI + run: ghaymah auth login --token "${{ secrets.GHAYMAH_API_TOKEN }}" + + - name: Deploy image to production app + run: | + ghaymah deploy \ + --app myapp \ + --image "${{ env.GHAYMAH_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ needs.build.outputs.image_tag }}" \ + --plan g5.large \ + --strategy rolling + + - name: Post-deploy health check + run: | + sleep 10 + curl -f https://myapp.ghaymah.systems/health || (echo "Health check failed after deploy" && exit 1)