diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..7515fad --- /dev/null +++ b/.gitattributes @@ -0,0 +1,4 @@ +*.sh text eol=lf +*.md text eol=lf +*.yml text eol=lf +*.yaml text eol=lf diff --git a/.github/workflows/shell-tests.yml b/.github/workflows/shell-tests.yml new file mode 100644 index 0000000..1bb25ac --- /dev/null +++ b/.github/workflows/shell-tests.yml @@ -0,0 +1,18 @@ +name: Shell tests + +on: + push: + pull_request: + +permissions: + contents: read + +jobs: + shell-tests: + runs-on: ubuntu-latest + timeout-minutes: 5 + steps: + - uses: actions/checkout@v7 + - run: | + bash -n browser.sh tests/browser_test.sh + bash tests/browser_test.sh diff --git a/README.md b/README.md index 0885edf..6a18813 100644 --- a/README.md +++ b/README.md @@ -12,28 +12,32 @@ It keeps an interactive menu for installing, uninstalling, checking status, and - Interactive Bash menu for install, uninstall, status, and exit. - Chromium and Firefox containers from linuxserver.io. -- Chromium HTTP on `3000` and HTTPS on `3001`. -- Firefox HTTP on `4000` and HTTPS on `4001`. +- Chromium HTTPS on `3001`; HTTP on `3000` is for a reverse proxy only. +- Firefox HTTPS on `4001`; HTTP on `4000` is for a reverse proxy only. - Persistent config in `/opt/instant-linux-browser//config`. - Username/password prompts, with `ILB_USERNAME` and `ILB_PASSWORD` overrides. - Supports amd64/x86_64 and arm64/aarch64 Linux servers when the upstream image supports them. -- Works when downloaded first or when run through `curl | sudo bash`. +- Keeps the one-command interactive installer and direct actions for automation. ## Install Use only `raw.githubusercontent.com` URLs for curl commands. Do not use normal GitHub page URLs such as `github.com/.../blob/...`, because those return an HTML page, not the raw Bash script. -### Interactive +### One-command interactive installer ```bash -curl -fsSLO https://raw.githubusercontent.com/Mammad3861/Instant-Linux-Browser/main/browser.sh -sudo bash browser.sh +curl -fsSL https://raw.githubusercontent.com/Mammad3861/Instant-Linux-Browser/main/browser.sh | sudo bash ``` -### One-line interactive +The script reads menu choices and credentials from your controlling terminal, so this remains interactive even though the script is streamed through standard input. + +Use the HTTPS browser URL shown after installation. The HTTP URL is for a reverse proxy only. + +### Download first ```bash -curl -fsSL https://raw.githubusercontent.com/Mammad3861/Instant-Linux-Browser/main/browser.sh | sudo bash +curl -fsSLO https://raw.githubusercontent.com/Mammad3861/Instant-Linux-Browser/main/browser.sh +sudo bash browser.sh ``` ### Non-interactive Chromium @@ -61,14 +65,14 @@ sudo bash browser.sh install-chromium sudo bash browser.sh install-firefox sudo bash browser.sh uninstall-chromium sudo bash browser.sh uninstall-firefox -sudo bash browser.sh status +sudo bash browser.sh diagnostics ``` Environment action form: ```bash sudo ILB_ACTION=install-chromium bash browser.sh -sudo ILB_ACTION=status bash browser.sh +sudo ILB_ACTION=diagnostics bash browser.sh ``` ## Menu Options @@ -77,18 +81,20 @@ sudo ILB_ACTION=status bash browser.sh - `2` - Uninstall Chromium - `3` - Install Firefox - `4` - Uninstall Firefox -- `5` - Show status/diagnostics +- `5` - Diagnostics - `6` - Exit -## Chromium Startup Flags +## Chromium Compatibility Chromium is launched with these flags by default: ```text ---no-sandbox --disable-gpu --disable-software-rasterizer --disable-dev-shm-usage --disable-setuid-sandbox +--no-sandbox --disable-gpu --disable-dev-shm-usage --disable-setuid-sandbox ``` -The script passes them to the linuxserver/chromium container through both `CHROME_CLI` and `CHROME_FLAGS`. +The script passes these flags through `CHROME_CLI` and retains `CHROME_FLAGS` for older setups. It also sets `PIXELFLUX_WAYLAND=false` to use the compatible X11 path on headless VPS servers. + +Chromium startup waits briefly for both the container and Chromium process. If either fails, the installer prints recent logs and focused Docker commands for diagnosis. To override them: @@ -107,7 +113,9 @@ Before starting a browser, the script: - pulls the selected Docker image; - creates the persistent config directory; - starts the container; -- verifies that the container is still running. +- verifies that the container is running and, for Chromium, that its process exists. + +`diagnostics` is read-only: it reports Docker state when available and never installs Docker or starts its daemon. If startup fails, check logs: @@ -132,9 +140,10 @@ Delete those directories manually only if you no longer need the browser profile If exposing the browser to the public internet: - use a strong password; -- restrict access with a firewall, VPN, or IP allow-list; -- consider putting it behind Nginx, Traefik, or another HTTPS reverse proxy; -- avoid exposing ports `3000`, `3001`, `4000`, or `4001` publicly unless needed. +- do not expose HTTP port `3000` directly; use it behind a reverse proxy; +- treat `CUSTOM_USER` and `PASSWORD` as basic protection for a trusted local network, not sufficient public Internet protection; +- use HTTPS and a reverse proxy with robust authentication for public exposure; +- restrict access with a firewall, VPN, or IP allow-list. Empty passwords are allowed, but the script warns when one is selected. diff --git a/browser.sh b/browser.sh index 95a4a25..36cbdc9 100644 --- a/browser.sh +++ b/browser.sh @@ -3,7 +3,7 @@ # ========================================================== # Project: Instant Linux Browser (Docker-based) # Author: Mammad3861 -# Version: 1.2.1 - Stable menu/curl dispatch + Docker reliability fixes +# Version: 1.2.2 - Chromium compatibility and startup checks # Description: Deploy web-accessible Chromium and Firefox containers. # ========================================================== @@ -17,26 +17,24 @@ YELLOW='\033[1;33m' NC='\033[0m' CONFIG_BASE="${CONFIG_BASE:-/opt/instant-linux-browser}" -CHROMIUM_FLAGS="${CHROMIUM_FLAGS:---no-sandbox --disable-gpu --disable-software-rasterizer --disable-dev-shm-usage --disable-setuid-sandbox}" +CHROMIUM_FLAGS="${CHROMIUM_FLAGS:---no-sandbox --disable-gpu --disable-dev-shm-usage --disable-setuid-sandbox}" info() { echo -e "${CYAN}$*${NC}"; } success() { echo -e "${GREEN}$*${NC}"; } warn() { echo -e "${YELLOW}$*${NC}"; } die() { echo -e "${RED}Error: $*${NC}" >&2; exit 1; } -# Root check -if [[ ${EUID:-$(id -u)} -ne 0 ]]; then - die "This script must be run with sudo or as root. Example: curl -fsSL URL | sudo bash" -fi +require_root() { + [[ ${EUID:-$(id -u)} -eq 0 ]] || die "This action must be run with sudo or as root." +} # Detect Timezone SERVER_TZ=$(cat /etc/timezone 2>/dev/null || echo "Etc/UTC") -# Use the real terminal for prompts. This keeps the menu working even when -# the script is executed with: curl -fsSL .../browser.sh | sudo bash -TTY_INPUT="" -if [[ -r /dev/tty ]]; then - TTY_INPUT="/dev/tty" +# Open the controlling terminal once so streamed scripts can still prompt. +TTY_FD="" +if { exec {TTY_FD}<>/dev/tty; } 2>/dev/null; then + : fi prompt_text() { @@ -44,10 +42,11 @@ prompt_text() { local default_value="${2:-}" local value="" - if [[ -n "$TTY_INPUT" ]]; then - read -r -p "$prompt" value < "$TTY_INPUT" + if [[ -n "$TTY_FD" ]]; then + printf "%s" "$prompt" >&"$TTY_FD" + read -r value <&"$TTY_FD" else - read -r -p "$prompt" value || true + read -r value || true fi echo "${value:-$default_value}" @@ -57,12 +56,13 @@ prompt_secret() { local prompt="$1" local value="" - if [[ -n "$TTY_INPUT" ]]; then - read -r -s -p "$prompt" value < "$TTY_INPUT" - echo > /dev/tty + if [[ -n "$TTY_FD" ]]; then + printf "%s" "$prompt" >&"$TTY_FD" + read -r -s value <&"$TTY_FD" + printf "\n" >&"$TTY_FD" else - read -r -s -p "$prompt" value || true - echo + read -r -s value || true + printf "\n" fi echo "$value" @@ -113,7 +113,7 @@ ensure_docker_ready() { docker info >/dev/null 2>&1 || die "Docker is installed but not running/reachable. Start Docker and run this script again." } -# Resolve PUID/PGID (prefer the sudo user; fallback safely) +# Resolve PUID/PGID (prefer the sudo user; fallback to the conventional host user) resolve_puid_pgid() { local puid pgid if [[ -n "${SUDO_USER:-}" && "${SUDO_USER}" != "root" ]]; then @@ -121,15 +121,8 @@ resolve_puid_pgid() { pgid=$(id -g "$SUDO_USER" 2>/dev/null) fi - if [[ -z "${puid:-}" || -z "${pgid:-}" ]]; then - if command -v getent >/dev/null 2>&1 && getent passwd 1000 >/dev/null 2>&1; then - puid=1000 - pgid=$(getent passwd 1000 | cut -d: -f4) - else - puid=0 - pgid=0 - fi - fi + puid="${puid:-1000}" + pgid="${pgid:-1000}" echo "$puid:$pgid" } @@ -153,6 +146,61 @@ container_running() { [[ "$(docker inspect -f '{{.State.Running}}' "$1" 2>/dev/null || echo false)" == "true" ]] } +run_docker_diagnostics() { + timeout 5 docker "$@" +} + +chromium_process_running() { + docker exec "$1" sh -c 'ps -eo comm=,args= 2>/dev/null | grep -Eq "[c]hromium|[c]hrome"' >/dev/null 2>&1 +} + +print_recent_logs() { + local container="$1" + local secret="${2:-}" + local line + + if [[ -z "$secret" ]]; then + docker logs --tail 80 "$container" 2>&1 || true + return + fi + + while IFS= read -r line; do + printf '%s\n' "${line//"$secret"/[REDACTED]}" + done < <(docker logs --tail 80 "$container" 2>&1 || true) +} + +print_chromium_failure() { + local reason="$1" + local secret="${2:-}" + echo -e "${RED}Chromium startup check failed: $reason${NC}" >&2 + echo "Recent container logs:" >&2 + print_recent_logs chromium "$secret" + echo "Debug: sudo docker ps -a --filter name=chromium" >&2 + echo "Debug: sudo docker exec chromium ps -eo pid,comm,args" >&2 +} + +verify_chromium_startup() { + local secret="${1:-}" + local attempt + + for ((attempt = 1; attempt <= 30; attempt++)); do + if ! container_running chromium; then + print_chromium_failure "the Docker container exited" "$secret" + return 1 + fi + + if chromium_process_running chromium; then + info "Chromium process detected." + return 0 + fi + + sleep 1 + done + + print_chromium_failure "the container is running but no Chromium process was found" "$secret" + return 1 +} + check_port_available() { local port="$1" if command -v ss >/dev/null 2>&1 && ss -ltnH "sport = :$port" 2>/dev/null | grep -q .; then @@ -209,6 +257,7 @@ install_browser() { local port="$3" local ssl_port=$((port + 1)) + require_root ensure_docker_ready show_arch_info @@ -252,23 +301,16 @@ install_browser() { mkdir -p "$config_dir" chown -R "${puid}:${pgid}" "${CONFIG_BASE}/${browser}" 2>/dev/null || true - local extra_caps=() - local extra_security=() local browser_env=() if [[ "$browser" == "chromium" ]]; then - # These flags help Chromium start on restricted VPS/Docker environments. - extra_caps+=(--cap-add=SYS_ADMIN) - extra_security+=(--security-opt seccomp=unconfined) - browser_env+=(-e "CHROME_CLI=$CHROMIUM_FLAGS" -e "CHROME_FLAGS=$CHROMIUM_FLAGS") + browser_env+=(-e "PIXELFLUX_WAYLAND=false" -e "CHROME_CLI=$CHROMIUM_FLAGS" -e "CHROME_FLAGS=$CHROMIUM_FLAGS") info "Applying Chromium flags through CHROME_CLI and CHROME_FLAGS: $CHROMIUM_FLAGS" fi info "Deploying $browser... Please wait." if ! docker run -d \ --name="$browser" \ - "${extra_caps[@]}" \ - "${extra_security[@]}" \ -e "PUID=$puid" \ -e "PGID=$pgid" \ -e "TZ=$SERVER_TZ" \ @@ -284,27 +326,30 @@ install_browser() { echo "Docker failed to start $browser." if container_exists "$browser"; then echo "Recent logs:" - docker logs --tail 80 "$browser" 2>/dev/null || true + print_recent_logs "$browser" "$password" fi die "Check ports, image availability, Docker permissions, and the logs above if present." fi - sleep 4 if ! container_running "$browser"; then echo -e "${RED}$browser did not start successfully.${NC}" echo "Recent logs:" - docker logs --tail 80 "$browser" 2>/dev/null || true + print_recent_logs "$browser" "$password" die "Container exited. Check the logs above." fi + if [[ "$browser" == "chromium" ]]; then + verify_chromium_startup "$password" || die "Chromium is not ready. Check the logs and debug commands above." + fi + local ip ip=$(detect_ip) success "================================================" success "Deployment Successful!" - echo -e "Access URL (HTTP) : ${CYAN}http://${ip}:${port}${NC}" - echo -e "Access URL (HTTPS): ${CYAN}https://${ip}:${ssl_port}${NC}" - echo -e "Credentials : ${YELLOW}$username / $password${NC}" + echo -e "Browser URL (HTTPS): ${CYAN}https://${ip}:${ssl_port}${NC}" + echo -e "HTTP (proxy-only) : ${CYAN}http://${ip}:${port}${NC}" + echo -e "Credentials : ${YELLOW}configured for $username${NC}" echo -e "${YELLOW}Note: Accept the SSL warning in your browser.${NC}" success "================================================" } @@ -312,39 +357,75 @@ install_browser() { uninstall_browser() { local browser="$1" info "Removing $browser..." + require_root ensure_docker_ready docker stop "$browser" >/dev/null 2>&1 || true docker rm "$browser" >/dev/null 2>&1 || true success "Cleanup complete. Persistent config was kept at ${CONFIG_BASE}/${browser}/config." } -show_status() { - ensure_docker_ready +show_diagnostics() { + local status + show_arch_info echo -e "${CYAN}Config base:${NC} ${CONFIG_BASE}" + if ! command -v docker >/dev/null 2>&1; then + echo "Docker: not installed" + return 0 + fi + + if ! command -v timeout >/dev/null 2>&1; then + echo "Docker: diagnostics timeout command is unavailable" + return 0 + fi + + echo "Checking Docker daemon (up to 5 seconds)..." + if run_docker_diagnostics info >/dev/null 2>&1; then + : + else + status=$? + if [[ "$status" -eq 124 ]]; then + echo "Docker: daemon check timed out after 5 seconds" + else + echo "Docker: installed but not reachable" + fi + return 0 + fi + + echo "Docker: reachable" echo -e "${CYAN}--- Containers ---${NC}" - docker ps -a --filter "name=chromium" --filter "name=firefox" --format 'table {{.Names}}\t{{.Status}}\t{{.Ports}}' + if run_docker_diagnostics ps -a --filter "name=chromium" --filter "name=firefox" --format 'table {{.Names}}\t{{.Status}}\t{{.Ports}}'; then + : + else + status=$? + if [[ "$status" -eq 124 ]]; then + echo "Docker: container query timed out after 5 seconds" + else + echo "Docker: container query failed" + fi + fi } show_menu() { echo -e "${CYAN}==========================================${NC}" echo -e "${GREEN} Instant Linux Browser Installer${NC}" echo -e "${CYAN}==========================================${NC}" - echo -e "1) Install Chromium (HTTP 3000 / HTTPS 3001)" + echo -e "1) Install Chromium (HTTPS 3001; HTTP 3000 proxy-only)" echo -e "2) Uninstall Chromium" - echo -e "3) Install Firefox (HTTP 4000 / HTTPS 4001)" + echo -e "3) Install Firefox (HTTPS 4001; HTTP 4000 proxy-only)" echo -e "4) Uninstall Firefox" - echo -e "5) Show Status" + echo -e "5) Diagnostics" echo -e "6) Exit" echo -e "${CYAN}==========================================${NC}" } read_menu_choice() { local choice="" - if [[ -n "$TTY_INPUT" ]]; then - read -r -p "Select an option [1-6]: " choice < "$TTY_INPUT" + if [[ -n "$TTY_FD" ]]; then + printf "Select an option [1-6]: " >&"$TTY_FD" + read -r choice <&"$TTY_FD" else - die "No interactive terminal was found. Download the script first and run 'sudo bash browser.sh', or run with ILB_ACTION=install-chromium." + die "No action and no controlling terminal. Use ILB_ACTION=install-chromium or download the script first." fi echo "$choice" } @@ -365,7 +446,7 @@ run_action() { uninstall_browser "firefox" ;; 5|status|diagnostics|diag) - show_status + show_diagnostics ;; 6|exit|quit) exit 0 @@ -384,9 +465,15 @@ main() { return fi + if [[ -z "$TTY_FD" ]]; then + die "No action and no controlling terminal. Use ILB_ACTION=install-chromium or download the script first." + fi + show_menu action=$(read_menu_choice) run_action "$action" } -main "$@" +if [[ -z "${BASH_SOURCE[0]:-}" || "${BASH_SOURCE[0]}" == "$0" ]]; then + main "$@" +fi diff --git a/tests/browser_test.sh b/tests/browser_test.sh new file mode 100644 index 0000000..680c394 --- /dev/null +++ b/tests/browser_test.sh @@ -0,0 +1,194 @@ +#!/usr/bin/env bash + +set -euo pipefail + +TEST_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_DIR="$(cd "$TEST_DIR/.." && pwd)" +SCRIPT="$PROJECT_DIR/browser.sh" +TEMP_DIR="$(mktemp -d)" +MOCK_BIN="$TEMP_DIR/bin" +MOCK_LOG="$TEMP_DIR/docker.log" +export MOCK_LOG + +cleanup() { + rm -rf "$TEMP_DIR" +} +trap cleanup EXIT + +fail() { + echo "FAIL: $*" >&2 + exit 1 +} + +assert_contains() { + local expected="$1" + local file="$2" + grep -Fq -- "$expected" "$file" || fail "Expected '$expected' in $file" +} + +assert_not_contains() { + local unexpected="$1" + local file="$2" + if grep -Fq -- "$unexpected" "$file"; then + fail "Did not expect '$unexpected' in $file" + fi +} + +argument_index() { + local argument="$1" + awk -F '\t' -v argument="$argument" '{ for (field_index = 1; field_index <= NF; field_index++) if ($field_index == argument) { print field_index; exit } }' "$RUN_RECORD" +} + +assert_environment_before_image() { + local argument="$1" + local argument_index_value + local environment_flag_index + + argument_index_value="$(argument_index "$argument")" + environment_flag_index=$((argument_index_value - 1)) + + [[ -n "$argument_index_value" && "$argument_index_value" -lt "$IMAGE_INDEX" ]] || fail "$argument must occur before the image" + [[ "$(awk -F '\t' -v field="$environment_flag_index" '{ print $field }' "$RUN_RECORD")" == "-e" ]] || fail "$argument must be preceded by -e" +} + +mkdir -p "$MOCK_BIN" +cat > "$MOCK_BIN/docker" <<'MOCK_DOCKER' +#!/usr/bin/env bash +set -eu + +{ + printf 'docker' + for argument in "$@"; do + printf '\t%s' "$argument" + done + printf '\n' +} >> "$MOCK_LOG" + +case "${1:-}" in + info|pull|run|stop|rm|ps) + exit 0 + ;; + inspect) + printf 'true\n' + exit 0 + ;; + exec) + [[ "${MOCK_CHROMIUM_PROCESS:-1}" == "1" ]] + ;; + logs) + printf '%s\n' "${MOCK_LOG_LINE:-mock container log}" + ;; + *) + exit 0 + ;; +esac +MOCK_DOCKER +chmod +x "$MOCK_BIN/docker" + +cat > "$MOCK_BIN/timeout" <<'MOCK_TIMEOUT' +#!/usr/bin/env bash +set -eu + +seconds="$1" +shift + +if [[ "${MOCK_DOCKER_INFO_TIMEOUT:-0}" == "1" && "${1:-}" == "docker" && "${2:-}" == "info" ]]; then + exit 124 +fi + +exec "$@" +MOCK_TIMEOUT +chmod +x "$MOCK_BIN/timeout" + +bash -n "$SCRIPT" + +NO_ACTION_OUTPUT="$TEMP_DIR/no-action.out" +if ( + source "$SCRIPT" + if [[ -n "$TTY_FD" ]]; then + exec {TTY_FD}>&- + fi + TTY_FD="" + main +) > "$NO_ACTION_OUTPUT" 2>&1; then + fail "A non-interactive run without an action succeeded" +fi +assert_contains "No action and no controlling terminal" "$NO_ACTION_OUTPUT" + +INVALID_OUTPUT="$TEMP_DIR/invalid.out" +if PATH="$MOCK_BIN:$PATH" bash "$SCRIPT" invalid-action > "$INVALID_OUTPUT" 2>&1; then + fail "An invalid action succeeded" +fi +assert_contains "Invalid option: invalid-action" "$INVALID_OUTPUT" + +DIAGNOSTICS_OUTPUT="$TEMP_DIR/diagnostics.out" +PATH="$MOCK_BIN:$PATH" bash "$SCRIPT" diagnostics > "$DIAGNOSTICS_OUTPUT" 2>&1 +PATH="$MOCK_BIN:$PATH" ILB_ACTION=diagnostics bash "$SCRIPT" > /dev/null 2>&1 +assert_contains "Checking Docker daemon (up to 5 seconds)..." "$DIAGNOSTICS_OUTPUT" +assert_contains "--- Containers ---" "$DIAGNOSTICS_OUTPUT" + +PIPED_DIAGNOSTICS_OUTPUT="$TEMP_DIR/piped-diagnostics.out" +cat "$SCRIPT" | PATH="$MOCK_BIN:$PATH" ILB_ACTION=diagnostics bash > "$PIPED_DIAGNOSTICS_OUTPUT" 2>&1 +assert_contains "--- Containers ---" "$PIPED_DIAGNOSTICS_OUTPUT" +assert_not_contains "apt-get" "$MOCK_LOG" +assert_not_contains "systemctl" "$MOCK_LOG" + +if command -v script >/dev/null 2>&1; then + TTY_OUTPUT="$TEMP_DIR/tty.out" + printf '5\n' | PATH="$MOCK_BIN:$PATH" script -qec "cat '$SCRIPT' | bash" /dev/null > "$TTY_OUTPUT" 2>&1 || fail "Streamed interactive diagnostics failed" + assert_contains "Instant Linux Browser Installer" "$TTY_OUTPUT" + assert_contains "--- Containers ---" "$TTY_OUTPUT" +else + echo "SKIP: streamed TTY test requires the util-linux script command" +fi + +export PATH="$MOCK_BIN:$PATH" +export MOCK_LOG +export CONFIG_BASE="$TEMP_DIR/config" +source "$SCRIPT" + +if declare -f show_diagnostics | grep -Eq 'check_docker|ensure_docker_ready|apt-get|systemctl'; then + fail "Diagnostics must not install or start Docker" +fi + +require_root() { :; } +detect_arch() { echo x86_64; } +sleep() { :; } + +DIAGNOSTICS_TIMEOUT_OUTPUT="$TEMP_DIR/diagnostics-timeout.out" +MOCK_DOCKER_INFO_TIMEOUT=1 show_diagnostics > "$DIAGNOSTICS_TIMEOUT_OUTPUT" 2>&1 +assert_contains "Checking Docker daemon (up to 5 seconds)..." "$DIAGNOSTICS_TIMEOUT_OUTPUT" +assert_contains "Docker: daemon check timed out after 5 seconds" "$DIAGNOSTICS_TIMEOUT_OUTPUT" + +RESOLVED_IDS="$(SUDO_USER=root resolve_puid_pgid)" +[[ "$RESOLVED_IDS" == "1000:1000" ]] || fail "Expected safe UID/GID fallback, got $RESOLVED_IDS" + +: > "$MOCK_LOG" +INSTALL_OUTPUT="$TEMP_DIR/install.out" +ILB_USERNAME=admin ILB_PASSWORD=do-not-print-this install_browser chromium lscr.io/linuxserver/chromium:latest 3000 > "$INSTALL_OUTPUT" 2>&1 +assert_not_contains "do-not-print-this" "$INSTALL_OUTPUT" + +RUN_RECORD="$TEMP_DIR/docker-run.log" +awk -F '\t' '$2 == "run" { print; found = 1; exit } END { exit !found }' "$MOCK_LOG" > "$RUN_RECORD" || fail "Docker run invocation was not recorded" +IMAGE_INDEX="$(argument_index "lscr.io/linuxserver/chromium:latest")" +[[ -n "$IMAGE_INDEX" ]] || fail "Chromium image was not passed to docker run" +assert_environment_before_image "PIXELFLUX_WAYLAND=false" +assert_environment_before_image "CHROME_CLI=--no-sandbox --disable-gpu --disable-dev-shm-usage --disable-setuid-sandbox" +assert_not_contains "--disable-software-rasterizer" "$RUN_RECORD" + +LOG_OUTPUT="$TEMP_DIR/log.out" +export MOCK_LOG_LINE='do-not-print-this' +print_recent_logs chromium do-not-print-this > "$LOG_OUTPUT" +unset MOCK_LOG_LINE +assert_not_contains "do-not-print-this" "$LOG_OUTPUT" +assert_contains "[REDACTED]" "$LOG_OUTPUT" + +PROCESS_OUTPUT="$TEMP_DIR/process.out" +export MOCK_CHROMIUM_PROCESS=0 +if verify_chromium_startup > "$PROCESS_OUTPUT" 2>&1; then + fail "Missing Chromium process was reported as ready" +fi +unset MOCK_CHROMIUM_PROCESS +assert_contains "container is running but no Chromium process was found" "$PROCESS_OUTPUT" + +echo "PASS: browser.sh checks"