Elyra
Elyra The coding agent eTerm The terminal that knows where each command ends Starf An activity monitor for Apple silicon that never invents a number Litr A small, native web browser for macOS Notr A notebook for macOS e The native code editor Elyra Grove Native local development environment Askr The real server for Laravel & PHP Elyra Framework Rust + Svelte 5 framework for desktop apps Elyra Conductor Local project conductor Refr Local-first PDF workspace for macOS Elyra SQL Server MySQL-compatible SQL server in Rust Elyra Félagi Agents as teammates on one board Elyra SQL Client Native desktop SQL workbench Elyra SQL Anywhere Replication-ready SQL engine Elyra Sjá SEO & GEO workspace for macOS Elyra DataGrid Server-driven data grid for Laravel
Internals
Architecture
Release notes
Changelog
Elyra
Testing Grove before tagging a version

Testing Grove before tagging a version

Two paths: a quick smoke test on high ports (no sudo), and a full real test with *.test domains in the browser (needs one elevated step).

0. Build

# Frontend (required before building the GUI binary)
cd crates/grove-gui/ui && pnpm install && pnpm build && cd -

# Binaries
cargo build --release            # -> target/release/grove and grove-gui

Put the binaries on PATH for convenience (optional):

export PATH="$PWD/target/release:$PATH"

Build the macOS app / .dmg

cargo install tauri-cli --version "^2.0" --locked    # once
cd crates/grove-gui/ui && pnpm install && pnpm build && cd -
cargo tauri build --manifest-path crates/grove-gui/Cargo.toml
# → target/release/bundle/dmg/Grove_<version>_<arch>.dmg  (+ Grove.app)

Releases build these automatically: pushing a v* tag runs .github/workflows/release.yml, which publishes the CLI tarballs and the .dmg / .deb / .AppImage bundles to a GitHub Release.

1. Quick smoke test (no sudo, high ports)

export GROVE_HOME=/tmp/grove-test
mkdir -p "$GROVE_HOME"
cat > "$GROVE_HOME/config.toml" <<'EOF'
[general]
tld = "test"
default_php = "8.5"
http_port = 8080
https_port = 8443
dns_port = 5354
[services]
mail_enabled = true
mail_port = 11025
EOF

# PHP: download a bundled static build, or register an existing php-fpm
grove php install 8.5
# grove php register 8.4 "$HOME/Library/Application Support/Herd/bin/php84-fpm"

grove start
grove park ~/Code              # or: grove link  inside a project
grove list

# Serve a site (Host header simulates DNS on the high port)
curl -H "Host: <yoursite>.test" http://127.0.0.1:8080/

# Services
grove service install postgres && grove service start postgres
grove service install redis    && grove service start redis
grove service list
grove env <yoursite>           # .env snippet for the bundled services

# Node
grove node install 22
grove node use <yoursite> 22

# Mail-catcher (send a test mail to 127.0.0.1:11025, then:)
grove mail

# GUI
grove gui                      # launches the desktop app against this daemon

grove stop

2. Full real test (*.test in the browser)

Uses the default ports 80/443/53, the system resolver and a trusted CA.

unset GROVE_HOME               # use the real ~/Library/Application Support/Grove

sudo grove init                # CA + resolver + a PHP build (one elevated step)
sudo grove start               # binds 80/443/53
grove park ~/Code
grove secure myproject         # HTTPS

# Now open https://myproject.test in your browser — no hosts editing needed.
grove doctor

To undo everything afterwards:

sudo grove uninstall           # removes service, resolver and CA trust

2b. The suites that don't run by default

cargo test --workspace deliberately skips two groups. Both exist because the code they cover cannot be exercised honestly from an ordinary test run, so neither being green in CI means they passed — they have to be run on purpose.

Privileged tests

