- 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.
110 lines
3.5 KiB
YAML
110 lines
3.5 KiB
YAML
name: ci
|
|
|
|
on:
|
|
push:
|
|
workflow_dispatch:
|
|
|
|
jobs:
|
|
test:
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
- uses: actions/setup-go@v5
|
|
with:
|
|
go-version: "1.23"
|
|
- run: go vet ./...
|
|
- run: go test -race ./...
|
|
- name: golangci-lint
|
|
run: |
|
|
if command -v golangci-lint >/dev/null 2>&1; then
|
|
golangci-lint run
|
|
else
|
|
echo "golangci-lint not available in runner image, skipping"
|
|
fi
|
|
|
|
# Release images are built only from version tags (vX.Y.Z).
|
|
docker:
|
|
if: gitea.ref_type == 'tag'
|
|
needs: test
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- name: Check tag is semantic version
|
|
run: |
|
|
if ! echo "${{ gitea.ref_name }}" | grep -qE '^v[0-9]+\.[0-9]+\.[0-9]+$'; then
|
|
echo "tag '${{ gitea.ref_name }}' is not a vX.Y.Z semantic version" >&2
|
|
exit 1
|
|
fi
|
|
|
|
- name: Compute lowercase image name
|
|
id: meta
|
|
run: |
|
|
REPO=git.rambossek.at/$(echo "${{ gitea.repository }}" | tr '[:upper:]' '[:lower:]')
|
|
echo "image=$REPO" >> "$GITHUB_OUTPUT"
|
|
|
|
- uses: docker/setup-buildx-action@v3
|
|
|
|
- uses: docker/login-action@v3
|
|
with:
|
|
registry: git.rambossek.at
|
|
username: ${{ gitea.actor }}
|
|
password: ${{ secrets.REGISTRY_TOKEN }}
|
|
|
|
- uses: docker/build-push-action@v6
|
|
with:
|
|
context: .
|
|
push: true
|
|
build-args: |
|
|
VERSION=${{ gitea.ref_name }}
|
|
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
|