Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 33 additions & 13 deletions .check/VerifySourceCalls.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,27 +138,47 @@ def parse_functions_in_file(filepath):

def parse_script_for_includes_and_local_funcs(script_path):
includes = set()
shellcheck_directives = set()
local_funcs = parse_functions_in_file(script_path)

if not os.path.isfile(script_path):
return includes, local_funcs

with open(script_path, "r", encoding="utf-8", newline='\n') as f:
for line in f:
line_stripped = line.strip()
lines = f.readlines()

for i, line in enumerate(lines):
line_stripped = line.strip()

# Check for shellcheck directive
sc_match = SHELLCHECK_SOURCE_REGEX.search(line_stripped)
if sc_match:
util_name = sc_match.group(1)
shellcheck_directives.add(util_name)

# Check for source statement
s_match = SOURCE_REGEX.search(line_stripped)
if s_match:
# e.g., "Prompts.sh" or "Cluster.sh"
includes.add(s_match.group(1))
# Look for matching source statement in next few lines (max 5)
found_source = False
for j in range(i + 1, min(i + 6, len(lines))):
next_line = lines[j].strip()
s_match = SOURCE_REGEX.search(next_line)
if s_match and s_match.group(1) == util_name:
found_source = True
break
# Stop if we hit another shellcheck or source for different file
if SHELLCHECK_SOURCE_REGEX.search(next_line) or SOURCE_REGEX.search(next_line):
break

if not found_source:
# Orphaned shellcheck directive - don't add to includes
print(f" [WARNING] Orphaned shellcheck directive for {util_name} at line {i+1}")
continue

# Check for source statement
s_match = SOURCE_REGEX.search(line_stripped)
if s_match:
# e.g., "Prompts.sh" or "Cluster.sh"
includes.add(s_match.group(1))

# Also check for shellcheck directive (for consistency checking)
sc_match = SHELLCHECK_SOURCE_REGEX.search(line_stripped)
if sc_match:
# Verify this matches an actual source line
includes.add(sc_match.group(1))

return includes, local_funcs

###############################################################################
Expand Down
27 changes: 27 additions & 0 deletions .check/_RunChecks.sh
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,33 @@ fi
CHECKS_RUN=$((CHECKS_RUN + 1))
echo ""

# Check 1a: Basic shell syntax validation
echo "1a. Validating shell syntax (bash -n)..."
SYNTAX_ERRORS=0
SYNTAX_FILES=()
while IFS= read -r -d '' file; do
if ! bash -n "$file" 2>/dev/null; then
SYNTAX_ERRORS=$((SYNTAX_ERRORS + 1))
SYNTAX_FILES+=("$file")
fi
done < <(find . -name "*.sh" -not -path "*/.git/*" -not -path "*/.check/*" -print0)

if [ $SYNTAX_ERRORS -eq 0 ]; then
echo "- All shell scripts have valid syntax"
CHECKS_PASSED=$((CHECKS_PASSED + 1))
else
echo "- FAILED: $SYNTAX_ERRORS file(s) with syntax errors"
if [ "$VERBOSE" = true ] || [ $SYNTAX_ERRORS -le 5 ]; then
for file in "${SYNTAX_FILES[@]}"; do
echo " $file"
bash -n "$file" 2>&1 | head -3 | sed 's/^/ /'
done
fi
CHECKS_FAILED=$((CHECKS_FAILED + 1))
fi
CHECKS_RUN=$((CHECKS_RUN + 1))
echo ""

# Check 2: Update function indices
echo "2. Updating function indices..."
python3 .check/UpdateFunctionIndex.py ./ 2>&1 | tail -3
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
nodes.json
TestConnectionInfo.json
.d/
.nfs*

# Downloaded Proxmox documentation (keep scripts, ignore generated content)
.docs/*.html
Expand Down
Binary file added .site/MultiView.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added .site/MultiView2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
62 changes: 62 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,68 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [2.1.6] - 2025-11-25

Bug fixes, username support, and validation improvements

### Added
- **Username Configuration** - Support for specifying SSH usernames per node
- Added `username` field to nodes.json configuration
- Username prompts in all node configuration flows (manual entry, saved nodes, IP ranges, VMID ranges)
- Default username is "root" with option to specify alternatives
- Display format changed to `username@ip` throughout GUI
- **Dependency Checking** - Runtime validation before remote execution
- `__check_remote_dependencies__()` function checks for sshpass and jq
- Helpful error messages with installation commands for all major distros
- Notes that sshpass is not required when using SSH keys
- **Syntax Validation** - Basic shell syntax checking added to validation suite
- New Check 1a. in `_RunChecks.sh` runs `bash -n` on all .sh files
- Catches structural errors and orphaned code blocks
- Shows file names and line numbers for syntax errors
- **Enhanced Source Verification** - Improved validation of shellcheck directives
- `VerifySourceCalls.py` now validates shellcheck comments have matching source statements
- Detects orphaned shellcheck directives within 5 lines
- Prevents mismatched documentation and code

### Changed
- **Remote Execution UI** - Scripts hidden in remote mode for better UX
- GUI.sh and CCPVE.sh hidden from root menu when in remote execution mode
- Prevents accidental execution of control scripts on remote nodes
- Scripts still shown in local mode and subdirectories
- **README.md** - Clarified dependency requirements
- Updated installation command to include `jq` and `sshpass`
- Documented that sshpass is only needed for password-based authentication
- Separated build-time tools from runtime dependencies

### Fixed
- **Critical: Orphaned Error Handler** - Fixed syntax error in `Host/HostInfo.sh`
- Removed orphaned error handler code block (lines 34-36)
- File had error message without matching source statement
- Bug prevented script execution on remote nodes
- **Username Hardcoding** - Removed hardcoded "root@" from all remote operations
- Updated all SSH/SCP operations in `RemoteExecutor.sh` to use configured username
- `__ssh_exec__`, `__scp_exec__`, `__scp_exec_recursive__`, `__scp_download__` now accept username parameter
- `ConfigManager.sh` tracks username per node in `NODE_USERNAMES` associative array
- **Missing Validation** - Syntax check gap closed
- `_RunChecks.sh` never validated basic syntax :C
- Now catches structural errors that bash -n would detect
- Prevents orphaned code and malformed control structures from entering repository

### Technical Details
- `nodes.json.template` - Added username field with "root" default
- `Utilities/ConfigManager.sh` - Added NODE_USERNAMES tracking and __get_node_username__() function
- `Utilities/RemoteExecutor.sh` - All remote operations parameterized with username
- `GUI.sh` - Dependency checking, username prompts, and script filtering
- `.check/VerifySourceCalls.py` - Enhanced shellcheck directive validation
- `.check/_RunChecks.sh` - Added Check 1a. for syntax validation

### Developer Notes
The orphaned error handler bug existed because:
- `bash -n` syntax check was not being run in validation suite
- `DeadCodeCheck.py` only checks unused functions/variables, not code structure
- `VerifySourceCalls.py` didn't validate orphaned error handlers
The fix adds syntax validation to prevent similar issues...

## [2.1.5] - 2025-11-24

PVE documentation automation and repository cleanup
Expand Down
Loading