Native Windows deployment: config file, service, signed auto-update

- internal/config: .env-style config file (gpu-turnstile.env next to the
  exe, -config flag or GPU_TURNSTILE_CONFIG); process env overrides file.
- internal/service: Windows service via golang.org/x/sys/windows/svc —
  graceful SCM stop, 'service install/remove' commands, restart-on-failure
  recovery (also applies staged updates). First external dependency,
  Windows-only; Linux/Docker build unaffected (go.mod stays at 1.23).
- internal/update: polls the Gitea releases API, verifies the Ed25519
  signature of the downloaded binary against an embedded public key
  (openssl-signed by CI), swaps it in next to the running exe, and once
  the GPU lock is idle exits with code 3 so service recovery restarts
  onto the new version. Dev builds and empty pubkey never update.
- CI: tag builds additionally produce gpu-turnstile.exe + .sig + .sha256
  attached to a Gitea release.
- LOG_FILE env var so the service has somewhere to log.
This commit is contained in:
mram
2026-09-20 21:33:29 +02:00
parent 5f6a22c2cf
commit e363c9e4e4
14 changed files with 1318 additions and 194 deletions
+47
View File
@@ -60,3 +60,50 @@ jobs:
tags: |
${{ steps.meta.outputs.image }}:${{ gitea.ref_name }}
${{ steps.meta.outputs.image }}:latest
# On version tags: build the signed Windows binary and attach it (plus
# signature and checksum) to a Gitea release for the auto-updater.
release:
if: gitea.ref_type == 'tag'
needs: test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: "1.23"
- name: Build Windows binary
run: |
GOOS=windows GOARCH=amd64 CGO_ENABLED=0 go build \
-ldflags="-s -w -X main.version=${{ gitea.ref_name }}" \
-o gpu-turnstile.exe ./cmd/gpu-turnstile
- name: Sign and checksum
run: |
printf '%s\n' "${{ secrets.SIGNING_KEY }}" > key.pem
chmod 600 key.pem
openssl pkeyutl -sign -inkey key.pem -rawin \
-in gpu-turnstile.exe -out gpu-turnstile.exe.sig
rm -f key.pem
sha256sum gpu-turnstile.exe > gpu-turnstile.exe.sha256
- name: Create release and upload assets
env:
TOKEN: ${{ secrets.GITEA_TOKEN }}
API: https://git.rambossek.at/api/v1/repos/${{ gitea.repository }}
TAG: ${{ gitea.ref_name }}
run: |
set -e
ID=$(curl -sf -H "Authorization: token $TOKEN" "$API/releases/tags/$TAG" | jq -r .id || true)
if [ -z "$ID" ] || [ "$ID" = "null" ]; then
ID=$(curl -sf -X POST -H "Authorization: token $TOKEN" \
-H "Content-Type: application/json" \
-d "{\"tag_name\":\"$TAG\",\"name\":\"$TAG\"}" \
"$API/releases" | jq -r .id)
fi
for f in gpu-turnstile.exe gpu-turnstile.exe.sig gpu-turnstile.exe.sha256; do
curl -sf -X POST -H "Authorization: token $TOKEN" \
-F "attachment=@$f" "$API/releases/$ID/assets?name=$f" > /dev/null
echo "uploaded $f"
done