Skip to content

Conversation

@AquaHorizonGaming
Copy link

@AquaHorizonGaming AquaHorizonGaming commented Jan 4, 2026

This PR adds fully automated, Docker-based installation scripts for Riven on both
standard Ubuntu systems and Proxmox LXC containers.

What’s included

Ubuntu installer

  • One-line install via curl
  • Installs Docker and Docker Compose only if missing
  • Configures Docker to use IPv4 only (no system-wide IPv6 changes)
  • Creates required directories:
    • /opt/riven (docker-compose.yml + .env)
    • /mnt/riven/backend (Riven backend + settings.json)
    • /mnt/riven/mount (media library: movies / TV / anime)
  • Sets up rshared mount propagation via systemd
  • Auto-generates secure environment variables
  • Starts all containers and retries failed ones (especially frontend)
  • Prints the frontend URL on completion
  • Clearly warns users that Riven will not function until
    /mnt/riven/backend/settings.json is configured with at least one scraper
    and one media server

Proxmox LXC installer

  • Designed for privileged Proxmox LXC containers
  • Handles Docker + mount propagation requirements specific to LXC
  • Uses IPv4-only Docker networking to avoid Python/httpx IPv6 issues
  • Mirrors the Ubuntu installer’s directory layout and behavior

Summary by CodeRabbit

  • New Features

    • Docker-first, single-command installers with clear backend/frontend access URLs, container IP guidance, and a Docker-based upgrade workflow; optional media-server Docker Compose profiles with healthchecks.
  • New Installers & Tools

    • Interactive Proxmox LXC and Ubuntu installers (Debian 12 unprivileged LXC or Ubuntu host) that bootstrap Docker/Compose, support GPU passthrough and host bind-mounts, plus remount, update, and uninstall utilities.
  • Documentation

    • Reorganized, Docker-centric READMEs with setup, access, required configuration, upgrade, and migration guidance.
  • Removed

    • Legacy bare-metal provisioning and standalone media-server installer helpers.

✏️ Tip: You can customize this high-level summary in your review settings.

Updated the Proxmox LXC installer script to improve structure and clarity. Added comments and organized sections for better readability.
Refactor install script for improved structure and clarity.
Refactor command detection and improve comments.
This script installs Docker and Docker Compose on Ubuntu, sets the timezone, and creates necessary directories and environment files for the Riven application.
Updated docker-compose.yml to define services for riven-db, riven, and riven-frontend with health checks and environment variables.
Refactor install script for better readability and structure, add interactive timezone selection, and improve dependency checks.
Updated warning message for Riven configuration steps.
This README provides detailed instructions for installing and configuring Riven on Ubuntu using Docker and Docker Compose, including supported systems, filesystem setup, deployment steps, required configurations, and troubleshooting tips.
Added instructions for running the Ubuntu installer script.
Updated formatting and section headers in readme.
@coderabbitai
Copy link

coderabbitai bot commented Jan 4, 2026

📝 Walkthrough

Walkthrough

Replaces previous bare‑metal Proxmox host provisioning and per‑host media installers with a Docker‑centric approach: removes legacy provisioning scripts; adds a Proxmox TUI installer that creates an unprivileged Debian 12 LXC, LXC creation/bootstrap scripts, in‑container Docker Compose manifests and Riven deploy/upgrade scripts; and adds a full Ubuntu installer and lifecycle helpers.

Changes

Cohort / File(s) Summary
Proxmox host installer (new)
proxmox/install.sh
New interactive TUI that validates PVE tools, collects CT parameters, creates/configures an unprivileged LXC, transfers bootstrap artifacts, bootstraps Docker in the CT, and prints CT IP / service URLs.
Proxmox LXC tooling (new)
proxmox/lxc/lxc-create.sh, proxmox/lxc/lxc-bootstrap.sh, proxmox/lxc/docker-compose.yml
lxc-create.sh provisions Debian 12 unprivileged LXC with nesting, FUSE, optional GPU and host bind; lxc-bootstrap.sh installs Docker & Compose inside the CT; docker-compose.yml defines riven-db, riven, frontend and optional Jellyfin/Plex/Emby profiles, volumes, healthchecks and device mappings.
In‑container deploy & maintenance (new)
proxmox/lxc/riven-install.sh, proxmox/lxc/upgrade.sh
riven-install.sh prepares /srv/riven, enforces rshared mount propagation, generates .env, ensures compose/upgrade artifacts, and starts the stack. upgrade.sh implements a Docker-centric upgrade (stop, pull, up -d, prune).
Removed legacy Proxmox orchestration
proxmox/build.func, proxmox/create_lxc.sh, proxmox/riven.sh, proxmox/riven-install.sh
Deleted prior interactive orchestration and bare‑metal installer logic including prompts, validations, and complex LXC provisioning flows.
Removed standalone media installers
proxmox/media-plex.sh, proxmox/media-jellyfin.sh, proxmox/media-emby.sh
Removed per‑host media server installer helpers; media server support now provided as Docker Compose profiles.
Ubuntu installer & lifecycle (new)
ubuntu/install.sh, ubuntu/docker-compose.yml, ubuntu/docker-compose.media.yml, ubuntu/readme.md, ubuntu/riven-uninstall.sh, ubuntu/riven-update.sh, ubuntu/riven-remount-cycle.sh
New interactive Ubuntu installer, platform compose manifests (main + media), README, uninstall/update/remount helpers, rshared mount handling, .env generation, media server selection, and lifecycle/update workflows.
Top‑level docs & Proxmox changelog
README.md, proxmox/README.md, proxmox/changelog.md
Documentation rewritten to a Docker‑centric narrative: Quick Start for Proxmox/Ubuntu, access URLs, repo layout, migration notes, and a Proxmox changelog describing storage/layout and UX changes.
Compose manifests (platform variants)
proxmox/lxc/docker-compose.yml, ubuntu/docker-compose.yml, ubuntu/docker-compose.media.yml
Added platform-specific compose manifests—review env wiring, volume paths, device mappings, healthchecks, and inter-service dependency semantics.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant PVE as Proxmox Host
    participant CT as LXC Container
    participant Docker as Docker Daemon
    participant DB as Postgres
    participant App as Riven Backend
    participant Front as Riven Frontend

    User->>PVE: run `proxmox/install.sh`
    PVE->>PVE: validate PVE tools, present TUI, collect CT params
    PVE->>PVE: create LXC (unprivileged, nesting, FUSE, mp0)
    PVE->>CT: start CT and push bootstrap scripts
    CT->>Docker: install/start Docker & Compose via `lxc-bootstrap.sh`
    PVE->>CT: push `riven-install.sh`, `docker-compose.yml`, `.env`
    CT->>CT: ensure rshared mount, prepare /srv/riven
    CT->>Docker: `docker compose up -d`
    Docker->>DB: start postgres container
    Docker->>App: start riven backend
    Docker->>Front: start frontend
    App->>DB: initialize DB
    CT->>PVE: report CT IP
    PVE->>User: display URLs and credentials
Loading
sequenceDiagram
    participant User
    participant Host as Ubuntu Host
    participant Docker as Docker Daemon
    participant Compose as Docker Compose
    participant DB as Postgres
    participant App as Riven Backend
    participant Front as Riven Frontend

    User->>Host: run `ubuntu/install.sh`
    Host->>Host: verify OS, install Docker, ensure rshared mount unit
    Host->>Host: generate `.env`, download compose manifests
    Host->>Compose: `docker compose pull` then `docker compose up -d`
    Compose->>Docker: create containers
    Docker->>DB: start postgres
    Docker->>App: start backend
    Docker->>Front: start frontend
    App->>DB: initialize DB
    Host->>User: display access URLs and config paths
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 31.58% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: adding automated installers for Ubuntu and Proxmox LXC environments with Docker-based Riven deployment.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 35

📜 Review details

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between b932af8 and efa8921.

📒 Files selected for processing (17)
  • proxmox/README.md
  • proxmox/build.func
  • proxmox/create_lxc.sh
  • proxmox/install.sh
  • proxmox/lxc/docker-compose.yml
  • proxmox/lxc/lxc-bootstrap.sh
  • proxmox/lxc/lxc-create.sh
  • proxmox/lxc/riven-install.sh
  • proxmox/lxc/upgrade.sh
  • proxmox/media-emby.sh
  • proxmox/media-jellyfin.sh
  • proxmox/media-plex.sh
  • proxmox/riven-install.sh
  • proxmox/riven.sh
  • ubuntu/docker-compose.yml
  • ubuntu/install.sh
  • ubuntu/readme.md
💤 Files with no reviewable changes (7)
  • proxmox/create_lxc.sh
  • proxmox/riven-install.sh
  • proxmox/media-emby.sh
  • proxmox/media-jellyfin.sh
  • proxmox/riven.sh
  • proxmox/build.func
  • proxmox/media-plex.sh
🧰 Additional context used
🧬 Code graph analysis (2)
proxmox/install.sh (1)
proxmox/lxc/lxc-create.sh (1)
  • require_cmd (33-33)
proxmox/lxc/lxc-create.sh (1)
proxmox/install.sh (1)
  • require_cmd (17-22)
🪛 markdownlint-cli2 (0.18.1)
proxmox/README.md

3-3: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


11-11: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


21-21: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


26-26: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


30-30: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


37-37: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


41-41: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


43-43: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


50-50: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


52-52: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)

ubuntu/readme.md

1-1: First line in a file should be a top-level heading

(MD041, first-line-heading, first-line-h1)


5-5: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


6-6: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Above

(MD022, blanks-around-headings)

🪛 Shellcheck (0.11.0)
proxmox/lxc/lxc-bootstrap.sh

[info] 19-19: Not following: /etc/os-release was not specified as input (see shellcheck -x).

(SC1091)

ubuntu/install.sh

[info] 28-28: Not following: /etc/os-release was not specified as input (see shellcheck -x).

(SC1091)

🔇 Additional comments (18)
proxmox/lxc/lxc-bootstrap.sh (1)

1-9: LGTM!

Good error handling with set -euo pipefail and appropriate use of DEBIAN_FRONTEND=noninteractive for automated installation. The package list covers necessary dependencies for Docker installation.

ubuntu/docker-compose.yml (2)

68-68: Clarify frontend database usage.

The frontend's DATABASE_URL points to /riven/data/riven.db within the riven-frontend-data volume, while the backend uses PostgreSQL. This suggests the frontend uses a separate SQLite database. If intentional, this is fine, but it should be documented. If not, this could indicate a configuration error.

Does the Riven frontend require its own SQLite database separate from the backend's PostgreSQL database, or should this path point to the backend's database?


1-1: Remove the obsolete version field from docker-compose.yml.

The version field is obsolete in Docker Compose V2 (GA since April 2022) and is ignored by current versions. Using it triggers a warning. Replace the version declaration with services: at the top level instead.

proxmox/README.md (2)

41-48: No issues found – profile names are correct.

The compose profiles jellyfin, plex, and emby in the documentation match the profiles defined in proxmox/lxc/docker-compose.yml.


30-39: Remove container name verification; clarify settings.json editing workflow.

The docker restart riven command correctly matches the container_name: riven defined in docker-compose.yml, so that concern is unfounded. However, the README should clarify that /mnt/riven/backend/settings.json is edited after the containers start (once auto-generated), and point users to the main Riven documentation for configuration details rather than expecting examples in this deployment guide.

Likely an incorrect or invalid review comment.

proxmox/lxc/riven-install.sh (4)

1-2: Consider adding pipefail equivalent error handling for subshells.

The set -euo pipefail is good practice. The script properly uses strict mode.


19-22: Mount operations may fail silently on subsequent runs.

If $MOUNT_DIR is already a mountpoint but not rshared, the mount --bind is skipped but mount --make-rshared still runs. This is correct behavior. However, if the bind mount exists but make-rshared fails, the script will exit due to set -e before reaching the validation check, which is appropriate.


85-87: Credential extraction may fail if .env has unexpected format.

Using grep -E | cut works for simple cases but will break if values contain = characters. Since POSTGRES_PASSWORD is generated via openssl rand -hex, this is safe here, but consider using a more robust parser for future-proofing.


53-74: The hardcoded DATABASE_URL path is intentional and not problematic. The frontend (riven-frontend service) uses its own SQLite database (/riven/data/riven.db) for frontend-local state (authentication, preferences), while the backend (riven service) uses PostgreSQL via RIVEN_DATABASE_HOST. These are separate databases serving different purposes and are properly configured with distinct environment variables. No conflict exists.

Likely an incorrect or invalid review comment.

proxmox/install.sh (2)

183-193: Good user guidance provided.

The final output clearly shows how to get the CT IP and access URLs. The log commands are helpful for troubleshooting.


61-72: [Rewritten review comment]
[Classification tag]

proxmox/lxc/docker-compose.yml (3)

22-35: Security concerns with elevated container privileges.

The riven container has significant privileges:

  • cap_add: SYS_ADMIN - broad capability
  • security_opt: apparmor:unconfined - disables AppArmor
  • /dev/fuse device access

These are likely required for FUSE-based media mounting, but document why these are needed and ensure users understand the security implications.


86-90: GPU device passthrough may fail if /dev/dri doesn't exist.

The devices: [/dev/dri:/dev/dri] will cause container startup failure if the device doesn't exist. Consider making this conditional or documenting the requirement.


92-106: Plex uses host network mode while others use port mapping.

This is a known Plex requirement for discovery, but it creates inconsistency. The PUID/PGID are hardcoded to 1000—ensure this matches the riven user created by the installer.

proxmox/lxc/lxc-create.sh (2)

50-52: Root password logged to console in plaintext.

The randomly generated password is echoed to stdout. While necessary for the user, this could be captured in logs. Consider advising users to change it or store securely.


73-79: Security implications of Docker-in-LXC configuration.

The configuration sets:

  • lxc.apparmor.profile: unconfined - disables AppArmor
  • lxc.cgroup2.devices.allow: a - allows access to ALL devices

This is very permissive and required for Docker-in-LXC, but essentially makes the container nearly as privileged as a privileged container. Document these security implications for users.

ubuntu/install.sh (2)

28-29: Sourcing /etc/os-release is safe but flagged by shellcheck.

The static analysis hint (SC1091) is a false positive for this use case—the file exists on all Ubuntu systems and sourcing it is the standard way to detect the OS. The current implementation is correct.


204-227: Clear and helpful final instructions.

The warning about required configuration is appropriately prominent. The instructions clearly explain what users must do and the consequences of not doing so.

Comment on lines +17 to +22
require_cmd() {
command -v "$1" >/dev/null 2>&1 || {
echo "ERROR: Missing required command: $1"
exit 1
}
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Helper function duplicated across scripts.

This require_cmd() function is nearly identical to the one in proxmox/lxc/lxc-create.sh (line 33). Consider extracting to a shared utilities file to follow DRY principles, though for standalone curl-pipe scripts, duplication may be acceptable for simplicity.

🤖 Prompt for AI Agents
In proxmox/install.sh lines 17-22 the helper function require_cmd() is
duplicated elsewhere (proxmox/lxc/lxc-create.sh line 33); extract this function
into a shared utilities file (e.g., proxmox/scripts/common.sh), make it
POSIX-safe, and replace the duplicated definition in both scripts with a single
source line that loads the common file (use a relative dirname-based path so
sourcing works when scripts are run directly). Ensure scripts still work
standalone when curl-piped by falling back to an inline minimal require_cmd if
the common file cannot be sourced (check for -f before sourcing and only define
the function inline as a last resort).

Comment on lines +35 to +47
PVE_VER_RAW="$(pveversion | head -n1)"
PVE_VER="$(echo "$PVE_VER_RAW" | sed -nE 's/.*pve-manager\/([0-9]+)\.([0-9]+).*/\1.\2/p')"

if [[ -z "$PVE_VER" ]]; then
echo "WARNING: Could not parse Proxmox version from: $PVE_VER_RAW"
else
MAJ="${PVE_VER%.*}"
MIN="${PVE_VER#*.}"
if (( MAJ < 8 )) || (( MAJ == 8 && MIN < 1 )); then
echo "ERROR: Proxmox 8.1+ required. Detected: $PVE_VER_RAW"
exit 1
fi
fi
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Version parsing could fail on non-standard pveversion output.

The regex extraction is reasonable, but if pveversion output format changes, PVE_VER could be empty. The script handles this with a warning (line 39), which is good. However, the comparison logic at lines 41-46 assumes MAJ and MIN are integers.

If PVE_VER is malformed (e.g., 8.x), the arithmetic comparison could fail. Consider adding numeric validation.

🔎 Proposed fix
 else
   MAJ="${PVE_VER%.*}"
   MIN="${PVE_VER#*.}"
+  if ! [[ "$MAJ" =~ ^[0-9]+$ && "$MIN" =~ ^[0-9]+$ ]]; then
+    echo "WARNING: Could not parse version numbers from: $PVE_VER"
+  else
   if (( MAJ < 8 )) || (( MAJ == 8 && MIN < 1 )); then
     echo "ERROR: Proxmox 8.1+ required. Detected: $PVE_VER_RAW"
     exit 1
   fi
+  fi
 fi
🤖 Prompt for AI Agents
In proxmox/install.sh around lines 35 to 47, the script extracts MAJ and MIN
from PVE_VER but does not validate they are numeric before performing arithmetic
comparisons; add a numeric validation step after splitting PVE_VER (e.g., check
MAJ and MIN match ^[0-9]+$) and if either is non-numeric print a clear error
(including PVE_VER_RAW) and exit 1 (or treat non-numeric as 0) so the subsequent
(( MAJ < 8 )) || (( MAJ == 8 && MIN < 1 )) comparisons cannot fail on malformed
input.

Comment on lines +79 to +85
while :; do
CANDIDATE=$(( (RANDOM % 900) + 100 ))
if ! pct status "$CANDIDATE" >/dev/null 2>&1; then
DEFAULT_CTID="$CANDIDATE"
break
fi
done
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

CTID generation loop could theoretically run indefinitely.

If all CTIDs 100-999 are taken, the while :; do loop never exits. This is unlikely in practice but worth noting.

🔎 Add a safeguard
 DEFAULT_CTID=""
+ATTEMPTS=0
 while :; do
+  (( ++ATTEMPTS > 1000 )) && { echo "ERROR: No free CTID found"; exit 1; }
   CANDIDATE=$(( (RANDOM % 900) + 100 ))
   if ! pct status "$CANDIDATE" >/dev/null 2>&1; then
     DEFAULT_CTID="$CANDIDATE"
     break
   fi
 done

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In proxmox/install.sh around lines 79-85 the random CTID selection loop can run
forever if all IDs 100-999 are taken; add a safeguard by introducing a
max_attempts counter (e.g., 1000) that increments each loop and breaks when
reached, and if the limit is hit then perform a deterministic fallback: iterate
sequentially from 100 to 999 to pick the first available CTID, and if none are
free exit with a clear error code/message; keep the original random selection
logic but ensure the loop exits in all cases.

Comment on lines 201 to 202
SERVER_IP="$(ip route get 1.1.1.1 2>/dev/null | awk '{print $7; exit}')"
[ -z "$SERVER_IP" ] && SERVER_IP="SERVER_IP"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

IP detection may fail in some network configurations.

The ip route get 1.1.1.1 approach assumes internet connectivity and may fail in isolated networks. The fallback to SERVER_IP string is good, but consider also trying hostname -I.

🔎 More robust IP detection
-SERVER_IP="$(ip route get 1.1.1.1 2>/dev/null | awk '{print $7; exit}')"
-[ -z "$SERVER_IP" ] && SERVER_IP="SERVER_IP"
+SERVER_IP="$(ip route get 1.1.1.1 2>/dev/null | awk '{print $7; exit}' || hostname -I | awk '{print $1}' || echo "SERVER_IP")"

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In ubuntu/install.sh around lines 201-202, the current IP detection using `ip
route get 1.1.1.1` can fail in isolated/no-internet setups and the fallback
currently sets SERVER_IP to the literal string "SERVER_IP"; update the logic to
try `hostname -I` (or `hostname -i` as a secondary option) when the `ip route`
command returns empty, trim and select the first non-empty address, and only
then fall back to a sensible default (e.g., empty string or a configurable
placeholder) instead of the literal "SERVER_IP"; ensure commands are guarded so
failures do not abort the script and preserve current behavior when a valid IP
is found.

ubuntu/readme.md Outdated
## ▶️ How to run the installer (Ubuntu Script)

```bash
sudo bash -c "$(curl -fsSL https://raw.githubusercontent.com/AquaHorizonGaming/distributables/main/ubuntu/install.sh)"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Consider security and stability implications.

Piping curl directly to bash is convenient but poses security risks if the source is compromised. Additionally, pointing to the main branch may expose users to unstable code.

Consider:

  • Recommending users inspect the script before running it
  • Using a stable release tag or branch instead of main
  • Providing a checksum for verification
🤖 Prompt for AI Agents
In ubuntu/readme.md around line 4, the install command pipes curl to bash from
the main branch which is a security and stability risk; update the docs to (1)
advise users to inspect the script before running (show how to download and view
it), (2) recommend using a specific release tag or stable branch URL instead of
main, (3) provide or link to a published checksum (SHA256) and explain verifying
the checksum before execution, and (4) optionally suggest running the script in
a dry-run or non-root environment first and only using sudo when verified.

ubuntu/readme.md Outdated
Comment on lines 45 to 59
REQUIRED CONFIGURATION (DO NOT SKIP)

AFTER INSTALL YOU MUST EDIT:
- /mnt/riven/backend/settings.json

YOU MUST:
- Add at least ONE scraper
- Configure at least ONE media server (Plex, Jellyfin, or Emby)

IF YOU DO NOT DO THIS:
- Containers WILL appear healthy
- NO content will load
- Scraping will silently fail

RIVEN WILL NOT WORK UNTIL THIS IS CONFIGURED.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Provide configuration examples or documentation links.

The warning is clear and emphatic, but users may struggle without concrete examples of how to configure scrapers and media servers in settings.json.

Consider adding:

  • A link to configuration documentation
  • Example JSON snippets for common configurations
  • A troubleshooting section for configuration-related issues
🤖 Prompt for AI Agents
In ubuntu/readme.md around lines 45 to 59, the strong warning about editing
/mnt/riven/backend/settings.json lacks concrete guidance; add actionable
configuration help by linking to the full configuration docs, inserting at least
one example JSON snippet for a common scraper and one for a media server
(Plex/Jellyfin/Emby) showing minimal required fields, and include a short
troubleshooting section that lists common misconfigurations and verification
steps (e.g., file path, JSON validity, service credentials, and how to validate
scrapers and media server connections).

Updated instructions for running on Proxmox host.
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between efa8921 and 334e22f.

📒 Files selected for processing (1)
  • proxmox/README.md
🧰 Additional context used
🪛 markdownlint-cli2 (0.18.1)
proxmox/README.md

7-7: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


8-8: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Above

(MD022, blanks-around-headings)


8-8: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


18-18: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


23-23: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


27-27: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


34-34: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


38-38: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


40-40: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


47-47: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


49-49: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)

Updated README to improve clarity and structure.
Updated installation script URLs to point to AquaHorizonGaming repository.
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 334e22f and 4aaeb3c.

📒 Files selected for processing (1)
  • README.md
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2026-01-04T07:07:27.617Z
Learnt from: AquaHorizonGaming
Repo: rivenmedia/distributables PR: 1
File: proxmox/lxc/docker-compose.yml:23-23
Timestamp: 2026-01-04T07:07:27.617Z
Learning: In the rivenmedia/distributables repository, the Docker image tags `spoked/riven:dev` and `spoked/riven-frontend:dev` are the main/production build tags, not development tags.

Applied to files:

  • README.md
🔇 Additional comments (2)
README.md (2)

11-48: Quick Start sections are clear and well-structured.

The documentation effectively communicates the two primary deployment paths with:

  • Clear one-line installer commands with appropriate privilege handling (sudo for Ubuntu, root context for Proxmox)
  • Concise descriptions of what each installer handles
  • References to detailed platform-specific READMEs for follow-up configuration

52-67: Repository structure and notes are appropriately concise.

The repository structure diagram clearly maps the directory layout, and the notes section provides helpful guidance without over-explaining. This supports the self-contained, per-platform documentation approach well.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 10

🤖 Fix all issues with AI agents
In @ubuntu/install.sh:
- Around line 873-880: The script currently echoes secrets (POSTGRES_PASSWORD,
BACKEND_API_KEY, AUTH_SECRET) to stdout which is being teed to the install log
(see tee at line ~160), causing plaintext secrets to persist in /tmp/logs;
remove or change those echo lines so secrets are not written to the log: either
write those echo outputs directly to the controlling terminal (e.g., redirect to
/dev/tty) so they bypass tee, or stop printing them entirely and save them only
to a restricted .env file and tighten the log file permissions (chmod 600)
before logging; update the three echo lines referencing POSTGRES_PASSWORD,
BACKEND_API_KEY and AUTH_SECRET and ensure logging behavior/LOG_FILE permissions
reflect the chosen approach.
- Around line 199-208: The current use of the `dpkg -s ... >/dev/null 2>&1 && ok
"System dependencies already installed" || { ... }` pattern can run the install
block if `ok` fails; change this to an explicit if/then/else: run `dpkg -s
ca-certificates curl gnupg lsb-release openssl fuse3` and if it exits zero, call
`ok "System dependencies already installed"`; else run `apt-get update || fail
"apt update failed"`, then `apt-get install -y ... || fail "dependency install
failed"`, then `ok "System dependencies installed"`. Keep the existing `banner`,
`ok`, and `fail` calls but remove the `&& ... || { ... }` chaining so the
install block only executes when `dpkg -s` fails.
- Around line 863-870: The summary block for "🔍 Scraper" is incomplete: add
checks for RIVEN_SCRAPING_COMET_ENABLED, RIVEN_SCRAPING_JACKETT_ENABLED, and
RIVEN_SCRAPING_ZILEAN_ENABLED (and include their URL vars e.g.
RIVEN_SCRAPING_COMET_URL, RIVEN_SCRAPING_JACKETT_URL, RIVEN_SCRAPING_ZILEAN_URL
when present) alongside the existing RIVEN_SCRAPING_TORRENTIO_ENABLED and
RIVEN_SCRAPING_PROWLARR_ENABLED checks, and change the branching so "NONE (❌
invalid state)" is only printed if none of these enabled flags are true; update
the echo lines for each provider to show a human-friendly name and URL where
applicable.
- Around line 315-363: The ensure_riven_rshared_mount() function is defined but
never invoked, and the script instead performs non-persistent one-off mounts
with redundant sudo; call ensure_riven_rshared_mount to install the systemd unit
and enforce rshared mounting, remove the trailing direct sudo mount commands
(sudo mount --bind ... and sudo mount --make-rshared ...) and the redundant
banner that follows, and ensure the call to ensure_riven_rshared_mount (which
uses MOUNT_PATH and SERVICE_NAME) runs as root at the appropriate point in the
flow so the persistent unit is created and systemd-enabled rather than only
performing a one-time mount.
- Around line 496-536: The downloader API key prompts currently call
require_non_empty instead of the masked input helper, so replace the three calls
setting RIVEN_DOWNLOADERS_REAL_DEBRID_API_KEY,
RIVEN_DOWNLOADERS_ALL_DEBRID_API_KEY, and RIVEN_DOWNLOADERS_DEBRID_LINK_API_KEY
with read_masked_non_empty to ensure sensitive tokens are not echoed; keep the
surrounding case branches and flag assignments
(RIVEN_DOWNLOADERS_REAL_DEBRID_ENABLED, RIVEN_DOWNLOADERS_ALL_DEBRID_ENABLED,
RIVEN_DOWNLOADERS_DEBRID_LINK_ENABLED) unchanged and preserve the prompt text
but pass the same prompt string into read_masked_non_empty.
- Around line 421-460: The media server case block collects sensitive API
keys/tokens using require_non_empty which echoes input; change those calls to
read_masked_non_empty so secrets are entered masked: replace
MEDIA_API_KEY="$(require_non_empty "Enter Jellyfin API Key")",
MEDIA_API_KEY="$(require_non_empty "Enter Plex X-Plex-Token")", and
MEDIA_API_KEY="$(require_non_empty "Enter Emby API Key")" with
MEDIA_API_KEY="$(read_masked_non_empty ...)" keeping the existing prompt text
and surrounding messages in the jellyfin, plex, and emby branches so input is
secure and behavior unchanged.
- Around line 889-892: The comment notes the script claims ".env Permissions:
600" but never enforces it; after the code that creates/writes the .env file
(near the .env creation around where INSTALL_DIR is used, e.g., after the block
that writes $INSTALL_DIR/.env around line ~806), add a command to set strict
permissions on that file (chmod 600 "$INSTALL_DIR/.env") so the claimed
permissions are actually applied; optionally ensure correct ownership with chown
if the script may run as root but the app runs under another user.

In @ubuntu/riven-remount-cycle.sh:
- Around line 115-123: The for-loop declares an unused variable i; update the
loop to use an underscore (_) as the iteration variable (e.g., for _ in $(seq 1
$MOUNT_WAIT); do) so shellcheck warnings are silenced, leaving the body (calls
to is_mounted and log "Mount active") unchanged and ensuring MOUNT_WAIT and
is_mounted remain referenced as before.
- Around line 33-35: The is_mounted() helper incorrectly uses findmnt -T which
returns true for any path under a mount; change it to check the exact mount
point by using findmnt -M with the same $MOUNT_PATH, or prepend an existence
check (e.g., test -e "$MOUNT_PATH") before calling findmnt -T; update the
is_mounted() function to use findmnt -M "$MOUNT_PATH" (or perform [ -e
"$MOUNT_PATH" ] && findmnt -T "$MOUNT_PATH") so it only returns success for the
actual mount point.
- Around line 74-79: The docker stop calls currently swallow failures with "||
true"; change them to capture the command exit status and output and log an
error via the existing log function when stopping fails. For both docker stop
"$RIVEN_CONTAINER" and docker stop "$MEDIA_CONTAINER" run the stop command, save
its stdout/stderr and exit code (e.g., cmd_output="$(docker stop
"$RIVEN_CONTAINER" 2>&1)"; rc=$?), and if rc is non-zero call log "Error
stopping container $RIVEN_CONTAINER: $cmd_output" (and similarly for
$MEDIA_CONTAINER); do not silently ignore failures.
📜 Review details

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 95da4fe and c936c22.

📒 Files selected for processing (2)
  • ubuntu/install.sh
  • ubuntu/riven-remount-cycle.sh
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2026-01-04T07:07:39.065Z
Learnt from: AquaHorizonGaming
Repo: rivenmedia/distributables PR: 1
File: proxmox/lxc/docker-compose.yml:23-23
Timestamp: 2026-01-04T07:07:39.065Z
Learning: In the rivenmedia/distributables repository, the Docker image tags `spoked/riven:dev` and `spoked/riven-frontend:dev` are the main/production build tags, not development tags.

Applied to files:

  • ubuntu/install.sh
🪛 Gitleaks (8.30.0)
ubuntu/install.sh

[high] 561-562: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


[high] 564-566: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


[high] 567-569: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)

🪛 Shellcheck (0.11.0)
ubuntu/riven-remount-cycle.sh

[warning] 117-117: i appears unused. Verify use (or export if used externally).

(SC2034)

ubuntu/install.sh

[info] 120-120: Not following: /etc/os-release was not specified as input (see shellcheck -x).

(SC1091)


[info] 202-202: Note that A && B || C is not if-then-else. C may run when A is true.

(SC2015)

🔇 Additional comments (7)
ubuntu/riven-remount-cycle.sh (2)

1-14: LGTM!

Root check and strict mode (set -euo pipefail) are correctly implemented. The error message provides a clear example of how to run the script.


136-141: LGTM!

The post-mount restart with a 5-second stabilization delay is a reasonable approach to ensure the media server picks up the remounted filesystem correctly.

ubuntu/install.sh (5)

1-17: LGTM!

Constants are well-defined with sensible defaults. The installer version tracking is useful for troubleshooting.


45-77: LGTM!

The masked input function properly handles backspace, provides visual feedback with asterisks, and trims whitespace. Good security practice for sensitive inputs.


554-569: False positive: Gitleaks flagging empty variable initialization.

The static analysis warning about "Generic API Key" on these lines is a false positive—these are empty string initializations, not actual secrets.


650-656: Temporary pipefail disable is correct but worth documenting.

Disabling pipefail around /dev/urandom piping is necessary since head -c 32 closes the pipe early, causing tr to exit non-zero. The subsequent validation at line 662 ensures correctness. Consider adding a brief comment explaining why.


810-816: LGTM!

Docker Compose startup is straightforward and correctly placed after all configuration is complete.

Comment on lines +199 to +208
banner "System Dependencies"

dpkg -s ca-certificates curl gnupg lsb-release openssl fuse3 >/dev/null 2>&1 \
&& ok "System dependencies already installed" \
|| {
apt-get update || fail "apt update failed"
apt-get install -y ca-certificates curl gnupg lsb-release openssl fuse3 \
|| fail "dependency install failed"
ok "System dependencies installed"
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

A && B || C pattern may execute C unexpectedly.

If dpkg -s succeeds but ok "..." fails (e.g., stdout issue), the apt-get block will still run. While unlikely, consider explicit if-else for robustness.

♻️ Suggested fix
-dpkg -s ca-certificates curl gnupg lsb-release openssl fuse3 >/dev/null 2>&1 \
-  && ok "System dependencies already installed" \
-  || {
-    apt-get update || fail "apt update failed"
-    apt-get install -y ca-certificates curl gnupg lsb-release openssl fuse3 \
-      || fail "dependency install failed"
-    ok "System dependencies installed"
-  }
+if dpkg -s ca-certificates curl gnupg lsb-release openssl fuse3 >/dev/null 2>&1; then
+  ok "System dependencies already installed"
+else
+  apt-get update || fail "apt update failed"
+  apt-get install -y ca-certificates curl gnupg lsb-release openssl fuse3 \
+    || fail "dependency install failed"
+  ok "System dependencies installed"
+fi
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
banner "System Dependencies"
dpkg -s ca-certificates curl gnupg lsb-release openssl fuse3 >/dev/null 2>&1 \
&& ok "System dependencies already installed" \
|| {
apt-get update || fail "apt update failed"
apt-get install -y ca-certificates curl gnupg lsb-release openssl fuse3 \
|| fail "dependency install failed"
ok "System dependencies installed"
}
banner "System Dependencies"
if dpkg -s ca-certificates curl gnupg lsb-release openssl fuse3 >/dev/null 2>&1; then
ok "System dependencies already installed"
else
apt-get update || fail "apt update failed"
apt-get install -y ca-certificates curl gnupg lsb-release openssl fuse3 \
|| fail "dependency install failed"
ok "System dependencies installed"
fi
🧰 Tools
🪛 Shellcheck (0.11.0)

[info] 202-202: Note that A && B || C is not if-then-else. C may run when A is true.

(SC2015)

🤖 Prompt for AI Agents
In @ubuntu/install.sh around lines 199 - 208, The current use of the `dpkg -s
... >/dev/null 2>&1 && ok "System dependencies already installed" || { ... }`
pattern can run the install block if `ok` fails; change this to an explicit
if/then/else: run `dpkg -s ca-certificates curl gnupg lsb-release openssl fuse3`
and if it exits zero, call `ok "System dependencies already installed"`; else
run `apt-get update || fail "apt update failed"`, then `apt-get install -y ...
|| fail "dependency install failed"`, then `ok "System dependencies installed"`.
Keep the existing `banner`, `ok`, and `fail` calls but remove the `&& ... || {
... }` chaining so the install block only executes when `dpkg -s` fails.

Comment on lines +315 to +363
ensure_riven_rshared_mount() {
local MOUNT_PATH="/mnt/riven/mount"
local SERVICE_NAME="riven-bind-shared.service"

banner "Ensuring rshared mount for Riven"

mkdir -p "$MOUNT_PATH"

# If already shared, do nothing
if findmnt -no PROPAGATION "$MOUNT_PATH" 2>/dev/null | grep -q shared; then
ok "Mount already rshared"
return
fi

warn "Mount is not rshared — installing systemd unit"

cat >/etc/systemd/system/$SERVICE_NAME <<EOF
[Unit]
Description=Make Riven mount bind shared
After=local-fs.target
Before=docker.service
[Service]
Type=oneshot
ExecStart=/usr/bin/mount --bind $MOUNT_PATH $MOUNT_PATH
ExecStart=/usr/bin/mount --make-rshared $MOUNT_PATH
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
EOF

systemctl daemon-reexec
systemctl daemon-reload
systemctl enable --now "$SERVICE_NAME"

# Re-check
if findmnt -no PROPAGATION "$MOUNT_PATH" | grep -q shared; then
ok "rshared mount enforced"
else
fail "Failed to enforce rshared mount on $MOUNT_PATH"
fi
}


sudo mount --bind $MOUNT_PATH $MOUNT_PATH
sudo mount --make-rshared $MOUNT_PATH

banner "Mounted $MOUNT_PATH"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Critical: ensure_riven_rshared_mount() function is defined but never called.

The function at lines 315-357 sets up the systemd unit for persistent rshared mounts, but it's never invoked. Instead, lines 360-363 run one-time mount commands directly, which won't persist across reboots. Additionally, sudo is redundant since the script already requires root (line 134).

🐛 Proposed fix
   fi
 }

-
-sudo mount --bind $MOUNT_PATH $MOUNT_PATH
-sudo mount --make-rshared $MOUNT_PATH
-
-  banner "Mounted $MOUNT_PATH"
+ensure_riven_rshared_mount
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
ensure_riven_rshared_mount() {
local MOUNT_PATH="/mnt/riven/mount"
local SERVICE_NAME="riven-bind-shared.service"
banner "Ensuring rshared mount for Riven"
mkdir -p "$MOUNT_PATH"
# If already shared, do nothing
if findmnt -no PROPAGATION "$MOUNT_PATH" 2>/dev/null | grep -q shared; then
ok "Mount already rshared"
return
fi
warn "Mount is not rshared — installing systemd unit"
cat >/etc/systemd/system/$SERVICE_NAME <<EOF
[Unit]
Description=Make Riven mount bind shared
After=local-fs.target
Before=docker.service
[Service]
Type=oneshot
ExecStart=/usr/bin/mount --bind $MOUNT_PATH $MOUNT_PATH
ExecStart=/usr/bin/mount --make-rshared $MOUNT_PATH
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reexec
systemctl daemon-reload
systemctl enable --now "$SERVICE_NAME"
# Re-check
if findmnt -no PROPAGATION "$MOUNT_PATH" | grep -q shared; then
ok "rshared mount enforced"
else
fail "Failed to enforce rshared mount on $MOUNT_PATH"
fi
}
sudo mount --bind $MOUNT_PATH $MOUNT_PATH
sudo mount --make-rshared $MOUNT_PATH
banner "Mounted $MOUNT_PATH"
ensure_riven_rshared_mount() {
local MOUNT_PATH="/mnt/riven/mount"
local SERVICE_NAME="riven-bind-shared.service"
banner "Ensuring rshared mount for Riven"
mkdir -p "$MOUNT_PATH"
# If already shared, do nothing
if findmnt -no PROPAGATION "$MOUNT_PATH" 2>/dev/null | grep -q shared; then
ok "Mount already rshared"
return
fi
warn "Mount is not rshared — installing systemd unit"
cat >/etc/systemd/system/$SERVICE_NAME <<EOF
[Unit]
Description=Make Riven mount bind shared
After=local-fs.target
Before=docker.service
[Service]
Type=oneshot
ExecStart=/usr/bin/mount --bind $MOUNT_PATH $MOUNT_PATH
ExecStart=/usr/bin/mount --make-rshared $MOUNT_PATH
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reexec
systemctl daemon-reload
systemctl enable --now "$SERVICE_NAME"
# Re-check
if findmnt -no PROPAGATION "$MOUNT_PATH" | grep -q shared; then
ok "rshared mount enforced"
else
fail "Failed to enforce rshared mount on $MOUNT_PATH"
fi
}
ensure_riven_rshared_mount
🤖 Prompt for AI Agents
In @ubuntu/install.sh around lines 315 - 363, The ensure_riven_rshared_mount()
function is defined but never invoked, and the script instead performs
non-persistent one-off mounts with redundant sudo; call
ensure_riven_rshared_mount to install the systemd unit and enforce rshared
mounting, remove the trailing direct sudo mount commands (sudo mount --bind ...
and sudo mount --make-rshared ...) and the redundant banner that follows, and
ensure the call to ensure_riven_rshared_mount (which uses MOUNT_PATH and
SERVICE_NAME) runs as root at the appropriate point in the flow so the
persistent unit is created and systemd-enabled rather than only performing a
one-time mount.

Comment on lines +421 to +460
case "$MEDIA_PROFILE" in
jellyfin)
echo "Jellyfin requires an API key."
echo
echo "How to get it:"
echo " 1) Open Jellyfin Web UI"
echo " 2) Dashboard → API Keys"
echo " 3) Create a new API key"
echo
echo "Paste ONLY the API key value below:"
MEDIA_API_KEY="$(require_non_empty "Enter Jellyfin API Key")"
;;
plex)
echo "Plex requires a USER TOKEN (NOT an API key)."
echo
echo "How to get it:"
echo " 1) Open Plex Web App and ensure you are logged in"
echo " 2) Visit: https://plex.tv/devices.xml"
echo " 3) Copy the value of X-Plex-Token"
echo
echo "⚠️ IMPORTANT:"
echo " • Paste ONLY the token value"
echo " • Do NOT include 'token='"
echo " • Do NOT paste XML or URLs"
echo
echo "Paste the token below:"
MEDIA_API_KEY="$(require_non_empty "Enter Plex X-Plex-Token")"
;;
emby)
echo "Emby requires an API key."
echo
echo "How to get it:"
echo " 1) Open Emby Web UI"
echo " 2) Settings → Advanced → API Keys"
echo " 3) Create a new API key"
echo
echo "Paste ONLY the API key value below:"
MEDIA_API_KEY="$(require_non_empty "Enter Emby API Key")"
;;
esac
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Security inconsistency: API keys/tokens collected without masking.

The script defines read_masked_non_empty() for secure input but uses require_non_empty() for media server API keys (lines 431, 447, 458). These sensitive tokens will be visible on screen during input.

🔒 Proposed fix
     echo "Paste ONLY the API key value below:"
-    MEDIA_API_KEY="$(require_non_empty "Enter Jellyfin API Key")"
+    MEDIA_API_KEY="$(read_masked_non_empty "Enter Jellyfin API Key")"
     ;;
   plex)
     ...
     echo "Paste the token below:"
-    MEDIA_API_KEY="$(require_non_empty "Enter Plex X-Plex-Token")"
+    MEDIA_API_KEY="$(read_masked_non_empty "Enter Plex X-Plex-Token")"
     ;;
   emby)
     ...
     echo "Paste ONLY the API key value below:"
-    MEDIA_API_KEY="$(require_non_empty "Enter Emby API Key")"
+    MEDIA_API_KEY="$(read_masked_non_empty "Enter Emby API Key")"
     ;;
🤖 Prompt for AI Agents
In @ubuntu/install.sh around lines 421 - 460, The media server case block
collects sensitive API keys/tokens using require_non_empty which echoes input;
change those calls to read_masked_non_empty so secrets are entered masked:
replace MEDIA_API_KEY="$(require_non_empty "Enter Jellyfin API Key")",
MEDIA_API_KEY="$(require_non_empty "Enter Plex X-Plex-Token")", and
MEDIA_API_KEY="$(require_non_empty "Enter Emby API Key")" with
MEDIA_API_KEY="$(read_masked_non_empty ...)" keeping the existing prompt text
and surrounding messages in the jellyfin, plex, and emby branches so input is
secure and behavior unchanged.

Comment on lines +496 to +536
case "$DL_SEL" in
1)
RIVEN_DOWNLOADERS_REAL_DEBRID_ENABLED=true
echo
echo "Real-Debrid API Token required."
echo
echo "How to get it:"
echo " 1) Visit https://real-debrid.com/apitoken"
echo " 2) Copy the API Token shown"
echo
echo "Paste ONLY the API token value below:"
RIVEN_DOWNLOADERS_REAL_DEBRID_API_KEY="$(require_non_empty "Enter Real-Debrid API Token")"
;;
2)
RIVEN_DOWNLOADERS_ALL_DEBRID_ENABLED=true
echo
echo "All-Debrid API Key required."
echo
echo "How to get it:"
echo " 1) Visit https://alldebrid.com/apikeys"
echo " 2) Generate or copy an existing key"
echo
echo "Paste ONLY the API key value below:"
RIVEN_DOWNLOADERS_ALL_DEBRID_API_KEY="$(require_non_empty "Enter All-Debrid API Key")"
;;
3)
RIVEN_DOWNLOADERS_DEBRID_LINK_ENABLED=true
echo
echo "Debrid-Link API Key required."
echo
echo "How to get it:"
echo " 1) Visit https://debrid-link.com/webapp/apikey"
echo " 2) Copy your API key"
echo
echo "Paste ONLY the API key value below:"
RIVEN_DOWNLOADERS_DEBRID_LINK_API_KEY="$(require_non_empty "Enter Debrid-Link API Key")"
;;
*)
fail "Downloader selection REQUIRED"
;;
esac
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Same masking issue for downloader API keys.

Lines 507, 519, and 531 use require_non_empty() for debrid API keys instead of read_masked_non_empty().

🔒 Proposed fix
     echo "Paste ONLY the API token value below:"
-    RIVEN_DOWNLOADERS_REAL_DEBRID_API_KEY="$(require_non_empty "Enter Real-Debrid API Token")"
+    RIVEN_DOWNLOADERS_REAL_DEBRID_API_KEY="$(read_masked_non_empty "Enter Real-Debrid API Token")"
     ;;
   2)
     ...
     echo "Paste ONLY the API key value below:"
-    RIVEN_DOWNLOADERS_ALL_DEBRID_API_KEY="$(require_non_empty "Enter All-Debrid API Key")"
+    RIVEN_DOWNLOADERS_ALL_DEBRID_API_KEY="$(read_masked_non_empty "Enter All-Debrid API Key")"
     ;;
   3)
     ...
     echo "Paste ONLY the API key value below:"
-    RIVEN_DOWNLOADERS_DEBRID_LINK_API_KEY="$(require_non_empty "Enter Debrid-Link API Key")"
+    RIVEN_DOWNLOADERS_DEBRID_LINK_API_KEY="$(read_masked_non_empty "Enter Debrid-Link API Key")"
     ;;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
case "$DL_SEL" in
1)
RIVEN_DOWNLOADERS_REAL_DEBRID_ENABLED=true
echo
echo "Real-Debrid API Token required."
echo
echo "How to get it:"
echo " 1) Visit https://real-debrid.com/apitoken"
echo " 2) Copy the API Token shown"
echo
echo "Paste ONLY the API token value below:"
RIVEN_DOWNLOADERS_REAL_DEBRID_API_KEY="$(require_non_empty "Enter Real-Debrid API Token")"
;;
2)
RIVEN_DOWNLOADERS_ALL_DEBRID_ENABLED=true
echo
echo "All-Debrid API Key required."
echo
echo "How to get it:"
echo " 1) Visit https://alldebrid.com/apikeys"
echo " 2) Generate or copy an existing key"
echo
echo "Paste ONLY the API key value below:"
RIVEN_DOWNLOADERS_ALL_DEBRID_API_KEY="$(require_non_empty "Enter All-Debrid API Key")"
;;
3)
RIVEN_DOWNLOADERS_DEBRID_LINK_ENABLED=true
echo
echo "Debrid-Link API Key required."
echo
echo "How to get it:"
echo " 1) Visit https://debrid-link.com/webapp/apikey"
echo " 2) Copy your API key"
echo
echo "Paste ONLY the API key value below:"
RIVEN_DOWNLOADERS_DEBRID_LINK_API_KEY="$(require_non_empty "Enter Debrid-Link API Key")"
;;
*)
fail "Downloader selection REQUIRED"
;;
esac
case "$DL_SEL" in
1)
RIVEN_DOWNLOADERS_REAL_DEBRID_ENABLED=true
echo
echo "Real-Debrid API Token required."
echo
echo "How to get it:"
echo " 1) Visit https://real-debrid.com/apitoken"
echo " 2) Copy the API Token shown"
echo
echo "Paste ONLY the API token value below:"
RIVEN_DOWNLOADERS_REAL_DEBRID_API_KEY="$(read_masked_non_empty "Enter Real-Debrid API Token")"
;;
2)
RIVEN_DOWNLOADERS_ALL_DEBRID_ENABLED=true
echo
echo "All-Debrid API Key required."
echo
echo "How to get it:"
echo " 1) Visit https://alldebrid.com/apikeys"
echo " 2) Generate or copy an existing key"
echo
echo "Paste ONLY the API key value below:"
RIVEN_DOWNLOADERS_ALL_DEBRID_API_KEY="$(read_masked_non_empty "Enter All-Debrid API Key")"
;;
3)
RIVEN_DOWNLOADERS_DEBRID_LINK_ENABLED=true
echo
echo "Debrid-Link API Key required."
echo
echo "How to get it:"
echo " 1) Visit https://debrid-link.com/webapp/apikey"
echo " 2) Copy your API key"
echo
echo "Paste ONLY the API key value below:"
RIVEN_DOWNLOADERS_DEBRID_LINK_API_KEY="$(read_masked_non_empty "Enter Debrid-Link API Key")"
;;
*)
fail "Downloader selection REQUIRED"
;;
esac
🤖 Prompt for AI Agents
In @ubuntu/install.sh around lines 496 - 536, The downloader API key prompts
currently call require_non_empty instead of the masked input helper, so replace
the three calls setting RIVEN_DOWNLOADERS_REAL_DEBRID_API_KEY,
RIVEN_DOWNLOADERS_ALL_DEBRID_API_KEY, and RIVEN_DOWNLOADERS_DEBRID_LINK_API_KEY
with read_masked_non_empty to ensure sensitive tokens are not echoed; keep the
surrounding case branches and flag assignments
(RIVEN_DOWNLOADERS_REAL_DEBRID_ENABLED, RIVEN_DOWNLOADERS_ALL_DEBRID_ENABLED,
RIVEN_DOWNLOADERS_DEBRID_LINK_ENABLED) unchanged and preserve the prompt text
but pass the same prompt string into read_masked_non_empty.

Comment on lines +863 to +870
echo "🔍 Scraper"
if [[ "$RIVEN_SCRAPING_TORRENTIO_ENABLED" == "true" ]]; then
echo " • Torrentio"
elif [[ "$RIVEN_SCRAPING_PROWLARR_ENABLED" == "true" ]]; then
echo " • Prowlarr ($RIVEN_SCRAPING_PROWLARR_URL)"
else
echo " • NONE (❌ invalid state)"
fi
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Incomplete scraper status in summary.

The summary only checks for Torrentio and Prowlarr but omits Comet, Jackett, and Zilean, potentially showing "NONE (❌ invalid state)" incorrectly.

🐛 Proposed fix
 echo "🔍 Scraper"
 if [[ "$RIVEN_SCRAPING_TORRENTIO_ENABLED" == "true" ]]; then
   echo "  • Torrentio"
 elif [[ "$RIVEN_SCRAPING_PROWLARR_ENABLED" == "true" ]]; then
   echo "  • Prowlarr ($RIVEN_SCRAPING_PROWLARR_URL)"
+elif [[ "$RIVEN_SCRAPING_COMET_ENABLED" == "true" ]]; then
+  echo "  • Comet ($RIVEN_SCRAPING_COMET_URL)"
+elif [[ "$RIVEN_SCRAPING_JACKETT_ENABLED" == "true" ]]; then
+  echo "  • Jackett ($RIVEN_SCRAPING_JACKETT_URL)"
+elif [[ "$RIVEN_SCRAPING_ZILEAN_ENABLED" == "true" ]]; then
+  echo "  • Zilean ($RIVEN_SCRAPING_ZILEAN_URL)"
 else
   echo "  • NONE (❌ invalid state)"
 fi
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
echo "🔍 Scraper"
if [[ "$RIVEN_SCRAPING_TORRENTIO_ENABLED" == "true" ]]; then
echo " • Torrentio"
elif [[ "$RIVEN_SCRAPING_PROWLARR_ENABLED" == "true" ]]; then
echo " • Prowlarr ($RIVEN_SCRAPING_PROWLARR_URL)"
else
echo " • NONE (❌ invalid state)"
fi
echo "🔍 Scraper"
if [[ "$RIVEN_SCRAPING_TORRENTIO_ENABLED" == "true" ]]; then
echo " • Torrentio"
elif [[ "$RIVEN_SCRAPING_PROWLARR_ENABLED" == "true" ]]; then
echo " • Prowlarr ($RIVEN_SCRAPING_PROWLARR_URL)"
elif [[ "$RIVEN_SCRAPING_COMET_ENABLED" == "true" ]]; then
echo " • Comet ($RIVEN_SCRAPING_COMET_URL)"
elif [[ "$RIVEN_SCRAPING_JACKETT_ENABLED" == "true" ]]; then
echo " • Jackett ($RIVEN_SCRAPING_JACKETT_URL)"
elif [[ "$RIVEN_SCRAPING_ZILEAN_ENABLED" == "true" ]]; then
echo " • Zilean ($RIVEN_SCRAPING_ZILEAN_URL)"
else
echo " • NONE (❌ invalid state)"
fi
🤖 Prompt for AI Agents
In @ubuntu/install.sh around lines 863 - 870, The summary block for "🔍 Scraper"
is incomplete: add checks for RIVEN_SCRAPING_COMET_ENABLED,
RIVEN_SCRAPING_JACKETT_ENABLED, and RIVEN_SCRAPING_ZILEAN_ENABLED (and include
their URL vars e.g. RIVEN_SCRAPING_COMET_URL, RIVEN_SCRAPING_JACKETT_URL,
RIVEN_SCRAPING_ZILEAN_URL when present) alongside the existing
RIVEN_SCRAPING_TORRENTIO_ENABLED and RIVEN_SCRAPING_PROWLARR_ENABLED checks, and
change the branching so "NONE (❌ invalid state)" is only printed if none of
these enabled flags are true; update the echo lines for each provider to show a
human-friendly name and URL where applicable.

Comment on lines +873 to +880
echo "🗄️ Database"
echo " • Postgres DB: riven"
echo " • User: postgres"
echo
echo " • POSTGRES PASSWORD: $POSTGRES_PASSWORD"
echo " • BACKEND API KEY: $BACKEND_API_KEY"
echo " • AUTH SECRET: $AUTH_SECRET"

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Security: Secrets printed to stdout are logged to file.

Lines 877-879 print POSTGRES_PASSWORD, BACKEND_API_KEY, and AUTH_SECRET to stdout. Since line 160 tees all output to the log file, these secrets persist in plaintext at /tmp/logs/riven/install-*.log. Consider either excluding these from logging or restricting log file permissions.

🔒 Suggested approaches

Option 1: Print secrets directly to terminal, bypassing tee:

echo "  • POSTGRES PASSWORD:  $POSTGRES_PASSWORD" >/dev/tty
echo "  • BACKEND API KEY:    $BACKEND_API_KEY" >/dev/tty
echo "  • AUTH SECRET:        $AUTH_SECRET" >/dev/tty

Option 2: Restrict log file permissions and warn user:

chmod 600 "$LOG_FILE"
echo "  • Secrets saved to .env file only (not logged)"
🤖 Prompt for AI Agents
In @ubuntu/install.sh around lines 873 - 880, The script currently echoes
secrets (POSTGRES_PASSWORD, BACKEND_API_KEY, AUTH_SECRET) to stdout which is
being teed to the install log (see tee at line ~160), causing plaintext secrets
to persist in /tmp/logs; remove or change those echo lines so secrets are not
written to the log: either write those echo outputs directly to the controlling
terminal (e.g., redirect to /dev/tty) so they bypass tee, or stop printing them
entirely and save them only to a restricted .env file and tighten the log file
permissions (chmod 600) before logging; update the three echo lines referencing
POSTGRES_PASSWORD, BACKEND_API_KEY and AUTH_SECRET and ensure logging
behavior/LOG_FILE permissions reflect the chosen approach.

Comment on lines +889 to +892
echo "📦 Environment"
echo " • .env Location: $INSTALL_DIR/.env"
echo " • Permissions: 600"
echo
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Claimed permissions not enforced.

The summary states .env has "Permissions: 600" but no chmod 600 .env command is executed. The file will have default umask permissions, potentially allowing other users to read secrets.

🔒 Proposed fix after .env creation (around line 806)
 mv .env.fixed .env
+chmod 600 .env

 ok ".env repaired and sanitized"
🤖 Prompt for AI Agents
In @ubuntu/install.sh around lines 889 - 892, The comment notes the script
claims ".env Permissions: 600" but never enforces it; after the code that
creates/writes the .env file (near the .env creation around where INSTALL_DIR is
used, e.g., after the block that writes $INSTALL_DIR/.env around line ~806), add
a command to set strict permissions on that file (chmod 600 "$INSTALL_DIR/.env")
so the claimed permissions are actually applied; optionally ensure correct
ownership with chown if the script may run as root but the app runs under
another user.

