Add GPG key file (#9608)

* Add files via upload

* Update build-all.yml

* Update build-linux.yml

* Update build-osx.yml

* Update build-windows-desktop.yml

* Update build-windows-x86.yml

* Update build-windows.yml

* Update package-zip.yml

* Update build-linux.yml

* Update build-osx.yml

* Update build-windows-x86.yml

* Update package-zip.yml

* Update upload-sign.yml

* Update pub-key.yml

* Update README.md

---------

Co-authored-by: 2dust <31833384+2dust@users.noreply.github.com>
This commit is contained in:
JieXu
2026-06-22 09:48:06 +08:00
committed by GitHub
parent ce380b861c
commit f1b88ccf2a
10 changed files with 278 additions and 74 deletions

View File

@@ -9,8 +9,17 @@ on:
permissions: permissions:
actions: write actions: write
contents: write
jobs: jobs:
public-key:
if: inputs.release_tag != ''
uses: ./.github/workflows/pub-key.yml
with:
release_tag: ${{ inputs.release_tag }}
secrets:
GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }}
update: update:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:

View File

@@ -12,6 +12,7 @@ on:
permissions: permissions:
contents: write contents: write
actions: read
jobs: jobs:
build: build:
@@ -26,6 +27,7 @@ jobs:
with: with:
target: linux target: linux
release_tag: ${{ inputs.release_tag }} release_tag: ${{ inputs.release_tag }}
secrets: inherit
deb: deb:
name: build and release deb x64 & arm64 name: build and release deb x64 & arm64
@@ -56,9 +58,9 @@ jobs:
find "$GITHUB_WORKSPACE/dist/deb" -name "v2rayn_*_arm64.deb" -exec mv {} "$GITHUB_WORKSPACE/dist/deb/v2rayN-linux-arm64.deb" \; || true find "$GITHUB_WORKSPACE/dist/deb" -name "v2rayn_*_arm64.deb" -exec mv {} "$GITHUB_WORKSPACE/dist/deb/v2rayN-linux-arm64.deb" \; || true
echo "==== Dist tree ====" echo "==== Dist tree ===="
ls -R "$GITHUB_WORKSPACE/dist/deb" || true ls -R "$GITHUB_WORKSPACE/dist/deb" || true
- name: Upload DEBs to release - name: Upload DEB artifact
uses: svenstaro/upload-release-action@v2 uses: actions/upload-artifact@v7
with: { file: "dist/deb/**/*.deb", tag: "${{ env.RELEASE_TAG }}", file_glob: true, prerelease: true } with: { name: release-deb, path: "dist/deb/**/*.deb", if-no-files-found: error }
rpm: rpm:
name: build and release rpm x64 & arm64 name: build and release rpm x64 & arm64
@@ -115,9 +117,9 @@ jobs:
find "$GITHUB_WORKSPACE/dist/rpm" -name "v2rayN-*-1*.aarch64.rpm" -exec mv {} "$GITHUB_WORKSPACE/dist/rpm/v2rayN-linux-rhel-arm64.rpm" \; || true find "$GITHUB_WORKSPACE/dist/rpm" -name "v2rayN-*-1*.aarch64.rpm" -exec mv {} "$GITHUB_WORKSPACE/dist/rpm/v2rayN-linux-rhel-arm64.rpm" \; || true
echo "==== Dist tree ====" echo "==== Dist tree ===="
ls -R "$GITHUB_WORKSPACE/dist/rpm" || true ls -R "$GITHUB_WORKSPACE/dist/rpm" || true
- name: Upload RPMs to release - name: Upload RPM artifact
uses: svenstaro/upload-release-action@v2 uses: actions/upload-artifact@v7
with: { file: "dist/rpm/**/*.rpm", tag: "${{ env.RELEASE_TAG }}", file_glob: true, prerelease: true } with: { name: release-rpm, path: "dist/rpm/**/*.rpm", if-no-files-found: error }
rpm-riscv64: rpm-riscv64:
name: build and release rpm riscv64 name: build and release rpm riscv64
@@ -155,25 +157,9 @@ jobs:
find "$GITHUB_WORKSPACE/dist/rpm-riscv64" -name "*.riscv64.rpm" -exec mv {} "$GITHUB_WORKSPACE/dist/rpm-riscv64/v2rayN-linux-rhel-riscv64.rpm" \; || true find "$GITHUB_WORKSPACE/dist/rpm-riscv64" -name "*.riscv64.rpm" -exec mv {} "$GITHUB_WORKSPACE/dist/rpm-riscv64/v2rayN-linux-rhel-riscv64.rpm" \; || true
echo "==== Dist tree ====" echo "==== Dist tree ===="
ls -R "$GITHUB_WORKSPACE/dist/rpm-riscv64" || true ls -R "$GITHUB_WORKSPACE/dist/rpm-riscv64" || true
- name: Upload RPMs to release - name: Upload RPM artifact
shell: bash uses: actions/upload-artifact@v7
env: { GITHUB_TOKEN: "${{ github.token }}" } with: { name: release-rpm-riscv64, path: "dist/rpm-riscv64/**/*.rpm", if-no-files-found: error }
run: |
set -euo pipefail
shopt -s globstar nullglob
files=(dist/rpm-riscv64/**/*.rpm)
(( ${#files[@]} )) || { echo "No RPMs found."; exit 1; }
api="${GITHUB_API_URL}/repos/${GITHUB_REPOSITORY}/releases/tags/${RELEASE_TAG}"
upload_url="$(curl -fsSL -H "Authorization: Bearer ${GITHUB_TOKEN}" "$api" | jq -r '.upload_url // empty' | sed 's/{?name,label}//')"
[[ "$upload_url" ]] || { echo "Release upload URL not found: ${RELEASE_TAG}"; exit 1; }
for f in "${files[@]}"; do
echo "Uploading ${f##*/}"
curl -fsSL -X POST \
-H "Authorization: Bearer ${GITHUB_TOKEN}" \
-H "Content-Type: application/x-rpm" \
--data-binary @"$f" \
"${upload_url}?name=${f##*/}"
done
deb-riscv64: deb-riscv64:
name: build and release deb riscv64 name: build and release deb riscv64
@@ -212,25 +198,9 @@ jobs:
find "$GITHUB_WORKSPACE/dist/deb-riscv64" -name "*.deb" -exec mv {} "$GITHUB_WORKSPACE/dist/deb-riscv64/v2rayN-linux-riscv64.deb" \; || true find "$GITHUB_WORKSPACE/dist/deb-riscv64" -name "*.deb" -exec mv {} "$GITHUB_WORKSPACE/dist/deb-riscv64/v2rayN-linux-riscv64.deb" \; || true
echo "==== Dist tree ====" echo "==== Dist tree ===="
ls -R "$GITHUB_WORKSPACE/dist/deb-riscv64" || true ls -R "$GITHUB_WORKSPACE/dist/deb-riscv64" || true
- name: Upload DEBs to release - name: Upload DEB artifact
shell: bash uses: actions/upload-artifact@v7
env: { GITHUB_TOKEN: "${{ github.token }}" } with: { name: release-deb-riscv64, path: "dist/deb-riscv64/**/*.deb", if-no-files-found: error }
run: |
set -euo pipefail
shopt -s globstar nullglob
files=(dist/deb-riscv64/**/*.deb)
(( ${#files[@]} )) || { echo "No DEBs found."; exit 1; }
api="${GITHUB_API_URL}/repos/${GITHUB_REPOSITORY}/releases/tags/${RELEASE_TAG}"
upload_url="$(curl -fsSL -H "Authorization: Bearer ${GITHUB_TOKEN}" "$api" | jq -r '.upload_url // empty' | sed 's/{?name,label}//')"
[[ "$upload_url" ]] || { echo "Release upload URL not found: ${RELEASE_TAG}"; exit 1; }
for f in "${files[@]}"; do
echo "Uploading ${f##*/}"
curl -fsSL -X POST \
-H "Authorization: Bearer ${GITHUB_TOKEN}" \
-H "Content-Type: application/vnd.debian.binary-package" \
--data-binary @"$f" \
"${upload_url}?name=${f##*/}"
done
deb-loong64: deb-loong64:
name: build and release deb loong64 name: build and release deb loong64
@@ -378,9 +348,9 @@ jobs:
find "$GITHUB_WORKSPACE/dist/deb-loong64" -name "*.deb" -exec mv {} "$GITHUB_WORKSPACE/dist/deb-loong64/v2rayN-linux-loong64.deb" \; || true find "$GITHUB_WORKSPACE/dist/deb-loong64" -name "*.deb" -exec mv {} "$GITHUB_WORKSPACE/dist/deb-loong64/v2rayN-linux-loong64.deb" \; || true
echo "==== Dist tree ====" echo "==== Dist tree ===="
ls -R "$GITHUB_WORKSPACE/dist/deb-loong64" ls -R "$GITHUB_WORKSPACE/dist/deb-loong64"
- name: Upload DEBs to release - name: Upload DEB artifact
uses: svenstaro/upload-release-action@v2 uses: actions/upload-artifact@v7
with: { file: "dist/deb-loong64/**/*.deb", tag: "${{ env.RELEASE_TAG }}", file_glob: true, prerelease: true } with: { name: release-deb-loong64, path: "dist/deb-loong64/**/*.deb", if-no-files-found: error }
rpm-loong64: rpm-loong64:
name: build and release rpm loong64 name: build and release rpm loong64
@@ -528,6 +498,48 @@ jobs:
find "$GITHUB_WORKSPACE/dist/rpm-loong64" -name "*.loongarch64.rpm" -exec mv {} "$GITHUB_WORKSPACE/dist/rpm-loong64/v2rayN-linux-rhel-loong64.rpm" \; || true find "$GITHUB_WORKSPACE/dist/rpm-loong64" -name "*.loongarch64.rpm" -exec mv {} "$GITHUB_WORKSPACE/dist/rpm-loong64/v2rayN-linux-rhel-loong64.rpm" \; || true
echo "==== Dist tree ====" echo "==== Dist tree ===="
ls -R "$GITHUB_WORKSPACE/dist/rpm-loong64" ls -R "$GITHUB_WORKSPACE/dist/rpm-loong64"
- name: Upload RPMs to release - name: Upload RPM artifact
uses: svenstaro/upload-release-action@v2 uses: actions/upload-artifact@v7
with: { file: "dist/rpm-loong64/**/*.rpm", tag: "${{ env.RELEASE_TAG }}", file_glob: true, prerelease: true } with: { name: release-rpm-loong64, path: "dist/rpm-loong64/**/*.rpm", if-no-files-found: error }
release-deb:
name: sign and upload deb x64 arm64
needs: deb
uses: ./.github/workflows/upload-sign.yml
with: { release_tag: "${{ case(inputs.release_tag != '', inputs.release_tag, github.ref_name) }}", artifact_name: release-deb, file_pattern: "*.deb" }
secrets: { GPG_PRIVATE_KEY: "${{ secrets.GPG_PRIVATE_KEY }}" }
release-rpm:
name: sign and upload rpm x64 arm64
needs: rpm
uses: ./.github/workflows/upload-sign.yml
with: { release_tag: "${{ case(inputs.release_tag != '', inputs.release_tag, github.ref_name) }}", artifact_name: release-rpm, file_pattern: "*.rpm" }
secrets: { GPG_PRIVATE_KEY: "${{ secrets.GPG_PRIVATE_KEY }}" }
release-rpm-riscv64:
name: sign and upload rpm riscv64
needs: rpm-riscv64
uses: ./.github/workflows/upload-sign.yml
with: { release_tag: "${{ case(inputs.release_tag != '', inputs.release_tag, github.ref_name) }}", artifact_name: release-rpm-riscv64, file_pattern: "*.rpm" }
secrets: { GPG_PRIVATE_KEY: "${{ secrets.GPG_PRIVATE_KEY }}" }
release-deb-riscv64:
name: sign and upload deb riscv64
needs: deb-riscv64
uses: ./.github/workflows/upload-sign.yml
with: { release_tag: "${{ case(inputs.release_tag != '', inputs.release_tag, github.ref_name) }}", artifact_name: release-deb-riscv64, file_pattern: "*.deb" }
secrets: { GPG_PRIVATE_KEY: "${{ secrets.GPG_PRIVATE_KEY }}" }
release-deb-loong64:
name: sign and upload deb loong64
needs: deb-loong64
uses: ./.github/workflows/upload-sign.yml
with: { release_tag: "${{ case(inputs.release_tag != '', inputs.release_tag, github.ref_name) }}", artifact_name: release-deb-loong64, file_pattern: "*.deb" }
secrets: { GPG_PRIVATE_KEY: "${{ secrets.GPG_PRIVATE_KEY }}" }
release-rpm-loong64:
name: sign and upload rpm loong64
needs: rpm-loong64
uses: ./.github/workflows/upload-sign.yml
with: { release_tag: "${{ case(inputs.release_tag != '', inputs.release_tag, github.ref_name) }}", artifact_name: release-rpm-loong64, file_pattern: "*.rpm" }
secrets: { GPG_PRIVATE_KEY: "${{ secrets.GPG_PRIVATE_KEY }}" }

View File

@@ -12,6 +12,7 @@ on:
permissions: permissions:
contents: write contents: write
actions: read
jobs: jobs:
build: build:
@@ -26,6 +27,7 @@ jobs:
with: with:
target: macos target: macos
release_tag: ${{ inputs.release_tag }} release_tag: ${{ inputs.release_tag }}
secrets: inherit
dmg: dmg:
name: package and release macOS dmg name: package and release macOS dmg
@@ -62,13 +64,24 @@ jobs:
- name: Package dmg - name: Package dmg
run: ./package-osx.sh macos-$Arch v2rayN-macos-$Arch ${{ inputs.release_tag }} run: ./package-osx.sh macos-$Arch v2rayN-macos-$Arch ${{ inputs.release_tag }}
- name: Sleep for race condition between matrix jobs - name: Upload dmg artifact
run: sleep "$(od -An -N2 -tu2 /dev/urandom | awk 'NR==1{printf "%.2f", $1/5461}')" uses: actions/upload-artifact@v7
- name: Upload dmg to release
uses: svenstaro/upload-release-action@v2
with: with:
file: ${{ github.workspace }}/v2rayN*.dmg name: release-dmg-${{ matrix.arch }}
tag: ${{ inputs.release_tag }} path: v2rayN*.dmg
file_glob: true if-no-files-found: error
prerelease: true
release-dmg:
name: sign and upload macOS dmg
if: inputs.release_tag != ''
needs: dmg
strategy:
matrix:
arch: [ x64, arm64 ]
uses: ./.github/workflows/upload-sign.yml
with:
release_tag: ${{ inputs.release_tag }}
artifact_name: release-dmg-${{ matrix.arch }}
file_pattern: '*.dmg'
secrets:
GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }}

View File

@@ -12,6 +12,7 @@ on:
permissions: permissions:
contents: write contents: write
actions: read
jobs: jobs:
build: build:
@@ -26,3 +27,4 @@ jobs:
with: with:
target: windows-desktop target: windows-desktop
release_tag: ${{ inputs.release_tag }} release_tag: ${{ inputs.release_tag }}
secrets: inherit

View File

@@ -9,6 +9,7 @@ on:
permissions: permissions:
contents: write contents: write
actions: read
jobs: jobs:
package-x86: package-x86:
@@ -222,10 +223,25 @@ jobs:
-DestinationPath "${{ matrix.zip_name }}" ` -DestinationPath "${{ matrix.zip_name }}" `
-Force -Force
- name: Upload zip archive to release - name: Upload zip artifact
uses: svenstaro/upload-release-action@v2 uses: actions/upload-artifact@v7
with: with:
file: ${{ matrix.zip_name }} name: release-windows-x86-${{ matrix.flavor }}
tag: ${{ inputs.release_tag }} path: ${{ matrix.zip_name }}
prerelease: true if-no-files-found: error
overwrite: true
release-x86:
name: sign and upload windows x86
if: inputs.release_tag != ''
needs: package-x86
strategy:
fail-fast: false
matrix:
flavor: [ wpf, desktop ]
uses: ./.github/workflows/upload-sign.yml
with:
release_tag: ${{ inputs.release_tag }}
artifact_name: release-windows-x86-${{ matrix.flavor }}
file_pattern: '*.zip'
secrets:
GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }}

View File

@@ -12,6 +12,7 @@ on:
permissions: permissions:
contents: write contents: write
actions: read
jobs: jobs:
build: build:
@@ -27,3 +28,4 @@ jobs:
with: with:
target: windows target: windows
release_tag: ${{ inputs.release_tag }} release_tag: ${{ inputs.release_tag }}
secrets: inherit

View File

@@ -9,9 +9,13 @@ on:
target: # windows linux macos windows-desktop target: # windows linux macos windows-desktop
required: true required: true
type: string type: string
secrets:
GPG_PRIVATE_KEY:
required: true
permissions: permissions:
contents: write contents: write
actions: read
jobs: jobs:
package: package:
@@ -55,13 +59,23 @@ jobs:
if: inputs.target == 'windows-desktop' if: inputs.target == 'windows-desktop'
run: mv "v2rayN-$Target-$Arch.zip" "v2rayN-$Target-$Arch-desktop.zip" run: mv "v2rayN-$Target-$Arch.zip" "v2rayN-$Target-$Arch-desktop.zip"
- name: Sleep for race condition between matrix jobs - name: Upload zip artifact
run: sleep "$(od -An -N2 -tu2 /dev/urandom | awk 'NR==1{printf "%.2f", $1/5461}')" uses: actions/upload-artifact@v7
- name: Upload zip archive to release
uses: svenstaro/upload-release-action@v2
with: with:
file: ${{ github.workspace }}/v2rayN*.zip name: release-${{ inputs.target }}-${{ matrix.arch }}
tag: ${{ inputs.release_tag }} path: v2rayN*.zip
file_glob: true if-no-files-found: error
prerelease: true
release:
name: sign and upload zip x64 arm64
needs: package
strategy:
matrix:
arch: [ x64, arm64 ]
uses: ./.github/workflows/upload-sign.yml
with:
release_tag: ${{ inputs.release_tag }}
artifact_name: release-${{ inputs.target }}-${{ matrix.arch }}
file_pattern: '*.zip'
secrets:
GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }}