One thing here can only be observed by a process that has privilege: what a root install does with the CA private key. sudo grove install creates the CA as root and then has to hand it to the user the daemon will run as, because since 1.8.0 that daemon is not root and a key it cannot read is HTTPS that does not work. The test skips itself unless it happens to be running as root — a no-op on your machine, real evidence in a container:

docker run --rm -v "$PWD:/w" -w /w \
  -v grove-linux-target:/target -e CARGO_TARGET_DIR=/target \
  rust:alpine sh -c '
    apk add --no-cache musl-dev openssl-dev &&
    cargo test -p grove-tls --test ca_ownership_root -- --nocapture'

The named volume is worth the extra flags. Cargo keys artefacts by target triple, so a container writing into ./target does not destroy your host build — but it does grow the directory by a second platform's worth of objects, and it starts from cold every run. In a volume the first run is a ~12-minute build and every run after it is seconds.

It covers all four directions: a root install hands the key to the recorded run user; a key root already owns moves on the next load; with no run user recorded it stays with root rather than going to a guessed account; and the certificate stays world-readable throughout, since nothing can verify a chain it cannot read.

Two sibling suites used to live here — grove-core --test privdrop_root and grove-runtime --test probe_root — and they went with the privilege-dropping machinery they tested. There is no drop left to prove.

Property tests

grove-proxy has proptest tests for the request-path sanitizer and the dotfile check (path_properties in handler.rs). They run with the normal suite, 2000 cases each. If one fails, proptest prints a minimal failing input and writes it to crates/grove-proxy/proptest-regressions/; commit that file so the case is replayed first on every future run.

Network tests

Checksum verification is only as good as its agreement with what publishers actually serve today: a parser that handles our idea of SHASUMS256.txt and not Node's would pass every unit test and fail every install. These are #[ignore]d because they download real artefacts:

cargo test -p grove-runtime --test download_verification -- --ignored --nocapture

The cheapest of them (published_checksum_documents_still_parse) fetches only the manifests, and is the one that catches a publisher changing format from under us. Worth running before a release even if you skip the rest.

2c. Releasing

A release is a v* tag. Pushing it runs .github/workflows/release.yml, which builds and notarizes the macOS app, builds the Linux bundles, uploads everything to the GitHub Release for that tag, and rewrites the updater's latest.json to direct download URLs.

# on main, after bumping Cargo.toml + tauri.conf.json and dating the changelog
git tag -a v1.6.0 -m "Grove 1.6.0"
git push origin v1.6.0

The first job step, Ensure the GitHub Release exists, creates the release before anything is compiled. It uses the RELEASE_TOKEN secret if one is set and the Actions token otherwise. If neither is allowed to create a release, the job fails there, within seconds, with the fix in the error — that is the point of doing it first. 1.5.0 learned after a 14-minute build that the Actions token was refused for creating a release while uploads to an existing one worked; 1.4.x had been created by the Actions token without trouble, so this is not a fixed property of the repository. Do not add RELEASE_TOKEN pre-emptively; add it if the pre-flight tells you to.

3. What to verify

  • *.test resolves and serves (Laravel / static / proxy drivers)
  • HTTPS works with the Grove CA (green padlock after grove init)
  • Per-site PHP (grove isolate) and Node (grove node use) take effect
  • grove php install / grove node install download and run self-contained
  • grove service install/start/stop/restart for postgres/mysql/redis
  • Mail-catcher captures mail; grove mail / GUI Mail panel show it
  • grove requests / GUI Requests panel show proxied requests live
  • grove path install puts php/composer/node on PATH; grove db snapshot/restore round-trips
  • grove up --write scaffolds grove.toml; grove up links + configures the project
  • grove license activate/status works; grove secret set/pull/share/revoke round-trips against the Teams backend
  • GUI: Sites, Services, Mail, PHP, Node, Tunnels, Requests, Tools, Logs, Doctor + Settings (⌘,)
  • grove doctor is all green

Tip: run the daemon in the foreground with logs while testing: GROVE_LOG=info grove daemon