Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 56 additions & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,15 @@ on:
permissions:
contents: write

concurrency:
group: release-${{ github.ref }}
cancel-in-progress: false

jobs:
release:
strategy:
fail-fast: false
max-parallel: 1
matrix:
include:
- os: macos-15
Expand Down Expand Up @@ -44,17 +49,31 @@ jobs:
git fetch --no-tags --depth=1 origin main:refs/remotes/origin/main
test "$(git rev-parse HEAD)" = "$(git rev-parse origin/main)"

- name: verify updater signing configuration
shell: bash
env:
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}
run: |
test -n "$TAURI_SIGNING_PRIVATE_KEY"
test -n "$TAURI_SIGNING_PRIVATE_KEY_PASSWORD"

- name: build ad-hoc signed macOS release
if: startsWith(matrix.os, 'macos')
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
APPLE_SIGNING_IDENTITY: "-"
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}
uses: tauri-apps/tauri-action@1deb371b0cd8bd54025b384f1cd735e725c4060f
with:
tagName: v__VERSION__
releaseName: proxybench v__VERSION__
releaseBody: Preview builds made without certificates yet. macOS DMGs need right-click Open on first launch. The Windows NSIS setup wizard may trigger SmartScreen; choose More info, then Run anyway.
releaseDraft: false
releaseDraft: true
uploadUpdaterJson: true
uploadUpdaterSignatures: true
updaterJsonPreferNsis: true
tauriScript: bun run tauri
args: ${{ matrix.args }}

Expand All @@ -63,10 +82,45 @@ jobs:
uses: tauri-apps/tauri-action@1deb371b0cd8bd54025b384f1cd735e725c4060f
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}
with:
tagName: v__VERSION__
releaseName: proxybench v__VERSION__
releaseBody: Preview builds made without certificates yet. macOS DMGs need right-click Open on first launch. The Windows NSIS setup wizard may trigger SmartScreen; choose More info, then Run anyway.
releaseDraft: false
releaseDraft: true
uploadUpdaterJson: true
uploadUpdaterSignatures: true
updaterJsonPreferNsis: true
tauriScript: bun run tauri
args: ${{ matrix.args }}

publish:
needs: release
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09

- name: install minisign
run: sudo apt-get update && sudo apt-get install -y minisign

- name: validate updater release
env:
GH_TOKEN: ${{ github.token }}
REPO: ${{ github.repository }}
TAG: ${{ github.ref_name }}
run: |
RELEASE_ID=$(gh api --paginate "repos/$REPO/releases?per_page=100" --jq ".[] | select(.tag_name == \"$TAG\" and .draft == true) | .id" | head -n 1)
test -n "$RELEASE_ID"
export RELEASE_ID
sh scripts/validate-release.sh

- name: publish release
env:
GH_TOKEN: ${{ github.token }}
REPO: ${{ github.repository }}
TAG: ${{ github.ref_name }}
run: |
RELEASE_ID=$(gh api --paginate "repos/$REPO/releases?per_page=100" --jq ".[] | select(.tag_name == \"$TAG\" and .draft == true) | .id" | head -n 1)
test -n "$RELEASE_ID"
gh api -X PATCH "repos/$REPO/releases/$RELEASE_ID" -F draft=false
5 changes: 5 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,3 +121,8 @@ GitHub Actions (`.github/workflows/ci.yml` on `main` and pull requests,
`.github/workflows/release.yml` on `vX.Y.Z`) builds macOS DMGs for Apple
Silicon and Intel and a Windows NSIS setup wizard. macOS uses ad-hoc signing;
Windows installers are unsigned.

Updater releases require `TAURI_SIGNING_PRIVATE_KEY` and
`TAURI_SIGNING_PRIVATE_KEY_PASSWORD`. The workflow keeps releases as drafts
until `latest.json` contains macOS arm64, macOS x64, and Windows x64. Never
replace published assets; ship a higher patch version.
4 changes: 4 additions & 0 deletions SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,7 @@ without real proxy credentials.

Please allow a reasonable amount of time for investigation before public
disclosure.

Application updates are signed and verified independently from operating
system code signing. Report suspected update or release-key compromise through
GitHub's private vulnerability reporting.
9 changes: 9 additions & 0 deletions bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 5 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "proxybench",
"version": "0.2.1",
"version": "0.3.0",
"description": "Split HTTP proxy lists by subnet and measure Connect and TTFB",
"type": "module",
"scripts": {
Expand All @@ -15,7 +15,10 @@
"dependencies": {
"@tanstack/svelte-table": "^9.1.2",
"@tauri-apps/api": "^2",
"@tauri-apps/plugin-dialog": "~2"
"@tauri-apps/plugin-dialog": "~2",
"@tauri-apps/plugin-opener": "2",
"@tauri-apps/plugin-process": "2",
"@tauri-apps/plugin-updater": "2.10.1"
},
"devDependencies": {
"@sveltejs/adapter-static": "^3.0.6",
Expand Down
41 changes: 41 additions & 0 deletions scripts/validate-release.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#!/bin/sh
set -eu

repo="${REPO:?REPO is required}"
tag="${TAG:?TAG is required}"
release_id="${RELEASE_ID:?RELEASE_ID is required}"
release="$(gh api "repos/$repo/releases/$release_id")"

test "$(printf '%s' "$release" | jq -r .draft)" = true
test "$(printf '%s' "$release" | jq -r .tag_name)" = "$tag"
assets="$(printf '%s' "$release" | jq -r '.assets[].name')"
test "$(printf '%s\n' "$assets" | grep -c '\.dmg$')" -eq 2
test "$(printf '%s\n' "$assets" | grep -c '\.app\.tar\.gz$')" -eq 2
test "$(printf '%s\n' "$assets" | grep -c '\.app\.tar\.gz\.sig$')" -eq 2
test "$(printf '%s\n' "$assets" | grep -c -- '-setup\.exe$')" -eq 1
test "$(printf '%s\n' "$assets" | grep -c -- '-setup\.exe\.sig$')" -eq 1
test "$(printf '%s\n' "$assets" | grep -c '^latest\.json$')" -eq 1

latest_url="$(printf '%s' "$release" | jq -r '.assets[] | select(.name == "latest.json") | .url')"
gh api -H 'Accept: application/octet-stream' "$latest_url" > latest.json
test "$(jq -r .version latest.json)" = "${tag#v}"

for platform in darwin-aarch64 darwin-x86_64 windows-x86_64; do
url="$(jq -er --arg platform "$platform" '.platforms[$platform].url' latest.json)"
signature="$(jq -er --arg platform "$platform" '.platforms[$platform].signature' latest.json)"
test -n "$signature"
asset="$(printf '%s' "$release" | jq -cer --arg url "$url" '.assets[] | select(.url == $url or .browser_download_url == $url)')"
name="$(printf '%s' "$asset" | jq -r .name)"
case "$platform:$name" in
darwin-aarch64:*_aarch64.app.tar.gz) ;;
darwin-x86_64:*_x64.app.tar.gz) ;;
windows-x86_64:*_x64-setup.exe) ;;
*) exit 1 ;;
esac
asset_url="$(printf '%s' "$asset" | jq -r .url)"
gh api -H 'Accept: application/octet-stream' "$asset_url" > "$name"
printf '%s' "$signature" | base64 --decode > "$name.sig"
public_key="$(jq -r '.plugins.updater.pubkey' src-tauri/tauri.conf.json)"
printf '%s' "$public_key" | base64 --decode > updater.pub
minisign -Vm "$name" -p updater.pub -x "$name.sig"
done
Loading