48
.github/workflows/pub-key.yml vendored Normal file
View File

@@ -0,0 +1,48 @@
name: publish GPG public key
on:
workflow_call:
inputs:
release_tag:
required: true
type: string
secrets:
GPG_PRIVATE_KEY:
required: true
workflow_dispatch:
inputs:
release_tag:
required: true
type: string
permissions:
contents: write
jobs:
publish:
runs-on: ubuntu-26.04
steps:
- name: Import GPG private key
shell: bash
env:
GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }}
run: |
set -euo pipefail
install -m 700 -d ~/.gnupg
printf '%s' "$GPG_PRIVATE_KEY" | gpg --batch --import
- name: Export GPG public key
shell: bash
run: |
set -euo pipefail
fingerprint="$(gpg --batch --list-secret-keys --with-colons | awk -F: '$1 == "fpr" { print $10; exit }')"
[[ -n "$fingerprint" ]] || { echo "No GPG secret key found."; exit 1; }
gpg --batch --armor --export "$fingerprint" > v2rayN-public-key.asc
- name: Upload GPG public key to release
uses: svenstaro/upload-release-action@v2
with:
file: v2rayN-public-key.asc
tag: ${{ inputs.release_tag }}
prerelease: true
overwrite: true

76
.github/workflows/upload-sign.yml vendored Normal file
View File

@@ -0,0 +1,76 @@
name: sign and upload release files
on:
workflow_call:
inputs:
release_tag:
required: true
type: string
artifact_name:
required: true
type: string
file_pattern:
required: false
type: string
default: '**/*'
content_type:
required: false
type: string
default: application/octet-stream
secrets:
GPG_PRIVATE_KEY:
required: true
permissions:
contents: write
actions: read
jobs:
upload:
runs-on: ubuntu-26.04
steps:
- name: Download release artifact
uses: actions/download-artifact@v8
with:
name: ${{ inputs.artifact_name }}
path: dist
- name: Import GPG private key
shell: bash
env:
GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }}
run: |
set -euo pipefail
install -m 700 -d ~/.gnupg
printf '%s' "$GPG_PRIVATE_KEY" | gpg --batch --import
- name: Sign release files
shell: bash
run: |
set -euo pipefail
cd dist
shopt -s globstar nullglob
files=( ${{ inputs.file_pattern }} )
(( ${#files[@]} )) || { echo "No files matched: ${{ inputs.file_pattern }}"; exit 1; }
for f in "${files[@]}"; do
[[ -f "$f" ]] || continue
gpg --batch --yes --armor --detach-sign --output "$f.sig" "$f"
done
- name: Upload release files
uses: svenstaro/upload-release-action@v2
with:
file: dist/${{ inputs.file_pattern }}
tag: ${{ inputs.release_tag }}
file_glob: true
prerelease: true
overwrite: true
- name: Upload release signatures
uses: svenstaro/upload-release-action@v2
with:
file: dist/${{ inputs.file_pattern }}.sig
tag: ${{ inputs.release_tag }}
file_glob: true
prerelease: true
overwrite: true

View File

@@ -16,3 +16,15 @@ Read the [Wiki](https://github.com/2dust/v2rayN/wiki) for details.
## Telegram Channel ## Telegram Channel
[github_2dust](https://t.me/github_2dust) [github_2dust](https://t.me/github_2dust)
## GPG 签名校验 (GPG Verification)
为了预防镜像站、运营商或 CDN 劫持,本项目发布的 Release 文件已使用 GPG 进行签名,以供用户校验文件的真实性与完整性。
To prevent hijacking by mirror sites, ISPs, or CDNs, the Release files of this project are signed with GPG for users to verify their authenticity and integrity.
### 公钥指纹 (Key Fingerprint)
```text
76945E9F3E9A168F8070F195805D661C134DFAF68903C199463C31E5AE903AE0
```