# ───────────────────────────────────────────────────────────────────────────── # GitHub Actions Rollback Pipeline – Claude Code Agent Monitor # # Manual workflow to roll back a Helm deployment to a previous revision. # ───────────────────────────────────────────────────────────────────────────── name: Rollback on: workflow_dispatch: inputs: environment: description: "Target environment to rollback" required: true type: choice options: - staging - production revision: description: "Helm revision number (leave empty for previous)" required: false type: string reason: description: "Reason for rollback" required: true type: string permissions: contents: read id-token: write concurrency: group: deploy-${{ github.event.inputs.environment }} cancel-in-progress: false jobs: rollback: name: Rollback ${{ github.event.inputs.environment }} runs-on: ubuntu-latest environment: name: ${{ github.event.inputs.environment }} steps: - name: Checkout code uses: actions/checkout@v4 - name: Configure AWS credentials (OIDC) uses: aws-actions/configure-aws-credentials@v4 with: role-to-assume: ${{ github.event.inputs.environment == 'production' && secrets.AWS_ROLE_ARN_PRODUCTION || secrets.AWS_ROLE_ARN_STAGING }} aws-region: ${{ vars.AWS_REGION || 'us-west-2' }} - name: Setup kubectl uses: azure/setup-kubectl@v3 with: version: "v1.29.0" - name: Setup Helm uses: azure/setup-helm@v4 with: version: "v3.14.0" - name: Update kubeconfig run: | CLUSTER_NAME="${{ github.event.inputs.environment == 'production' && vars.EKS_CLUSTER_PRODUCTION || vars.EKS_CLUSTER_STAGING }}" CLUSTER_NAME="${CLUSTER_NAME:-agent-monitor-${{ github.event.inputs.environment }}}" aws eks update-kubeconfig \ --region ${{ vars.AWS_REGION || 'us-west-2' }} \ --name "${CLUSTER_NAME}" - name: Show Helm history run: | NAMESPACE="agent-monitor-${{ github.event.inputs.environment }}" echo "## Current Helm History" helm history agent-monitor -n "${NAMESPACE}" --max 10 || echo "No history found" - name: Execute rollback run: | NAMESPACE="agent-monitor-${{ github.event.inputs.environment }}" REVISION="${{ github.event.inputs.revision }}" echo "Rolling back in namespace: ${NAMESPACE}" ROLLBACK_ARGS="helm rollback agent-monitor" if [[ -n "${REVISION}" ]]; then ROLLBACK_ARGS="${ROLLBACK_ARGS} ${REVISION}" echo "Target revision: ${REVISION}" else echo "Target revision: previous" fi ${ROLLBACK_ARGS} -n "${NAMESPACE}" --wait --timeout 300s echo "✔ Rollback command succeeded" - name: Health check after rollback run: | NAMESPACE="agent-monitor-${{ github.event.inputs.environment }}" echo "Waiting for pods to be ready..." kubectl wait --for=condition=ready pod \ -l app.kubernetes.io/name=agent-monitor \ -n "${NAMESPACE}" \ --timeout=300s kubectl port-forward svc/agent-monitor 14820:4820 -n "${NAMESPACE}" & PF_PID=$! sleep 5 HEALTHY=false for i in $(seq 1 10); do if curl -sf http://localhost:14820/api/health | grep -q '"status":"ok"'; then echo "✔ Health check passed after rollback" HEALTHY=true break fi echo "Attempt $i/10..." sleep 5 done kill $PF_PID 2>/dev/null || true if [[ "$HEALTHY" != true ]]; then echo "✖ Health check failed after rollback!" exit 1 fi - name: Show post-rollback status if: always() run: | NAMESPACE="agent-monitor-${{ github.event.inputs.environment }}" echo "## Post-Rollback Status" echo "" echo "### Helm Status" helm status agent-monitor -n "${NAMESPACE}" || true echo "" echo "### Pod Status" kubectl get pods -n "${NAMESPACE}" -l app.kubernetes.io/name=agent-monitor || true echo "" echo "### Recent Events" kubectl get events -n "${NAMESPACE}" --sort-by='.lastTimestamp' | tail -20 || true - name: Notify Slack if: always() uses: slackapi/slack-github-action@v1.26.0 with: payload: | { "text": "${{ job.status == 'success' && '⏪' || '🚨' }} Rollback ${{ job.status }} on ${{ github.event.inputs.environment }}", "blocks": [ { "type": "section", "text": { "type": "mrkdwn", "text": "${{ job.status == 'success' && ':rewind:' || ':rotating_light:' }} *Rollback ${{ job.status }}*\n*Environment:* `${{ github.event.inputs.environment }}`\n*Revision:* `${{ github.event.inputs.revision || 'previous' }}`\n*Reason:* ${{ github.event.inputs.reason }}\n*Actor:* ${{ github.actor }}\n*Workflow:* <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|View Run>" } } ] } env: SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK