Agent host: SilverBullet boots into accounts and the vault, not a bare space
SB_NAME alone put SilverBullet 2.11 in single-space mode: no accounts, no setup wizard, and its /data folder served instead of the vault. The compose file sets only PUID and PGID now, a test holds it to that, and the host check fails on a single-space boot. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01J5Utyfzw7gF7UhjRDEtjTk
This commit is contained in:
1 parent
e287eea2d3
commit
1d33d50907
3 files changed
+24
-2
No files matched your search
@@ -10,6 +10,11 @@ bad() { echo "FAIL: $1"; fail=1; }
|
|||||||
cd "$stack" || { echo "FAIL: no $stack"; exit 1; }
|
cd "$stack" || { echo "FAIL: no $stack"; exit 1; }
|
||||||
[ "$(sudo docker compose ps --status running -q | wc -l)" -ge 1 ] \
|
[ "$(sudo docker compose ps --status running -q | wc -l)" -ge 1 ] \
|
||||||
&& ok "SilverBullet is running" || bad "SilverBullet isn't running"
|
&& ok "SilverBullet is running" || bad "SilverBullet isn't running"
|
||||||
|
if sudo docker compose logs --no-color silverbullet 2>/dev/null | grep -q 'boot mode: single-space'; then
|
||||||
|
bad "it booted a single space with no accounts (an SB_* setting?)"
|
||||||
|
else
|
||||||
|
ok "it keeps accounts (no single-space boot)"
|
||||||
|
fi
|
||||||
code=$(curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:3000/)
|
code=$(curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:3000/)
|
||||||
case $code in 2??|3??) ok "it answers locally ($code)" ;; *) bad "it answers $code" ;; esac
|
case $code in 2??|3??) ok "it answers locally ($code)" ;; *) bad "it answers $code" ;; esac
|
||||||
probe=.nisse-probe-$$
|
probe=.nisse-probe-$$
|
||||||
|
|||||||
@@ -8,9 +8,10 @@ services:
|
|||||||
image: ghcr.io/silverbulletmd/silverbullet:2.11.1-slim
|
image: ghcr.io/silverbulletmd/silverbullet:2.11.1-slim
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
environment:
|
environment:
|
||||||
|
# Only these. Any SB_* setting (even SB_NAME) boots a single space with
|
||||||
|
# no accounts, serving /data instead of the vault.
|
||||||
PUID: "1000"
|
PUID: "1000"
|
||||||
PGID: "1000"
|
PGID: "1000"
|
||||||
SB_NAME: Nisse vault
|
|
||||||
ports:
|
ports:
|
||||||
# IPv4 only; setup.sh's firewall lets only the operator's Caddy in.
|
# IPv4 only; setup.sh's firewall lets only the operator's Caddy in.
|
||||||
- "0.0.0.0:3000:3000"
|
- "0.0.0.0:3000:3000"
|
||||||
|
|||||||
@@ -67,6 +67,12 @@ def test_no_secrets_in_the_compose_file() -> None:
|
|||||||
assert not [k for k in environment if re.search(r"USER|TOKEN|PASS|SECRET|KEY", k)]
|
assert not [k for k in environment if re.search(r"USER|TOKEN|PASS|SECRET|KEY", k)]
|
||||||
|
|
||||||
|
|
||||||
|
def test_it_boots_into_accounts_and_the_vault_not_a_bare_space() -> None:
|
||||||
|
# SB_NAME alone switched 2.11 to single-space mode: no accounts, no setup
|
||||||
|
# wizard, and /data served in place of the vault.
|
||||||
|
assert set(silverbullet()["environment"]) == {"PUID", "PGID"}
|
||||||
|
|
||||||
|
|
||||||
def test_its_port_caddys_and_the_firewalls_agree() -> None:
|
def test_its_port_caddys_and_the_firewalls_agree() -> None:
|
||||||
port = setting("SB_PORT")
|
port = setting("SB_PORT")
|
||||||
assert silverbullet()["ports"] == [f"0.0.0.0:{port}:3000"] # IPv4 only
|
assert silverbullet()["ports"] == [f"0.0.0.0:{port}:3000"] # IPv4 only
|
||||||
@@ -120,7 +126,9 @@ def test_the_firewall_lets_only_one_address_in_and_replaces_its_own_rule() -> No
|
|||||||
SCRIPT = HOST.parents[1] / "scripts" / "agent-host.sh"
|
SCRIPT = HOST.parents[1] / "scripts" / "agent-host.sh"
|
||||||
|
|
||||||
|
|
||||||
def _fake_host(tmp_path: Path, *, memory_writable: bool) -> dict[str, str]:
|
def _fake_host(
|
||||||
|
tmp_path: Path, *, memory_writable: bool, boot: str = "multi-space"
|
||||||
|
) -> dict[str, str]:
|
||||||
"""Commands standing in for the host's: ssh runs the command here, sudo
|
"""Commands standing in for the host's: ssh runs the command here, sudo
|
||||||
just runs it, and docker reads all of stdin, as docker compose exec does."""
|
just runs it, and docker reads all of stdin, as docker compose exec does."""
|
||||||
bin_ = tmp_path / "bin"
|
bin_ = tmp_path / "bin"
|
||||||
@@ -134,6 +142,7 @@ def _fake_host(tmp_path: Path, *, memory_writable: bool) -> dict[str, str]:
|
|||||||
"cat > /dev/null\n"
|
"cat > /dev/null\n"
|
||||||
'case "$*" in\n'
|
'case "$*" in\n'
|
||||||
' *"ps --status running"*) echo abc123 ;;\n'
|
' *"ps --status running"*) echo abc123 ;;\n'
|
||||||
|
f' *" logs "*) echo "boot mode: {boot}" ;;\n'
|
||||||
f' *"/vault/memory/"*) exit {0 if memory_writable else 1} ;;\n'
|
f' *"/vault/memory/"*) exit {0 if memory_writable else 1} ;;\n'
|
||||||
"esac"
|
"esac"
|
||||||
),
|
),
|
||||||
@@ -167,6 +176,7 @@ def test_the_check_runs_every_step_even_though_docker_reads_stdin(
|
|||||||
assert result.returncode == 0, result.stdout + result.stderr
|
assert result.returncode == 0, result.stdout + result.stderr
|
||||||
assert result.stdout.splitlines() == [
|
assert result.stdout.splitlines() == [
|
||||||
"ok: SilverBullet is running",
|
"ok: SilverBullet is running",
|
||||||
|
"ok: it keeps accounts (no single-space boot)",
|
||||||
"ok: it answers locally (200)",
|
"ok: it answers locally (200)",
|
||||||
"ok: the operator's folders are writable",
|
"ok: the operator's folders are writable",
|
||||||
"ok: memory/ is read-only to SilverBullet",
|
"ok: memory/ is read-only to SilverBullet",
|
||||||
@@ -184,3 +194,9 @@ def test_a_writable_memory_folder_fails_the_check(tmp_path: Path) -> None:
|
|||||||
)
|
)
|
||||||
assert "ok: the firewall rule is in place" in result.stdout # still checked
|
assert "ok: the firewall rule is in place" in result.stdout # still checked
|
||||||
assert "all checks passed" not in result.stdout
|
assert "all checks passed" not in result.stdout
|
||||||
|
|
||||||
|
|
||||||
|
def test_a_single_space_boot_fails_the_check(tmp_path: Path) -> None:
|
||||||
|
result = _check(_fake_host(tmp_path, memory_writable=False, boot="single-space"))
|
||||||
|
assert result.returncode == 1
|
||||||
|
assert "FAIL: it booted a single space with no accounts" in result.stdout
|
||||||
Reference in new issue
Block a user