# Repository state ## Project summary - Name: `netupgrade` - Language: Bash - Entry point: `bin/netupgrade` - Purpose: interactive CLI to run maintenance and upgrade actions on multiple remote hosts over SSH - Config model: Bash configuration files sourced from `~/.config/netupgrade/*.cfg` ## Repository structure - `bin/netupgrade`: main executable script containing CLI parsing, node selection, remote execution, and logging - `config/netupgrade/*.cfg`: sample configuration files defining host groups and action sequences - `README.md`: installation and usage documentation - `TODO.md`: prioritized next actions and follow-up work ## Current behavior - Loads a Bash configuration file - Expects a `NODES` array with entries formatted as `host;display-name;action1;action2;...` - Displays an interactive multi-select checklist using `whiptail` - Executes selected actions sequentially over SSH - Uses `root@host` by default, or `SSH_USER@host` when configured - Writes execution logs to `~/netupgrade.log` - Opens the log with `$EDITOR`, then `nano`, `vi`, or `less`; if none is available, prints the log path and continues with the existing optional cleanup prompt ## Supported actions - `apt` - `yum` - `dnf` - `pkg` - `pacman` - `apk` - `reboot` - `cmd:` - `docker-stacks:` ## Architecture and constraints - The project is intentionally lightweight and shell-based - The main execution flow still lives mostly in a single Bash script - Configuration is code-driven rather than declarative, because config files are sourced as shell files - Config files are trusted inputs and imply arbitrary code execution - Remote operations are sequential, not parallel - Logging is file-based and tightly coupled to command execution - Backward compatibility for existing config files should be preserved where possible - Changes to SSH command construction require extra care because quoting regressions are easy to introduce ## Notable implementation details - SSH execution is centralized through a `runSSH` helper - `SSH_USER` is configurable and defaults to `root` - `NODES` parsing was hardened to preserve spaces in action values such as `cmd:...` - `cmd:<...>` is executed through a remote shell to support shell operators, but remains intentionally powerful and unsafe - `reboot` uses a detached remote command to reduce false failures caused by expected SSH disconnects - `docker-stacks` runs through a remote shell script sent over SSH stdin to improve path handling and quoting - Startup dependency checks cover required local commands, including `mv` for log-summary rewriting ## Sensitive areas for future changes - SSH command construction and shell quoting behavior - `cmd:<...>` execution semantics - `docker-stacks:<...>` path handling and remote shell behavior - Package-manager cleanup commands and confirmation flags - Error propagation consistency across action types - Documentation and runtime behavior alignment - Sample configuration accuracy to avoid operator mistakes ## Recent meaningful changes - README and CLI help were aligned with current behavior, including the meaning of `-f` - Startup dependency checks were added and updated - Log viewer fallback was made more flexible - `NODES` parsing was hardened to preserve spaces in action values - SSH execution was centralized and made configurable through `SSH_USER` - Remote command construction was improved for `pacman`, `docker-stacks`, and `reboot` - Log summary generation was rewritten to avoid `sed -i` interpolation and now replaces the log atomically - `apk` and `apt` cleanup behavior was corrected to better match real package-manager semantics - The sample configuration in `config/netupgrade/hypervisor-01.cfg` now keeps the alternate `docker-01` reboot example commented out rather than active by default - A new `dnf` action was added alongside the existing `yum` action to support newer RPM-based systems without breaking existing configurations ## Change guidance - `STATE.md` should stay focused on current state, architecture, and constraints - `TODO.md` should hold prioritized follow-up work and next implementation steps - Prefer small, reviewable hardening changes over broad rewrites - Keep the tool simple and admin-friendly - Treat documentation consistency as part of functional correctness - Be cautious with remote command construction, because quoting changes can easily introduce regressions - Avoid introducing a global `set -euo pipefail` baseline in one step without first documenting and validating the intended failure semantics - Focus future testing first on parsing, command construction, and result reporting