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
12 changes: 11 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,15 @@ All notable changes to kage are recorded here. The format follows

## [Unreleased]

## [0.3.9] - 2026-07-08

### Fixed

- The Windows build no longer embeds the leakless watchdog binary that Windows Defender flags as `Trojan:Win32/Kepavll!rfn`, which made a fresh `scoop install` fail with a virus warning on `leakless.exe` ([#68](https://github.com/tamnd/kage/issues/68)).
go-rod's launcher imports [leakless](https://github.com/ysmood/leakless), which base64/gzip-embeds a prebuilt helper for every platform and links the Windows one into `kage.exe`.
kage already launches Chrome with leakless disabled, so the helper never ran, only added the flagged bytes.
A `replace` directive now points the package at an API-compatible stub under `third_party/leakless` that carries no embedded binary, dropping about 1.28 MB from the Windows build.

## [0.3.6] - 2026-06-19

### Fixed
Expand Down Expand Up @@ -255,7 +264,8 @@ can browse offline, with every script stripped out.
a multi-arch container image on GHCR (Chromium bundled), checksums, SBOMs, and
a cosign signature, all cut from one version tag by GoReleaser.

[Unreleased]: https://github.com/tamnd/kage/compare/v0.3.4...HEAD
[Unreleased]: https://github.com/tamnd/kage/compare/v0.3.9...HEAD
[0.3.9]: https://github.com/tamnd/kage/compare/v0.3.8...v0.3.9
[0.3.4]: https://github.com/tamnd/kage/compare/v0.3.3...v0.3.4
[0.3.3]: https://github.com/tamnd/kage/compare/v0.3.2...v0.3.3
[0.3.2]: https://github.com/tamnd/kage/compare/v0.3.1...v0.3.2
Expand Down
6 changes: 6 additions & 0 deletions docs/content/reference/release-notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@ weight: 40

The authoritative, commit-level history lives in [`CHANGELOG.md`](https://github.com/tamnd/kage/blob/main/CHANGELOG.md) and on the [releases page](https://github.com/tamnd/kage/releases). This page summarises each version.

## v0.3.9

A fix for the antivirus warning some Windows users hit when installing kage.

- **The Windows build no longer ships the leakless helper antivirus flags.** kage renders pages with [go-rod](https://github.com/go-rod/rod), whose launcher pulls in [leakless](https://github.com/ysmood/leakless), a small watchdog that force-kills Chrome if kage exits. leakless carries a prebuilt helper binary for every platform and links the Windows one straight into `kage.exe`. Windows Defender recognises that helper as `Trojan:Win32/Kepavll!rfn` and quarantines it, so a fresh `scoop install` failed with a virus warning on `leakless.exe` ([#68](https://github.com/tamnd/kage/issues/68)). kage already launches Chrome with leakless switched off, so the helper never ran anyway. It is now replaced with a stub that carries no embedded binary, which drops about 1.28 MB from the Windows build and clears the warning. Thanks to John Pywtorak for the report. `go install`, unaffected before, stays clean.

## v0.3.4

Two community fixes: a clean stop for `kage serve`, and pages with heavy JavaScript that used to be dropped.
Expand Down
8 changes: 8 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,11 @@ require (
golang.org/x/text v0.38.0 // indirect
google.golang.org/protobuf v1.34.2 // indirect
)

// go-rod's launcher imports github.com/ysmood/leakless, which base64/gzip-embeds
// a prebuilt leakless.exe into the Windows build. Antivirus engines flag that
// embedded helper as malware and quarantine kage on install (issue #68). kage
// always launches Chrome with leakless disabled (browser/leakless.go), so the
// guard is dead weight; this replace swaps in an API-compatible stub that
// carries no embedded binary.
replace github.com/ysmood/leakless => ./third_party/leakless
3 changes: 0 additions & 3 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -107,9 +107,6 @@ github.com/ysmood/gotrace v0.6.0 h1:SyI1d4jclswLhg7SWTL6os3L1WOKeNn/ZtzVQF8QmdY=
github.com/ysmood/gotrace v0.6.0/go.mod h1:TzhIG7nHDry5//eYZDYcTzuJLYQIkykJzCRIo4/dzQM=
github.com/ysmood/gson v0.7.3 h1:QFkWbTH8MxyUTKPkVWAENJhxqdBa4lYTQWqZCiLG6kE=
github.com/ysmood/gson v0.7.3/go.mod h1:3Kzs5zDl21g5F/BlLTNcuAGAYLKt2lV5G8D1zF3RNmg=
github.com/ysmood/leakless v0.8.0/go.mod h1:R8iAXPRaG97QJwqxs74RdwzcRHT1SWCGTNqY8q0JvMQ=
github.com/ysmood/leakless v0.9.0 h1:qxCG5VirSBvmi3uynXFkcnLMzkphdh3xx5FtrORwDCU=
github.com/ysmood/leakless v0.9.0/go.mod h1:R8iAXPRaG97QJwqxs74RdwzcRHT1SWCGTNqY8q0JvMQ=
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI=
golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo=
Expand Down
3 changes: 3 additions & 0 deletions third_party/leakless/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module github.com/ysmood/leakless

go 1.26.4
55 changes: 55 additions & 0 deletions third_party/leakless/leakless.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// Package leakless is kage's drop-in replacement for
// github.com/ysmood/leakless, wired in through a replace directive in the root
// go.mod.
//
// The upstream package guards a child process by extracting a small helper
// executable that force-kills the child when the parent dies. It ships that
// helper by base64/gzip-embedding a prebuilt binary for every target
// (bin_amd64_windows.go and friends), so the packed leakless.exe ends up linked
// into any program that imports the package, kage included. Antivirus engines
// flag that embedded Windows helper as malware, so a fresh install of kage got
// quarantined before it ever ran (issue #68).
//
// kage already launches Chrome with leakless disabled (see
// browser/leakless.go), so the guard is never used. This stub keeps the exact
// public surface go-rod's launcher depends on (New, Support, LockPort, and the
// Launcher type's Command/Pid/Err) while carrying no embedded binary, which
// removes the false positive entirely. Support reports no guard is available,
// so go-rod's launcher never takes the leakless path even if a caller asked
// for it.
package leakless

import "os/exec"

// Launcher mirrors the upstream type. The channel is left unbuffered and is
// never written to, matching the "may never receive the pid" contract go-rod
// already tolerates.
type Launcher struct {
pid chan int
}

// New returns a Launcher. It allocates nothing beyond the pid channel.
func New() *Launcher {
return &Launcher{pid: make(chan int)}
}

// Command builds the command without a guard wrapper. Because Support returns
// false, go-rod never calls this in practice; if some other caller did, running
// the target directly is the correct no-guard behaviour.
func (l *Launcher) Command(name string, arg ...string) *exec.Cmd {
return exec.Command(name, arg...)
}

// Pid returns the (never-signalled) pid channel.
func (l *Launcher) Pid() chan int { return l.pid }

// Err returns the guard error, always empty here since there is no guard.
func (l *Launcher) Err() string { return "" }

// Support reports whether a guard binary is available. It always returns false
// so callers skip leakless entirely.
func Support() bool { return false }

// LockPort is the cross-process mutex the upstream guard uses to serialise
// extraction. With no guard there is nothing to serialise, so it is a no-op.
func LockPort(port int) func() { return func() {} }
Loading