Comment on lines +33 to +35
is_mounted() {
findmnt -T "$MOUNT_PATH" >/dev/null 2>&1
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

findmnt -T checks if path is within a mount, not if it's a mount point.

Using findmnt -T will return success even if $MOUNT_PATH doesn't exist but is under a mounted filesystem (e.g., root). Consider using findmnt -M for an exact mount point check, or verify the path specifically.

♻️ Suggested fix
 is_mounted() {
-  findmnt -T "$MOUNT_PATH" >/dev/null 2>&1
+  findmnt -M "$MOUNT_PATH" >/dev/null 2>&1
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
is_mounted() {
findmnt -T "$MOUNT_PATH" >/dev/null 2>&1
}
is_mounted() {
findmnt -M "$MOUNT_PATH" >/dev/null 2>&1
}
🤖 Prompt for AI Agents
In @ubuntu/riven-remount-cycle.sh around lines 33 - 35, The is_mounted() helper
incorrectly uses findmnt -T which returns true for any path under a mount;
change it to check the exact mount point by using findmnt -M with the same
$MOUNT_PATH, or prepend an existence check (e.g., test -e "$MOUNT_PATH") before
calling findmnt -T; update the is_mounted() function to use findmnt -M
"$MOUNT_PATH" (or perform [ -e "$MOUNT_PATH" ] && findmnt -T "$MOUNT_PATH") so
it only returns success for the actual mount point.

Comment on lines 74 to 79
############################################
log "Stopping Riven container"
docker stop "$RIVEN_CONTAINER" || true

log "Stopping media container"
docker stop "$MEDIA_CONTAINER" || true
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Consider logging when container stop fails.

Using || true silently ignores container stop failures. If a container doesn't exist or Docker is unreachable, the script continues without warning, which may confuse operators debugging issues.

♻️ Suggested improvement
 log "Stopping Riven container"
-docker stop "$RIVEN_CONTAINER" || true
+docker stop "$RIVEN_CONTAINER" 2>/dev/null || warn "Riven container not running or not found"

 log "Stopping media container"
-docker stop "$MEDIA_CONTAINER" || true
+docker stop "$MEDIA_CONTAINER" 2>/dev/null || warn "Media container not running or not found"
🤖 Prompt for AI Agents
In @ubuntu/riven-remount-cycle.sh around lines 74 - 79, The docker stop calls
currently swallow failures with "|| true"; change them to capture the command
exit status and output and log an error via the existing log function when
stopping fails. For both docker stop "$RIVEN_CONTAINER" and docker stop
"$MEDIA_CONTAINER" run the stop command, save its stdout/stderr and exit code
(e.g., cmd_output="$(docker stop "$RIVEN_CONTAINER" 2>&1)"; rc=$?), and if rc is
non-zero call log "Error stopping container $RIVEN_CONTAINER: $cmd_output" (and
similarly for $MEDIA_CONTAINER); do not silently ignore failures.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 9

🤖 Fix all issues with AI agents
In @ubuntu/readme.md:
- Around line 14-15: Remove the duplicated "Riven Ubuntu Installer" heading and
place the anchor <a id="installer"></a> immediately before the single heading
"Riven Ubuntu Installer" with a blank line separating the anchor and heading;
ensure only one heading remains and delete the extra line so the file contains a
single anchor + heading pair.
- Around line 7-12: The installer instructions reference the wrong script:
update the command in the "How to run the installer (Ubuntu Script)" section so
the curl URL points to install.sh instead of riven-remount-cycle.sh; locate the
command string containing "riven-remount-cycle.sh" in the README and replace it
with "install.sh" so users run the intended installer script.
- Around line 102-105: Add a blank line before the horizontal rule '---' that
follows the URL lines (the lines containing "http://<SERVER_IP>:3000" and
"http://<domain>") so the Markdown has an empty line between the text and the
'---' separator; edit the section where '---' appears and insert a single empty
line above it.
- Around line 44-53: Replace the indented directory listing with a fenced code
block to match the rest of the README and satisfy markdownlint MD046: wrap the
directory tree lines (the block starting with "/opt/riven" and ending with
"Media library (movies, TV, anime)") with triple backticks (``` ) before and
after the block so it becomes a fenced code block, preserving the exact
indentation and characters inside the fenced block.
- Around line 142-143: Remove the extraneous blank line immediately before the
anchor "<a id="uninstaller"></a>" and ensure there is one blank line after that
anchor and before the following heading so the anchor sits alone with a single
blank line both above and below (fixes MD022).

In @ubuntu/riven-remount-cycle.sh:
- Around line 136-140: Clarify the rationale for the docker restart by replacing
the vague "mount stabilization" comment above the sleep/restart block
(referencing MEDIA_CONTAINER and the restart sequence) with a concise
explanation of the specific failure mode this addresses (e.g., the media service
caching stale mount state or failing to revalidate mounts on first start), state
why a restart (docker restart "$MEDIA_CONTAINER") is required instead of only
waiting, and include any expected timing (5s) and a note to revisit if fixed;
keep the sleep 5 and docker restart "$MEDIA_CONTAINER" intact unless a reliable
mount-check/loopback exists, in which case implement that check in place of the
unconditional restart.
- Around line 117-123: The for-loop uses an unused iteration variable i which
triggers shellcheck SC2034; change the loop to use _ as the iterator (for _ in
$(seq 1 $MOUNT_WAIT); do ...) so the intent of an unused counter is clear and
the warning is silenced; update the loop surrounding is_mounted and log "Mount
active" accordingly while leaving the body logic unchanged.
- Around line 56-68: The case branch handling option 4 does not validate empty
input for MEDIA_CONTAINER, so if the user presses Enter the variable is empty
and later docker stop ""/start "" will fail; update the branch in the case that
prompts for the custom container name (the read -rp for MEDIA_CONTAINER) to trim
and validate the response (reject empty/whitespace-only input), re-prompt in a
loop until a non-empty name is provided or call fail with an explanatory
message, ensuring subsequent docker stop/start calls receive a valid
MEDIA_CONTAINER value.
- Around line 7-14: The root-check echo shown in the if-block prints an
incorrect example URL; replace the example lines that currently print the raw
GitHub URL with a concrete sudo invocation so users know how to run the script
(update the echo lines inside the if [[ "$EUID" -ne 0 ]] block to show something
like "Example: sudo ./riven-remount-cycle.sh" or "Example: sudo bash
riven-remount-cycle.sh" instead of the raw URL).
📜 Review details

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between c936c22 and fb61906.

📒 Files selected for processing (2)
  • ubuntu/readme.md
  • ubuntu/riven-remount-cycle.sh
🧰 Additional context used
🪛 markdownlint-cli2 (0.18.1)
ubuntu/readme.md

1-1: First line in a file should be a top-level heading

(MD041, first-line-heading, first-line-h1)


10-10: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


15-15: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Above

(MD022, blanks-around-headings)


33-33: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


44-44: Code block style
Expected: fenced; Actual: indented

(MD046, code-block-style)


65-65: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


74-74: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


102-102: Code block style
Expected: fenced; Actual: indented

(MD046, code-block-style)


120-120: Code block style
Expected: fenced; Actual: indented

(MD046, code-block-style)


124-124: Code block style
Expected: fenced; Actual: indented

(MD046, code-block-style)


130-130: Code block style
Expected: fenced; Actual: indented

(MD046, code-block-style)


144-144: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Above

(MD022, blanks-around-headings)


154-154: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


155-155: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Above

(MD022, blanks-around-headings)


170-170: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Above

(MD022, blanks-around-headings)

🪛 Shellcheck (0.11.0)
ubuntu/riven-remount-cycle.sh

[warning] 117-117: i appears unused. Verify use (or export if used externally).

(SC2034)

🔇 Additional comments (2)
ubuntu/riven-remount-cycle.sh (2)

29-35: LGTM!

Clean helper functions with consistent styling. The is_mounted function using findmnt is a reliable approach for checking mount status.


86-95: LGTM!

Good retry logic with configurable attempts and wait intervals. Using || true prevents the script from exiting on unmount failure, which is appropriate here since the loop handles retries.

ubuntu/readme.md Outdated
Comment on lines 14 to 15
<a id="installer"></a># 🔁 Riven Ubuntu Installer
# Riven Ubuntu Installer
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Duplicate heading and anchor placement issue.

Line 14 contains an anchor tag followed immediately by a heading on line 15, creating a duplicate "Riven Ubuntu Installer" heading. The anchor should precede a single heading with proper blank lines.

📝 Proposed fix
-<a id="installer"></a># 🔁 Riven Ubuntu Installer
-# Riven Ubuntu Installer
+<a id="installer"></a>
+
+# 🔁 Riven Ubuntu Installer
🧰 Tools
🪛 markdownlint-cli2 (0.18.1)

15-15: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Above

(MD022, blanks-around-headings)

🤖 Prompt for AI Agents
In @ubuntu/readme.md around lines 14 - 15, Remove the duplicated "Riven Ubuntu
Installer" heading and place the anchor <a id="installer"></a> immediately
before the single heading "Riven Ubuntu Installer" with a blank line separating
the anchor and heading; ensure only one heading remains and delete the extra
line so the file contains a single anchor + heading pair.

Comment on lines +44 to +53
/opt/riven
├─ docker-compose.yml
└─ .env

/mnt/riven/backend
├─ Riven backend data
└─ settings.json (auto-generated)

/mnt/riven/mount
└─ Media library (movies, TV, anime)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Consider using fenced code blocks for consistency.

The directory structure uses indented code blocks, but fenced code blocks (```) are used elsewhere. Consistent formatting improves readability. This is also flagged by markdownlint (MD046).

📝 Suggested improvement
 Creates and manages the following paths:

-    /opt/riven
-     ├─ docker-compose.yml
-     └─ .env
-
-    /mnt/riven/backend
-     ├─ Riven backend data
-     └─ settings.json (auto-generated)
-
-    /mnt/riven/mount
-     └─ Media library (movies, TV, anime)
+```
+/opt/riven
+ ├─ docker-compose.yml
+ └─ .env
+
+/mnt/riven/backend
+ ├─ Riven backend data
+ └─ settings.json (auto-generated)
+
+/mnt/riven/mount
+ └─ Media library (movies, TV, anime)
+```
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
/opt/riven
├─ docker-compose.yml
└─ .env
/mnt/riven/backend
├─ Riven backend data
└─ settings.json (auto-generated)
/mnt/riven/mount
└─ Media library (movies, TV, anime)
🧰 Tools
🪛 markdownlint-cli2 (0.18.1)

44-44: Code block style
Expected: fenced; Actual: indented

(MD046, code-block-style)

🤖 Prompt for AI Agents
In @ubuntu/readme.md around lines 44 - 53, Replace the indented directory
listing with a fenced code block to match the rest of the README and satisfy
markdownlint MD046: wrap the directory tree lines (the block starting with
"/opt/riven" and ending with "Media library (movies, TV, anime)") with triple
backticks (``` ) before and after the block so it becomes a fenced code block,
preserving the exact indentation and characters inside the fenced block.

Comment on lines +142 to +143

<a id="uninstaller"></a>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Extraneous blank line before anchor.

There's a blank line at 142 before the anchor at 143, but the anchor itself lacks a blank line after it before the heading at 144 (per MD022).

📝 Suggested fix
 - No further setup is required

-
 <a id="uninstaller"></a>
+
 ## 🗑️ Riven Ubuntu Uninstaller
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<a id="uninstaller"></a>
- No further setup is required
<a id="uninstaller"></a>
## 🗑️ Riven Ubuntu Uninstaller
🤖 Prompt for AI Agents
In @ubuntu/readme.md around lines 142 - 143, Remove the extraneous blank line
immediately before the anchor "<a id="uninstaller"></a>" and ensure there is one
blank line after that anchor and before the following heading so the anchor sits
alone with a single blank line both above and below (fixes MD022).

Comment on lines 7 to 14
if [[ "$EUID" -ne 0 ]]; then
echo
echo "[✖] This script must be run with sudo"
echo " Example:"
echo " https://raw.githubusercontent.com/AquaHorizonGaming/riven-scripts/main/ubuntu/riven-remount-cycle.sh"
echo
exit 1
fi
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Root check looks good, but the example URL seems incorrect.

The error message shows a URL to riven-remount-cycle.sh, but the example should show how to run the script with sudo, not the raw URL. Consider providing the actual invocation command.

💡 Suggested improvement
 if [[ "$EUID" -ne 0 ]]; then
   echo
   echo "[✖] This script must be run with sudo"
   echo "    Example:"
-  echo "    https://raw.githubusercontent.com/AquaHorizonGaming/riven-scripts/main/ubuntu/riven-remount-cycle.sh"
+  echo "    sudo bash riven-remount-cycle.sh"
   echo
   exit 1
 fi
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if [[ "$EUID" -ne 0 ]]; then
echo
echo "[✖] This script must be run with sudo"
echo " Example:"
echo " https://raw.githubusercontent.com/AquaHorizonGaming/riven-scripts/main/ubuntu/riven-remount-cycle.sh"
echo
exit 1
fi
if [[ "$EUID" -ne 0 ]]; then
echo
echo "[✖] This script must be run with sudo"
echo " Example:"
echo " sudo bash riven-remount-cycle.sh"
echo
exit 1
fi
🤖 Prompt for AI Agents
In @ubuntu/riven-remount-cycle.sh around lines 7 - 14, The root-check echo shown
in the if-block prints an incorrect example URL; replace the example lines that
currently print the raw GitHub URL with a concrete sudo invocation so users know
how to run the script (update the echo lines inside the if [[ "$EUID" -ne 0 ]]
block to show something like "Example: sudo ./riven-remount-cycle.sh" or
"Example: sudo bash riven-remount-cycle.sh" instead of the raw URL).

Comment on lines 56 to 68
read -rp "Enter choice [1-4]: " MEDIA_CHOICE

case "$MEDIA_CHOICE" in
1) MEDIA_CONTAINER="plex" ;;
2) MEDIA_CONTAINER="jellyfin" ;;
3) MEDIA_CONTAINER="emby" ;;
4)
read -rp "Enter Docker container name: " MEDIA_CONTAINER
;;
*)
fail "Invalid selection"
;;
esac
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Empty input for custom container name is not validated.

If the user selects option 4 and presses Enter without typing anything, MEDIA_CONTAINER becomes empty, causing subsequent docker stop "" and docker start "" calls to fail unexpectedly.

🛠️ Proposed fix
   4)
      read -rp "Enter Docker container name: " MEDIA_CONTAINER
+     if [[ -z "$MEDIA_CONTAINER" ]]; then
+       fail "Container name cannot be empty"
+     fi
      ;;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
read -rp "Enter choice [1-4]: " MEDIA_CHOICE
case "$MEDIA_CHOICE" in
1) MEDIA_CONTAINER="plex" ;;
2) MEDIA_CONTAINER="jellyfin" ;;
3) MEDIA_CONTAINER="emby" ;;
4)
read -rp "Enter Docker container name: " MEDIA_CONTAINER
;;
*)
fail "Invalid selection"
;;
esac
read -rp "Enter choice [1-4]: " MEDIA_CHOICE
case "$MEDIA_CHOICE" in
1) MEDIA_CONTAINER="plex" ;;
2) MEDIA_CONTAINER="jellyfin" ;;
3) MEDIA_CONTAINER="emby" ;;
4)
read -rp "Enter Docker container name: " MEDIA_CONTAINER
if [[ -z "$MEDIA_CONTAINER" ]]; then
fail "Container name cannot be empty"
fi
;;
*)
fail "Invalid selection"
;;
esac
🤖 Prompt for AI Agents
In @ubuntu/riven-remount-cycle.sh around lines 56 - 68, The case branch handling
option 4 does not validate empty input for MEDIA_CONTAINER, so if the user
presses Enter the variable is empty and later docker stop ""/start "" will fail;
update the branch in the case that prompts for the custom container name (the
read -rp for MEDIA_CONTAINER) to trim and validate the response (reject
empty/whitespace-only input), re-prompt in a loop until a non-empty name is
provided or call fail with an explanatory message, ensuring subsequent docker
stop/start calls receive a valid MEDIA_CONTAINER value.

Comment on lines 136 to 140
# 7. RESTART MEDIA (POST-MOUNT SAFETY)
############################################
log "Restarting media container after mount stabilization"
sleep 5
docker restart "$MEDIA_CONTAINER"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Clarify the purpose of the redundant restart after a 5-second sleep.

The media container is started at line 133, then restarted at line 140 after a 5-second delay. The comment mentions "mount stabilization," but it's unclear why a restart is needed rather than just waiting. Consider adding a more detailed comment explaining the specific issue this workaround addresses (e.g., media server caching stale mount state).

🤖 Prompt for AI Agents
In @ubuntu/riven-remount-cycle.sh around lines 136 - 140, Clarify the rationale
for the docker restart by replacing the vague "mount stabilization" comment
above the sleep/restart block (referencing MEDIA_CONTAINER and the restart
sequence) with a concise explanation of the specific failure mode this addresses
(e.g., the media service caching stale mount state or failing to revalidate
mounts on first start), state why a restart (docker restart "$MEDIA_CONTAINER")
is required instead of only waiting, and include any expected timing (5s) and a
note to revisit if fixed; keep the sleep 5 and docker restart "$MEDIA_CONTAINER"
intact unless a reliable mount-check/loopback exists, in which case implement
that check in place of the unconditional restart.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🤖 Fix all issues with AI agents
In @ubuntu/readme.md:
- Around line 36-37: Add blank lines before and after Markdown headings to
improve readability and satisfy linting: update each heading such as "### SYSTEM
& DOCKER", "### DURING INSTALL YOU WILL BE PROMPTED TO:", "### THE SCRIPT WILL:"
(and any other flagged headings) so there is an empty line above and below the
heading text; ensure the surrounding paragraphs or lists are separated by a
single blank line from the heading to conform to Markdown best practices.
- Line 1: Replace the current second-level heading "## 📚 Table of Contents"
with a top-level heading by changing it to "# 📚 Table of Contents" so the
document begins with a single `#` top-level heading (ensure this is the very
first line of ubuntu/readme.md).
- Around line 89-98: Update the "IMPORTANT CHANGE" section by either removing it
if there was no prior Ubuntu installer, or explicitly clarifying the comparison
context: modify the "OLD BEHAVIOR" and "NEW BEHAVIOR" lines under the "IMPORTANT
CHANGE" header to state what "OLD" refers to (for example "OLD BEHAVIOR (manual
installation / compared to Proxmox approach):" and "NEW BEHAVIOR (Ubuntu
installer):") so readers understand this is a change versus manual installation
rather than a previous Ubuntu installer.
- Line 272: Add a single trailing newline character at the end of the file so
the document ends with exactly one blank line after the last line (do not add
extra empty lines).
- Around line 17-18: Remove the duplicate markdown heading by deleting the
second "# Riven Ubuntu Installer" and keep only the first line "# 🔁 Riven
Ubuntu Installer" (the emoji version) so there is a single heading; ensure any
surrounding whitespace is normalized after removal.
📜 Review details

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between fb61906 and 436922c.

📒 Files selected for processing (1)
  • ubuntu/readme.md
🧰 Additional context used
🪛 markdownlint-cli2 (0.18.1)
ubuntu/readme.md

1-1: First line in a file should be a top-level heading

(MD041, first-line-heading, first-line-h1)


17-17: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Above

(MD022, blanks-around-headings)


17-17: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


18-18: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Above

(MD022, blanks-around-headings)


36-36: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


68-68: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


77-77: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


139-139: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Above

(MD022, blanks-around-headings)


228-228: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Above

(MD022, blanks-around-headings)


257-257: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Above

(MD022, blanks-around-headings)


272-272: Files should end with a single newline character

(MD047, single-trailing-newline)

🔇 Additional comments (1)
ubuntu/readme.md (1)

14-14: The repository reference in the installation command is intentional and correct. The scripts are hosted in AquaHorizonGaming/riven-scripts (not in rivenmedia/distributables), and verification confirms the script exists and is accessible at that URL. No change needed.

Likely an incorrect or invalid review comment.

@@ -0,0 +1,272 @@
## 📚 Table of Contents
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Start with a top-level heading.

The document should begin with a single # top-level heading rather than ## for proper Markdown hierarchy.

📝 Proposed fix
-## 📚 Table of Contents
+# 📚 Table of Contents
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
## 📚 Table of Contents
# 📚 Table of Contents
🧰 Tools
🪛 markdownlint-cli2 (0.18.1)

1-1: First line in a file should be a top-level heading

(MD041, first-line-heading, first-line-h1)

🤖 Prompt for AI Agents
In @ubuntu/readme.md at line 1, Replace the current second-level heading "## 📚
Table of Contents" with a top-level heading by changing it to "# 📚 Table of
Contents" so the document begins with a single `#` top-level heading (ensure
this is the very first line of ubuntu/readme.md).

Comment on lines +17 to +18
# 🔁 Riven Ubuntu Installer
# Riven Ubuntu Installer
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Remove duplicate heading.

Two identical headings appear consecutively. Keep only one (preferably the one with the emoji for visual consistency with other sections).

🔧 Proposed fix
-<a id="installer"></a>
-# 🔁 Riven Ubuntu Installer
 # Riven Ubuntu Installer

or

 <a id="installer"></a>
 # 🔁 Riven Ubuntu Installer
-# Riven Ubuntu Installer
🧰 Tools
🪛 markdownlint-cli2 (0.18.1)

17-17: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Above

(MD022, blanks-around-headings)


17-17: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


18-18: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Above

(MD022, blanks-around-headings)

🤖 Prompt for AI Agents
In @ubuntu/readme.md around lines 17 - 18, Remove the duplicate markdown heading
by deleting the second "# Riven Ubuntu Installer" and keep only the first line
"# 🔁 Riven Ubuntu Installer" (the emoji version) so there is a single heading;
ensure any surrounding whitespace is normalized after removal.

Comment on lines +36 to +37
### SYSTEM & DOCKER
- Installs Docker and Docker Compose ONLY if missing
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Add blank lines around headings for better readability.

Several headings throughout the document are missing blank lines before or after them. Consider adding blank lines around headings at:

  • Line 36: "### SYSTEM & DOCKER"
  • Line 68: "### DURING INSTALL YOU WILL BE PROMPTED TO:"
  • Line 77: "### THE SCRIPT WILL:"
  • And others flagged by static analysis

This improves readability and follows Markdown best practices.

Also applies to: 68-69, 77-78

🧰 Tools
🪛 markdownlint-cli2 (0.18.1)

36-36: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)

🤖 Prompt for AI Agents
In @ubuntu/readme.md around lines 36 - 37, Add blank lines before and after
Markdown headings to improve readability and satisfy linting: update each
heading such as "### SYSTEM & DOCKER", "### DURING INSTALL YOU WILL BE PROMPTED
TO:", "### THE SCRIPT WILL:" (and any other flagged headings) so there is an
empty line above and below the heading text; ensure the surrounding paragraphs
or lists are separated by a single blank line from the heading to conform to
Markdown best practices.

Comment on lines +89 to +98
## IMPORTANT CHANGE

OLD BEHAVIOR:
- Manual editing of /mnt/riven/backend/settings.json was required

NEW BEHAVIOR:
- All configuration is handled during the installer
- Riven starts fully configured
- Scraping and media integration work immediately

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Clarify the "IMPORTANT CHANGE" context.

The OLD vs NEW behavior comparison may confuse new users, as this appears to be the initial Ubuntu installer. Consider either:

  • Removing this section if there was no previous Ubuntu installer
  • Clarifying what "OLD" refers to (e.g., "compared to manual installation" or "compared to the Proxmox approach")
📝 Suggested clarification
 ## IMPORTANT CHANGE
 
+Compared to manual Riven installation:
+
 OLD BEHAVIOR:
 - Manual editing of /mnt/riven/backend/settings.json was required
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
## IMPORTANT CHANGE
OLD BEHAVIOR:
- Manual editing of /mnt/riven/backend/settings.json was required
NEW BEHAVIOR:
- All configuration is handled during the installer
- Riven starts fully configured
- Scraping and media integration work immediately
## IMPORTANT CHANGE
Compared to manual Riven installation:
OLD BEHAVIOR:
- Manual editing of /mnt/riven/backend/settings.json was required
NEW BEHAVIOR:
- All configuration is handled during the installer
- Riven starts fully configured
- Scraping and media integration work immediately
🤖 Prompt for AI Agents
In @ubuntu/readme.md around lines 89 - 98, Update the "IMPORTANT CHANGE" section
by either removing it if there was no prior Ubuntu installer, or explicitly
clarifying the comparison context: modify the "OLD BEHAVIOR" and "NEW BEHAVIOR"
lines under the "IMPORTANT CHANGE" header to state what "OLD" refers to (for
example "OLD BEHAVIOR (manual installation / compared to Proxmox approach):" and
"NEW BEHAVIOR (Ubuntu installer):") so readers understand this is a change
versus manual installation rather than a previous Ubuntu installer.

- `.env`
- Media libraries

--- No newline at end of file
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Add trailing newline at end of file.

Markdown files should end with a single newline character as per standard formatting conventions.

📝 Proposed fix

Add a blank line after line 272:

 - Media libraries
+
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
---
---
🧰 Tools
🪛 markdownlint-cli2 (0.18.1)

272-272: Files should end with a single newline character

(MD047, single-trailing-newline)

