3cba0998a7
- Remove duplicate log/error_exit/warning/success/info from hops and uninstall; remove validate_password, generate_secure_password, create_docker_networks, validate_timezone from install. Single canonical copies now live in lib/common.sh, lib/security.sh, lib/validation.sh, and lib/docker.sh (A5, Q1) - Fix lib/docker.sh, lib/validation.sh, lib/security.sh to use LIB_DIR instead of SCRIPT_DIR so sourcing them inside a function does not clobber the caller's SCRIPT_DIR - Move SCRIPT_VERSION to lib/common.sh as the single source of truth; remove local declarations from hops, install, and uninstall - uninstall now sources lib/common.sh directly for standalone safety - validate_timezone updated to warn-and-default instead of error_exit - validate_password updated to handle empty input (return 3) - Update CHANGELOG and TODO to reflect resolved items (B1-B6, A1, A3, A5, Q1) and bump version to 1.0.1 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
12 KiB
12 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] -- RESOLVED
- File:
services:25-46 get_timezone_mount()andget_gpu_devices()called themselves on the non-Darwin branch. Fixed: both functions now return literal YAML strings directly.
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] -- RESOLVED
- Files:
hops:154-166,uninstall:127-147 - Glob removed from array; expanded separately via
compgen -G "/home/*/hops". Also fixedeval echo "~$SUDO_USER"->getent passwdinuninstall.
B4 -- Missing service definitions file reference [HIGH] -- RESOLVED
- File:
install:916 - Corrected source path from
hops_service_definitions.shtoservices.
B5 -- ((x++)) aborts script under set -e [HIGH] -- RESOLVED
- Files:
hops,install - All
((x++))occurrences replaced withx=$((x + 1)).
B6 -- hops entry point is Linux-only despite macOS library support [HIGH] -- RESOLVED
- File:
hops - Added Linux-only guard at top of script; exits immediately with a clear error on non-Linux.
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] -- DO FIRST
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. - Must be done before port collision fix (B7) so there is one authoritative map.
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 [HIGH] -- RESOLVED
log,error_exit,warning,success,info,validate_timezone,validate_password,generate_secure_password,create_docker_networksremoved fromhops,uninstall, andinstall. Canonical copies kept inlib/common.sh,lib/security.sh,lib/validation.sh,lib/docker.sh.- Fixed
lib/docker.sh,lib/validation.sh,lib/security.shto useLIB_DIRinstead ofSCRIPT_DIRso sourcing them inside a function doesn't clobber the caller'sSCRIPT_DIR. validate_timezoneupdated to warn-and-default instead of error_exit.validate_passwordupdated to handle empty input (return 3).
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)
M6 -- Deprecate Watchtower [LOW]
- Watchtower auto-updates running containers without user review, which can silently break working setups. At odds with HOPS managing its own deploys.
- Remove from the selectable service list and SERVICES.md.
- Users who want auto-updates can add it manually.
M8 -- Deprecate Readarr [LOW]
- Readarr project has been retired upstream. Remove from the selectable service list, services definition, and SERVICES.md.
- Add a note in SERVICES.md under the *arr section if users ask why it's gone.
M7 -- Investigate adding Profilarr [LOW]
- Profilarr manages and syncs quality profiles across Radarr/Sonarr instances.
- Evaluate: image source, default port, dependencies, config requirements.
- Determine if it fits the existing *arr service template or needs a custom definition.
M5 -- Review Huntarr inclusion -- switch to elfhosted rebuild [MED]
- The current
servicesdefinition uses the original plexguide/Huntarr.io image. The project has been rebuilt by elfhosted under a new image/repo. - Review the new elfhosted image name, default port, and any config changes.
- Update the service definition in
servicesand the entry in SERVICES.md. - Verify the new image is actively maintained before shipping 1.0.0.
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 [HIGH] -- RESOLVED
- Covered by A5; all resolved.
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 [MED] -- DO FIRST
- Files:
lib/system.sh:605,823,1043,1046,1084,1089,1149-1156 DEBUG:prefixed echo lines should be removed or gated behind a$DEBUGflag.- Clean these before bug fixes so signal isn't buried in debug noise.
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
Cleanup first (do before any bug fixes)
- [DONE] Delete Path B files (A1/A3)
- [DONE] Consolidate duplicate functions into
lib/common.sh(A5, Q1) - Reconcile
lib/docker.shservice maps withservices(A2) -- one catalog to fix - Remove debug echo statements from
lib/system.sh(Q3) -- reduce noise
Bug fixes
- [DONE] Fix B1 (infinite recursion in
services) - [DONE] Fix B5 (
((x++))underset -e) - [DONE] Fix B3 (glob directory detection)
- [DONE] Fix B4 (wrong filename in firewall setup)
- Fix B7 (intra-selection port collision detection)
Security pass
- S3 (default Authelia cred), S5 (eval on env var), S6 (mktemp), S7 (string-built commands), S2 (passphrase on cmdline)
- Fix and wire in
lib/secrets.sh: replace broken crypto, hook into install flow to encrypt.envat rest (A4/S1/S2)
Remaining
- Fix B12 empty-password regex, B8 watchtower port, B9 backup self-copy
- macOS / WSL2 support (B6, P4) -- future roadmap