Skip to content
Open
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
7 changes: 7 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -968,6 +968,13 @@ jobs:
# Serial: windows_resolver_tests mutate process-global env
# (BUZZ_SHELL/GIT_BASH/SystemRoot) that SharedState::new reads.
run: cargo test -p buzz-dev-mcp --target $env:TARGET -- --test-threads=1
- name: Test (buzz-backend-ssh)
# The provider ships to a user PATH on every desktop platform, so its
# path resolution (tailscale.exe candidates, ssh.exe lookup) and JSON
# parsing only gate if the crate is tested ON Windows. Its shell-script
# execution tests are #[cfg(unix)] and cover the remote side, which is
# always POSIX.
run: cargo test -p buzz-backend-ssh --target $env:TARGET
# Smoke-test the new host-prereq contract: Git for Windows (which provides
# bash) is available on the runner, a shell command round-trips, and bash
# does NOT resolve from System32 (so WSL's launcher is never picked up).
Expand Down
11 changes: 11 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ members = [
"crates/buzz-audit",
"crates/buzz-acp",
"crates/buzz-agent",
"crates/buzz-backend-ssh",
"crates/sprig",
"crates/buzz-test-client",
"crates/buzz-ws-client",
Expand Down
6 changes: 6 additions & 0 deletions Justfile
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,12 @@ test-unit:
# Gateway unit and black-box HTTP tests are infra-free. Postgres-backed
# contract/race tests run in the dedicated CI job below.
cargo nextest run -p buzz-push-gateway
# Remote-deploy provider (buzz-backend-ssh). Infra-free: the deploy
# tests execute the generated script against a local /bin/sh with a
# stubbed HOME, no network. This is the only place the shell-injection
# canary runs — the Windows job's copy of these tests is #[cfg(unix)]d
# out — so dropping this step lets an injection regression ship green.
cargo nextest run -p buzz-backend-ssh
else
./scripts/run-tests.sh unit
fi
Expand Down
31 changes: 31 additions & 0 deletions crates/buzz-backend-ssh/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
[package]
name = "buzz-backend-ssh"
version.workspace = true
edition.workspace = true
rust-version.workspace = true
license.workspace = true
repository.workspace = true
description = "Buzz backend provider that deploys managed agents to a remote host over SSH"

# Deliberately binary-only and deliberately NOT bundled with the desktop app
# (not in `tauri.conf.json` externalBin, not in `scripts/bundle-sidecars.sh`).
# `discover_provider_candidates` prepends the app bundle's own directory to the
# provider search path, so shipping this inside the bundle would give every
# install an auto-discovered SSH-deploy capability and quietly undermine the
# "Only use providers from trusted sources" warning the desktop shows. It is a
# release artifact the user installs to `~/.local/bin`, which is already on the
# discovery path.
[[bin]]
name = "buzz-backend-ssh"
path = "src/main.rs"

[dependencies]
serde = { workspace = true }
serde_json = { workspace = true }
zeroize = { workspace = true }
# Deploy can install `buzz-acp` on the host by streaming it inside the script
# that already travels on the SSH stdin channel. base64 is what keeps raw bytes
# from corrupting that stream; sha2 is what lets the host refuse a payload that
# arrived damaged. Both are already workspace dependencies.
base64 = { workspace = true }
sha2 = { workspace = true }
24 changes: 24 additions & 0 deletions crates/buzz-backend-ssh/assets/[email protected]
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
[Unit]
Description=Buzz agent %i
After=network-online.target
Wants=network-online.target
# A long-running agent must never be rate-limited into staying down: a unit
# held by the start limiter looks exactly like an agent that silently died,
# and only `systemctl reset-failed` clears it.
StartLimitIntervalSec=0

[Service]
Type=simple
# Holds the agent's minted nsec. Written by the provider with umask 077 and
# chmod 600; systemd reads it as the owning user.
EnvironmentFile=%h/.config/buzz-acp/%i.env
# Absolute path, substituted at install time from the host's resolved
# `buzz-acp`. systemd does not expand environment variables in the program
# position, and the shell indirection that would work around that is not worth
# adding to a unit whose environment carries a private key.
ExecStart=@BUZZ_ACP_BIN@
Restart=always
RestartSec=5

[Install]
WantedBy=default.target
Loading