#!/usr/bin/env bats load install.helpers setup() { setup_install_env stub_bin id 'echo 0' skip_enrollment_wait export SERVER_ADDRESS="https://cloud.example.test" export AGENT_VERSION="v0.0.0-test" export AGENT_IMAGE="shellhubio/agent:v0.0.0-test" export INSTALL_DIR="$BATS_TEST_TMPDIR/usr-local-bin" export TMP_DIR="$BATS_TEST_TMPDIR/tmp" export AGENT_KEY="$BATS_TEST_TMPDIR/shellhub.key" export PRIVATE_KEY="/host$AGENT_KEY" export PROC_VERSION="$BATS_TEST_TMPDIR/proc-version" export OS_RELEASE="$BATS_TEST_TMPDIR/os-release" mkdir -p "$INSTALL_DIR" "$TMP_DIR" echo "Linux version 6.8.0-generic" > "$PROC_VERSION" echo 'NAME="Ubuntu"' > "$OS_RELEASE" RUNTIME=docker } skip_enrollment_wait() { touch "$BATS_TEST_TMPDIR/shellhub.key" stub_bin sleep 'exit 0' } stub_agent_log() { cat > "$BATS_TEST_TMPDIR/agent.log" stub_bin agent-log "cat '$BATS_TEST_TMPDIR/agent.log'" } stub_runtime() { stub_bin "$1" "echo \"$1 \$*\" >> \"\$CALLS\"; ${2:+$2; }[ \"\$1\" = ps ] && echo shellhub; exit 0" } stub_container_logs() { stub_runtime "$1" "[ \"\$1\" = logs ] && cat '$BATS_TEST_TMPDIR/agent.log'" } stub_journal() { stub_bin journalctl "cat '$BATS_TEST_TMPDIR/agent.log'" } with_tenant() { export TENANT_ID="00000000-0000-4000-a000-000000000000" } as_non_root() { stub_bin id 'echo 1000' stub_sudo } stub_sudo() { stub_bin sudo 'echo "sudo $*" >> "$CALLS"; export RAN_UNDER_SUDO=1; exec "$@"' } use_podman() { RUNTIME=podman stub_bin systemctl 'exit 0' } container_install() { [ -x "$STUB_DIR/$RUNTIME" ] || stub_runtime "$RUNTIME" call_install "${RUNTIME}_install" "$@" } fake_agent_binary() { export AGENT_BINARY="$BATS_TEST_TMPDIR/fake-agent" printf '#!/bin/sh\n[ "$*" = "install --help" ] && exit 0\necho "agent $*" >> "$CALLS"\nexit %s\n' "${1:-0}" > "$AGENT_BINARY" chmod +x "$AGENT_BINARY" } enter_wsl() { echo "Linux version ${1:-5.15.167.4-microsoft-standard-WSL2} (Microsoft@Microsoft.com) #1 SMP" > "$PROC_VERSION" } serve_release() { export BINARY_ARCH=amd64 RELEASE_DIR="$BATS_TEST_TMPDIR/release" mkdir -p "$RELEASE_DIR" printf '#!/bin/sh\necho "release binary ran $*" >> "$CALLS"\n' | gzip > "$RELEASE_DIR/shellhub-agent-linux-amd64.gz" (cd "$RELEASE_DIR" && sha256sum shellhub-agent-linux-amd64.gz > checksums.txt) local tool="${1:-curl}" stub_bin "$tool" "echo \"$tool \$*\" >> \"\$CALLS\" for a; do case \"\$prev\" in --output|-o|-O) out=\$a ;; esac case \"\$a\" in https://*) url=\$a ;; esac prev=\$a done cp '$RELEASE_DIR'/\"\${url##*/}\" \"\$out\" 2>/dev/null || exit 1" stub_bin id 'echo 1000' stub_bin sudo "echo \"sudo \$*\" >> \"\$CALLS\"; [ \"\${1%.new}\" = '$INSTALL_DIR/shellhub-agent' ] && exit 0; exec \"\$@\"" } assert_installed_release_binary() { gzip -dc "$RELEASE_DIR/shellhub-agent-linux-amd64.gz" | cmp -s - "$INSTALL_DIR/shellhub-agent" || { echo "$INSTALL_DIR/shellhub-agent is not the binary the release served" return 1 } assert_called "sudo $INSTALL_DIR/shellhub-agent install --server-address=$SERVER_ADDRESS" refute_called "release binary ran" } discover_version() { unset AGENT_VERSION printf '{"version":"%s","endpoints":{"ssh":"localhost:22"}}\n' "$1" > "$BATS_TEST_TMPDIR/info" stub_bin curl "echo \"curl \$*\" >> \"\$CALLS\"; case \"\$*\" in */info*) cat '$BATS_TEST_TMPDIR/info' ;; esac" } @test "check_podman_boot_restart aborts when systemctl is missing" { call_install check_podman_boot_restart [ "$status" -eq 1 ] assert_output_contains "systemctl not found" assert_output_contains "SKIP_BOOT_RESTART_CHECK=1" } @test "check_podman_boot_restart aborts when podman-restart.service is disabled" { stub_bin systemctl 'echo "systemctl $*" >> "$CALLS"; exit 1' call_install check_podman_boot_restart [ "$status" -eq 1 ] assert_called "systemctl is-enabled podman-restart.service" assert_output_contains "podman-restart.service is not enabled" assert_output_contains "sudo systemctl enable podman-restart.service" } @test "check_podman_boot_restart passes silently when podman-restart.service is enabled" { stub_bin systemctl 'echo "systemctl $*" >> "$CALLS"; exit 0' call_install check_podman_boot_restart [ "$status" -eq 0 ] [ -z "$output" ] assert_called "systemctl is-enabled podman-restart.service" } @test "SKIP_BOOT_RESTART_CHECK installs anyway when systemctl is missing" { export SKIP_BOOT_RESTART_CHECK=1 call_install check_podman_boot_restart [ "$status" -eq 0 ] assert_output_contains "skipping podman-restart.service check" assert_output_contains "will NOT auto-start on boot" } @test "SKIP_BOOT_RESTART_CHECK installs anyway when podman-restart.service is disabled" { export SKIP_BOOT_RESTART_CHECK=1 stub_bin systemctl 'echo "systemctl $*" >> "$CALLS"; exit 1' call_install check_podman_boot_restart [ "$status" -eq 0 ] refute_called "systemctl is-enabled" assert_output_contains "skipping podman-restart.service check" } @test "enrollment_summary reports a provisioning key ahead of a tenant" { with_tenant export PROVISIONING_KEY=key-1 call_install enrollment_summary [ "$output" = "provisioning key" ] } @test "enrollment_summary reports a tenant as landing pending" { with_tenant call_install enrollment_summary [ "$output" = "tenant $TENANT_ID" ] } @test "enrollment_summary points at the login flow when no credential is given" { call_install enrollment_summary [ "$output" = "none — enroll with 'shellhub-agent login'" ] } @test "enrollment_summary reports a tenant a previous enrollment left behind" { export PRIVATE_KEY="$BATS_TEST_TMPDIR/shellhub.key" export PERSISTED_TENANT=00000000-0000-4000-0000-000000000000 call_install enrollment_summary [ "$output" = "tenant 00000000-0000-4000-0000-000000000000 (persisted by a previous enrollment)" ] } @test "enrollment_summary reports a persisted tenant ahead of a provisioning key" { export PROVISIONING_KEY=key-1 export PRIVATE_KEY="$BATS_TEST_TMPDIR/shellhub.key" export PERSISTED_TENANT=00000000-0000-4000-0000-000000000000 call_install enrollment_summary [ "$output" = "tenant 00000000-0000-4000-0000-000000000000 (persisted by a previous enrollment)" ] } @test "persisted_tenant escalates to read a tenant file only root can read" { as_non_root export PRIVATE_KEY="$BATS_TEST_TMPDIR/shellhub.key" echo "00000000-0000-4000-0000-000000000000" > "$PRIVATE_KEY.tenant" chmod 000 "$PRIVATE_KEY.tenant" call_install persisted_tenant assert_called "sudo head -n 1 $PRIVATE_KEY.tenant" } @test "persisted_tenant reads the tenant file a container install names under /host" { export PRIVATE_KEY="/host$BATS_TEST_TMPDIR/shellhub.key" echo "00000000-0000-4000-0000-000000000000" > "$BATS_TEST_TMPDIR/shellhub.key.tenant" call_install persisted_tenant [ "$output" = "00000000-0000-4000-0000-000000000000" ] } @test "enroll_agent_interactively runs the login flow when no credential names a namespace" { stub_bin shellhub-agent call_install enroll_agent_interactively shellhub-agent "$AGENT_KEY" [ "$status" -eq 0 ] assert_called "shellhub-agent login" } @test "enroll_agent_interactively waits for the agent key before starting the login flow" { rm -f "$AGENT_KEY" stub_bin sleep 'echo "sleep $*" >> "$CALLS"' stub_bin shellhub-agent call_install enroll_agent_interactively shellhub-agent "$AGENT_KEY" [ "$status" -eq 0 ] [ "$(grep -c '^sleep 1$' "$CALLS")" -eq 30 ] assert_called "shellhub-agent login" } @test "enroll_agent_interactively does not wait when the agent key is already on disk" { stub_bin sleep 'echo "sleep $*" >> "$CALLS"' stub_bin shellhub-agent call_install enroll_agent_interactively shellhub-agent "$AGENT_KEY" [ "$status" -eq 0 ] refute_called "sleep" } @test "enroll_agent_interactively survives a login the user abandons" { stub_bin shellhub-agent 'echo "shellhub-agent $*" >> "$CALLS"; kill -INT "$PPID" "$$"' call_install enroll_agent_interactively shellhub-agent "$AGENT_KEY" [ "$status" -eq 0 ] } @test "enroll_agent_interactively lets Ctrl-C stop the installer again after the login" { stub_bin shellhub-agent 'echo "shellhub-agent $*" >> "$CALLS"; kill -INT "$PPID" "$$"' call_install eval "enroll_agent_interactively shellhub-agent '$AGENT_KEY'; kill -INT \$\$; echo survived" [ "$status" -eq 130 ] refute_output_contains "survived" } @test "enroll_agent_interactively skips the login flow for a provisioning key" { export PROVISIONING_KEY=key-1 stub_bin shellhub-agent call_install enroll_agent_interactively shellhub-agent "$AGENT_KEY" [ "$status" -eq 0 ] refute_called "shellhub-agent" } @test "enroll_agent_interactively skips the login flow for a persisted tenant" { export PERSISTED_TENANT=00000000-0000-4000-0000-000000000000 export PRIVATE_KEY="$AGENT_KEY" stub_bin shellhub-agent call_install enroll_agent_interactively shellhub-agent "$AGENT_KEY" [ "$status" -eq 0 ] refute_called "shellhub-agent" assert_output_contains "remembered at $AGENT_KEY.tenant" } @test "enroll_agent_interactively reports a persisted tenant ahead of a provisioning key" { export PROVISIONING_KEY=key-1 export PRIVATE_KEY="$AGENT_KEY" export PERSISTED_TENANT=00000000-0000-4000-0000-000000000000 call_install enroll_agent_interactively shellhub-agent "$AGENT_KEY" [ "$status" -eq 0 ] assert_output_contains "remembered at $AGENT_KEY.tenant" } @test "enroll_agent_interactively skips the login flow for a tenant" { with_tenant stub_bin shellhub-agent call_install enroll_agent_interactively shellhub-agent "$AGENT_KEY" [ "$status" -eq 0 ] refute_called "shellhub-agent" } @test "observe_enrollment reports a device the server accepted" { stub_bin agent-log 'echo "time=now level=info msg=\"Listening for connections\" status=accepted tenant_id=t"' call_install observe_enrollment agent-log [ "$status" -eq 0 ] assert_output_contains "The device is accepted" refute_output_contains "pending" } @test "observe_enrollment reports a device the server left pending" { stub_bin agent-log 'echo "time=now level=info msg=\"Listening for connections\" status=pending tenant_id=t"' call_install observe_enrollment agent-log [ "$status" -eq 0 ] assert_output_contains "The device is pending: accept it in the console" } @test "observe_enrollment reports a device rejected in the console" { stub_bin agent-log 'echo "time=now level=info msg=\"Listening for connections\" status=rejected tenant_id=t"' call_install observe_enrollment agent-log [ "$status" -eq 1 ] assert_output_contains "the device is rejected" assert_output_contains "A member rejected it in the console. Accept it there to enroll it." refute_output_contains "provisioning key" refute_output_contains "pending" } @test "observe_enrollment names the provisioning key's policy for a rejected device" { export PROVISIONING_KEY=key-1 stub_bin agent-log 'echo "time=now level=info msg=\"Listening for connections\" status=rejected tenant_id=t"' call_install observe_enrollment agent-log [ "$status" -eq 1 ] assert_output_contains "provisioning key's allowlist or webhook refused it" } @test "enroll_agent_interactively names a persisted tenant ahead of the observed outcome" { export PERSISTED_TENANT=00000000-0000-4000-0000-000000000000 export PRIVATE_KEY="$AGENT_KEY" stub_bin agent-log 'echo "time=now level=info msg=\"Listening for connections\" status=accepted tenant_id=t"' call_install enroll_agent_interactively shellhub-agent "$AGENT_KEY" agent-log assert_output_contains "remembered at $AGENT_KEY.tenant" assert_output_contains "The device is accepted" } @test "observe_enrollment does not claim a status the agent did not log" { stub_bin agent-log 'echo "time=now level=info msg=\"Listening for connections\" tenant_id=t"' call_install observe_enrollment agent-log [ "$status" -eq 0 ] assert_output_contains "is listening for connections" assert_output_contains "accepted or still pending" } @test "enroll_agent_interactively does not predict a pending device before a refusal" { with_tenant stub_bin agent-log 'echo "level=fatal msg=\"Failed to authorize the device\" error=\"the server answered 404 Not Found\""' call_install enroll_agent_interactively shellhub-agent "$AGENT_KEY" agent-log assert_output_contains "404 Not Found" refute_output_contains "pending" } @test "refusal_reason prints only the reason a log line carries" { call_install refusal_reason 'time="now" level=warning msg="Cannot authorize the device" attempt=1 error="the server answered 404 Not Found: {\"message\":\"namespace not found\"}" server_address="http://localhost:80"' [ "$status" -eq 0 ] [ "$output" = 'the server answered 404 Not Found: {"message":"namespace not found"}' ] } @test "refusal_reason falls back to the line when it carries no reason" { call_install refusal_reason 'level=warning msg="Cannot authorize the device"' [ "$status" -eq 0 ] [ "$output" = 'level=warning msg="Cannot authorize the device"' ] } @test "observe_enrollment reports the server's refusal" { stub_agent_log <<'LOG' time="now" level=fatal msg="Failed to authorize the device" error="the server answered 404 Not Found: {\"message\":\"namespace not found\"}" server_address="http://localhost:80" LOG call_install observe_enrollment agent-log [ "$status" -eq 1 ] assert_output_contains "The server refused this device" assert_output_contains 'the server answered 404 Not Found: {"message":"namespace not found"}' } @test "observe_enrollment keeps the agent's own bookkeeping out of what it reports" { stub_agent_log <<'LOG' time="now" level=fatal msg="Failed to authorize the device" error="the server answered 404 Not Found" server_address="http://localhost:80" LOG call_install observe_enrollment agent-log assert_output_contains "the server answered 404 Not Found" refute_output_contains "level=fatal" refute_output_contains "server_address" } @test "observe_enrollment reports the settings an agent refused its own configuration over" { stub_agent_log <<'LOG' time="now" level=error msg="SHELLHUB_TENANT_ID must be a UUID" time="now" level=fatal msg="Failed to load the configuration from the environment variables" error="validation failed" LOG call_install observe_enrollment agent-log [ "$status" -eq 1 ] assert_output_contains "refused its own configuration" assert_output_contains "SHELLHUB_TENANT_ID must be a UUID" refute_output_contains "has not enrolled yet" } @test "observe_enrollment names the host path of a persisted tenant the agent refused" { stub_agent_log <<'LOG' time="now" level=error msg="/host/etc/shellhub.key.tenant must be a UUID" time="now" level=fatal msg="Failed to load the configuration from the environment variables" error="invalid structure" LOG call_install observe_enrollment agent-log [ "$status" -eq 1 ] assert_output_contains " /etc/shellhub.key.tenant must be a UUID" refute_output_contains "invalid structure" } @test "observe_enrollment names each refused setting once across agent restarts" { stub_agent_log <<'LOG' time="now" level=error msg="SHELLHUB_TENANT_ID must be a UUID" time="now" level=fatal msg="Failed to load the configuration from the environment variables" error="invalid structure" time="now" level=error msg="SHELLHUB_TENANT_ID must be a UUID" time="now" level=fatal msg="Failed to load the configuration from the environment variables" error="invalid structure" LOG call_install observe_enrollment agent-log [ "$status" -eq 1 ] [ "$(echo "$output" | grep -c 'SHELLHUB_TENANT_ID must be a UUID')" -eq 1 ] } @test "observe_enrollment falls back to the error when a refused configuration names no setting" { stub_agent_log <<'LOG' time="now" level=fatal msg="Failed to load the configuration from the environment variables" error="missing required value: SERVER_ADDRESS" LOG call_install observe_enrollment agent-log [ "$status" -eq 1 ] assert_output_contains "missing required value: SERVER_ADDRESS" refute_output_contains "has not enrolled yet" } @test "observe_enrollment reports an agent still retrying when the window closes" { stub_agent_log <<'LOG' time="now" level=warning msg="Cannot authorize the device, retrying until the server accepts it" attempt=1 error="the server answered 404 Not Found: {\"message\":\"namespace not found\"}" LOG call_install observe_enrollment agent-log [ "$status" -eq 1 ] assert_output_contains "The server is still refusing this device" assert_output_contains 'the server answered 404 Not Found: {"message":"namespace not found"}' refute_output_contains "level=warning" } @test "observe_enrollment names the command to inspect an agent that says nothing" { stub_bin agent-log call_install observe_enrollment agent-log [ "$status" -eq 0 ] assert_output_contains "agent-log" } @test "observe_enrollment does not claim an outcome for a runtime it cannot read" { call_install observe_enrollment "" [ "$status" -eq 0 ] assert_output_contains "does not expose" } @test "enroll_agent_interactively observes the outcome of a provisioning key enrollment" { export PROVISIONING_KEY=key-1 stub_bin agent-log 'echo "level=fatal msg=\"Failed to authorize the device\" error=\"the server answered 404 Not Found\""' call_install enroll_agent_interactively shellhub-agent "$AGENT_KEY" agent-log assert_output_contains "404 Not Found" } @test "enroll_agent_interactively does not claim an outcome it cannot observe" { export PROVISIONING_KEY=key-1 call_install enroll_agent_interactively shellhub-agent "$AGENT_KEY" assert_output_contains "does not expose" } @test "enroll_agent_interactively observes the outcome of a persisted tenant enrollment" { export PERSISTED_TENANT=00000000-0000-4000-0000-000000000000 export PRIVATE_KEY="$AGENT_KEY" stub_bin agent-log 'echo "level=fatal msg=\"Failed to authorize the device\" error=\"the server answered 404 Not Found\""' call_install enroll_agent_interactively shellhub-agent "$AGENT_KEY" agent-log assert_output_contains "remembered at $AGENT_KEY.tenant" assert_output_contains "404 Not Found" } @test "enroll_agent_interactively observes the outcome of a tenant enrollment" { with_tenant stub_bin agent-log 'echo "level=fatal msg=\"Failed to authorize the device\" error=\"the server answered 404 Not Found\""' call_install enroll_agent_interactively shellhub-agent "$AGENT_KEY" agent-log assert_output_contains "404 Not Found" } @test "docker_install runs the container with unless-stopped so it survives a reboot" { container_install [ "$status" -eq 0 ] assert_called "docker run -d --name=shellhub --restart=unless-stopped" } @test "podman_install runs the container with unless-stopped so podman-restart.service picks it up" { use_podman container_install [ "$status" -eq 0 ] assert_called "podman run -d --name=shellhub --replace --restart=unless-stopped" } @test "docker_install grants the agent the host access it needs" { container_install [ "$status" -eq 0 ] assert_called "--privileged --net=host --pid=host" assert_called "-v /:/host" assert_called "-v /var/run/docker.sock:/var/run/docker.sock" assert_called "-v /etc/resolv.conf:/etc/resolv.conf" } @test "podman_install grants the agent the host access it needs" { use_podman container_install [ "$status" -eq 0 ] assert_called "--privileged --pid=host --security-opt label=disable --network host" assert_called "-v /:/host" } @test "podman_install presents the podman socket to the agent as the docker socket" { use_podman container_install [ "$status" -eq 0 ] assert_called "-v /var/run/podman/podman.sock:/var/run/docker.sock" } @test "docker_install labels the agent container so the wrapper can find it" { container_install [ "$status" -eq 0 ] assert_called "--label shellhub.role=agent" assert_output_contains "Starting ShellHub container in Agent mode" } @test "podman_install labels the agent container so the wrapper can find it" { use_podman container_install [ "$status" -eq 0 ] assert_called "--label shellhub.role=agent" } @test "docker_install treats an explicit agent mode as the default mode" { container_install agent [ "$status" -eq 0 ] assert_called "--label shellhub.role=agent" assert_output_contains "Starting ShellHub container in Agent mode" } @test "podman_install treats an explicit agent mode as the default mode" { use_podman container_install agent [ "$status" -eq 0 ] assert_called "--label shellhub.role=agent" } @test "docker_install omits the agent label in connector mode" { with_tenant container_install connector [ "$status" -eq 0 ] refute_called "--label shellhub.role=agent" assert_called "--name=shellhub-connector" assert_called "-e SHELLHUB_PRIVATE_KEYS=/host/etc/shellhub/connector/keys" } @test "podman_install omits the agent label in connector mode" { use_podman with_tenant container_install connector [ "$status" -eq 0 ] refute_called "--label shellhub.role=agent" assert_called "--name=shellhub-connector" assert_called "-e SHELLHUB_PRIVATE_KEYS=/host/etc/shellhub/connector/keys" } @test "docker_install refuses connector mode without a tenant or a provisioning key" { container_install connector [ "$status" -eq 1 ] assert_output_contains "TENANT_ID or PROVISIONING_KEY is required" refute_called "docker run" } @test "podman_install refuses connector mode without a tenant or a provisioning key" { use_podman container_install connector [ "$status" -eq 1 ] assert_output_contains "TENANT_ID or PROVISIONING_KEY is required" refute_called "podman run" } @test "docker_install starts the connector with a provisioning key alone" { export PROVISIONING_KEY=key-1 container_install connector [ "$status" -eq 0 ] assert_called "-e SHELLHUB_PROVISIONING_KEY=key-1" refute_called "SHELLHUB_TENANT_ID" } @test "podman_install starts the connector with a provisioning key alone" { use_podman export PROVISIONING_KEY=key-1 container_install connector [ "$status" -eq 0 ] assert_called "-e SHELLHUB_PROVISIONING_KEY=key-1" refute_called "SHELLHUB_TENANT_ID" } @test "docker_install rejects an unknown mode" { container_install bogus [ "$status" -eq 1 ] assert_output_contains "Invalid mode: bogus" refute_called "docker run" } @test "podman_install rejects an unknown mode" { use_podman container_install bogus [ "$status" -eq 1 ] assert_output_contains "Invalid mode: bogus" refute_called "podman run" } @test "docker_install maps credentials and preferences onto the agent environment" { with_tenant export PROVISIONING_KEY=key-1 KEEPALIVE_INTERVAL=45 export PREFERRED_HOSTNAME=box PREFERRED_IDENTITY=eth0 container_install [ "$status" -eq 0 ] assert_called "-e SHELLHUB_PROVISIONING_KEY=key-1" assert_called "-e SHELLHUB_KEEPALIVE_INTERVAL=45" assert_called "-e SHELLHUB_PREFERRED_HOSTNAME=box" assert_called "-e SHELLHUB_PREFERRED_IDENTITY=eth0" assert_called "-e SHELLHUB_TENANT_ID=$TENANT_ID" assert_called "-e SHELLHUB_SERVER_ADDRESS=$SERVER_ADDRESS" } @test "podman_install maps credentials and preferences onto the agent environment" { use_podman with_tenant export PROVISIONING_KEY=key-1 KEEPALIVE_INTERVAL=45 export PREFERRED_HOSTNAME=box PREFERRED_IDENTITY=eth0 container_install [ "$status" -eq 0 ] assert_called "-e SHELLHUB_PROVISIONING_KEY=key-1" assert_called "-e SHELLHUB_KEEPALIVE_INTERVAL=45" assert_called "-e SHELLHUB_PREFERRED_HOSTNAME=box" assert_called "-e SHELLHUB_PREFERRED_IDENTITY=eth0" assert_called "-e SHELLHUB_TENANT_ID=$TENANT_ID" assert_called "-e SHELLHUB_SERVER_ADDRESS=$SERVER_ADDRESS" } @test "docker_install omits environment variables for options left unset" { container_install [ "$status" -eq 0 ] refute_called "SHELLHUB_TENANT_ID" refute_called "SHELLHUB_PROVISIONING_KEY" refute_called "SHELLHUB_KEEPALIVE_INTERVAL" refute_called "SHELLHUB_PREFERRED_" assert_called "-e SHELLHUB_PRIVATE_KEY=$PRIVATE_KEY" } @test "podman_install omits environment variables for options left unset" { use_podman container_install [ "$status" -eq 0 ] refute_called "SHELLHUB_TENANT_ID" refute_called "SHELLHUB_PROVISIONING_KEY" refute_called "SHELLHUB_KEEPALIVE_INTERVAL" refute_called "SHELLHUB_PREFERRED_" assert_called "-e SHELLHUB_PRIVATE_KEY=$PRIVATE_KEY" } @test "docker_install pulls the agent image by default" { container_install [ "$status" -eq 0 ] assert_called "docker pull -q $AGENT_IMAGE" assert_output_contains "Downloading ShellHub container image" } @test "podman_install pulls the agent image by default" { use_podman container_install [ "$status" -eq 0 ] assert_called "podman pull -q $AGENT_IMAGE" assert_output_contains "Downloading ShellHub container image" } @test "docker_install skips the pull when the image was overridden" { export AGENT_IMAGE_OVERRIDDEN=1 container_install [ "$status" -eq 0 ] refute_called "docker pull" assert_output_contains "skipping pull" } @test "podman_install skips the pull when the image was overridden" { use_podman export AGENT_IMAGE_OVERRIDDEN=1 container_install [ "$status" -eq 0 ] refute_called "podman pull" assert_output_contains "skipping pull" } @test "docker_install aborts when the image pull fails" { stub_bin docker 'echo "docker $*" >> "$CALLS"; [ "$1" = pull ] && exit 1; exit 0' container_install [ "$status" -eq 1 ] assert_output_contains "Failed to download shellhub container image" refute_called "docker run" } @test "podman_install aborts when the image pull fails" { use_podman stub_bin podman 'echo "podman $*" >> "$CALLS"; [ "$1" = pull ] && exit 1; exit 0' container_install [ "$status" -eq 1 ] assert_output_contains "Failed to download shellhub container image" refute_called "podman run" } @test "docker_install honours CONTAINER_NAME" { export CONTAINER_NAME=my-agent container_install [ "$status" -eq 0 ] assert_called "--name=my-agent" assert_called "docker rm -f my-agent" } @test "podman_install honours CONTAINER_NAME" { use_podman export CONTAINER_NAME=my-agent container_install [ "$status" -eq 0 ] assert_called "--name=my-agent" } @test "docker_install removes an existing container so the new one carries the role label" { container_install [ "$status" -eq 0 ] assert_called "docker rm -f shellhub" } @test "podman_install checks the boot restart unit before touching podman" { RUNTIME=podman container_install [ "$status" -eq 1 ] assert_output_contains "systemctl not found" refute_called "podman" } @test "install_agent_wrapper writes an executable wrapper bound to podman" { call_install install_agent_wrapper podman [ "$status" -eq 0 ] [ -x "$INSTALL_DIR/shellhub-agent" ] assert_output_contains "Installed shellhub-agent wrapper at $INSTALL_DIR/shellhub-agent" assert_file_contains "$INSTALL_DIR/shellhub-agent" "podman ps --filter label=shellhub.role=agent" assert_file_contains "$INSTALL_DIR/shellhub-agent" "podman exec" refute_file_contains "$INSTALL_DIR/shellhub-agent" "docker exec" } @test "install_agent_wrapper writes an executable wrapper bound to docker" { call_install install_agent_wrapper docker [ "$status" -eq 0 ] [ -x "$INSTALL_DIR/shellhub-agent" ] assert_file_contains "$INSTALL_DIR/shellhub-agent" "docker ps --filter label=shellhub.role=agent" assert_file_contains "$INSTALL_DIR/shellhub-agent" "docker exec" refute_file_contains "$INSTALL_DIR/shellhub-agent" "podman exec" } @test "install_agent_wrapper escalates to write into a root-owned directory" { as_non_root call_install install_agent_wrapper docker [ "$status" -eq 0 ] assert_called "sudo tee $INSTALL_DIR/shellhub-agent" assert_called "sudo chmod +x $INSTALL_DIR/shellhub-agent" } @test "install_agent_wrapper aborts when the install directory does not exist" { export INSTALL_DIR="$BATS_TEST_TMPDIR/absent" call_install install_agent_wrapper docker [ "$status" -eq 1 ] assert_output_contains "Failed to install shellhub-agent wrapper" } @test "snap_install requires a tenant" { stub_bin snap call_install snap_install [ "$status" -eq 1 ] assert_output_contains "TENANT_ID is required" refute_called "snap install" } @test "snap_install refuses a provisioning key it cannot honour" { with_tenant export PROVISIONING_KEY=key-1 stub_bin snap call_install snap_install [ "$status" -eq 1 ] assert_output_contains "PROVISIONING_KEY is not supported by the snap install method" refute_called "snap install" } @test "snap_install aborts when snap is not available" { with_tenant call_install snap_install [ "$status" -eq 1 ] assert_output_contains "Snap is not installed or not supported on this system" } @test "snap_install configures the service from the environment" { with_tenant export PREFERRED_HOSTNAME=box KEEPALIVE_INTERVAL=45 stub_bin snap stub_sudo call_install snap_install [ "$status" -eq 0 ] assert_called "snap install --classic --channel=latest/stable shellhub" assert_called "snap set shellhub server-address=$SERVER_ADDRESS" assert_called "snap set shellhub tenant-id=$TENANT_ID" assert_called "snap set shellhub preferred-hostname=box" assert_called "snap set shellhub keepalive-interval=45" assert_called "snap start shellhub" } @test "standalone_install passes the credentials on to the agent service" { with_tenant export PROVISIONING_KEY=key-1 KEEPALIVE_INTERVAL=45 fake_agent_binary call_install standalone_install [ "$status" -eq 0 ] assert_called "agent install --server-address=$SERVER_ADDRESS --tenant-id=$TENANT_ID --provisioning-key=key-1 --keepalive-interval=45" [ -x "$INSTALL_DIR/shellhub-agent" ] } @test "standalone_install reads only the journal of the service it started" { with_tenant fake_agent_binary stub_bin date 'echo 1700000000' stub_bin journalctl call_install standalone_install [ "$status" -eq 0 ] assert_called "journalctl -u shellhub-agent --no-pager -n 50 --since @1700000000" } @test "standalone_install escalates when it is not already root" { with_tenant as_non_root fake_agent_binary call_install standalone_install [ "$status" -eq 0 ] assert_output_contains "This install method requires root privileges" assert_called "sudo $INSTALL_DIR/shellhub-agent install" } @test "standalone_install removes the binary when the service install fails" { with_tenant fake_agent_binary 1 call_install standalone_install [ "$status" -eq 1 ] assert_output_contains "Failed to install ShellHub agent service" [ ! -e "$INSTALL_DIR/shellhub-agent" ] [ ! -e "$TMP_DIR" ] } @test "standalone_install starts the agent it stopped again when the service install fails" { with_tenant fake_agent_binary 1 local stopped="$BATS_TEST_TMPDIR/old-agent-stopped" stub_bin systemctl "echo \"systemctl \$*\" >> \"\$CALLS\" case \"\$1\" in stop) : > '$stopped' ;; is-active) [ ! -e '$stopped' ] ;; esac" call_install standalone_install [ "$status" -eq 1 ] assert_called "systemctl enable --now shellhub-agent" [ -x "$INSTALL_DIR/shellhub-agent" ] } @test "standalone_install leaves the running agent alone when the new binary cannot run its installer" { with_tenant export AGENT_BINARY="$BATS_TEST_TMPDIR/foreign-agent" printf '#!/bin/sh\n[ "$1" = --help ] && exit 0\nexit 1\n' > "$AGENT_BINARY" chmod +x "$AGENT_BINARY" mkdir -p "$INSTALL_DIR" echo "old agent" > "$INSTALL_DIR/shellhub-agent" stub_bin systemctl 'echo "systemctl $*" >> "$CALLS"; exit 0' call_install standalone_install [ "$status" -eq 1 ] assert_output_contains "cannot run its installer" refute_called "systemctl stop" [ "$(cat "$INSTALL_DIR/shellhub-agent")" = "old agent" ] [ ! -e "$INSTALL_DIR/shellhub-agent.new" ] } @test "standalone_install reports a local binary it cannot copy" { with_tenant fake_agent_binary mkdir -p "$INSTALL_DIR" cp "$AGENT_BINARY" "$INSTALL_DIR/shellhub-agent.new" export AGENT_BINARY="$BATS_TEST_TMPDIR/missing-agent" call_install standalone_install [ "$status" -eq 1 ] assert_output_contains "Could not copy $AGENT_BINARY" [ ! -e "$INSTALL_DIR/shellhub-agent" ] [ ! -e "$INSTALL_DIR/shellhub-agent.new" ] [ ! -e "$TMP_DIR" ] } @test "standalone_install reports a release binary it cannot extract" { with_tenant serve_release echo "not gzip" > "$RELEASE_DIR/shellhub-agent-linux-amd64.gz" (cd "$RELEASE_DIR" && sha256sum shellhub-agent-linux-amd64.gz > checksums.txt) call_install standalone_install [ "$status" -eq 1 ] assert_output_contains "Failed to extract the agent binary" refute_output_contains "Could not replace" [ ! -e "$INSTALL_DIR/shellhub-agent" ] [ ! -e "$TMP_DIR" ] } @test "standalone_install installs the agent binary that matches the release checksum" { with_tenant serve_release call_install standalone_install [ "$status" -eq 0 ] assert_called "https://github.com/shellhub-io/shellhub/releases/download/v0.0.0-test/shellhub-agent-linux-amd64.gz" assert_called "https://github.com/shellhub-io/shellhub/releases/download/v0.0.0-test/checksums.txt" assert_installed_release_binary } @test "standalone_install installs the agent binary that matches the release checksum with wget" { with_tenant serve_release wget call_install standalone_install [ "$status" -eq 0 ] assert_called "wget" assert_called "https://github.com/shellhub-io/shellhub/releases/download/v0.0.0-test/checksums.txt" assert_installed_release_binary } @test "standalone_install refuses an agent binary that does not match the release checksum" { with_tenant for tool in curl wget; do echo "downloading with $tool" rm -f "$STUB_DIR/curl" "$STUB_DIR/wget" mkdir -p "$TMP_DIR" serve_release "$tool" printf '#!/bin/sh\necho "tampered $*" >> "$CALLS"\n' | gzip > "$RELEASE_DIR/shellhub-agent-linux-amd64.gz" call_install standalone_install [ "$status" -eq 1 ] assert_called "$tool" assert_output_contains "does not match the checksum published with release v0.0.0-test" refute_called "tampered" [ ! -e "$INSTALL_DIR/shellhub-agent" ] done } @test "standalone_install refuses a release whose checksums do not list the agent binary" { with_tenant serve_release sed -i 's/linux-amd64/linux-arm64/' "$RELEASE_DIR/checksums.txt" call_install standalone_install [ "$status" -eq 1 ] assert_output_contains "does not match the checksum published with release v0.0.0-test" refute_called "agent install" [ ! -e "$INSTALL_DIR/shellhub-agent" ] } @test "standalone_install refuses a release whose checksums it cannot download" { with_tenant serve_release rm "$RELEASE_DIR/checksums.txt" call_install standalone_install [ "$status" -eq 1 ] assert_output_contains "Could not download the checksums published with release v0.0.0-test" refute_called "agent install" [ ! -e "$INSTALL_DIR/shellhub-agent" ] } @test "docker_uninstall removes the container and the wrapper" { stub_bin docker 'echo "docker $*" >> "$CALLS"; [ "$1" = ps ] && echo deadbeef; exit 0' call_install install_agent_wrapper docker call_install docker_uninstall [ "$status" -eq 0 ] assert_called "docker rm -f shellhub" [ ! -e "$INSTALL_DIR/shellhub-agent" ] } @test "docker_uninstall escalates when it is not already root" { stub_bin docker 'echo "docker $*" >> "$CALLS"; [ "$1" = ps ] && echo deadbeef; exit 0' call_install install_agent_wrapper docker as_non_root call_install docker_uninstall [ "$status" -eq 0 ] assert_called "sudo docker rm -f shellhub" assert_called "sudo rm -f $INSTALL_DIR/shellhub-agent" } @test "podman_uninstall removes the container and the wrapper" { stub_bin podman 'echo "podman $*" >> "$CALLS"; [ "$1" = ps ] && echo deadbeef; exit 0' call_install install_agent_wrapper podman call_install podman_uninstall [ "$status" -eq 0 ] assert_called "podman rm -f shellhub" [ ! -e "$INSTALL_DIR/shellhub-agent" ] } @test "podman_uninstall escalates when it is not already root" { stub_bin podman 'echo "podman $*" >> "$CALLS"; [ "$1" = ps ] && echo deadbeef; exit 0' call_install install_agent_wrapper podman as_non_root call_install podman_uninstall [ "$status" -eq 0 ] assert_called "sudo podman rm -f shellhub" assert_called "sudo rm -f $INSTALL_DIR/shellhub-agent" } @test "docker_uninstall reports a container that was already gone" { stub_bin docker call_install docker_uninstall [ "$status" -eq 0 ] assert_output_contains "not found (may already be removed)" refute_called "docker rm -f" } @test "docker_uninstall aborts when the container cannot be removed" { stub_bin docker 'echo "docker $*" >> "$CALLS"; [ "$1" = ps ] && echo deadbeef; [ "$1" != rm ]' call_install docker_uninstall [ "$status" -eq 1 ] assert_output_contains "Failed to remove container 'shellhub'" refute_output_contains "uninstalled" } @test "podman_uninstall aborts when the container cannot be removed" { stub_bin podman 'echo "podman $*" >> "$CALLS"; [ "$1" = ps ] && echo deadbeef; [ "$1" != rm ]' call_install podman_uninstall [ "$status" -eq 1 ] assert_output_contains "Failed to remove container 'shellhub'" refute_output_contains "uninstalled" } @test "docker_uninstall aborts when it cannot list containers" { stub_bin docker 'echo "docker $*" >> "$CALLS"; [ "$1" != ps ]' call_install docker_uninstall [ "$status" -eq 1 ] assert_output_contains "Failed to look up container 'shellhub'" refute_output_contains "not found" refute_output_contains "uninstalled" } @test "podman_uninstall aborts when it cannot list containers" { stub_bin podman 'echo "podman $*" >> "$CALLS"; [ "$1" != ps ]' call_install podman_uninstall [ "$status" -eq 1 ] assert_output_contains "Failed to look up container 'shellhub'" refute_output_contains "not found" refute_output_contains "uninstalled" } @test "podman_uninstall reports a container that was already gone" { stub_bin podman call_install podman_uninstall [ "$status" -eq 0 ] assert_output_contains "not found (may already be removed)" refute_called "podman rm -f" } @test "uninstall names the tenant file it leaves behind" { export PRIVATE_KEY="$BATS_TEST_TMPDIR/shellhub.key" echo "00000000-0000-4000-0000-000000000000" > "$PRIVATE_KEY.tenant" stub_bin docker call_install docker_uninstall assert_output_contains "$PRIVATE_KEY.tenant" } @test "uninstall names the tenant file a container install left behind under /host" { export PRIVATE_KEY="/host$BATS_TEST_TMPDIR/shellhub.key" echo "00000000-0000-4000-0000-000000000000" > "$BATS_TEST_TMPDIR/shellhub.key.tenant" stub_bin docker call_install docker_uninstall assert_output_contains "$BATS_TEST_TMPDIR/shellhub.key.tenant" [[ "$output" != *"/host$BATS_TEST_TMPDIR"* ]] } @test "podman_uninstall names the tenant file it leaves behind" { export PRIVATE_KEY="$BATS_TEST_TMPDIR/shellhub.key" echo "00000000-0000-4000-0000-000000000000" > "$PRIVATE_KEY.tenant" stub_bin podman call_install podman_uninstall assert_output_contains "$PRIVATE_KEY.tenant" } @test "standalone_uninstall names the tenant file it leaves behind" { export PRIVATE_KEY="$BATS_TEST_TMPDIR/shellhub.key" echo "00000000-0000-4000-0000-000000000000" > "$PRIVATE_KEY.tenant" fake_agent_binary cp "$AGENT_BINARY" "$INSTALL_DIR/shellhub-agent" call_install standalone_uninstall assert_output_contains "$PRIVATE_KEY.tenant" } @test "uninstall names a tenant file it cannot read a tenant from" { export PRIVATE_KEY="$BATS_TEST_TMPDIR/shellhub.key" : > "$PRIVATE_KEY.tenant" stub_bin docker call_install docker_uninstall [ "$status" -eq 0 ] assert_output_contains "remembered in $PRIVATE_KEY.tenant" } @test "uninstall stays quiet about a tenant file that is not there" { export PRIVATE_KEY="$BATS_TEST_TMPDIR/shellhub.key" stub_bin docker call_install docker_uninstall [ "$status" -eq 0 ] assert_output_contains "ShellHub agent uninstalled." refute_output_contains ".tenant" } @test "standalone_uninstall reports a missing binary" { call_install standalone_uninstall [ "$status" -eq 1 ] assert_output_contains "ShellHub agent binary not found" } @test "standalone_uninstall looks in the default install dir when the environment names none" { unset INSTALL_DIR call_install standalone_uninstall [ "$status" -eq 1 ] assert_output_contains "/usr/local/bin/shellhub-agent" } @test "standalone_uninstall stops the service and removes the binary" { with_tenant fake_agent_binary call_install standalone_install call_install standalone_uninstall [ "$status" -eq 0 ] assert_called "agent uninstall" [ ! -e "$INSTALL_DIR/shellhub-agent" ] } @test "wsl_install aborts when systemd is not enabled" { stub_bin systemctl 'exit 1' call_install wsl_install [ "$status" -eq 1 ] assert_output_contains "requires systemd to be enabled" } @test "wsl_install aborts when WSL networking is not mirrored" { stub_bin systemctl 'exit 0' stub_bin wslinfo 'echo nat' call_install wsl_install [ "$status" -eq 1 ] assert_output_contains "networking mode must be set to mirrored" } @test "wsl_install falls through to the standalone install once both preconditions hold" { with_tenant stub_bin systemctl 'exit 0' stub_bin wslinfo 'echo mirrored' fake_agent_binary call_install wsl_install [ "$status" -eq 0 ] assert_called "agent install --server-address=$SERVER_ADDRESS" } @test "the installer aborts on FreeBSD" { stub_bin uname 'echo FreeBSD' run_install [ "$status" -eq 1 ] assert_output_contains "Automatic installation is not supported on FreeBSD" } @test "detection prefers docker when it is accessible" { stub_runtime docker stub_runtime podman run_install [ "$status" -eq 0 ] assert_output_contains "Installing ShellHub using docker method" assert_called "docker run -d" refute_called "podman run" } @test "detection falls back to podman when docker is absent" { stub_runtime podman stub_bin systemctl 'exit 0' run_install [ "$status" -eq 0 ] assert_output_contains "Installing ShellHub using podman method" assert_called "podman run -d" } @test "detection retries docker with sudo when it is only reachable as root" { unset AGENT_IMAGE stub_runtime docker '[ -z "$RAN_UNDER_SUDO" ] && exit 1' stub_sudo run_install [ "$status" -eq 0 ] assert_called "sudo docker info" assert_called "sudo docker pull -q docker.io/shellhubio/agent:$AGENT_VERSION" assert_called "sudo docker run -d" assert_called "sudo $INSTALL_DIR/shellhub-agent login" } @test "detection retries podman with sudo when it is only reachable as root" { unset AGENT_IMAGE stub_runtime podman '[ -z "$RAN_UNDER_SUDO" ] && exit 1' stub_bin systemctl 'exit 0' stub_sudo run_install [ "$status" -eq 0 ] assert_called "sudo podman info" assert_called "sudo podman pull -q docker.io/shellhubio/agent:$AGENT_VERSION" assert_called "sudo podman run -d" assert_called "sudo $INSTALL_DIR/shellhub-agent login" } @test "detection falls back to snap when no container runtime is available" { with_tenant stub_bin snap stub_sudo run_install [ "$status" -eq 0 ] assert_output_contains "Installing ShellHub using snap method" assert_called "snap install --classic --channel=latest/stable shellhub" } @test "detection falls back to the standalone install when nothing else is available" { fake_agent_binary run_install [ "$status" -eq 0 ] assert_output_contains "Installing ShellHub using standalone method" assert_called "agent install --server-address=$SERVER_ADDRESS" } @test "an explicit INSTALL_METHOD skips detection entirely" { export INSTALL_METHOD=standalone stub_bin docker fake_agent_binary run_install [ "$status" -eq 0 ] assert_output_contains "Installing ShellHub using standalone method" refute_called "docker info" } @test "an unsupported INSTALL_METHOD is rejected" { export INSTALL_METHOD=bogus run_install [ "$status" -eq 1 ] assert_output_contains "Install method not supported" } @test "detection reports WSL 2 on Ubuntu" { enter_wsl stub_bin systemctl 'exit 0' stub_bin wslinfo 'echo mirrored' fake_agent_binary run_install [ "$status" -eq 0 ] assert_output_contains "Detected WSL environment" assert_output_contains "Installing ShellHub using WSL method" assert_called "agent install --server-address=$SERVER_ADDRESS" } @test "detection aborts on WSL 1" { enter_wsl 4.4.0-19041-Microsoft run_install [ "$status" -eq 1 ] assert_output_contains "WSL version 2 is required" } @test "detection aborts on the 2016 WSL 1 kernel release" { enter_wsl 3.4.0-Microsoft run_install [ "$status" -eq 1 ] assert_output_contains "WSL version 2 is required" } @test "detection lets a non-WSL-1 kernel release through once /proc/version names Microsoft" { enter_wsl 6.1.0-custom-WSL2 stub_bin systemctl 'exit 0' stub_bin wslinfo 'echo mirrored' fake_agent_binary run_install [ "$status" -eq 0 ] assert_output_contains "Installing ShellHub using WSL method" } @test "detection aborts on WSL with a distro other than Ubuntu" { enter_wsl echo 'NAME="Debian GNU/Linux"' > "$OS_RELEASE" run_install [ "$status" -eq 1 ] assert_output_contains "Only Ubuntu is supported in WSL" } @test "WSL detection overrides an explicit INSTALL_METHOD, so a chosen method does not survive WSL" { export INSTALL_METHOD=standalone enter_wsl stub_bin systemctl 'exit 0' stub_bin wslinfo 'echo mirrored' fake_agent_binary run_install [ "$status" -eq 0 ] assert_output_contains "Installing ShellHub using WSL method" } @test "the installer reports the enrollment credential before installing anything" { with_tenant stub_bin docker run_install [ "$status" -eq 0 ] assert_output_contains "Enrollment: tenant $TENANT_ID" } @test "the installer discovers the agent version from the server" { discover_version v0.27.0-rc.17 unset AGENT_IMAGE stub_runtime docker run_install [ "$status" -eq 0 ] assert_called "docker pull -q docker.io/shellhubio/agent:v0.27.0-rc.17" } @test "the installer refuses a server whose certificate it cannot verify" { discover_version v0.27.0-rc.17 stub_bin curl "echo \"curl \$*\" >> \"\$CALLS\"; for a; do case \"\$a\" in --insecure|-k*|-[!-]*k*) cat '$BATS_TEST_TMPDIR/info'; exit 0 ;; esac; done; exit 60" unset AGENT_IMAGE stub_bin docker run_install [ "$status" -eq 1 ] assert_output_contains "did not report an agent version" assert_output_contains "trust the certificate" refute_called "docker pull" } @test "the installer refuses a server version that points the download at another repository" { discover_version "../../../../audit-owner/audit-repo/releases/download/v1" export INSTALL_METHOD=standalone run_install [ "$status" -eq 1 ] assert_output_contains "not a ShellHub release tag" refute_called "releases/download" } @test "the installer refuses a server version that is not a valid image tag" { discover_version 'v0.27.0$(id)' unset AGENT_IMAGE stub_bin docker run_install [ "$status" -eq 1 ] assert_output_contains "not a ShellHub release tag" refute_called "docker pull" } @test "the installer refuses an agent version that is not a release tag" { export INSTALL_METHOD=standalone stub_bin curl for version in "" "v1.2" "v0.27.0/../../x" $'v0.27.0\nv0.27.1' 'v0.27.0$(id)' "v0.27.0 x"; do echo "AGENT_VERSION=$version" AGENT_VERSION="$version" run_install [ "$status" -eq 1 ] if [ -z "$version" ]; then assert_output_contains "did not report an agent version" else assert_output_contains "not a ShellHub release tag" refute_output_contains "certificate" fi done refute_called "releases/download" } @test "the installer accepts latest as the agent version" { export AGENT_VERSION=latest unset AGENT_IMAGE stub_runtime docker run_install [ "$status" -eq 0 ] assert_called "docker pull -q docker.io/shellhubio/agent:latest" } @test "the installer needs no server version when the agent image is given" { discover_version "" stub_runtime docker run_install [ "$status" -eq 0 ] assert_called "docker run -d" } @test "the installer needs no server version when the agent binary is given" { discover_version "" export INSTALL_METHOD=standalone fake_agent_binary run_install [ "$status" -eq 0 ] assert_called "agent install --server-address=$SERVER_ADDRESS" } @test "uninstall does not depend on the server reporting a release version" { discover_version "not a version" stub_bin docker 'echo "docker $*" >> "$CALLS"; [ "$1" = ps ] && echo deadbeef; exit 0' run_install uninstall [ "$status" -eq 0 ] assert_called "docker rm -f shellhub" } @test "the installer reports a tenant a previous enrollment left behind" { echo "00000000-0000-4000-0000-000000000000" > "$AGENT_KEY.tenant" stub_bin docker run_install [ "$status" -eq 0 ] assert_output_contains "Enrollment: tenant 00000000-0000-4000-0000-000000000000 (persisted by a previous enrollment)" } @test "the installer prefers a tenant given to this run over the persisted one" { with_tenant echo "00000000-0000-4000-0000-000000000000" > "$AGENT_KEY.tenant" stub_bin docker run_install [ "$status" -eq 0 ] assert_output_contains "Enrollment: tenant $TENANT_ID" refute_output_contains "remembered at" } @test "the installer fails when the server refuses a device installed with docker" { with_tenant stub_agent_log <<'LOG' time="now" level=fatal msg="Failed to authorize the device" error="the server answered 404 Not Found" LOG stub_container_logs docker run_install [ "$status" -eq 1 ] assert_output_contains "The server refused this device" assert_called "docker run -d" } @test "the installer succeeds when docker leaves the device pending" { with_tenant stub_agent_log <<'LOG' time="now" level=info msg="Listening for connections" status=pending tenant_id=t LOG stub_container_logs docker run_install [ "$status" -eq 0 ] assert_output_contains "The device is pending" } @test "the installer fails when the login flow fails" { stub_runtime docker '[ "$1" = exec ] && exit 2' run_install [ "$status" -eq 1 ] assert_called "docker exec shellhub agent login" } @test "the installer fails when docker cannot start the agent container" { with_tenant stub_runtime docker '[ "$1" = run ] && exit 1' run_install [ "$status" -eq 1 ] assert_output_contains "Failed to start the ShellHub container" } @test "the installer fails when podman cannot start the agent container" { with_tenant use_podman stub_runtime podman '[ "$1" = run ] && exit 1' run_install [ "$status" -eq 1 ] assert_output_contains "Failed to start the ShellHub container" } @test "the installer fails when the server refuses a device installed with podman" { with_tenant use_podman stub_agent_log <<'LOG' time="now" level=fatal msg="Failed to authorize the device" error="the server answered 404 Not Found" LOG stub_container_logs podman run_install [ "$status" -eq 1 ] assert_output_contains "The server refused this device" assert_called "podman run -d" } @test "the installer fails and still cleans up when the server refuses a standalone device" { with_tenant export INSTALL_METHOD=standalone fake_agent_binary stub_agent_log <<'LOG' time="now" level=fatal msg="Failed to authorize the device" error="the server answered 404 Not Found" LOG stub_journal run_install [ "$status" -eq 1 ] assert_output_contains "The server refused this device" [ -x "$INSTALL_DIR/shellhub-agent" ] [ ! -e "$TMP_DIR" ] } @test "the installer ignores what the agent it replaced logged before a standalone reinstall" { with_tenant export INSTALL_METHOD=standalone fake_agent_binary local stopped="$BATS_TEST_TMPDIR/old-agent-stopped" polls="$BATS_TEST_TMPDIR/journal-polls" stub_bin systemctl "[ \"\$1\" = stop ] && : > '$stopped'; exit 0" stub_bin sleep "[ -e '$stopped' ] && : > '$stopped.slept'; exit 0" stub_bin date "[ -e '$stopped.slept' ] && echo 1700000001 || echo 1700000000" stub_bin journalctl "echo >> '$polls' case \"\$*\" in *'--since @1700000000'*) echo 'level=fatal msg=\"Failed to authorize the device\" error=\"the server answered 404 Not Found\"' ;; esac [ \$(wc -l < '$polls') -gt 1 ] && echo 'level=info msg=\"Listening for connections\" status=accepted tenant_id=t' exit 0" run_install [ "$status" -eq 0 ] assert_output_contains "The device is accepted" refute_output_contains "The server refused this device" } @test "the installer succeeds when a standalone device is accepted" { with_tenant export INSTALL_METHOD=standalone fake_agent_binary stub_agent_log <<'LOG' time="now" level=info msg="Listening for connections" status=accepted tenant_id=t LOG stub_journal run_install [ "$status" -eq 0 ] assert_output_contains "The device is accepted" } @test "uninstall dispatches to the detected method" { stub_bin docker 'echo "docker $*" >> "$CALLS"; [ "$1" = ps ] && echo deadbeef; exit 0' run_install uninstall [ "$status" -eq 0 ] assert_output_contains "Uninstalling ShellHub using docker method" assert_called "docker rm -f shellhub" } @test "uninstall does no installer work before removing the agent" { stub_bin docker stub_bin curl 'echo "curl $*" >> "$CALLS"' stub_bin wget 'echo "wget $*" >> "$CALLS"' run_install uninstall [ "$status" -eq 0 ] refute_called "curl" refute_called "wget" [[ "$output" != *"Detected settings"* ]] [[ "$output" != *"ShellHub Agent Installer"* ]] } @test "uninstall is refused for install methods that do not support it" { export INSTALL_METHOD=snap run_install uninstall [ "$status" -eq 1 ] assert_output_contains "Uninstall is not yet supported for 'snap' install method" }