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
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [0.34.58] - 2026-10-20

### Fixed
- **An unattended run reported NetBird not joined on a machine already connected to it.** With 0.34.57 a new installation joins NetBird by default; run with `--yes` or without a terminal on a host already in NDP's network (another Endpoint on it had joined), the installer said it needed `sudo` and could not ask for the password, and wrote `NETBIRD_ENABLED=False`. It checked for passwordless `sudo` before looking at the existing connection, which needs no `sudo`. It now reads the connection first (`netbird status` as the user, through `sudo` only if that fails) and only requires `sudo` to install or join. New test in `install/tests/test_netbird_affinities.py`. Verified on a host already connected to NetBird: re-running the installer unattended on a second Endpoint recorded the connection (`NETBIRD_ENABLED=True`, the NetBird address, reported in its metrics), with the rest of its `.env` unchanged (#367).

## [0.34.57] - 2026-10-20

### Changed
Expand Down
2 changes: 1 addition & 1 deletion api/config/swagger_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ class Settings(BaseSettings):

swagger_title: str = "API Documentation"
swagger_description: str = "This is the API documentation."
swagger_version: str = "0.34.57"
swagger_version: str = "0.34.58"
root_path: str = "" # API root path prefix (e.g., "/test" or "")
is_public: bool = True
metrics_endpoint: str = "https://federation.ndp.utah.edu/metrics/"
Expand Down
17 changes: 14 additions & 3 deletions install/install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -1299,8 +1299,11 @@ if [[ "$want_affinities" == "yes" ]]; then
fi

netbird_status() {
# The client's own view: management connection and address, as JSON.
"${netbird_sudo[@]}" netbird status --json 2>/dev/null || true
# The client's own view: management connection and address, as JSON. Read
# as the user first, which needs no sudo; through sudo only if that fails.
netbird status --json 2>/dev/null \
|| { [[ ${#netbird_sudo[@]} -gt 0 ]] && "${netbird_sudo[@]}" netbird status --json 2>/dev/null; } \
|| true
}

netbird_field() {
Expand Down Expand Up @@ -1345,10 +1348,18 @@ join_netbird() {
(Federation 1.12.9 or later, with --config-id) or --netbird-management-url." || return 1
fi
netbird_sudo=()
# A machine already connected (another Endpoint on this host joined it) needs
# no sudo at all: seeing the connection does not (issue #367).
already_connected="no"
if command -v netbird >/dev/null 2>&1 \
&& [[ "$(netbird_status | netbird_field connected)" == "yes" ]]; then
already_connected="yes"
fi
if [[ "$(id -u)" != "0" ]]; then
netbird_sudo=(sudo)
# Asked for its password only where someone can answer.
if [[ "$want_netbird" == "default" ]] && ! interactive && ! sudo -n true 2>/dev/null; then
if [[ "$want_netbird" == "default" && "$already_connected" == "no" ]] \
&& ! interactive && ! sudo -n true 2>/dev/null; then
netbird_stop "it needs sudo, and sudo would ask for a password nobody can type here." || return 1
fi
fi
Expand Down
18 changes: 18 additions & 0 deletions install/tests/test_netbird_affinities.py
Original file line number Diff line number Diff line change
Expand Up @@ -460,3 +460,21 @@ def test_by_default_without_passwordless_sudo_it_carries_on(host, federation):
assert "needs sudo" in result.stderr
assert "netbird up" not in _netbird_calls(host)
assert _env(host)["NETBIRD_ENABLED"] == "False"


def test_an_unattended_run_on_a_connected_machine_records_netbird(host, federation):
"""Issue #367: seeing an existing connection needs no sudo."""
federation["config"] = _configuration(netbird_management_url=MANAGEMENT_URL)
# Already connected, as the second Endpoint on a host that joined before.
(host["tmp"] / "netbird.joined").touch()
# sudo that would need a password: -n refuses, anything else fails too.
(host["stubs"] / "sudo").write_text("#!/bin/sh\nexit 1\n", encoding="utf-8")

result = _install(host, federation)

assert result.returncode == 0, result.stdout + result.stderr
assert "needs sudo" not in result.stderr
assert "netbird up" not in _netbird_calls(host)
assert _env(host)["NETBIRD_ENABLED"] == "True"
assert _env(host)["NETBIRD_IP"] == "100.64.0.7"
assert _state(host)["NETBIRD"] == "yes"
Loading