21 Commits

Author SHA1 Message Date
root 349711bcf0 Add 'drover gui' subcommand: native Win32 MessageBox smoke test
Build / test (push) Successful in 20s
Build / build-windows (push) Successful in 6s
Release / release (push) Successful in 1m45s
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>
v0.1.0-rc9 v0.1.0
2026-05-01 02:55:29 +03:00
root 4b1e072a35 installer.iss: use x64 not x64compatible (6.2.2 compat)
Build / test (push) Successful in 18s
Build / build-windows (push) Successful in 6s
Release / release (push) Successful in 1m48s
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>
v0.1.0-rc8
2026-05-01 02:49:42 +03:00
root c5bf4a3435 release.yml: install wine32:i386 — ISCC.exe is 32-bit
Build / test (push) Successful in 18s
Build / build-windows (push) Successful in 6s
Release / release (push) Failing after 1m50s
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>
2026-05-01 02:46:46 +03:00
root 5e7b5d0d13 release.yml: add xauth — xvfb-run requires it
Build / test (push) Successful in 18s
Build / build-windows (push) Successful in 6s
Release / release (push) Failing after 1m6s
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>
2026-05-01 02:44:52 +03:00
root 516346c587 release.yml: pin Inno Setup to 6.2.2 (innoextract 1.9 in trixie)
Build / test (push) Successful in 19s
Build / build-windows (push) Successful in 6s
Release / release (push) Failing after 1m4s
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>
2026-05-01 02:42:54 +03:00
root 804e32a418 workflows: surface GITHUB_TOKEN via env, use it in clone URL
Build / test (push) Successful in 19s
Build / build-windows (push) Successful in 6s
Release / release (push) Failing after 1m3s
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>
2026-05-01 02:39:42 +03:00
root 8c70640bfd workflows: clone without auth (public repo, no basic-auth needed)
Build / test (push) Failing after 1s
Build / build-windows (push) Has been skipped
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>
2026-05-01 02:38:25 +03:00
root 076cae6064 workflows: use x-access-token for git clone (Gitea-compatible)
Build / test (push) Failing after 1s
Build / build-windows (push) Has been skipped
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>
2026-05-01 02:37:39 +03:00
root 0f63f15fd3 Move workflows: .forgejo/workflows → .gitea/workflows
Build / test (push) Failing after 1s
Build / build-windows (push) Has been skipped
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>
2026-05-01 02:35:48 +03:00
root 1945ff96be release.yml: pin Inno Setup to 6.4.3 for innoextract 1.11 compatibility
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>
2026-05-01 02:34:38 +03:00
root 4e19d8eeb1 release.yml: install Inno Setup via innoextract (no Wine GUI install)
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>
2026-05-01 01:44:05 +03:00
root d3de6bdde8 release.yml: fix Inno Setup download URL (jrsoftware GitHub releases)
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>
2026-05-01 01:05:00 +03:00
root ca90facbdd Add .forgejo/workflows/release.yml: tag v* publishes Forgejo release
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>
2026-05-01 00:58:40 +03:00
root 956356ff2b build.yml: drop Node.js-dependent actions (cache, upload-artifact)
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>
2026-05-01 00:29:09 +03:00
root 96b6192bb0 Add .forgejo/workflows/build.yml: vet, test, cross-compile to windows/amd64
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>
2026-05-01 00:26:46 +03:00
root ff56cd9601 Add installer/installer.iss (Inno Setup 6 minimal)
Produces drover-vX.Y.Z-setup.exe via `iscc /DMyAppVersion=X.Y.Z installer/installer.iss`.

- Stable AppId UUID for upgrade compatibility
- Bundles drover.exe, WinDivert.dll/sys, LICENSE, README, WinDivert-LGPL
- English + Russian wizard languages
- Optional desktop icon and Windows autostart tasks
- HKCU registry entry for updater install-path discovery
- Best-effort service stop/uninstall on uninstall
- ARM64 refusal in [Code] InitializeSetup (WinDivert has no ARM64 build)
- Requires admin (kernel driver install), x64-compatible only, Win10 1809+

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 00:23:24 +03:00
root 1ad8de32f2 Implement internal/updater: selfupdate via Forgejo Releases API
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>
2026-05-01 00:20:24 +03:00
root 25df64213c Embed WinDivert v2.2.2 (x64) in third_party/windivert/
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>
2026-05-01 00:12:16 +03:00
root 0acbc83e40 Add directory skeleton and CLI entry point with Cobra
- Create internal/{app,config,engine,divert,socks5,bypass,checker,service,tray,procscan,updater} with placeholder doc.go per package.
- Add .gitkeep stubs for internal/frontend, third_party/{windivert,icons}, installer/, .forgejo/workflows/, docs/.
- Implement cmd/drover/main.go: Cobra root with Version/Commit/BuildDate ldflags, --config global flag, and stub subcommands (check, update --check-only, service install/uninstall/start/stop).
- Add github.com/spf13/cobra v1.10.2 dependency.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 00:10:30 +03:00
root b2e20bab00 .gitattributes: LF-by-default + CRLF for .bat/.ps1, mark binaries
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>
2026-05-01 00:07:17 +03:00
root d1420593f6 Initial commit: README, LICENSE (MIT), .gitignore, go.mod
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>
2026-05-01 00:06:51 +03:00