name: "MCP: PyPI Release" on: release: types: - "published" concurrency: group: ${{ github.workflow }}-${{ github.event.release.tag_name }} cancel-in-progress: false env: RELEASE_TAG: ${{ github.event.release.tag_name }} PYTHON_VERSION: "3.12" WORKING_DIRECTORY: ./mcp_server permissions: {} jobs: validate-release: if: github.repository == 'prowler-cloud/prowler' runs-on: ubuntu-latest timeout-minutes: 5 permissions: contents: read outputs: prowler_version: ${{ steps.parse-version.outputs.version }} major_version: ${{ steps.parse-version.outputs.major }} steps: - name: Harden the runner (Audit all outbound calls) uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 with: egress-policy: audit - name: Parse and validate version id: parse-version run: | PROWLER_VERSION="${RELEASE_TAG}" echo "version=${PROWLER_VERSION}" >> "${GITHUB_OUTPUT}" # Extract major version MAJOR_VERSION="${PROWLER_VERSION%%.*}" echo "major=${MAJOR_VERSION}" >> "${GITHUB_OUTPUT}" # Validate major version (only Prowler 3, 4, 5 supported) case ${MAJOR_VERSION} in 3|4|5) echo "✓ Releasing Prowler MCP for tag ${PROWLER_VERSION}" ;; *) echo "::error::Unsupported Prowler major version: ${MAJOR_VERSION}" exit 1 ;; esac publish-prowler-mcp: needs: validate-release runs-on: ubuntu-latest timeout-minutes: 15 permissions: contents: read id-token: write environment: name: pypi-prowler-mcp url: https://pypi.org/project/prowler-mcp/ steps: - name: Harden the runner (Audit all outbound calls) uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 with: egress-policy: audit - name: Checkout repository uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false - name: Install uv uses: astral-sh/setup-uv@5a095e7a2014a4212f075830d4f7277575a9d098 # v7.3.1 with: enable-cache: false - name: Set up Python ${{ env.PYTHON_VERSION }} uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 with: python-version: ${{ env.PYTHON_VERSION }} # The MCP server version (mcp_server/pyproject.toml) is decoupled from the Prowler release # version: it only changes when MCP code changes. mcp-bump-version.yml normally keeps it in # sync with mcp_server/CHANGELOG.md (separate from the release bump-version.yml), but this # publish workflow still runs on every release. # Pre-flight PyPI check covers the legitimate "no MCP changes for this release" case (and any # workflow_dispatch re-runs) without failing with HTTP 400 (version exists). - name: Check if prowler-mcp version already exists on PyPI id: pypi-check working-directory: ${{ env.WORKING_DIRECTORY }} run: | MCP_VERSION=$(grep '^version' pyproject.toml | head -1 | sed -E 's/^version[[:space:]]*=[[:space:]]*"([^"]+)".*/\1/') echo "mcp_version=${MCP_VERSION}" >> "$GITHUB_OUTPUT" if curl -fsS "https://pypi.org/pypi/prowler-mcp/${MCP_VERSION}/json" >/dev/null 2>&1; then echo "skip=true" >> "$GITHUB_OUTPUT" echo "::notice title=Skipping prowler-mcp publish::Version ${MCP_VERSION} already exists on PyPI; bump mcp_server/pyproject.toml to publish a new release." else echo "skip=false" >> "$GITHUB_OUTPUT" echo "::notice title=Publishing prowler-mcp::Version ${MCP_VERSION} not on PyPI yet; proceeding." fi - name: Build prowler-mcp package if: steps.pypi-check.outputs.skip != 'true' working-directory: ${{ env.WORKING_DIRECTORY }} run: uv build - name: Publish prowler-mcp package to PyPI if: steps.pypi-check.outputs.skip != 'true' uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # v1.14.2 with: packages-dir: ${{ env.WORKING_DIRECTORY }}/dist/ print-hash: true