Development
How to build, run and test Gone from source. The pull request process and coding rules are in Contributing.
Requirements
- Go 1.27.3 or newer. Gone is pure Go: SQLite comes from
modernc.org/sqlite. It builds withCGO_ENABLED=0into a fully static binary. - Task, which runs the build steps in
Taskfile.yml. - Node 20.19 or newer, for the JavaScript tests and linters. The web client itself needs no npm install.
- minify, for production builds only.
Build and run
| Task | What it does |
|---|---|
task dev | Builds development binaries, bin/goned (server) and bin/gone (CLI). Assets are served from web/ on disk, so edits show on reload, the pseudo-language en-XA appears in the language picker, and the ?preview= design modes from web/dev/ work. |
task prod | Production build: minifies the assets into web/dist, embeds them in bin/goned with -tags=prod, and builds bin/gone. |
task run | Rebuilds the dev binary and runs it with a temporary data directory (.tmp). It sets GONE_METRICS_ADDR=:9090, but metrics stay off, with a warning, unless you also set GONE_METRICS_TOKEN. |
task release -- vX.Y.Z | Cross-builds the release archives, SHA256SUMS and release notes into dist/. This is what the tag workflow publishes. |
Run with your own settings:
Terminal
task dev
GONE_ADDR=127.0.0.1:8080 \
GONE_DATA_DIR="$(pwd)/.tmp" \
GONE_METRICS_ADDR=127.0.0.1:9090 \
GONE_METRICS_TOKEN=local-dev-token-0123 \
./bin/gonedEvery variable is listed in Configuration. The container image is covered in Running Gone with Docker.
Tests
| Task | What it runs |
|---|---|
task test | Go tests (go test ./...), then the JavaScript unit tests. |
task test-js | JavaScript unit tests in test/js/, with node --test and no dependencies. |
task cover / task cover-js | The same, with coverage. Go and JS line coverage are kept at or near 100%. |
task e2e | Browser end-to-end tests in test/e2e/: a production build, served over HTTPS, in Chromium, Firefox and WebKit with Playwright. Run task e2e-install once first to install the browsers. It needs Go, which builds the test TLS proxy. |
task interop-signin | Sign-in against real proxies in Docker: Dex with oauth2-proxy, and Authelia behind Caddy. Not run in CI; see test/interop/signin. |
task perf | The latency target: p95 under 50 ms at 100 requests per second, against the real stack. |
task lint | golangci-lint (configured in .golangci.yml) for the default and dev build tags. |
task lint-web | ESLint (flat config in eslint.config.cjs) and stylelint, at the versions pinned in tools/lint, as CI runs them. |
eslint.config.cjs is the ESLint config that CI and task lint-web use. .eslintrc.json is kept only for Codacy’s older ESLint, which reads just the legacy format, and must mirror it.
What each suite covers
- Go unit tests sit next to the code. Integration tests in
test/run the real router and store in-process. - Fuzz targets in
internal/httpx(FuzzParseSecretHeaders,FuzzParseFillHeaders,FuzzConsumeRoute) are seeded fromtest/vectors/server_headers.json. Plaingo testruns the seeds; fuzz one withgo test ./internal/httpx -run '^$' -fuzz FuzzParseSecretHeaders -fuzztime 60s. - The OpenAPI drift test (
test/openapi_drift_test.go) readsdocs/openapi.yamland checks the real router against it: every documented operation is routed, the statuses it returns are documented, and theAllowandRetry-Afterheaders are. Change the spec and the code together. - Shared test vectors in
test/vectors/are checked by both the Go and JavaScript suites, so the two implementations of the encryption format can’t drift apart by a byte. - Interop tests (
test/cli_interop_test.go,test/request_interop_test.go) exchange secrets and requests between the CLI and the browser’s crypto code, run in Node throughtest/interop/interop.js. They skip whennodeis missing, unlessGONE_REQUIRE_NODE=1is set, as it is in CI. - JavaScript unit tests load each script through
test/js/harness.jswith a fake DOM. - End-to-end tests start the real
bin/gonedwith its templates and CSP, and drive real browsers through sending, opening, managing, requesting, replying and switching languages.- Each test fails on any console error, uncaught exception, CSP violation, or error status for a page or asset.
- Pass Playwright arguments after
--, for exampletask e2e -- --project=webkit request.spec.js. GONE_E2E_PORTchanges the port; the default is8199. A second server for the rate-limit tests uses the next port.- The tests run over HTTPS, so the
Securecookie, WebCrypto’s secure-context check and the 429 paths are exercised in a browser.gonedserves plain HTTP behindtest/e2e/tlsproxy, a small TLS-terminating reverse proxy (httputil.ReverseProxy) with a self-signed certificate made in memory at startup and trusted by nothing, so Playwright runs withignoreHTTPSErrors.test/e2e/servers.jsholds the ports and rate settings thatplaywright.config.jsand the specs share. - Set
GONE_E2E_PLAIN=1to serve plainhttp://127.0.0.1straight fromgoned, without the proxy, to debug a failure. The HTTPS-only checks inhttps.spec.jsare skipped then. - The main server runs with the default rate limits and
GONE_RATE_BURST=1000: every browser connects from127.0.0.1, so a lower burst would make the suite trip its own limiter.ratelimit.spec.jsuses the second server, with a burst of 3, and gives each test its own client with anX-Forwarded-Forheader (the proxy’s address is trusted, and the proxy appends the real peer). - Browsers started by Playwright can’t be made to use the back-forward cache deterministically, so
leave.spec.jschecks a page’spagehidecleanup by dispatching the event.
- The latency test runs only with
GONE_PERF=1, whichtask perfsets.GONE_PERF_DURATIONchanges the run length (default10s).GONE_PERF_RPSoffers a different rate, to find a machine’s limit.- Set
TMPDIRto a directory on the disk you deploy on to benchmark that disk. CI runs it on a RAM disk, so CI checks the code, not the runner’s disk.
Debugging
To log client-side timings in the browser console:
- add
?debug=timingto a page URL; or - run
localStorage.setItem('goneDebugTiming', '1')in DevTools, then reload.
Remove the parameter and the key to turn it off.
Layout
| Path | What’s there |
|---|---|
cmd/goned, cmd/gone | The server and CLI entry points |
internal/ | The Go packages: httpx (handlers), app (service), store (SQLite and blobs), envelope (Go encryption), cli, client, i18n, metrics, ratelimit, … |
web/ | Templates (*.tmpl.html), js/, css/, messages/ (translations), fonts and images; dev/ holds development-only scripts (the ?preview= design modes) that production builds never contain |
test/ | Integration, interop, vector, perf and end-to-end tests |
docs/ | This documentation, the protocol and the OpenAPI spec |
deploy/ | The Compose and Caddy setup |