openvibers/openvibe.link Commits

Scan root and pi crontabs, skip service checks under test overrides (#7)

OP OpenVibers committed 2 Oct 2026 · 95a1ddf744 · 4 files, +64 −16

local checks ✗ 0/2 · CI ✓ 9/9 · review SHIP by space-bunny-alpha · 2 fix rounds

https://github.com/OpenVibers/OpenVibe.Node/pull/7

Changes

ddiff --git a/docs/install.md b/docs/install.md
iindex 1eabe0a..8ad0bdd 100644
---- a/docs/install.md
++++ b/docs/install.md
@@@ -117,8 +117,12 @@ Raspberry Pi OS Bookworm (64-bit recommended). Enable I²C and SPI: `sudo raspi-
`--driver adeept` (or `adeept-mecanum`).
The kit's own software (`Adeept_Robot.service`, `WebServer.py` on `0.0.0.0:8888` with the fixed login
--`admin:123456`, MJPEG on `:5000`) must not run: anyone on the network could drive the car. The installer disables it;
--check with `systemctl status Adeept_Robot.service`. The Node replaces it.
++`admin:123456`, MJPEG on `:5000`) must not run: anyone on the network could drive the car. The installer disables it,
++including autostart lines in root's and the invoking user's crontabs and `/etc/rc.local`. From a root shell, it checks
++`pi`'s crontab when that account exists. It comments out the kit's lines with the marker
++`#openvibe-node-disabled:` and keeps the original text, so running the installer again changes nothing. Check with
++`systemctl status Adeept_Robot.service`, `crontab -l` (and `sudo crontab -l -u pi` for a root-shell install) and
++`grep openvibe-node-disabled /etc/rc.local`. The Node replaces it.
If a direction is wrong on your car, fix it in `config.json` → `plugins[0].config`: `motors.<wheel>.direction`,
`pan.invert`, `tilt.invert`, `line.invert`. See [the plugin README](../plugins/adeept_adr036/README.md).
ddiff --git a/install/install.sh b/install/install.sh
iindex 55c2d4e..56a7eb3 100755
---- a/install/install.sh
++++ b/install/install.sh
@@@ -84,7 +84,10 @@ SUDO=""
# (marked, never deleted) so they cannot start it again.
STOCK_SERVER_RE='Server_(Ordinary|Mecanum)Wheels/(WebServer|APPServer|GUIServer|app)\.py'
STOCK_SERVER_MARKER='#openvibe-node-disabled:'
++# Root's crontab is always scanned. Scan the invoking user's crontab on the normal install path or through sudo.
++# From a plain root shell (sudo -i, root login), use the kit's usual owner pi when that account exists.
CRON_USER="${SUDO_USER:-$(id -un 2>/dev/null || printf '%s' root)}"
++if [ "$CRON_USER" = root ] && id pi >/dev/null 2>&1; then CRON_USER=pi; fi
# Comment out the stock-server lines in one crontab-like file: read $1, write $2, print one line per disabled
# entry. A line whose first non-blank character is "#" is left alone, so our marker makes a second run a no-op.
@@@ -137,16 +140,20 @@ disable_stock_rc_local() {
}
disable_stock_server() {
-- if command -v systemctl >/dev/null 2>&1; then
-- unit=Adeept_Robot.service
-- if systemctl is-enabled "$unit" >/dev/null 2>&1 || systemctl is-active "$unit" >/dev/null 2>&1; then
-- say "disabling the Adeept kit's stock server ($unit): it listens on 0.0.0.0:8888 with a fixed password"
-- $SUDO systemctl disable --now "$unit" || true
++ # The OPENVIBE_* file overrides are test-only: when any is set they point the crontab/rc.local checks at temp
++ # files, so skip the real systemd and running-process branches too (a test must touch no service or process).
++ if [ -z "${OPENVIBE_CRONTAB_ROOT:-}${OPENVIBE_CRONTAB_USER:-}${OPENVIBE_RC_LOCAL:-}" ]; then
++ if command -v systemctl >/dev/null 2>&1; then
++ unit=Adeept_Robot.service
++ if systemctl is-enabled "$unit" >/dev/null 2>&1 || systemctl is-active "$unit" >/dev/null 2>&1; then
++ say "disabling the Adeept kit's stock server ($unit): it listens on 0.0.0.0:8888 with a fixed password"
++ $SUDO systemctl disable --now "$unit" || true
++ fi
++ fi
++ if command -v pgrep >/dev/null 2>&1 && pgrep -f "$STOCK_SERVER_RE" >/dev/null 2>&1; then
++ say "stopping a running Adeept stock server process"
++ $SUDO pkill -f "$STOCK_SERVER_RE" || true
fi
-- fi
-- if command -v pgrep >/dev/null 2>&1 && pgrep -f "$STOCK_SERVER_RE" >/dev/null 2>&1; then
-- say "stopping a running Adeept stock server process"
-- $SUDO pkill -f "$STOCK_SERVER_RE" || true
fi
# Autostart: root's crontab and the invoking user's, then rc.local. OPENVIBE_CRONTAB_* / OPENVIBE_RC_LOCAL
# are test-only file overrides so the checks can run without root and without touching the real system.
@@@ -156,8 +163,8 @@ disable_stock_server() {
disable_stock_crontab root
fi
if [ -n "${OPENVIBE_CRONTAB_USER:-}" ]; then
-- disable_stock_file "$OPENVIBE_CRONTAB_USER" "the crontab of $CRON_USER"
-- elif [ "$CRON_USER" != root ]; then
++ disable_stock_file "$OPENVIBE_CRONTAB_USER" "the crontab of ${CRON_USER:-$(id -un 2>/dev/null || printf '%s' root)}"
++ elif [ -n "$CRON_USER" ] && [ "$CRON_USER" != root ]; then
disable_stock_crontab "$CRON_USER"
fi
if [ -n "${OPENVIBE_RC_LOCAL:-}" ]; then
ddiff --git a/plugins/adeept_adr036/README.md b/plugins/adeept_adr036/README.md
iindex a5df907..7a8ed6b 100644
---- a/plugins/adeept_adr036/README.md
++++ b/plugins/adeept_adr036/README.md
@@@ -8,8 +8,12 @@ kit's code is imported.
## Keep the kit's stock server disabled
The kit's own server listens on `0.0.0.0:8888` with the fixed login `admin` / `123456` and streams MJPEG on `:5000`.
--Anyone on the network could drive the car with it. Disable its autostart (the kit installer adds it to the user's
--crontab or `/etc/rc.local`, depending on version) and do not run it next to the Node. This plugin never starts it.
++Anyone on the network could drive the car with it. The installer disables its autostart in root's and the invoking
++user's crontabs and `/etc/rc.local`. From a root shell, it checks `pi`'s crontab when that account exists. It comments
++out the kit's lines with the marker `#openvibe-node-disabled:` and keeps the original text, so running the installer
++again changes nothing. Check with `systemctl status Adeept_Robot.service`, `crontab -l` (and
++`sudo crontab -l -u pi` for a root-shell install) and
++`grep openvibe-node-disabled /etc/rc.local`. Do not run it next to the Node. This plugin never starts it.
## Wiring (kit defaults)
ddiff --git a/scripts/test-install-stock-server.sh b/scripts/test-install-stock-server.sh
iindex 63e75c9..491ab29 100644
---- a/scripts/test-install-stock-server.sh
++++ b/scripts/test-install-stock-server.sh
@@@ -1,7 +1,7 @@
#!/bin/sh
# Tests install.sh's handling of the Adeept kit's stock-server autostart: crontab (root's and the invoking
# user's, including @reboot lines) and /etc/rc.local. The OPENVIBE_* test overrides point the checks at files in
--# a temp dir, so this needs no root and touches no real crontab or /etc/rc.local.
++# a temp dir, so this needs no root and touches no real crontab, rc.local, service or process.
set -eu
here="$(cd "$(dirname "$0")" && pwd)"
@@@ -96,4 +96,37 @@ if printf '%s\n' "$out3" | grep -q "stock server"; then fail "reported changes o
grep -qx '0 5 \* \* \* /usr/bin/echo hello' "$none/cron" || fail "unrelated cron line changed without the kit"
grep -qx '#!/bin/sh' "$none/rc" || fail "unrelated rc.local changed without the kit"
++# Without SUDO_USER, the normal install path must still scan the logged-in user's crontab. Mock the system commands
++# so this checks user selection without touching any real crontab, even when CI runs as root.
++mock_bin="$tmp/mock-bin"
++mkdir -p "$mock_bin"
++cat > "$mock_bin/id" <<'EOF'
++#!/bin/sh
++case "$1" in
++ -un) printf '%s\n' invoking_user ;;
++ pi) exit 1 ;;
++ *) exit 1 ;;
++esac
++EOF
++cat > "$mock_bin/crontab" <<'EOF'
++#!/bin/sh
++[ "$1" = -u ] && [ "$2" = invoking_user ] || exit 1
++case "$3" in
++ -l) cat "$MOCK_USER_CRON" ;;
++ *) cp "$3" "$MOCK_USER_CRON" ;;
++esac
++EOF
++chmod +x "$mock_bin/id" "$mock_bin/crontab"
++fallback_cron="$tmp/fallback-crontab"
++printf '%s\n' '@reboot python3 /home/pi/adeept_awr/Server/Server_OrdinaryWheels/WebServer.py' > "$fallback_cron"
++out4="$(
++ unset SUDO_USER
++ PATH="$mock_bin:$PATH" MOCK_USER_CRON="$fallback_cron" OPENVIBE_INSTALL_STOCK_ONLY=1 \
++ OPENVIBE_CRONTAB_ROOT="$root_cron" OPENVIBE_CRONTAB_USER='' OPENVIBE_RC_LOCAL="$rc_local" sh "$installer"
++)"
++printf '%s\n' "$out4" | grep -q 'stock server autostart in the crontab of invoking_user' ||
++ fail "logged-in user's crontab was not scanned without SUDO_USER"
++grep -q '^#openvibe-node-disabled: @reboot python3 /home/pi/adeept_awr/Server/Server_OrdinaryWheels/WebServer\.py$' \
++ "$fallback_cron" || fail "logged-in user's stock line was not commented out"
++
printf 'ok: install.sh stock-server crontab/rc.local handling\n'