🤖 Prompt for AI Agents
In @ubuntu/readme.md at line 272, Add a single trailing newline character at the
end of the file so the document ends with exactly one blank line after the last
line (do not add extra empty lines).

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Fix all issues with AI agents
In @ubuntu/riven-remount-cycle.sh:
- Around line 122-126: The script currently calls docker start on
RIVEN_CONTAINER and MEDIA_CONTAINER which will produce an unhelpful Docker error
if a user-supplied name is invalid; before attempting docker start in the block
that runs RIVEN_CONTAINER and MEDIA_CONTAINER, add existence checks for both
container names by querying docker ps -a --format '{{.Names}}' and testing for
an exact match for the variables RIVEN_CONTAINER and MEDIA_CONTAINER, and call
the existing fail helper with a clear message (e.g., "Container '<name>' not
found") if either check fails so the script exits with a helpful error instead
of proceeding to docker start.
- Around line 37-40: Validate the user-provided MOUNT_PATH immediately after
it's set: check that MOUNT_PATH (and fallback DEFAULT_MOUNT) refers to an
existing directory and if not call the script's fail function with a clear
message like "Mount path does not exist: $MOUNT_PATH"; add this check right
after the block that reads/sets MOUNT_PATH (the section using read -rp,
MOUNT_PATH=..., and ok "Using mount path: $MOUNT_PATH") so the script fails fast
with a helpful error before any mount/bind operations.
- Around line 18-20: The variable REMOUNT_WAIT is defined but never used;
replace the hardcoded sleep 5 at the remount loop (where sleep 5 is used) with
sleep "$REMOUNT_WAIT" so the configured timeout is honored, or if the fixed 5s
is intentional remove the REMOUNT_WAIT variable declaration (UNMOUNT_RETRIES and
WAIT_BETWEEN should be left unchanged); update the sleep call in the remount
logic to reference REMOUNT_WAIT to fix the unused-variable warning.
📜 Review details

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 436922c and 7611dd0.

📒 Files selected for processing (1)
  • ubuntu/riven-remount-cycle.sh
🧰 Additional context used
🪛 Shellcheck (0.11.0)
ubuntu/riven-remount-cycle.sh

[warning] 20-20: REMOUNT_WAIT appears unused. Verify use (or export if used externally).

(SC2034)

🔇 Additional comments (1)
ubuntu/riven-remount-cycle.sh (1)

1-136: Overall structure and implementation looks good.

The script follows good practices with set -euo pipefail, proper quoting, retry logic for unmounting, and clear section separators. The remount cycle logic (bind mount + rshared propagation) is correct for enabling mount propagation into Docker containers.

Comment on lines 122 to 126
docker start "$RIVEN_CONTAINER" >/dev/null
ok "Riven started"

docker start "$MEDIA_CONTAINER" >/dev/null
ok "Media server started"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Container start may fail silently for invalid custom names.

If the user provides an invalid custom container name at line 56, the script will fail here with an unhelpful Docker error. Consider validating that both containers exist before attempting operations.

Suggested validation before line 66
if ! docker ps -a --format '{{.Names}}' | grep -qx "$RIVEN_CONTAINER"; then
  fail "Container '$RIVEN_CONTAINER' not found"
fi
if ! docker ps -a --format '{{.Names}}' | grep -qx "$MEDIA_CONTAINER"; then
  fail "Container '$MEDIA_CONTAINER' not found"
fi
🤖 Prompt for AI Agents
In @ubuntu/riven-remount-cycle.sh around lines 122 - 126, The script currently
calls docker start on RIVEN_CONTAINER and MEDIA_CONTAINER which will produce an
unhelpful Docker error if a user-supplied name is invalid; before attempting
docker start in the block that runs RIVEN_CONTAINER and MEDIA_CONTAINER, add
existence checks for both container names by querying docker ps -a --format
'{{.Names}}' and testing for an exact match for the variables RIVEN_CONTAINER
and MEDIA_CONTAINER, and call the existing fail helper with a clear message
(e.g., "Container '<name>' not found") if either check fails so the script exits
with a helpful error instead of proceeding to docker start.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In @ubuntu/riven-remount-cycle.sh:
- Around line 133-135: Add a one-line explanatory comment above the
sleep/restart sequence to clarify why the delay and restart are needed: mention
that we sleep briefly to allow the remount to settle and for the container to
pick up the reattached volume, then restart the MEDIA_CONTAINER so the media
server detects the remounted filesystem; place this comment immediately before
the sleep 5/docker restart "$MEDIA_CONTAINER" block and keep the existing ok
"Media server restarted (post-mount)" message.
- Around line 18-20: The script defines REMOUNT_WAIT but never uses it; replace
the hardcoded sleep 5 with sleep $REMOUNT_WAIT (or ${REMOUNT_WAIT}) where the
remount pause occurs (currently a plain "sleep 5") so the configured constant is
honored, or if you prefer remove the REMOUNT_WAIT declaration to avoid an unused
variable—update the remount logic in the remount loop/function that currently
calls "sleep 5".
📜 Review details

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 7611dd0 and 434a940.

📒 Files selected for processing (1)
  • ubuntu/riven-remount-cycle.sh
🧰 Additional context used
🪛 Shellcheck (0.11.0)
ubuntu/riven-remount-cycle.sh

[warning] 20-20: REMOUNT_WAIT appears unused. Verify use (or export if used externally).

(SC2034)

🔇 Additional comments (5)
ubuntu/riven-remount-cycle.sh (5)

1-10: LGTM!

Good use of strict mode with set -euo pipefail and clear root privilege enforcement.


22-32: LGTM!

Clean helper functions with consistent output formatting. The is_mounted check using findmnt is reliable.


34-60: LGTM!

User prompts with sensible defaults and proper input validation. Variables are correctly quoted throughout.


62-95: LGTM!

Robust container stop handling with || true fallback, and well-implemented unmount retry logic with proper verification.


97-120: LGTM!

Proper bind mount with rshared propagation setup and verification. Accepting both "shared" and "rshared" is correct since rshared implies shared.

Comment on lines 18 to 20
UNMOUNT_RETRIES=5
WAIT_BETWEEN=2
REMOUNT_WAIT=5
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Unused variable REMOUNT_WAIT.

REMOUNT_WAIT is defined but never used. Line 133 uses a hardcoded sleep 5 which appears to be the intended use case for this variable.

Proposed fix

Either use the variable:

-sleep 5
+sleep "$REMOUNT_WAIT"

Or remove the unused declaration:

 UNMOUNT_RETRIES=5
 WAIT_BETWEEN=2
-REMOUNT_WAIT=5
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
UNMOUNT_RETRIES=5
WAIT_BETWEEN=2
REMOUNT_WAIT=5
UNMOUNT_RETRIES=5
WAIT_BETWEEN=2
🧰 Tools
🪛 Shellcheck (0.11.0)

[warning] 20-20: REMOUNT_WAIT appears unused. Verify use (or export if used externally).

(SC2034)

🤖 Prompt for AI Agents
In @ubuntu/riven-remount-cycle.sh around lines 18 - 20, The script defines
REMOUNT_WAIT but never uses it; replace the hardcoded sleep 5 with sleep
$REMOUNT_WAIT (or ${REMOUNT_WAIT}) where the remount pause occurs (currently a
plain "sleep 5") so the configured constant is honored, or if you prefer remove
the REMOUNT_WAIT declaration to avoid an unused variable—update the remount
logic in the remount loop/function that currently calls "sleep 5".

Comment on lines 133 to 135
sleep 5
docker restart "$MEDIA_CONTAINER" >/dev/null
ok "Media server restarted (post-mount)"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Consider adding a clarifying comment for the restart logic.

The sleep-then-restart pattern for the media server is a reasonable workaround to ensure it properly detects the remounted volume, but the rationale isn't immediately obvious. A brief comment would help future maintainers understand why this is necessary.

Suggested improvement
+# Allow media server to initialize, then restart to ensure it detects the remounted volume
 sleep 5
 docker restart "$MEDIA_CONTAINER" >/dev/null
 ok "Media server restarted (post-mount)"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
sleep 5
docker restart "$MEDIA_CONTAINER" >/dev/null
ok "Media server restarted (post-mount)"
# Allow media server to initialize, then restart to ensure it detects the remounted volume
sleep 5
docker restart "$MEDIA_CONTAINER" >/dev/null
ok "Media server restarted (post-mount)"
🤖 Prompt for AI Agents
In @ubuntu/riven-remount-cycle.sh around lines 133 - 135, Add a one-line
explanatory comment above the sleep/restart sequence to clarify why the delay
and restart are needed: mention that we sleep briefly to allow the remount to
settle and for the container to pick up the reattached volume, then restart the
MEDIA_CONTAINER so the media server detects the remounted filesystem; place this
comment immediately before the sleep 5/docker restart "$MEDIA_CONTAINER" block
and keep the existing ok "Media server restarted (post-mount)" message.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Fix all issues with AI agents
In @ubuntu/riven-remount-cycle.sh:
- Around line 35-41: show_version() is defined but never called; either remove
the dead function or invoke show_version after the script's root-check sequence
(i.e., immediately following the root-check function or logic) so the version is
displayed at startup; update any callers accordingly and ensure no unused
variables remain if you choose to delete show_version.
- Around line 47-50: Validate the chosen mount directory after reading
MOUNT_PATH (and after applying DEFAULT_MOUNT fallback) by checking test -d
"$MOUNT_PATH"; if it doesn't exist either prompt to create it or attempt mkdir
-p "$MOUNT_PATH" and fail with a clear error via the existing ok/error logging
functions (referencing MOUNT_PATH, DEFAULT_MOUNT and ok) — ensure you perform
this check immediately after the MOUNT_PATH assignment and exit with a non-zero
code on irrecoverable failure.
- Around line 18-21: The script defines REMOUNT_WAIT but still uses a hardcoded
sleep 5; update the remount/wait call that currently does "sleep 5" to use the
REMOUNT_WAIT variable (e.g., sleep "$REMOUNT_WAIT") so the configured timeout is
honored; locate the remount loop or function in riven-remount-cycle.sh where the
hardcoded sleep occurs and replace it with the REMOUNT_WAIT variable, ensuring
the variable is exported/available in scope if needed.
- Around line 74-80: The script currently always prints success via ok "Riven
stopped" and ok "Media server stopped" even when docker stop silently fails;
update the stop logic for RIVEN_CONTAINER and MEDIA_CONTAINER to detect whether
the container exists or docker stop returned an error and emit a warning instead
of a success message. Specifically, before or after calling docker stop for the
variables RIVEN_CONTAINER and MEDIA_CONTAINER, check container existence (e.g.,
via docker ps -a or docker inspect) or capture docker stop’s exit status, call a
warn/error helper when the container is missing or stop failed, and only call ok
"Riven stopped" / ok "Media server stopped" when the stop actually succeeded.
Ensure you reference the RIVEN_CONTAINER and MEDIA_CONTAINER variables and the
ok function when locating where to change behavior.
📜 Review details

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 434a940 and 0f619b4.

📒 Files selected for processing (1)
  • ubuntu/riven-remount-cycle.sh
🧰 Additional context used
🪛 Shellcheck (0.11.0)
ubuntu/riven-remount-cycle.sh

[warning] 20-20: REMOUNT_WAIT appears unused. Verify use (or export if used externally).

(SC2034)

🔇 Additional comments (4)
ubuntu/riven-remount-cycle.sh (4)

1-10: LGTM!

Good use of set -euo pipefail for strict error handling and proper root privilege check.


82-105: LGTM!

Robust unmount logic with proper retry handling and final verification.


107-130: LGTM!

Mount propagation setup and verification logic is correct.


132-151: LGTM!

Container restart sequence is appropriate. Note: the sleep 5 on line 143 should use $REMOUNT_WAIT as flagged earlier.

Comment on lines 18 to 21
UNMOUNT_RETRIES=5
WAIT_BETWEEN=2
REMOUNT_WAIT=5
VERSION=1.0
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Use REMOUNT_WAIT variable instead of hardcoded value.

REMOUNT_WAIT is defined but never used. Line 143 hardcodes sleep 5 instead of using this variable.

♻️ Proposed fix
-sleep 5
+sleep "$REMOUNT_WAIT"
🧰 Tools
🪛 Shellcheck (0.11.0)

[warning] 20-20: REMOUNT_WAIT appears unused. Verify use (or export if used externally).

(SC2034)

🤖 Prompt for AI Agents
In @ubuntu/riven-remount-cycle.sh around lines 18 - 21, The script defines
REMOUNT_WAIT but still uses a hardcoded sleep 5; update the remount/wait call
that currently does "sleep 5" to use the REMOUNT_WAIT variable (e.g., sleep
"$REMOUNT_WAIT") so the configured timeout is honored; locate the remount loop
or function in riven-remount-cycle.sh where the hardcoded sleep occurs and
replace it with the REMOUNT_WAIT variable, ensuring the variable is
exported/available in scope if needed.

Comment on lines +47 to +50
section "Mount Configuration"
read -rp "Mount path [${DEFAULT_MOUNT}]: " MOUNT_PATH
MOUNT_PATH="${MOUNT_PATH:-$DEFAULT_MOUNT}"
ok "Using mount path: $MOUNT_PATH"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Consider validating mount path existence.

The script doesn't verify that $MOUNT_PATH exists before proceeding. This could lead to confusing failures during mount operations.

♻️ Proposed validation
 MOUNT_PATH="${MOUNT_PATH:-$DEFAULT_MOUNT}"
+[[ -d "$MOUNT_PATH" ]] || fail "Mount path does not exist: $MOUNT_PATH"
 ok "Using mount path: $MOUNT_PATH"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
section "Mount Configuration"
read -rp "Mount path [${DEFAULT_MOUNT}]: " MOUNT_PATH
MOUNT_PATH="${MOUNT_PATH:-$DEFAULT_MOUNT}"
ok "Using mount path: $MOUNT_PATH"
section "Mount Configuration"
read -rp "Mount path [${DEFAULT_MOUNT}]: " MOUNT_PATH
MOUNT_PATH="${MOUNT_PATH:-$DEFAULT_MOUNT}"
[[ -d "$MOUNT_PATH" ]] || fail "Mount path does not exist: $MOUNT_PATH"
ok "Using mount path: $MOUNT_PATH"
🤖 Prompt for AI Agents
In @ubuntu/riven-remount-cycle.sh around lines 47 - 50, Validate the chosen
mount directory after reading MOUNT_PATH (and after applying DEFAULT_MOUNT
fallback) by checking test -d "$MOUNT_PATH"; if it doesn't exist either prompt
to create it or attempt mkdir -p "$MOUNT_PATH" and fail with a clear error via
the existing ok/error logging functions (referencing MOUNT_PATH, DEFAULT_MOUNT
and ok) — ensure you perform this check immediately after the MOUNT_PATH
assignment and exit with a non-zero code on irrecoverable failure.

Comment on lines 74 to 80
############################################
section "Stopping Containers"
docker stop "$RIVEN_CONTAINER" >/dev/null 2>&1 || true
ok "Riven stopped"

docker stop "$MEDIA_CONTAINER" >/dev/null 2>&1 || true
ok "Media server stopped"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Consider warning if containers don't exist.

The script reports success even when containers don't exist, which could mislead users.

♻️ Proposed improvement
 section "Stopping Containers"
-docker stop "$RIVEN_CONTAINER" >/dev/null 2>&1 || true
-ok "Riven stopped"
+if docker ps -a --format '{{.Names}}' | grep -qx "$RIVEN_CONTAINER"; then
+  docker stop "$RIVEN_CONTAINER" >/dev/null 2>&1 || true
+  ok "Riven stopped"
+else
+  warn "Riven container not found, skipping"
+fi

-docker stop "$MEDIA_CONTAINER" >/dev/null 2>&1 || true
-ok "Media server stopped"
+if docker ps -a --format '{{.Names}}' | grep -qx "$MEDIA_CONTAINER"; then
+  docker stop "$MEDIA_CONTAINER" >/dev/null 2>&1 || true
+  ok "Media server stopped"
+else
+  warn "Media container '$MEDIA_CONTAINER' not found, skipping"
+fi
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
############################################
section "Stopping Containers"
docker stop "$RIVEN_CONTAINER" >/dev/null 2>&1 || true
ok "Riven stopped"
docker stop "$MEDIA_CONTAINER" >/dev/null 2>&1 || true
ok "Media server stopped"
############################################
section "Stopping Containers"
if docker ps -a --format '{{.Names}}' | grep -qx "$RIVEN_CONTAINER"; then
docker stop "$RIVEN_CONTAINER" >/dev/null 2>&1 || true
ok "Riven stopped"
else
warn "Riven container not found, skipping"
fi
if docker ps -a --format '{{.Names}}' | grep -qx "$MEDIA_CONTAINER"; then
docker stop "$MEDIA_CONTAINER" >/dev/null 2>&1 || true
ok "Media server stopped"
else
warn "Media container '$MEDIA_CONTAINER' not found, skipping"
fi
🤖 Prompt for AI Agents
In @ubuntu/riven-remount-cycle.sh around lines 74 - 80, The script currently
always prints success via ok "Riven stopped" and ok "Media server stopped" even
when docker stop silently fails; update the stop logic for RIVEN_CONTAINER and
MEDIA_CONTAINER to detect whether the container exists or docker stop returned
an error and emit a warning instead of a success message. Specifically, before
or after calling docker stop for the variables RIVEN_CONTAINER and
MEDIA_CONTAINER, check container existence (e.g., via docker ps -a or docker
inspect) or capture docker stop’s exit status, call a warn/error helper when the
container is missing or stop failed, and only call ok "Riven stopped" / ok
"Media server stopped" when the stop actually succeeded. Ensure you reference
the RIVEN_CONTAINER and MEDIA_CONTAINER variables and the ok function when
locating where to change behavior.

- Add robust bind remount cycle with rshared propagation
- Handle Docker and systemd media servers (Plex, Jellyfin, Emby)
- Fix unmount loop to exit cleanly when already unmounted
- Add version banner and consistent output helpers
- Improve safety under set -euo pipefail
Increment script version to v1.3 after remount, propagation, and media runtime improvements.
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Fix all issues with AI agents
In @ubuntu/riven-remount-cycle.sh:
- Around line 121-127: The systemctl stop branch can cause the script to exit
under set -e when the service is already stopped or missing; mirror the Docker
branch's graceful handling by swallowing errors: change the systemctl stop
"$MEDIA_SERVICE" line to redirect output and append || true (e.g., systemctl
stop "$MEDIA_SERVICE" >/dev/null 2>&1 || true) so MEDIA_MODE, systemctl stop,
MEDIA_SERVICE and the subsequent ok "Media service stopped" behave consistently
with the docker stop "$MEDIA_CONTAINER" path.
- Around line 134-153: The unmount loop mishandles umount output and lacks a
failure branch: change the umount invocation that currently pipes to grep so it
captures stderr (or test umount's exit status directly) and detect the "not
mounted" message from stderr OR simply check umount's return code instead of
piping (refer to umount and MOUNT_PATH in the loop), ensure you do not discard
umount's exit status, and after the for loop add explicit failure handling when
the mount is still mounted (use is_mounted()) — log an error and exit non‑zero
(or return failure) instead of proceeding to remount; keep UNMOUNT_RETRIES and
WAIT_BETWEEN behavior but fail fast with a clear message if all attempts
exhaust.
- Around line 18-21: REMOUNT_WAIT is defined but unused; replace the hardcoded
sleep 5 calls with sleep "${REMOUNT_WAIT}" at the two locations where they occur
(the sleep calls currently using 5) so the script uses the REMOUNT_WAIT variable
value, and keep the REMOUNT_WAIT=5 declaration as the single source of truth for
that delay.
📜 Review details

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 0f619b4 and 12da4ca.

📒 Files selected for processing (1)
  • ubuntu/riven-remount-cycle.sh
🧰 Additional context used
🪛 Shellcheck (0.11.0)
ubuntu/riven-remount-cycle.sh

[warning] 20-20: REMOUNT_WAIT appears unused. Verify use (or export if used externally).

(SC2034)

🔇 Additional comments (7)
ubuntu/riven-remount-cycle.sh (7)

1-10: LGTM!

Good use of strict mode (set -euo pipefail) and clear root privilege enforcement.


23-33: LGTM!

Clean helper functions with consistent formatting. Using findmnt for mount detection is reliable.


35-51: LGTM!

Version display and mount path prompt with sensible defaults.


53-111: LGTM!

Well-structured two-step selection with appropriate defaults for known media servers and custom input fallback.


155-178: LGTM!

Correct implementation of bind mount with rshared propagation and proper verification.


180-200: LGTM!

The start-sleep-restart pattern ensures the media server properly recognizes the new mount. The hardcoded sleep values were noted earlier as candidates for using REMOUNT_WAIT.


202-206: LGTM!

Clean completion output.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🤖 Fix all issues with AI agents
In @ubuntu/riven-remount-cycle.sh:
- Around line 121-127: The systemd branch is not tolerant of failures while the
Docker branch silences errors (docker stop ... || true), causing unexpected
exits under set -e; make the systemctl stop call behave similarly by guarding it
(e.g., check service state with systemctl is-active "$MEDIA_SERVICE" || true
before stopping, or append || true to the systemctl stop invocation) and keep
the ok "Media service stopped" call only after handling suppressed errors;
reference MEDIA_MODE, MEDIA_CONTAINER, MEDIA_SERVICE, the docker stop and
systemctl stop invocations, and the ok function when making the change.
- Around line 18-21: Remove the dead variable by deleting the unused
REMOUNT_WAIT assignment (REMOUNT_WAIT=5) from the script; keep UNMOUNT_RETRIES,
WAIT_BETWEEN and VERSION intact and run a quick shellcheck/static lint to
confirm no other references to REMOUNT_WAIT remain.
- Around line 134-153: The unmount retry loop can exit without error if the
mount remains active; after the for loop that uses UNMOUNT_RETRIES and calls
is_mounted and umount on MOUNT_PATH, add a final check that calls is_mounted
once more and if it still returns true log an error (e.g., using
warn/processLogger/error function used in the script) and exit non‑zero to
prevent proceeding to the remount phase; ensure you reference the same log style
used elsewhere and return a non-zero status to fail fast when unmounts are
exhausted.
- Around line 185-200: The start/restart branches for RIVEN_CONTAINER and MEDIA
containers/services lack error handling and diagnostics; update the blocks that
reference RIVEN_CONTAINER, MEDIA_MODE, MEDIA_CONTAINER, and MEDIA_SERVICE to
capture stdout/stderr from docker start/docker restart and systemctl
start/systemctl restart, check each command's exit code, log failures via the
existing ok/error logging functions (including the command output or exit
status), and exit with a non-zero code on fatal failures; also add a brief
comment above the sleep+restart sequence explaining why an immediate restart is
required (post-mount remount delay) so future readers understand the purpose.
- Around line 140-145: The unmount retry logic currently pipes umount into grep
so the loop reacts to grep's exit status; instead run umount on "$MOUNT_PATH",
capture its output/exit code, and then explicitly check the output for "not
mounted" and call ok "Mount was already unmounted" + break if found; for all
other failures simply warn and continue to the next iteration (the existing
is_mounted check at the top will decide whether to retry). Update the block
around the umount call (referencing the umount invocation, MOUNT_PATH, warn, ok,
and is_mounted) to avoid relying on a pipe to grep and make the logic explicit
and clearer.
📜 Review details

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 12da4ca and b3e2c5f.

📒 Files selected for processing (1)
  • ubuntu/riven-remount-cycle.sh
🧰 Additional context used
🪛 Shellcheck (0.11.0)
ubuntu/riven-remount-cycle.sh

[warning] 20-20: REMOUNT_WAIT appears unused. Verify use (or export if used externally).

(SC2034)

🔇 Additional comments (5)
ubuntu/riven-remount-cycle.sh (5)

1-10: LGTM!

The shebang, strict mode (set -euo pipefail), and root enforcement are correctly implemented.


23-33: LGTM!

Output helpers and is_mounted function are clean and idiomatic.


45-111: LGTM!

The interactive prompts for mount path, media runtime, and server selection are well-structured with sensible defaults and clear feedback.


155-178: LGTM!

The bind remount with rshared propagation and verification logic is correctly implemented. The propagation check properly validates both "shared" and "rshared" states.


202-206: LGTM!

Clean completion section.

Comment on lines 18 to 21
UNMOUNT_RETRIES=5
WAIT_BETWEEN=2
REMOUNT_WAIT=5
VERSION=1.3
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Remove unused variable REMOUNT_WAIT.

REMOUNT_WAIT is defined but never used in the script. Based on the static analysis hint, this appears to be dead code.

Proposed fix
 UNMOUNT_RETRIES=5
 WAIT_BETWEEN=2
-REMOUNT_WAIT=5
 VERSION=1.3
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
UNMOUNT_RETRIES=5
WAIT_BETWEEN=2
REMOUNT_WAIT=5
VERSION=1.3
UNMOUNT_RETRIES=5
WAIT_BETWEEN=2
VERSION=1.3
🧰 Tools
🪛 Shellcheck (0.11.0)

[warning] 20-20: REMOUNT_WAIT appears unused. Verify use (or export if used externally).

(SC2034)

🤖 Prompt for AI Agents
In @ubuntu/riven-remount-cycle.sh around lines 18 - 21, Remove the dead variable
by deleting the unused REMOUNT_WAIT assignment (REMOUNT_WAIT=5) from the script;
keep UNMOUNT_RETRIES, WAIT_BETWEEN and VERSION intact and run a quick
shellcheck/static lint to confirm no other references to REMOUNT_WAIT remain.

Comment on lines +121 to +127
if [[ "$MEDIA_MODE" == "docker" ]]; then
docker stop "$MEDIA_CONTAINER" >/dev/null 2>&1 || true
ok "Media container stopped"
else
systemctl stop "$MEDIA_SERVICE"
ok "Media service stopped"
fi
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Inconsistent error handling between Docker and systemd paths.

docker stop uses || true to suppress failures (line 122), but systemctl stop (line 125) does not. With set -e, if the systemd service doesn't exist or is already stopped, the script will exit unexpectedly.

Proposed fix
 if [[ "$MEDIA_MODE" == "docker" ]]; then
   docker stop "$MEDIA_CONTAINER" >/dev/null 2>&1 || true
   ok "Media container stopped"
 else
-  systemctl stop "$MEDIA_SERVICE"
+  systemctl stop "$MEDIA_SERVICE" 2>/dev/null || true
   ok "Media service stopped"
 fi
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if [[ "$MEDIA_MODE" == "docker" ]]; then
docker stop "$MEDIA_CONTAINER" >/dev/null 2>&1 || true
ok "Media container stopped"
else
systemctl stop "$MEDIA_SERVICE"
ok "Media service stopped"
fi
if [[ "$MEDIA_MODE" == "docker" ]]; then
docker stop "$MEDIA_CONTAINER" >/dev/null 2>&1 || true
ok "Media container stopped"
else
systemctl stop "$MEDIA_SERVICE" 2>/dev/null || true
ok "Media service stopped"
fi
🤖 Prompt for AI Agents
In @ubuntu/riven-remount-cycle.sh around lines 121 - 127, The systemd branch is
not tolerant of failures while the Docker branch silences errors (docker stop
... || true), causing unexpected exits under set -e; make the systemctl stop
call behave similarly by guarding it (e.g., check service state with systemctl
is-active "$MEDIA_SERVICE" || true before stopping, or append || true to the
systemctl stop invocation) and keep the ok "Media service stopped" call only
after handling suppressed errors; reference MEDIA_MODE, MEDIA_CONTAINER,
MEDIA_SERVICE, the docker stop and systemctl stop invocations, and the ok
function when making the change.

Comment on lines +140 to +145
warn "Unmount attempt $attempt"

if umount "$MOUNT_PATH" 2>&1 | grep -q "not mounted"; then
ok "Mount was already unmounted"
break
fi
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Consider simplifying umount retry logic.

The pattern umount ... 2>&1 | grep -q "not mounted" checks grep's exit status rather than umount's. While this works for detecting "not mounted" messages, other umount failures (e.g., device busy) will fall through to the retry loop silently. Consider a clearer approach:

Alternative approach
   warn "Unmount attempt $attempt"
-
-  if umount "$MOUNT_PATH" 2>&1 | grep -q "not mounted"; then
-    ok "Mount was already unmounted"
-    break
-  fi
+  umount "$MOUNT_PATH" 2>/dev/null || true

   sleep "$WAIT_BETWEEN"

This attempts umount, ignores errors, waits, then relies on the is_mounted check at the top of the next iteration.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
warn "Unmount attempt $attempt"
if umount "$MOUNT_PATH" 2>&1 | grep -q "not mounted"; then
ok "Mount was already unmounted"
break
fi
warn "Unmount attempt $attempt"
umount "$MOUNT_PATH" 2>/dev/null || true
🤖 Prompt for AI Agents
In @ubuntu/riven-remount-cycle.sh around lines 140 - 145, The unmount retry
logic currently pipes umount into grep so the loop reacts to grep's exit status;
instead run umount on "$MOUNT_PATH", capture its output/exit code, and then
explicitly check the output for "not mounted" and call ok "Mount was already
unmounted" + break if found; for all other failures simply warn and continue to
the next iteration (the existing is_mounted check at the top will decide whether
to retry). Update the block around the umount call (referencing the umount
invocation, MOUNT_PATH, warn, ok, and is_mounted) to avoid relying on a pipe to
grep and make the logic explicit and clearer.

Comment on lines 185 to 200
docker start "$RIVEN_CONTAINER" >/dev/null
ok "Riven container started"

if [[ "$MEDIA_MODE" == "docker" ]]; then
docker start "$MEDIA_CONTAINER" >/dev/null
ok "Media container started"
sleep 5
docker restart "$MEDIA_CONTAINER" >/dev/null
ok "Media container restarted (post-mount)"
else
systemctl start "$MEDIA_SERVICE"
ok "Media service started"
sleep 5
systemctl restart "$MEDIA_SERVICE"
ok "Media service restarted (post-mount)"
fi
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Consider adding error handling for service start commands.

Unlike the stop commands, docker start (line 185, 189) and systemctl start (line 195) lack error suppression. If containers or services fail to start due to configuration issues, the script will exit abruptly without useful diagnostics.

Additionally, the purpose of the sleep-and-restart pattern (lines 191-193, 197-199) would benefit from a brief comment explaining why a restart is needed immediately after start.

Proposed improvement
 docker start "$RIVEN_CONTAINER" >/dev/null
 ok "Riven container started"
 
 if [[ "$MEDIA_MODE" == "docker" ]]; then
   docker start "$MEDIA_CONTAINER" >/dev/null
   ok "Media container started"
+  # Allow container to initialize before restarting to pick up refreshed mounts
   sleep 5
   docker restart "$MEDIA_CONTAINER" >/dev/null
   ok "Media container restarted (post-mount)"
 else
   systemctl start "$MEDIA_SERVICE"
   ok "Media service started"
+  # Allow service to initialize before restarting to pick up refreshed mounts
   sleep 5
   systemctl restart "$MEDIA_SERVICE"
   ok "Media service restarted (post-mount)"
 fi
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
docker start "$RIVEN_CONTAINER" >/dev/null
ok "Riven container started"
if [[ "$MEDIA_MODE" == "docker" ]]; then
docker start "$MEDIA_CONTAINER" >/dev/null
ok "Media container started"
sleep 5
docker restart "$MEDIA_CONTAINER" >/dev/null
ok "Media container restarted (post-mount)"
else
systemctl start "$MEDIA_SERVICE"
ok "Media service started"
sleep 5
systemctl restart "$MEDIA_SERVICE"
ok "Media service restarted (post-mount)"
fi
docker start "$RIVEN_CONTAINER" >/dev/null
ok "Riven container started"
if [[ "$MEDIA_MODE" == "docker" ]]; then
docker start "$MEDIA_CONTAINER" >/dev/null
ok "Media container started"
# Allow container to initialize before restarting to pick up refreshed mounts
sleep 5
docker restart "$MEDIA_CONTAINER" >/dev/null
ok "Media container restarted (post-mount)"
else
systemctl start "$MEDIA_SERVICE"
ok "Media service started"
# Allow service to initialize before restarting to pick up refreshed mounts
sleep 5
systemctl restart "$MEDIA_SERVICE"
ok "Media service restarted (post-mount)"
fi
🤖 Prompt for AI Agents
In @ubuntu/riven-remount-cycle.sh around lines 185 - 200, The start/restart
branches for RIVEN_CONTAINER and MEDIA containers/services lack error handling
and diagnostics; update the blocks that reference RIVEN_CONTAINER, MEDIA_MODE,
MEDIA_CONTAINER, and MEDIA_SERVICE to capture stdout/stderr from docker
start/docker restart and systemctl start/systemctl restart, check each command's
exit code, log failures via the existing ok/error logging functions (including
the command output or exit status), and exit with a non-zero code on fatal
failures; also add a brief comment above the sleep+restart sequence explaining
why an immediate restart is required (post-mount remount delay) so future
readers understand the purpose.

- Start media service before Riven to ensure mount readiness
- Restart media after Riven for reliable mount propagation
- Bump riven-remount-cycle version to v1.4
Increase wait time before restarting media server to ensure Riven is fully initialized and mounts are ready.
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Fix all issues with AI agents
In @ubuntu/riven-remount-cycle.sh:
- Around line 135-154: The unmount retry loop may exit without unmounting and
the script continues, so after the loop check the mount state and fail fast:
after the for-loop that uses is_mounted, UNMOUNT_RETRIES, umount and
WAIT_BETWEEN, call is_mounted again for MOUNT_PATH and if it still returns true
log a fatal error (use warn/error) indicating unmount failed after
UNMOUNT_RETRIES and exit non-zero (or return non-zero) to avoid creating a bind
mount over a still-mounted path; ensure messages reference MOUNT_PATH and
include attempt/count context.
- Around line 119-128: The script treats docker stops as tolerant (using "docker
stop ... || true") but lets "systemctl stop $MEDIA_SERVICE" potentially fail the
script; make error handling consistent by treating systemd stop failures as
non-fatal: modify the branch that runs systemctl stop "$MEDIA_SERVICE" (and the
earlier docker stop for RIVEN_CONTAINER if needed) to either append "|| true" or
explicitly check the service existence/status before stopping so that
missing/already-stopped services do not cause the script to exit; target the
systemctl stop call and the MEDIA_SERVICE/MEDIA_MODE logic for the change.
- Around line 18-22: The script defines REMOUNT_WAIT and WAIT_TIME but doesn't
use them; replace the hardcoded sleep 5 calls with the constants by changing the
two occurrences of sleep 5 to sleep "$REMOUNT_WAIT" and sleep "$WAIT_TIME"
respectively (or if you prefer, remove the REMOUNT_WAIT and WAIT_TIME variable
declarations and keep the hardcoded sleeps); ensure the variables are exported
or in scope when used and quoted when passed to sleep.
📜 Review details

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between b3e2c5f and 7ea56ad.

📒 Files selected for processing (1)
  • ubuntu/riven-remount-cycle.sh
🧰 Additional context used
🪛 Shellcheck (0.11.0)
ubuntu/riven-remount-cycle.sh

[warning] 20-20: REMOUNT_WAIT appears unused. Verify use (or export if used externally).

(SC2034)


[warning] 21-21: WAIT_TIME appears unused. Verify use (or export if used externally).

(SC2034)

🔇 Additional comments (8)
ubuntu/riven-remount-cycle.sh (8)

1-2: LGTM!

Good use of set -euo pipefail for strict error handling.


7-10: LGTM!

Root enforcement is clear and correct.


27-34: LGTM!

Output helpers are concise and is_mounted() correctly defers variable resolution to call time.


62-74: LGTM!

Case statements correctly handle all branches with clear fail-fast on invalid input.


161-165: LGTM!

Bind mount and rshared propagation are correctly applied. Error handling via set -e is sufficient here.


172-179: LGTM!

Propagation verification with explicit fail on unexpected state is a good safeguard.


186-212: LGTM!

The start sequence (media → Riven → restart media) correctly ensures mount propagation as described in the PR objectives. The lack of error suppression on docker start is appropriate since failure to start indicates a real problem.


218-219: LGTM!

Clear completion message.

Comment on lines 18 to 22
UNMOUNT_RETRIES=5
WAIT_BETWEEN=2
REMOUNT_WAIT=5
WAIT_TIME=5
VERSION=1.4
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Remove or use the unused variables.

REMOUNT_WAIT and WAIT_TIME are defined but never used. Lines 196 and 203 use hardcoded sleep 5 instead of these constants.

♻️ Proposed fix: use the defined constants or remove them

Either remove the unused variables:

 UNMOUNT_RETRIES=5
 WAIT_BETWEEN=2
-REMOUNT_WAIT=5
-WAIT_TIME=5
 VERSION=1.4

Or use them in the sleep calls (lines 196 and 203):

-sleep 5
+sleep "$WAIT_TIME"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
UNMOUNT_RETRIES=5
WAIT_BETWEEN=2
REMOUNT_WAIT=5
WAIT_TIME=5
VERSION=1.4
UNMOUNT_RETRIES=5
WAIT_BETWEEN=2
VERSION=1.4
🧰 Tools
🪛 Shellcheck (0.11.0)

[warning] 20-20: REMOUNT_WAIT appears unused. Verify use (or export if used externally).

(SC2034)


[warning] 21-21: WAIT_TIME appears unused. Verify use (or export if used externally).

(SC2034)

🤖 Prompt for AI Agents
In @ubuntu/riven-remount-cycle.sh around lines 18 - 22, The script defines
REMOUNT_WAIT and WAIT_TIME but doesn't use them; replace the hardcoded sleep 5
calls with the constants by changing the two occurrences of sleep 5 to sleep
"$REMOUNT_WAIT" and sleep "$WAIT_TIME" respectively (or if you prefer, remove
the REMOUNT_WAIT and WAIT_TIME variable declarations and keep the hardcoded
sleeps); ensure the variables are exported or in scope when used and quoted when
passed to sleep.

- Reduced mount retry attempts to 3
- Bumped script version to v2.0
- Minor reliability tweaks to remount flow
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Fix all issues with AI agents
In @ubuntu/riven-remount-cycle.sh:
- Around line 119-128: The systemd branch inconsistently fails under set -e
because systemctl stop on MEDIA_SERVICE can exit non-zero; modify the MEDIA_MODE
== "docker" else branch to first verify the service exists (e.g., with systemctl
list-unit-files or systemctl is-enabled) before calling systemctl stop
"$MEDIA_SERVICE", and if the service is missing log a warning (using warn) and
skip stopping; ensure behavior mirrors the docker branch's tolerant handling of
missing containers (RIVEN_CONTAINER / MEDIA_CONTAINER) so non-existent services
do not cause the script to exit.
- Around line 18-22: Remove or use the unused variables REMOUNT_WAIT and
WAIT_TIME: either delete both variable definitions (REMOUNT_WAIT and WAIT_TIME)
if you prefer the current hardcoded sleep values, or replace the hardcoded sleep
5 and sleep 15 calls with the variables (e.g., sleep "$REMOUNT_WAIT" and sleep
"$WAIT_TIME"), and if choosing to keep and clarify semantics, rename WAIT_TIME
to a more descriptive name like PROPAGATION_WAIT and update its value and usages
accordingly.
- Around line 135-154: The unmount loop incorrectly relies on grepping umount
stdout for "not mounted" and lacks failure handling; change the loop around
is_mounted/umount (using the is_mounted function and MOUNT_PATH) to check
umount's exit status and capture its stderr/output—treat exit code 0 as success,
if stderr contains "not mounted" treat as already unmounted, otherwise log the
error and retry; after the for loop, if is_mounted still returns true (using
UNMOUNT_RETRIES and WAIT_BETWEEN), fail fast (exit non-zero) with an error
message so the script does not proceed to remount when unmounting ultimately
failed.
📜 Review details

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 7ea56ad and fc06f7e.

📒 Files selected for processing (1)
  • ubuntu/riven-remount-cycle.sh
🧰 Additional context used
🪛 Shellcheck (0.11.0)
ubuntu/riven-remount-cycle.sh

[warning] 20-20: REMOUNT_WAIT appears unused. Verify use (or export if used externally).

(SC2034)


[warning] 21-21: WAIT_TIME appears unused. Verify use (or export if used externally).

(SC2034)

🔇 Additional comments (8)
ubuntu/riven-remount-cycle.sh (8)

1-10: LGTM!

Good use of set -euo pipefail for strict error handling and clear root privilege enforcement.


24-34: LGTM!

Clean helper functions for consistent output formatting and a proper mount check using findmnt.


36-74: LGTM!

Well-structured interactive prompts with sensible defaults and input validation.


76-112: LGTM!

Good mapping of media servers to their respective Docker container names and systemd service names with a custom fallback option.


156-165: LGTM!

Correct approach for establishing bind mount with rshared propagation for container visibility.


167-179: LGTM!

Good verification of mount propagation with clear failure messaging.


181-212: LGTM!

The restart sequence ensures proper mount propagation visibility. The hardcoded sleep values were addressed in an earlier comment about unused variables.


214-219: LGTM!

Clear completion message.

Comment on lines +18 to +22
UNMOUNT_RETRIES=3
WAIT_BETWEEN=2
REMOUNT_WAIT=5
WAIT_TIME=5
VERSION=2.0
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Remove unused variables.

REMOUNT_WAIT and WAIT_TIME are defined but never used in the script. The hardcoded sleep 5 and sleep 15 calls later in the script (lines 196, 203) could use these variables, or they should be removed to reduce confusion.

♻️ Proposed fix: Either remove unused variables or use them

Option 1: Remove unused variables

 UNMOUNT_RETRIES=3
 WAIT_BETWEEN=2
-REMOUNT_WAIT=5
-WAIT_TIME=5
 VERSION=2.0

Option 2: Use the variables for the sleep calls

-# 2. Wait before starting Riven
-sleep 5
+# 2. Wait before starting Riven
+sleep "$REMOUNT_WAIT"
 
-# 4. Wait for mount propagation
-sleep 15
+# 4. Wait for mount propagation
+sleep "$WAIT_TIME"

(Note: If using Option 2, consider renaming WAIT_TIME to something more descriptive like PROPAGATION_WAIT and adjusting the value.)

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
UNMOUNT_RETRIES=3
WAIT_BETWEEN=2
REMOUNT_WAIT=5
WAIT_TIME=5
VERSION=2.0
UNMOUNT_RETRIES=3
WAIT_BETWEEN=2
VERSION=2.0
🧰 Tools
🪛 Shellcheck (0.11.0)

[warning] 20-20: REMOUNT_WAIT appears unused. Verify use (or export if used externally).

(SC2034)


[warning] 21-21: WAIT_TIME appears unused. Verify use (or export if used externally).

(SC2034)

🤖 Prompt for AI Agents
In @ubuntu/riven-remount-cycle.sh around lines 18 - 22, Remove or use the unused
variables REMOUNT_WAIT and WAIT_TIME: either delete both variable definitions
(REMOUNT_WAIT and WAIT_TIME) if you prefer the current hardcoded sleep values,
or replace the hardcoded sleep 5 and sleep 15 calls with the variables (e.g.,
sleep "$REMOUNT_WAIT" and sleep "$WAIT_TIME"), and if choosing to keep and
clarify semantics, rename WAIT_TIME to a more descriptive name like
PROPAGATION_WAIT and update its value and usages accordingly.

Comment on lines +119 to +128
docker stop "$RIVEN_CONTAINER" >/dev/null 2>&1 || true
ok "Riven container stopped"

if [[ "$MEDIA_MODE" == "docker" ]]; then
docker stop "$MEDIA_CONTAINER" >/dev/null 2>&1 || true
ok "Media container stopped"
else
systemctl stop "$MEDIA_SERVICE"
ok "Media service stopped"
fi
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Inconsistent error handling between Docker and systemd modes.

The docker stop commands use || true to gracefully handle non-existent containers, but systemctl stop on line 126 will cause the script to exit immediately (due to set -e) if the service doesn't exist or fails to stop.

🐛 Proposed fix
 if [[ "$MEDIA_MODE" == "docker" ]]; then
   docker stop "$MEDIA_CONTAINER" >/dev/null 2>&1 || true
   ok "Media container stopped"
 else
-  systemctl stop "$MEDIA_SERVICE"
+  systemctl stop "$MEDIA_SERVICE" 2>/dev/null || true
   ok "Media service stopped"
 fi

Alternatively, validate the service exists before stopping:

if systemctl list-unit-files "$MEDIA_SERVICE.service" &>/dev/null; then
  systemctl stop "$MEDIA_SERVICE"
  ok "Media service stopped"
else
  warn "Service $MEDIA_SERVICE not found, skipping"
fi
🤖 Prompt for AI Agents
In @ubuntu/riven-remount-cycle.sh around lines 119 - 128, The systemd branch
inconsistently fails under set -e because systemctl stop on MEDIA_SERVICE can
exit non-zero; modify the MEDIA_MODE == "docker" else branch to first verify the
service exists (e.g., with systemctl list-unit-files or systemctl is-enabled)
before calling systemctl stop "$MEDIA_SERVICE", and if the service is missing
log a warning (using warn) and skip stopping; ensure behavior mirrors the docker
branch's tolerant handling of missing containers (RIVEN_CONTAINER /
MEDIA_CONTAINER) so non-existent services do not cause the script to exit.

Comment on lines +135 to +154
for attempt in $(seq 1 $UNMOUNT_RETRIES); do
if ! is_mounted; then
ok "Mount is already unmounted"
break
fi

warn "Unmount attempt $attempt"

if umount "$MOUNT_PATH" 2>&1 | grep -q "not mounted"; then
ok "Mount was already unmounted"
break
fi

sleep "$WAIT_BETWEEN"

if ! is_mounted; then
ok "Mount successfully unmounted"
break
fi
done
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Unmount loop has logic issues and missing failure handling.

  1. Flawed umount check (line 143-146): If umount succeeds, it produces no output, so grep -q "not mounted" will never match. This check only works if umount fails with that specific message.

  2. No failure after retries exhausted: If the mount is still mounted after all retries, the script silently proceeds to remount, which may cause issues.

🐛 Proposed fix
 for attempt in $(seq 1 $UNMOUNT_RETRIES); do
   if ! is_mounted; then
     ok "Mount is already unmounted"
     break
   fi

   warn "Unmount attempt $attempt"

-  if umount "$MOUNT_PATH" 2>&1 | grep -q "not mounted"; then
-    ok "Mount was already unmounted"
-    break
-  fi
-
-  sleep "$WAIT_BETWEEN"
-
-  if ! is_mounted; then
+  if umount "$MOUNT_PATH" 2>/dev/null; then
     ok "Mount successfully unmounted"
     break
   fi
+
+  sleep "$WAIT_BETWEEN"
 done
+
+# Fail if still mounted after all retries
+if is_mounted; then
+  fail "Failed to unmount $MOUNT_PATH after $UNMOUNT_RETRIES attempts"
+fi
🤖 Prompt for AI Agents
In @ubuntu/riven-remount-cycle.sh around lines 135 - 154, The unmount loop
incorrectly relies on grepping umount stdout for "not mounted" and lacks failure
handling; change the loop around is_mounted/umount (using the is_mounted
function and MOUNT_PATH) to check umount's exit status and capture its
stderr/output—treat exit code 0 as success, if stderr contains "not mounted"
treat as already unmounted, otherwise log the error and retry; after the for
loop, if is_mounted still returns true (using UNMOUNT_RETRIES and WAIT_BETWEEN),
fail fast (exit non-zero) with an error message so the script does not proceed
to remount when unmounting ultimately failed.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@README.md`:
- Around line 54-59: Replace the incorrect top-level directory name in the
README structure diagram: change the string "Riven-Scripts/" to
"distributables/" in the fenced code block so the diagram accurately reflects
this repository; keep the rest of the lines (proxmox/, ubuntu/, README.md) and
the code block formatting intact.
- Around line 19-20: Add a security notice around the direct remote script
execution examples (the bash/wget installer commands shown at the current
installer snippets) that instructs users to review the script before running it,
shows the safer download-then-review pattern (download with curl/wget, inspect
the file, then run with sudo), recommends verifying integrity via checksums or
signatures, and suggests using tagged release URLs instead of the main branch;
place this guidance immediately adjacent to the two installer command blocks
(the ones currently using wget/curl and sudo bash) so readers see the warning
whenever they encounter those commands.
♻️ Duplicate comments (2)
README.md (2)

19-19: Installer URL references different repository.

The Proxmox installer URL points to AquaHorizonGaming/Riven-Scripts but this PR is for rivenmedia/distributables. Users viewing this README in the rivenmedia/distributables repository will download scripts from a different repository, potentially getting outdated or incorrect versions.

If AquaHorizonGaming/Riven-Scripts is the canonical upstream and this is a downstream mirror, add a note clarifying the relationship. Otherwise, update to reference this repository:

-bash -c "$(wget -qLO - https://raw.githubusercontent.com/AquaHorizonGaming/Riven-Scripts/main/proxmox/install.sh)"
+bash -c "$(wget -qLO - https://raw.githubusercontent.com/rivenmedia/distributables/main/proxmox/install.sh)"

39-39: Installer URL references different repository.

Same issue as line 19: the Ubuntu installer URL points to AquaHorizonGaming/Riven-Scripts instead of rivenmedia/distributables.

Update to:

-sudo bash -c "$(curl -fsSL https://raw.githubusercontent.com/AquaHorizonGaming/Riven-Scripts/main/ubuntu/install.sh)"
+sudo bash -c "$(curl -fsSL https://raw.githubusercontent.com/rivenmedia/distributables/main/ubuntu/install.sh)"
📜 Review details

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between fc06f7e and 7c8f7ef.

📒 Files selected for processing (1)
  • README.md
🔇 Additional comments (2)
README.md (2)

63-68: LGTM!

The Notes section provides clear guidance about platform independence and directs users to platform-specific documentation. The structure is helpful for maintainability and future expansion.


1-1: Repository name mismatch in title requires manual verification.

The title references "Riven Scripts" but this repository is rivenmedia/distributables. This may indicate outdated documentation, a repository rename, or intentional branding for a mirror/distribution repository. Verify whether this repository should be renamed, the title updated, or if the current naming is intentional given the repository's purpose in the rivenmedia organization.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

Comment on lines +19 to 20
bash -c "$(wget -qLO - https://raw.githubusercontent.com/AquaHorizonGaming/Riven-Scripts/main/proxmox/install.sh)"
```
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Consider security guidance for direct script execution.

Both installer commands execute remote scripts directly (with elevated privileges for Ubuntu). While this is a common installation pattern, consider adding security guidance such as:

  • Recommending users review the script first before execution
  • Providing checksums for verification
  • Offering tagged releases instead of pulling from main branch

Example addition to documentation:

> **Security Note:** Always review scripts before executing them with elevated privileges.
> You can download and inspect the script first:
> ```bash
> curl -fsSL https://raw.githubusercontent.com/.../install.sh -o install.sh
> # Review install.sh
> sudo bash install.sh
> ```

Also applies to: 39-40

🤖 Prompt for AI Agents
In `@README.md` around lines 19 - 20, Add a security notice around the direct
remote script execution examples (the bash/wget installer commands shown at the
current installer snippets) that instructs users to review the script before
running it, shows the safer download-then-review pattern (download with
curl/wget, inspect the file, then run with sudo), recommends verifying integrity
via checksums or signatures, and suggests using tagged release URLs instead of
the main branch; place this guidance immediately adjacent to the two installer
command blocks (the ones currently using wget/curl and sudo bash) so readers see
the warning whenever they encounter those commands.

Comment on lines +54 to +59
```text
Riven-Scripts/
├── proxmox/ # Proxmox VE LXC installer + docs
├── ubuntu/ # Ubuntu installer + docs
└── README.md # This file
```
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Repository structure shows incorrect directory name.

The repository structure diagram shows Riven-Scripts/ but this repository is distributables. This should be updated to match the actual repository name:

 ```text
-Riven-Scripts/
+distributables/
 ├── proxmox/        # Proxmox VE LXC installer + docs
 ├── ubuntu/         # Ubuntu installer + docs
 └── README.md       # This file

<details>
<summary>🤖 Prompt for AI Agents</summary>

In @README.md around lines 54 - 59, Replace the incorrect top-level directory
name in the README structure diagram: change the string "Riven-Scripts/" to
"distributables/" in the fenced code block so the diagram accurately reflects
this repository; keep the rest of the lines (proxmox/, ubuntu/, README.md) and
the code block formatting intact.


</details>

<!-- fingerprinting:phantom:triton:puma -->

<!-- This is an auto-generated comment by CodeRabbit -->

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant