a0e4e63d01
Reset all Path A script versions from 3.x to 1.0.0 following architectural decision to treat this as a fresh stable baseline after the Path B cleanup. Added TODO.md with prioritized audit findings and replaced the old CHANGELOG with a clean stub. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
11 KiB
11 KiB
HOPS TODO
Generated by codebase audit (2026-06-10). Ranked by severity.
Decisions (2026-06-10)
- Canonical pipeline: Path A (
hops->install->services). Path B deleted. - Deleted:
setup,privileged-setup,user-operations,services-improved,lib/privileges.sh-- all Path B artifacts, gone. - Service catalog:
servicesis the single source of truth. Latest tags kept. lib/secrets.sh: keep and fix. Goal is to encrypt the.envfile at rest (passwords/API keys written byinstall). Fix the broken AES-GCM crypto and wire encryption/decryption into the install flow.- macOS: future roadmap. Linux is the target for now.
CRITICAL BUGS (breaks primary use cases)
B1 -- Infinite recursion in services on Linux [CRITICAL]
- File:
services:25-46 get_timezone_mount()andget_gpu_devices()call themselves on the non-Darwin branch viaecho "$(get_timezone_mount)". Hits bash FUNCNEST limit on every Linux compose generation. Main./hopsinstall is broken on Linux.- Fix: replace the recursive calls with the literal YAML strings they should emit.
B2 -- Brace mismatch in lib/privileges.sh [CRITICAL] -- RESOLVED: delete file
- File:
lib/privileges.sh:429,612 - Moot --
lib/privileges.shis Path B dead code, scheduled for deletion (see A3).
HIGH BUGS
B3 -- Glob stored as string, directory detection always fails [HIGH]
- Files:
hops:154-166,uninstall:127-147 homelab_dirs=( "/home/*/hops" )stores a literal glob; the quoted for-loop never expands it. Multi-user detection is broken,cd "$HOMELAB_DIR"fails underset -e.- Fix: iterate unquoted or use
compgen -G "/home/*/hops".
B4 -- Missing service definitions file reference [HIGH]
- File:
install:916 setup_firewall()sources"$SCRIPT_DIR/hops_service_definitions.sh"which does not exist (the file is namedservices). Per-service firewall rules are silently never applied.- Fix: correct the filename to
services.
B5 -- ((x++)) aborts script under set -e [HIGH]
- Files:
hops:299,317,install:784, and others ((running_count++))returns exit code 1 when the pre-increment value is 0, which kills the script underset -e.- Fix: use
running_count=$((running_count + 1))or append|| true.
B6 -- hops entry point is Linux-only despite macOS library support [HIGH]
- File:
hops:108-136,263 check_dependenciesrequiressystemctl,check_system_requirementscallsfreeanddf -BG,show_service_statuscallssystemctl. All Linux-only. The documented entry point fails immediately on macOS.- Fix: add OS guards or document
hopsas Linux-only.
B7 -- Port collisions not detected within a selection [HIGH]
- File:
services(port map) - sabnzbd and traefik dashboard both use 8080; traefik and nginx-proxy-manager both bind 80/443; authelia and transmission both use 9091.
check_all_portsonly checks host listeners, not intra-selection conflicts, so users can generate an un-startable compose silently.- Fix: add intra-selection conflict check before compose generation.
MEDIUM BUGS
B8 -- Watchtower assigned a bogus port [MED]
- Files:
lib/docker.sh:47,services-improved:90 - Watchtower has no web UI. Assigning it port 8080 emits a spurious
ports:block and broken healthcheck in the generated compose.
B9 -- Update backup copies into itself [MED]
- File:
hops:586-595 update_hopsdoescp -r "$SCRIPT_DIR" "$backup_dir"where$backup_diris inside$SCRIPT_DIR. Results in recursive self-copy including.git/.- Fix: create the backup dir outside the script directory.
B10 -- secure_delete stat flag wrong on macOS [MED]
- File:
lib/secrets.sh:146 - Uses
stat -c%s(GNU) which fails on macOS (stat -f%z). Manual-overwrite fallback silently no-ops on macOS.
B11 -- jellystat generated with wrong template in services-improved [MED]
- File:
services-improved:422 - Routed through the generic media-server template; gets no postgres DB and no
JWT_SECRET, so it cannot run. The hand-written
servicesversion is correct.
B12 -- Empty-password detection regex broken [LOW]
- File:
lib/security.sh:361-384 grep "PASSWORD=\s*$"without-Eor-Pmeans\sis matched literally, not as whitespace. Empty-password detection is dead.
SECURITY
S1 -- Broken/unauthenticated encryption [HIGH]
- File:
lib/secrets.sh:85,115 openssl enc -aes-256-gcmvia the CLI does not handle the GCM auth tag. This is not authenticated encryption and round-trips unreliably.- Fix: use a supported openssl mode or switch to
gpg --symmetric.
S2 -- Passphrases/keys exposed in process list [HIGH]
- Files:
lib/secrets.sh:85,115,lib/security.sh:140,156,175,204,416,442 -pass pass:"$key"and--passphrase "$x"on the command line are visible to any local user viaps.- Fix: use
-pass fd:Nor--passphrase-fd Nwith a file descriptor.
S3 -- Committed default Authelia credential [HIGH]
- File:
services:1148-1157 users_database.ymlships a default admin account with a known password hash (hash of literal "password"). Every Authelia deploy has this credential.- Fix: force password change on first login or generate the hash at deploy time.
S4 -- Traefik dashboard exposed with no auth [MED]
- File:
services:672-673,684 api.insecure=trueexposes the Traefik dashboard on :8080 with no auth. Consider disabling or requiring middleware auth.
S5 -- eval on environment-derived value [MED]
- Files:
install:598,671,uninstall:136,462,lib/system.sh:306, others eval echo "~$SUDO_USER"expands an env-sourced value through eval.- Fix:
getent passwd "$SUDO_USER" | cut -d: -f6
S6 -- Predictable temp file paths [MED]
- Files:
lib/secrets.sh:16,188,288,uninstall:374 /tmp/hops_env_$$etc. in world-writable/tmpare symlink-race targets before thechmod 600runs.- Fix: use
mktempand assign before use.
S7 -- Commands built as strings, run unquoted [MED]
- File:
install:731-736,755,773-779 pull_cmd="sudo -u $SUDO_USER docker compose pull"run as$pull_cmdis fragile with unusual usernames and bypasses quoting.- Fix: use bash arrays.
S9 -- Non-idempotent sysctl append [LOW]
- File:
privileged-setup:224 echo 'net.ipv4.ip_forward = 1' >> /etc/sysctl.confappended every run. Accumulates duplicate lines.- Fix: check before appending (
grep -q ... || echo ... >>)
ARCHITECTURE / DESIGN
A1 -- Two divergent install pipelines [HIGH] -- RESOLVED
- Path A chosen. Delete:
setup,privileged-setup,user-operations,services-improved.
A2 -- Three sources of truth for the service catalog [HIGH]
services:get_service_ports()+ inline image strings (CANONICAL)services-improved: scheduled for deletion (Path B)lib/docker.sh:HOPS_SERVICESarray -- reconcile or remove duplicates- Fix:
lib/docker.shservice maps must matchservices; remove anything only used by Path B.
A3 -- lib/privileges.sh is dead code [MED] -- RESOLVED: delete
- Path B artifact. Delete it.
A4 -- lib/secrets.sh crypto needs fixing and wiring in [MED]
- Goal: encrypt the
.envfile at rest afterinstallwrites it. - Fix broken AES-GCM (use
gpg --symmetricor a supported openssl mode). - Fix passphrase-on-command-line exposure (S1, S2).
- Wire encrypt/decrypt calls into
installflow.
A5 -- hops duplicates functions from lib/common.sh [MED]
log,error_exit,warning,success,info,validate_timezone,validate_password,generate_secure_password,create_docker_networks,get_service_port/imageare all defined twice (or three times).- Fix: source
lib/common.shfromhopsand remove local duplicates.
A6 -- Caddy is unreachable via the menu [LOW]
servicesdefinesgenerate_caddybut theselect_servicesmenu ininstallnever lists caddy as a selectable option.
A7 -- Committed dev artifacts [LOW]
summary7-19.txtanddiscord-header.mdshould not be in the repo. Add to.gitignoreor delete.
MISSING / INCOMPLETE
M1 -- RESOLVED (Path B deleted)
M2 -- RESOLVED (Path B deleted)
M3 -- RESOLVED (Path B deleted)
M4 -- RESOLVED (lib/privileges.sh deleted)
PLATFORM SUPPORT
P2 -- uninstall is Linux-only [HIGH] -- deferred (Linux-first)
- Unconditional
apt-get,dpkg,systemctl,groupdel,ufwwith no OS branching. Acceptable for now; revisit when macOS support is scoped.
P3 -- RESOLVED (Path B deleted)
P4 -- No WSL2 detection [MED]
- README claims WSL2 support but there is no WSL2 detection.
systemctl-based service management fails on WSL distros without systemd.
P5 -- Inconsistent port-check tools [MED]
lib/common.shusesss;installuseslsof.ssis absent on macOS.
P6 -- Hardcoded render GID for Jellyfin GPU [LOW]
- File:
services:435 group_add: "109"is the render GID on a specific distro, wrong on most systems and meaningless on macOS.
CODE QUALITY
Q1 -- Three separate error-handling implementations [MED]
hops,uninstall, andlib/common.sheach define their ownerror_exitandlogwith different formats. Consolidate inlib/common.sh.
Q2 -- set -e + intentional non-zero returns is a minefield [MED]
validate_passwordreturns 1/2/3,check_portreturns 1 -- these work only because they happen to be in conditionals. Combined with B5 this is fragile. Considerset -euo pipefailwith explicit|| truewhere non-zero is intended.
Q3 -- Debug echo statements left in production code [LOW]
- Files:
lib/system.sh:605,823,1043,1046,1084,1089,1149-1156,privileged-setup:72 DEBUG:prefixed echo lines should be removed or gated behind a$DEBUGflag.
Q4 -- services-improved leaks set -e when sourced [LOW]
- File:
services-improvedtop of file - File sets
set -ethen is sourced byuser-operationsandprivileges, leaking the option into the caller's shell.
SUGGESTED ORDER OF ATTACK
- Delete Path B files:
setup,privileged-setup,user-operations,services-improved,lib/privileges.sh(A1/A3 -- resolved) - Fix B1 (infinite recursion in
services) -- unblocks all Linux installs - Fix B5 (
((x++))underset -e) -- prevents silent aborts - Fix B3 (glob directory detection) -- fixes multi-user and uninstall
- Fix B4 (wrong filename in firewall setup)
- Reconcile
lib/docker.shservice maps withservices(A2) - Security pass: S3 (default Authelia cred), S2/S6 (passphrase on cmdline, mktemp), S5 (eval on env var), S7 (string-built commands)
- Fix and wire in
lib/secrets.sh: replace broken crypto, hook into install flow to encrypt.envat rest (A4/S1/S2) - Fix B12 empty-password regex, B8 watchtower port, B9 backup self-copy
- Consolidate duplicate functions into
lib/common.sh(A5, Q1) - Remove debug echo statements (Q3)
- macOS / WSL2 support (B6, P4) -- future roadmap