-
Notifications
You must be signed in to change notification settings - Fork 1
189 lines (170 loc) · 7.17 KB
/
publish.yml
File metadata and controls
189 lines (170 loc) · 7.17 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
# .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'