Fix CodeQL Issues #24
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: Build and Push Docker Images | |
| on: | |
| push: | |
| branches: [ master ] | |
| tags: [ 'v*' ] | |
| pull_request: | |
| branches: [ master ] | |
| env: | |
| REGISTRY: docker.io | |
| IMAGE_NAME: writenotenow/mysql-mcp | |
| permissions: | |
| contents: read | |
| packages: write | |
| security-events: write # For security scanning | |
| pull-requests: write # For PR comments | |
| id-token: write # For supply chain attestations | |
| attestations: write # For generating attestations | |
| jobs: | |
| # Quality gate - must pass before any builds | |
| quality-gate: | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v6 | |
| - name: Set up Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '20' | |
| cache: 'npm' | |
| - name: Install dependencies | |
| run: npm ci | |
| - name: Lint | |
| run: npm run lint | |
| - name: Type check | |
| run: npm run typecheck | |
| - name: Run tests | |
| run: npm test | |
| # Build each platform on native architecture (avoids QEMU emulation issues) | |
| build-platform: | |
| needs: quality-gate | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - platform: linux/amd64 | |
| runner: ubuntu-latest | |
| - platform: linux/arm64 | |
| runner: ubuntu-24.04-arm | |
| runs-on: ${{ matrix.runner }} | |
| permissions: | |
| contents: read | |
| packages: write | |
| id-token: write | |
| attestations: write | |
| outputs: | |
| version: ${{ steps.version.outputs.version }} | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v6 | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v3 | |
| - name: Log in to Docker Hub | |
| if: github.event_name != 'pull_request' | |
| uses: docker/login-action@v3 | |
| continue-on-error: true | |
| with: | |
| registry: ${{ env.REGISTRY }} | |
| username: ${{ secrets.DOCKER_USERNAME }} | |
| password: ${{ secrets.DOCKER_PASSWORD }} | |
| - name: Read version from VERSION file | |
| id: version | |
| run: | | |
| if [ -f "VERSION" ]; then | |
| VERSION=$(head -1 VERSION | tr -d '[:space:]') | |
| fi | |
| if [ -z "$VERSION" ]; then | |
| VERSION=$(grep -oP '"version":\s*"\K[0-9.]+' package.json | head -1) | |
| fi | |
| if [ -z "$VERSION" ]; then | |
| VERSION="1.0.0" | |
| fi | |
| echo "version=$VERSION" >> $GITHUB_OUTPUT | |
| echo "Detected version: $VERSION" | |
| - name: Extract metadata | |
| id: meta | |
| uses: docker/metadata-action@v5 | |
| with: | |
| images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} | |
| flavor: | | |
| latest=false | |
| suffix=-${{ matrix.platform == 'linux/amd64' && 'amd64' || 'arm64' }} | |
| tags: | | |
| type=sha,prefix=sha-,format=short | |
| - name: Build and push platform image | |
| id: build | |
| uses: docker/build-push-action@v6 | |
| with: | |
| context: . | |
| file: Dockerfile | |
| platforms: ${{ matrix.platform }} | |
| push: ${{ github.event_name != 'pull_request' }} | |
| tags: ${{ steps.meta.outputs.tags }} | |
| labels: ${{ steps.meta.outputs.labels }} | |
| cache-from: type=gha,scope=${{ matrix.platform }} | |
| cache-to: type=gha,scope=${{ matrix.platform }},mode=max | |
| provenance: mode=max | |
| sbom: true | |
| - name: Export digest | |
| if: github.event_name != 'pull_request' | |
| run: | | |
| mkdir -p /tmp/digests | |
| digest="${{ steps.build.outputs.digest }}" | |
| touch "/tmp/digests/${digest#sha256:}" | |
| - name: Upload digest | |
| if: github.event_name != 'pull_request' | |
| uses: actions/upload-artifact@v6 | |
| with: | |
| name: digests-${{ matrix.platform == 'linux/amd64' && 'amd64' || 'arm64' }} | |
| path: /tmp/digests/* | |
| if-no-files-found: error | |
| retention-days: 1 | |
| # Security scan on amd64 image only (runs in parallel) | |
| security-scan: | |
| runs-on: ubuntu-latest | |
| needs: build-platform | |
| if: github.event_name != 'pull_request' | |
| permissions: | |
| contents: read | |
| security-events: write | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v6 | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v3 | |
| - name: Build image for scanning | |
| uses: docker/build-push-action@v6 | |
| with: | |
| context: . | |
| file: Dockerfile | |
| platforms: linux/amd64 | |
| push: false | |
| load: true | |
| tags: local-scan:latest | |
| cache-from: type=gha,scope=linux/amd64 | |
| - name: Docker Scout security scan | |
| timeout-minutes: 10 | |
| run: | | |
| curl -sSfL https://raw.githubusercontent.com/docker/scout-cli/main/install.sh | sh -s -- | |
| docker images local-scan:latest | |
| echo "🔍 Running Docker Scout security scan" | |
| if timeout 480 docker scout cves local-scan:latest > scout_output.txt 2>&1; then | |
| echo "📊 Scan completed successfully" | |
| cat scout_output.txt | |
| if grep -E "(CRITICAL|HIGH)" scout_output.txt | grep -v "0 " > /dev/null; then | |
| echo "⚠️ Critical or high severity vulnerabilities detected (informational)" | |
| else | |
| echo "✅ No critical/high severity vulnerabilities" | |
| fi | |
| else | |
| echo "⚠️ Docker Scout scan timed out or failed" | |
| fi | |
| # Merge platform images into multi-arch manifest | |
| merge-and-push: | |
| runs-on: ubuntu-latest | |
| needs: [build-platform, security-scan] | |
| if: github.event_name != 'pull_request' | |
| permissions: | |
| contents: read | |
| packages: write | |
| id-token: write | |
| attestations: write | |
| deployments: write | |
| environment: | |
| name: ${{ github.ref == 'refs/heads/master' && 'production' || '' }} | |
| url: https://hub.docker.com/r/writenotenow/mysql-mcp | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v6 | |
| - name: Download digests | |
| uses: actions/download-artifact@v7 | |
| with: | |
| path: /tmp/digests | |
| pattern: digests-* | |
| merge-multiple: true | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v3 | |
| - name: Log in to Docker Hub | |
| uses: docker/login-action@v3 | |
| with: | |
| registry: ${{ env.REGISTRY }} | |
| username: ${{ secrets.DOCKER_USERNAME }} | |
| password: ${{ secrets.DOCKER_PASSWORD }} | |
| - name: Read version | |
| id: version | |
| run: | | |
| if [ -f "VERSION" ]; then | |
| VERSION=$(head -1 VERSION | tr -d '[:space:]') | |
| fi | |
| if [ -z "$VERSION" ]; then | |
| VERSION=$(grep -oP '"version":\s*"\K[0-9.]+' package.json | head -1) | |
| fi | |
| if [ -z "$VERSION" ]; then | |
| VERSION="1.0.0" | |
| fi | |
| echo "version=$VERSION" >> $GITHUB_OUTPUT | |
| - name: Extract metadata for manifest | |
| id: meta | |
| uses: docker/metadata-action@v5 | |
| with: | |
| images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} | |
| flavor: | | |
| latest=auto | |
| tags: | | |
| type=semver,pattern=v{{version}} | |
| type=raw,value=v${{ steps.version.outputs.version }},enable={{is_default_branch}} | |
| type=raw,value=latest,enable={{is_default_branch}} | |
| type=sha,prefix=sha-,format=short | |
| - name: Create and push manifest | |
| working-directory: /tmp/digests | |
| run: | | |
| docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \ | |
| $(printf '${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@sha256:%s ' *) | |
| - name: Inspect manifest | |
| run: | | |
| docker buildx imagetools inspect ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.meta.outputs.version }} | |
| # Update Docker Hub description | |
| - name: Update Docker Hub Description | |
| if: github.ref == 'refs/heads/master' | |
| uses: peter-evans/dockerhub-description@v5 | |
| continue-on-error: true | |
| timeout-minutes: 5 | |
| with: | |
| username: ${{ secrets.DOCKER_USERNAME }} | |
| password: ${{ secrets.DOCKER_PASSWORD }} | |
| repository: ${{ env.IMAGE_NAME }} | |
| readme-filepath: ./DOCKER_README.md | |
| short-description: "Enterprise-grade MySQL MCP Server with 191 tools, OAuth 2.0 and Tool Filtering." | |
| - name: Deployment Summary | |
| if: github.ref == 'refs/heads/master' | |
| run: | | |
| echo "✅ Successfully published Docker images to production" | |
| echo "🐳 Registry: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}" | |
| echo "🏷️ Tags: ${{ steps.meta.outputs.tags }}" | |
| echo "📝 Commit: ${{ github.sha }}" | |
| echo "👤 Published by: ${{ github.actor }}" |