fix(ci): make production lambda check robust #2
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Deploy Preprod Hotfix | |
| on: | |
| push: | |
| branches: | |
| - "hotfix/**" | |
| workflow_dispatch: | |
| inputs: | |
| branch: | |
| description: "Branch to deploy (defaults to current ref)" | |
| required: false | |
| type: string | |
| skip_tests: | |
| description: "Skip tests before deployment" | |
| required: false | |
| default: "false" | |
| type: choice | |
| options: | |
| - "true" | |
| - "false" | |
| concurrency: | |
| group: deploy-preprod-hotfix-${{ github.ref_name }} | |
| cancel-in-progress: true | |
| jobs: | |
| pre-deployment-checks: | |
| name: Pre-Deployment Validation | |
| runs-on: ubuntu-latest | |
| if: ${{ github.event_name != 'workflow_dispatch' || github.event.inputs.skip_tests != 'true' }} | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| with: | |
| ref: ${{ github.event.inputs.branch || github.ref }} | |
| - name: Set up Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: "3.11" | |
| - name: Set up uv | |
| uses: astral-sh/setup-uv@v5 | |
| with: | |
| version: "latest" | |
| enable-cache: true | |
| - name: Create virtual environment | |
| run: uv venv .venv | |
| - name: Install dependencies | |
| run: | | |
| source .venv/bin/activate | |
| uv pip install -r coaching/requirements.txt | |
| uv pip install -r coaching/requirements-dev.txt | |
| shell: bash | |
| - name: Run Ruff Linting | |
| run: | | |
| source .venv/bin/activate | |
| python -m ruff check . --exclude=".venv,venv,__pycache__,.pytest_cache" | |
| shell: bash | |
| - name: Run MyPy Type Checking | |
| run: | | |
| source .venv/bin/activate | |
| python -m mypy coaching/src/ shared/ --config-file=pyproject.toml | |
| shell: bash | |
| - name: Run Unit Tests | |
| run: | | |
| source .venv/bin/activate | |
| python -m pytest coaching/tests/unit/ -v --cov=coaching/src --cov-fail-under=70 | |
| shell: bash | |
| env: | |
| PYTHONPATH: coaching:shared:. | |
| deploy-coaching: | |
| name: Deploy to Preprod | |
| runs-on: ubuntu-latest | |
| needs: [pre-deployment-checks] | |
| if: ${{ always() && (needs.pre-deployment-checks.result == 'success' || (github.event_name == 'workflow_dispatch' && github.event.inputs.skip_tests == 'true')) }} | |
| permissions: | |
| id-token: write | |
| contents: read | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| with: | |
| ref: ${{ github.event.inputs.branch || github.ref }} | |
| - name: Setup Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: "3.11" | |
| - name: Install Pulumi Python dependencies | |
| working-directory: coaching/pulumi | |
| run: pip install -r requirements.txt | |
| - name: Configure AWS credentials | |
| uses: aws-actions/configure-aws-credentials@v4 | |
| with: | |
| aws-region: us-east-1 | |
| aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} | |
| aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} | |
| - name: Deploy Coaching Service | |
| uses: pulumi/actions@v5 | |
| with: | |
| command: up | |
| stack-name: preprod | |
| work-dir: coaching/pulumi | |
| env: | |
| PULUMI_ACCESS_TOKEN: ${{ secrets.PULUMI_ACCESS_TOKEN }} | |
| AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} | |
| AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} | |
| AWS_REGION: us-east-1 | |
| smoke-tests: | |
| name: Post-Deployment Smoke Tests | |
| runs-on: ubuntu-latest | |
| needs: [deploy-coaching] | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| with: | |
| ref: ${{ github.event.inputs.branch || github.ref }} | |
| - name: Install Pulumi CLI | |
| uses: pulumi/actions@v5 | |
| with: | |
| pulumi-version: "latest" | |
| - name: Configure AWS credentials | |
| uses: aws-actions/configure-aws-credentials@v4 | |
| with: | |
| aws-region: us-east-1 | |
| aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} | |
| aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} | |
| - name: Get API Gateway URL | |
| id: api-url | |
| working-directory: coaching/pulumi | |
| run: | | |
| URL=$(pulumi stack output customDomainUrl --stack preprod) | |
| echo "url=$URL" >> $GITHUB_OUTPUT | |
| env: | |
| PULUMI_ACCESS_TOKEN: ${{ secrets.PULUMI_ACCESS_TOKEN }} | |
| - name: Health Check | |
| run: | | |
| HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" "${{ steps.api-url.outputs.url }}/health" || echo "000") | |
| if [ "$HTTP_CODE" != "200" ] && [ "$HTTP_CODE" != "404" ]; then | |
| echo "❌ Health check failed with HTTP $HTTP_CODE" | |
| exit 1 | |
| fi | |
| echo "✅ Health check passed ($HTTP_CODE)" | |
| - name: CORS Preflight Check | |
| run: | | |
| ORIGIN="https://preprod.purposepath.app" | |
| TARGET="${{ steps.api-url.outputs.url }}/api/v1/ai/execute-async" | |
| CORS_HEADERS=$(curl -s -D - -o /dev/null -X OPTIONS "$TARGET" \ | |
| -H "Origin: $ORIGIN" \ | |
| -H "Access-Control-Request-Method: POST" \ | |
| -H "Access-Control-Request-Headers: Authorization,Content-Type,X-Tenant-Id") | |
| ALLOW_ORIGIN=$(echo "$CORS_HEADERS" | tr -d '\r' | awk -F': ' 'tolower($1)=="access-control-allow-origin"{print $2}' | tail -n 1) | |
| ALLOW_CREDENTIALS=$(echo "$CORS_HEADERS" | tr -d '\r' | awk -F': ' 'tolower($1)=="access-control-allow-credentials"{print $2}' | tail -n 1) | |
| if [ "$ALLOW_ORIGIN" != "$ORIGIN" ]; then | |
| echo "❌ Invalid Access-Control-Allow-Origin: '$ALLOW_ORIGIN' (expected '$ORIGIN')" | |
| exit 1 | |
| fi | |
| if [ "$ALLOW_CREDENTIALS" != "true" ]; then | |
| echo "❌ Invalid Access-Control-Allow-Credentials: '$ALLOW_CREDENTIALS' (expected 'true')" | |
| exit 1 | |
| fi | |
| echo "✅ CORS preflight returned expected headers" |