Merge pull request #99 from Nya-Foundation/staging #40
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
| # .github/workflows/publish.yml | |
| # | |
| # Standard Publish Workflow for Nya Foundation | |
| # | |
| # This workflow handles the full CI/CD pipeline for Foundation: | |
| # 1. Runs tests and checks | |
| # 2. Uses semantic-release to automatically version the project based on commit messages | |
| # 3. Publishes the package to PyPI | |
| # 4. Builds and pushes Docker images to both Docker Hub and GitHub Container Registry | |
| # 5. Creates GitHub releases with changelog | |
| # | |
| # Required Secrets: | |
| # - CI_APP_ID: GitHub App ID for token generation | |
| # - CI_APP_PRIVATE_KEY: GitHub App private key for token generation | |
| # - DOCKERHUB_USERNAME: Username for Docker Hub | |
| # - DOCKERHUB_TOKEN: Access token for Docker Hub (not password) | |
| # | |
| # Optional Variables (set in repository variables): | |
| # - GCR_IMAGE_NAME: Image name for GitHub Container Registry (example: nya-foundation/nya-proxy) | |
| # - DOCKERHUB_IMAGE_NAME: Image name for Docker Hub (example: k3scat/nya-proxy) | |
| # | |
| # Permissions needed: | |
| # - contents: write (for creating GitHub releases) | |
| # - id-token: write (for PyPI trusted publishing) | |
| # - packages: write (for publishing to GitHub Container Registry) | |
| name: CI - Publish and Release | |
| on: | |
| push: | |
| branches: | |
| - main # Trigger release only on pushes to main | |
| paths: | |
| - '**/*.py' # Trigger on changes to Python files | |
| # Prevent multiple concurrent releases | |
| concurrency: | |
| group: ${{ github.workflow }}-release | |
| cancel-in-progress: false # Do not cancel releases once started | |
| jobs: | |
| publish: | |
| runs-on: ubuntu-latest | |
| environment: | |
| name: Publish and Release | |
| permissions: | |
| contents: write # Needed to create GitHub releases and tags | |
| id-token: write # Needed for PyPI trusted publishing (OIDC) - Recommended! | |
| packages: write # Needed for publishing Docker images | |
| steps: | |
| # Generate Token for the GitHub App | |
| - name: Generate GitHub App Token | |
| id: generate-token | |
| # Uses App ID and Private Key secrets to generate a short-lived installation token | |
| uses: actions/create-github-app-token@v2 | |
| with: | |
| app-id: ${{ secrets.CI_APP_ID }} | |
| private-key: ${{ secrets.CI_APP_PRIVATE_KEY }} | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| with: | |
| token: ${{ steps.generate-token.outputs.token }} | |
| fetch-depth: 0 | |
| persist-credentials: true | |
| # Setup Python - semantic-release might need it or specific tools | |
| - name: Set up Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: '3.12' | |
| # Configured with PyPI Trusted Publishing (OIDC) | |
| # https://docs.pypi.org/trusted-publishers/ | |
| - name: Python Semantic Release | |
| id: semantic-release | |
| uses: python-semantic-release/python-semantic-release@v9 | |
| with: | |
| github_token: ${{ steps.generate-token.outputs.token }} | |
| - name: Publish package to PyPI | |
| if: steps.semantic-release.outputs.released == 'true' | |
| uses: pypa/gh-action-pypi-publish@release/v1 | |
| with: | |
| verbose: true | |
| print-hash: true | |
| # Check if Dockerfile exists | |
| - name: Check for Dockerfile | |
| id: check_dockerfile | |
| run: | | |
| if [ -f "Dockerfile" ]; then | |
| echo "dockerfile_exists=true" >> $GITHUB_OUTPUT | |
| else | |
| echo "dockerfile_exists=false" >> $GITHUB_OUTPUT | |
| fi | |
| # Set up QEMU for multi-platform builds | |
| - name: Set up QEMU | |
| if: steps.check_dockerfile.outputs.dockerfile_exists == 'true' | |
| uses: docker/setup-qemu-action@v3 | |
| # Set up Docker Buildx | |
| - name: Set up Docker Buildx | |
| if: steps.check_dockerfile.outputs.dockerfile_exists == 'true' | |
| uses: docker/setup-buildx-action@v3 | |
| # Define image name variables for reusability | |
| - name: Set image name variables | |
| if: steps.check_dockerfile.outputs.dockerfile_exists == 'true' | |
| id: image-names | |
| run: | | |
| # Define the GitHub Container Registry image name (using organization) | |
| GITHUB_IMG="${{ vars.GCR_IMAGE_NAME }}" | |
| # Define the Docker Hub image name (using personal account) | |
| DOCKERHUB_IMG="${{ vars.DOCKERHUB_IMAGE_NAME }}" | |
| # Convert to lowercase (Docker best practice) | |
| GITHUB_IMG=$(echo "$GITHUB_IMG" | tr '[:upper:]' '[:lower:]') | |
| DOCKERHUB_IMG=$(echo "$DOCKERHUB_IMG" | tr '[:upper:]' '[:lower:]') | |
| echo "GCR_IMAGE_NAME=$GITHUB_IMG" >> $GITHUB_ENV | |
| echo "DOCKERHUB_IMAGE_NAME=$DOCKERHUB_IMG" >> $GITHUB_ENV | |
| # Log in to Docker Hub | |
| - name: Login to Docker Hub | |
| if: steps.check_dockerfile.outputs.dockerfile_exists == 'true' | |
| uses: docker/login-action@v3 | |
| with: | |
| username: ${{ secrets.DOCKERHUB_USERNAME }} | |
| password: ${{ secrets.DOCKERHUB_TOKEN }} | |
| # Extract version for tagging (only if Dockerfile exists) | |
| - name: Get project version | |
| if: steps.check_dockerfile.outputs.dockerfile_exists == 'true' | |
| id: get-version | |
| run: | | |
| # If semantic release created a new version, use it; otherwise extract from pyproject.toml | |
| if [ "${{ steps.semantic-release.outputs.released }}" == "true" ]; then | |
| VERSION="${{ steps.semantic-release.outputs.version }}" | |
| else | |
| VERSION=$(grep -m 1 'version = ' pyproject.toml | sed 's/version = //; s/"//g; s/^[[:space:]]*//; s/[[:space:]]*$//') | |
| fi | |
| echo "version=$VERSION" >> $GITHUB_OUTPUT | |
| echo "version_tag=v$VERSION" >> $GITHUB_OUTPUT | |
| # Log in to GitHub Container Registry | |
| - name: Login to GitHub Container Registry | |
| if: steps.check_dockerfile.outputs.dockerfile_exists == 'true' | |
| uses: docker/login-action@v3 | |
| with: | |
| registry: ghcr.io | |
| username: ${{ github.repository_owner }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| # Build and push Docker image | |
| - name: Build and push Docker image | |
| if: steps.check_dockerfile.outputs.dockerfile_exists == 'true' | |
| uses: docker/build-push-action@v5 | |
| with: | |
| context: . | |
| push: true | |
| platforms: linux/amd64,linux/arm64 | |
| tags: | | |
| ${{ env.DOCKERHUB_IMAGE_NAME }}:latest | |
| ${{ env.DOCKERHUB_IMAGE_NAME }}:${{ steps.get-version.outputs.version }} | |
| ghcr.io/${{ env.GCR_IMAGE_NAME }}:latest | |
| ghcr.io/${{ env.GCR_IMAGE_NAME }}:${{ steps.get-version.outputs.version }} | |
| cache-from: type=gha | |
| cache-to: type=gha,mode=max | |
| labels: | | |
| org.opencontainers.image.title=NyaProxy | |
| org.opencontainers.image.description=A lightweight, flexible API proxy with dynamic token rotation | |
| org.opencontainers.image.url=https://github.com/Nya-Foundation/nyaproxy | |
| org.opencontainers.image.source=https://github.com/Nya-Foundation/nyaproxy | |
| org.opencontainers.image.version=${{ steps.get-version.outputs.version }} | |
| org.opencontainers.image.created=${{ github.event.repository.updated_at }} | |
| org.opencontainers.image.revision=${{ github.sha }} | |
| - name: Scan Docker image | |
| if: steps.check_dockerfile.outputs.dockerfile_exists == 'true' | |
| uses: aquasecurity/trivy-action@master | |
| with: | |
| image-ref: ${{ env.DOCKERHUB_IMAGE_NAME }}:${{ steps.get-version.outputs.version }} | |
| format: 'table' | |
| exit-code: '1' | |
| ignore-unfixed: true | |
| vuln-type: 'os,library' | |
| severity: 'CRITICAL,HIGH' |