Without this, double-clicking drover.exe printed CLI help to stdout —
fine in a terminal but invisible to a user who just clicked an icon.
Adding a RunE on the root command opens the smoke-test message box
when no subcommand was given. CLI flags (--version, --help) and
explicit subcommands keep their old behaviour.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Shows a small message box with version metadata + build info. Used as
a fastest possible end-user smoke check after install: double-click
drover.exe in a portable bundle (or run 'drover gui' from cmd) and
see "OK — the binary launched and the Windows API is reachable" with
the right version on screen. No network calls, no admin needed.
Implementation: cgo-free, uses only golang.org/x/sys/windows (already
pulled in by the updater package). gui_other.go is a stub so the
package still compiles on Linux for the CI smoke build.
Locally verified: built with -X main.Version=test-local, ran
'drover.exe gui' on Windows 11, message box appeared with correct
version/commit/Go runtime info.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Inno Setup 6.2.2 (pinned because innoextract 1.9 in Debian trixie
can't parse 6.3+ headers) doesn't recognise the 'x64compatible'
keyword. Use the legacy 'x64' which works across 6.0-6.7.
Failure: 'Error on line 25 in installer.iss: Value of [Setup]
section directive ArchitecturesAllowed is invalid' (run #11).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Wine bailed with 'init_peb ... experimental wow64 mode / failed to
load syswow64/ntdll.dll' on 'wine ISCC.exe'. wine32:i386 ships the
needed 32-bit Wine internals; we already had dpkg --add-architecture
i386 from earlier (carried over).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
xvfb-run wraps wine in a fake X display, but it shells out to xauth
to set up the cookie. xauth isn't part of the xvfb package on
Debian trixie. Add it explicitly.
Failure: 'xvfb-run: error: xauth command not found' (run #7, task 8).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
innoextract 1.11/1.10/1.9 in Debian trixie chokes on 6.4.3 too — actual line where innoextract added 6.4 support requires upstream HEAD. 6.2.2 is the last version reliably parsed by innoextract 1.9+ which is what trixie ships.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Root cause of the earlier "Failed to authenticate" / "could not read
Username" failures: shell scripts in Gitea Actions don't automatically
inherit secrets — \${GITHUB_TOKEN} expanded to an empty string, so the
URL became "https://forgejo-runner:@..." (empty password) and Gitea's
auth layer rejected it.
Fix: explicit env: block on the Checkout step pulls the token in,
then the URL uses it via x-access-token (canonical token-as-password
username, accepted by Gitea, GitHub, Forgejo alike).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Both 'forgejo-runner:$TOKEN' and 'x-access-token:$TOKEN' formulas
are rejected by Gitea's act_runner with HTTP 401:
remote: Failed to authenticate user
fatal: Authentication failed
For public repos the simplest fix is: don't send credentials at all.
Plain https://host/owner/repo.git clones unauthenticated and Gitea
serves it (root/drover-go is public).
If/when we move to private repos this'll need a different approach
(GITEA_TOKEN env, oauth2 username, or .netrc) — but that's a future
problem.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The hardcoded "forgejo-runner" username worked on Forgejo because its
runner accepted any user when the password is a valid GITHUB_TOKEN.
Gitea's act_runner v0.6+ rejects unknown usernames with:
remote: Failed to authenticate user
fatal: Authentication failed for 'https://git.okcu.io/.../...'
x-access-token is the canonical "the password IS the token" username
on GitHub Actions and works equally on Gitea, Forgejo and gitea.com.
Run that surfaced the issue: gitea run #1, task 1, sha 0f63f15,
"Cloning into '/tmp/src'... remote: Failed to authenticate user".
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
After Forgejo→Gitea migration, the new server only scans
.gitea/workflows/ (and .github/workflows/ as fallback) for action
definitions. .forgejo/workflows/ is Forgejo-specific and ignored.
Both files (build.yml, release.yml) move as-is — the YAML schema
itself is identical between Forgejo Actions and Gitea Actions
(both forks of GitHub Actions schema).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Previous attempt with 6.7.1 failed at the innoextract step:
Warning: Unexpected setup loader revision: 2
Warning: Setup loader checksum mismatch!
Could not determine setup data version!
Done with 1 error and 2 warnings.
innoextract 1.11 (Debian trixie's latest) only supports Inno Setup
through 6.4.x. 6.5+ requires innoextract 1.12 which hasn't shipped
yet. 6.4.3 is the last release in the 6.4 line — newer than 6.4.0
(more bugfixes), still innoextract-1.11-compatible.
Verified URL https://github.com/jrsoftware/issrc/releases/download/is-6_4_3/innosetup-6.4.3.exe
returns HTTP 200.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Previous attempt (rc1, rc2) tried to run innosetup-6.7.1.exe under
xvfb-run wine /VERYSILENT — silently failed (|| true masked it),
ISCC.exe never appeared at C:\InnoSetup\ISCC.exe.
Switch strategy: apt-get install innoextract (Debian package), use
it to unpack the Inno Setup installer's payload directly to disk,
then copy the extracted Inno Setup tree into the Wine prefix where
ISCC.exe can be invoked normally. Wine is still needed to run ISCC
itself, but no longer for the install step.
Also: ignore /.claude/ directory (local Claude Code session settings).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The pinned URL https://files.jrsoftware.org/is/6/innosetup-6.4.0.exe
returns 404 — jrsoftware no longer redistributes versioned files there.
Switch to GitHub releases (jrsoftware/issrc), pinned to the latest
stable Inno Setup 6.7.1 (2026-02-17). Verified the URL resolves with
HTTP 200 from the runner network.
Caught by Task #8 (E2E smoke test): tag v0.1.0-rc1 / run #4 / task 717
failed at "Install Wine + Inno Setup" with "curl: (22) ... 404".
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Triggered on `push` of any `v*` tag. Single `release` job on the `go`
runner produces and uploads four assets to the matching Forgejo release:
- drover-vX.Y.Z-windows-amd64.exe (cross-compiled portable binary)
- drover-vX.Y.Z-windows-amd64.zip (portable bundle + WinDivert + docs)
- drover-vX.Y.Z-setup.exe (Inno Setup installer via Wine)
- SHA256SUMS.txt (sha256 of the three above)
The asset names match what internal/updater/updater.go looks for, so
selfupdate keeps working on tagged releases.
Notes mirroring build.yml constraints:
- manual git clone instead of actions/checkout (no Node in golang
image; JS-based actions fail with `node: not found`)
- apt-get installs wine/wine32:i386/xvfb/zip/jq in-job
- Inno Setup 6.4.0 pinned, /VERYSILENT /CURRENTUSER install under Wine
- prerelease auto-detected from a hyphen in the version (rc/beta/alpha)
- curl uses -fsS so 409 (release exists) and other API errors fail loud
- secrets.GITHUB_TOKEN handles both clone and Forgejo REST API writes
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The runner image (golang:*) ships without Node.js, and actions/cache@v4
plus actions/upload-artifact@v4 transitively need it for hashFiles +
artifact upload. Verified by CI failure on first push (run #1, task 710):
"OCI runtime exec failed ... 'node': executable file not found in $PATH".
For now we accept ~20-30s of go module download per run (small project,
fine). Real release artifacts go via release.yml (next task) which will
use curl + Forgejo REST API to upload — pure bash, no Node needed.
Drop the smoke-build artifact upload too — it was only for inspection
during dev. Add `./bin/drover --version` to the linux smoke build so we
get exit-code verification that the CLI bootstraps correctly.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two jobs: 'test' runs go vet + go test -race + a Linux smoke build to
catch generic compile errors cheaply. 'build-windows' cross-compiles
drover.exe with version metadata baked in and uploads it as an artifact
with 14-day retention. CGO is disabled - divert-go integration in a
later phase will switch it on with mingw.
Manual git clone (no actions/checkout/setup-go) because the runner's
golang:1.23-bookworm image lacks Node.js. Both jobs cache GOMODCACHE
and GOCACHE keyed by go.sum hash. Concurrency cancel-in-progress keeps
the queue tidy when commits land in quick succession.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds a small, well-tested package that:
- Queries /api/v1/repos/root/drover-go/releases/latest (404 = no updates,
not an error).
- Compares the published tag against the running Version using
golang.org/x/mod/semver, so v0.1.0-rc.2 < v0.1.0. "dev" or any
semver-invalid current version is treated as "always update".
- Downloads the windows-amd64 asset + SHA256SUMS.txt, verifies the
sha256 of the binary against its line in the sums file (tolerates
the asterisk binary-mode prefix), and atomically swaps the running
exe via github.com/minio/selfupdate.
- Uses a 15s connect timeout with no overall request deadline, so
large asset downloads aren't truncated.
- Reports progress via an optional callback.
Public surface: Source interface + ForgejoSource implementation,
CheckForUpdate, ApplyUpdate, SetVersion. No GUI/cobra/Wails imports
in the package, so the same code is reusable from the CLI, the
Windows service, and the future tray UI.
Wires the package into "drover update" / "drover update --check-only"
in cmd/drover/main.go. --check-only exits 0 whether or not an update
is available; only network/sha/apply errors are non-zero.
Tests cover CheckForUpdate (table-driven incl. semver pre-release
ordering, dev fallthrough, source errors), parseSHA256Sums (text and
binary modes, CRLF, malformed lines, missing entries),
ForgejoSource.Latest (httptest with canned JSON, 404, 500, missing
asset, missing SHA256SUMS), and downloadAndVerify (success, sha
mismatch, HTTP 404, context cancellation). All run with -race.
Smoke-tested manually: built drover.exe and "drover update --check-only"
against git.okcu.io prints "No updates available" and exits 0 (no
releases yet).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Embedded files (Microsoft-signed kernel driver + user-mode loader):
- WinDivert.dll (x64, 47 KB)
- WinDivert64.sys (x64, 92 KB)
- WinDivert.lib (cgo import library)
- windivert.h (C header for bindings)
- LICENSE-LGPL (upstream LGPLv3/GPLv2 license)
Source: https://github.com/basil00/WinDivert/releases/tag/v2.2.2
Archive sha256: 63cb41763bb4b20f600b6de04e991a9c2be73279e317d4d82f237b150c5f3f15
The kernel driver is auto-installed by Windows when WinDivertOpen() is
first called from a process running as administrator. Per LGPLv3 §6 we
preserve the upstream license and ship a pointer to the source repo.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Without this, Windows clients commit CRLF and Linux CI runner can't
parse YAML/IS/shell scripts cleanly. Binaries (dll/sys/exe/zip/ico)
are explicitly marked so git doesn't try to text-normalize them
(critical for embedded WinDivert.sys in third_party/).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Drover-Go is a Discord proxy tool that routes traffic through SOCKS5
via kernel-level packet capture (WinDivert), surviving Discord
auto-updates and bypassing the limitations of in-app proxy settings.
This commit lays out base project files:
- README with architecture overview and acknowledgements
- LICENSE MIT
- .gitignore for Go + Wails + IDE artifacts
- go.mod with module git.okcu.io/root/drover-go on Go 1.23
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>