feat: add comprehensive module validation tooling

Add validate-modules.sh script that validates critical naming conventions
and module structure to prevent common RPC and HTTP 404 errors.

New validation checks:
- RPCD script names must match ubus object names (luci.* prefix)
- Menu paths must match view file locations
- View files must have corresponding menu entries
- RPCD scripts must be executable
- JSON files must have valid syntax
- ubus objects must follow naming convention

Updated CLAUDE.md documentation with:
- Critical naming conventions section with examples
- Common error patterns and solutions
- Updated development workflow to include validation
- Enhanced troubleshooting guide for RPC and 404 errors
- Updated package structure diagram with correct RPCD naming

Added secubox-tools/README.md:
- Detailed usage instructions for validation script
- Common fixes for naming issues
- CI/CD integration examples
- Quick reference for critical naming rules

This tooling prevents deployment of modules with naming mismatches that
cause runtime errors like:
- RPC call failed with error -32000: Object not found
- HTTP error 404 while loading view files

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
CyberMind-FR 2025-12-24 09:56:42 +01:00
parent 16ad6d6a43
commit 92f3318729
3 changed files with 539 additions and 9 deletions

163
CLAUDE.md
View File

@ -38,6 +38,9 @@ opkg install /tmp/luci-app-*.ipk
### Validation
```bash
# Run comprehensive module validation (RECOMMENDED)
./secubox-tools/validate-modules.sh
# Validate shell scripts (RPCD backends)
shellcheck luci-app-*/root/usr/libexec/rpcd/*
@ -71,7 +74,8 @@ luci-app-<module-name>/
└── root/
├── etc/config/<module-name> # UCI configuration (optional)
└── usr/
├── libexec/rpcd/<module-name> # RPCD backend script
├── libexec/rpcd/
│ └── luci.<module-name> # RPCD backend script (MUST use luci. prefix!)
└── share/
├── luci/menu.d/ # Menu JSON definition
│ └── luci-app-<module-name>.json
@ -99,6 +103,93 @@ luci-app-<module-name>/
- Defines access control for ubus methods
- Maps read/write permissions to user groups
### Critical Naming Conventions
**IMPORTANT**: The following naming rules are MANDATORY for modules to work correctly:
#### 1. RPCD Script Must Match ubus Object Name
The RPCD script filename MUST exactly match the ubus object name used in JavaScript:
```javascript
// In JavaScript (htdocs/luci-static/resources/view/*/):
var callStatus = rpc.declare({
object: 'luci.cdn-cache', // ← This object name
method: 'status'
});
```
```bash
# RPCD script filename MUST match:
root/usr/libexec/rpcd/luci.cdn-cache # ← Must be exactly 'luci.cdn-cache'
```
**Common Error**: If the names don't match, you'll get:
- `RPC call to luci.cdn-cache/status failed with error -32000: Object not found`
- `Command failed: Method not found`
**Solution**: All RPCD scripts MUST use the `luci.` prefix:
- ✅ Correct: `luci.cdn-cache`, `luci.system-hub`, `luci.wireguard-dashboard`
- ❌ Wrong: `cdn-cache`, `system-hub`, `wireguard-dashboard`
#### 2. Menu Paths Must Match View File Locations
Menu JSON path entries MUST correspond to actual view files:
```json
// In menu.d/luci-app-netifyd-dashboard.json:
{
"action": {
"type": "view",
"path": "netifyd-dashboard/overview" // ← Must match file location
}
}
```
```bash
# View file MUST exist at:
htdocs/luci-static/resources/view/netifyd-dashboard/overview.js
# ↑ Same path as menu ↑
```
**Common Error**: If paths don't match:
- `HTTP error 404 while loading class file '/luci-static/resources/view/netifyd/overview.js'`
**Solution**: Ensure menu paths match directory structure:
- ✅ Correct: Menu path `netifyd-dashboard/overview` → file `view/netifyd-dashboard/overview.js`
- ❌ Wrong: Menu path `netifyd/overview` → file `view/netifyd-dashboard/overview.js`
#### 3. ubus Object Naming Convention
All ubus objects MUST start with `luci.` prefix:
```javascript
// ✅ Correct:
object: 'luci.cdn-cache'
object: 'luci.system-hub'
object: 'luci.wireguard-dashboard'
// ❌ Wrong:
object: 'cdn-cache'
object: 'systemhub'
```
#### 4. Validation Before Deployment
**ALWAYS** run validation before deploying:
```bash
./secubox-tools/validate-modules.sh
```
This script checks:
- RPCD script names match ubus objects
- Menu paths match view file locations
- View files have corresponding menu entries
- RPCD scripts are executable
- JSON files are valid syntax
- ubus objects follow naming convention
### Makefile Structure
Each package Makefile must define:
@ -244,11 +335,49 @@ x86: x86-64, x86-generic
## Common Issues and Solutions
### RPC Errors: "Object not found" or "Method not found"
**Error**: `RPC call to luci.cdn-cache/status failed with error -32000: Object not found`
**Cause**: RPCD script name doesn't match ubus object name in JavaScript
**Solution**:
1. Check JavaScript files for ubus object name:
```bash
grep -r "object:" luci-app-*/htdocs --include="*.js"
```
2. Rename RPCD script to match exactly (including `luci.` prefix):
```bash
mv root/usr/libexec/rpcd/cdn-cache root/usr/libexec/rpcd/luci.cdn-cache
```
3. Restart RPCD on router:
```bash
/etc/init.d/rpcd restart
```
### HTTP 404 Errors: View Files Not Found
**Error**: `HTTP error 404 while loading class file '/luci-static/resources/view/netifyd/overview.js'`
**Cause**: Menu path doesn't match actual view file location
**Solution**:
1. Check menu JSON for path:
```bash
grep '"path":' root/usr/share/luci/menu.d/*.json
```
2. Verify view file exists at matching location:
```bash
ls htdocs/luci-static/resources/view/
```
3. Update menu path to match file location OR move file to match menu path
### RPCD Not Responding
After installing/updating a package:
```bash
/etc/init.d/rpcd restart
/etc/init.d/uhttpd restart
```
### Menu Not Appearing
@ -257,30 +386,46 @@ Check that:
1. Menu JSON is valid: `jsonlint root/usr/share/luci/menu.d/*.json`
2. ACL grants access: Check `root/usr/share/rpcd/acl.d/*.json`
3. Dependencies are installed: Check Makefile `LUCI_DEPENDS`
4. Menu path matches view file location (see above)
### Build Failures
Common causes:
1. Missing fields in Makefile (PKG_NAME, LUCI_TITLE, etc.)
2. Invalid JSON syntax in menu.d or acl.d
3. RPCD script not executable
3. RPCD script not executable (chmod +x needed)
4. Wrong include path (should be `include ../../luci.mk`)
5. RPCD script name doesn't match ubus object (must use `luci.` prefix)
Use repair tool: `./secubox-tools/secubox-repair.sh`
### Quick Diagnosis
Run the validation script to check all naming conventions:
```bash
./secubox-tools/validate-modules.sh
```
## Development Workflow
1. Make changes to module files
2. Test JSON syntax: `jsonlint <file>.json`
3. Test shell scripts: `shellcheck <script>`
4. Build package: `make package/luci-app-<name>/compile V=s`
5. Install on test router and verify functionality
6. Run repair tool if needed: `./secubox-tools/secubox-repair.sh`
7. Commit changes and push (triggers CI validation)
8. Create tag for release: `git tag -a v1.0.0 -m "Release 1.0.0"`
2. **Run validation checks** (CRITICAL):
```bash
./secubox-tools/validate-modules.sh
```
3. Test JSON syntax: `jsonlint <file>.json`
4. Test shell scripts: `shellcheck <script>`
5. Build package: `make package/luci-app-<name>/compile V=s`
6. Install on test router and verify functionality
7. Run repair tool if needed: `./secubox-tools/secubox-repair.sh`
8. Commit changes and push (triggers CI validation)
9. Create tag for release: `git tag -a v1.0.0 -m "Release 1.0.0"`
## Important Notes
- **CRITICAL**: RPCD script names MUST match ubus object names (use `luci.` prefix)
- **CRITICAL**: Menu paths MUST match view file directory structure
- **CRITICAL**: Always run `./secubox-tools/validate-modules.sh` before committing
- All modules use Apache-2.0 license
- RPCD backends must be executable (chmod +x)
- JavaScript files use strict mode: `'use strict';`

130
secubox-tools/README.md Normal file
View File

@ -0,0 +1,130 @@
# SecuBox Development Tools
This directory contains utilities for validating, debugging, and maintaining SecuBox modules.
## Tools
### validate-modules.sh
Comprehensive validation script that checks all critical naming conventions and module structure.
**Usage:**
```bash
./secubox-tools/validate-modules.sh
```
**Checks performed:**
1. **RPCD script names vs ubus objects** - Ensures RPCD script filenames match JavaScript ubus object declarations
2. **Menu paths vs view files** - Verifies menu.d JSON paths correspond to actual view files
3. **View files have menu entries** - Checks that all view files are referenced in menus
4. **RPCD script permissions** - Ensures scripts are executable
5. **JSON syntax validation** - Validates all menu.d and acl.d JSON files
6. **ubus naming convention** - Verifies all ubus objects use the `luci.` prefix
**Exit codes:**
- `0` - All checks passed (or only warnings)
- `1` - Critical errors found
**Example output:**
```
✓ luci-app-cdn-cache: RPCD script 'luci.cdn-cache' matches ubus object 'luci.cdn-cache'
✓ luci-app-cdn-cache: Menu path 'cdn-cache/overview' → file exists
❌ ERROR: luci-app-example: RPCD script 'example' does not match ubus object 'luci.example'
```
### secubox-repair.sh
Auto-repair tool that fixes common issues in Makefiles and RPCD scripts.
**Usage:**
```bash
./secubox-tools/secubox-repair.sh
```
### secubox-debug.sh
Validates individual package structure and dependencies.
**Usage:**
```bash
./secubox-tools/secubox-debug.sh luci-app-<module-name>
```
## Recommended Workflow
Before committing changes:
1. **Run validation** (CRITICAL):
```bash
./secubox-tools/validate-modules.sh
```
2. Fix any errors reported
3. Run shellcheck on RPCD scripts:
```bash
shellcheck luci-app-*/root/usr/libexec/rpcd/*
```
4. Commit changes
## Common Fixes
### Fix RPCD naming mismatch
If validation reports RPCD script name doesn't match ubus object:
```bash
# Rename the script to include luci. prefix
cd luci-app-example/root/usr/libexec/rpcd
mv example luci.example
```
### Fix menu path mismatch
If validation reports menu path doesn't match view file:
```bash
# Option 1: Update menu.d JSON to match file location
# Edit: root/usr/share/luci/menu.d/luci-app-example.json
# Change: "path": "example/view" → "path": "example-dashboard/view"
# Option 2: Move view files to match menu path
mv htdocs/luci-static/resources/view/example-dashboard \
htdocs/luci-static/resources/view/example
```
### Fix non-executable RPCD script
```bash
chmod +x luci-app-example/root/usr/libexec/rpcd/luci.example
```
## Integration with CI/CD
The validation script can be integrated into GitHub Actions workflows:
```yaml
- name: Validate modules
run: |
chmod +x secubox-tools/validate-modules.sh
./secubox-tools/validate-modules.sh
```
## Critical Naming Rules
**These rules are MANDATORY** - violations will cause runtime errors:
1. **RPCD scripts** must be named `luci.<module-name>`
- ✅ `luci.cdn-cache`
- ❌ `cdn-cache`
2. **Menu paths** must match view file locations
- Menu: `"path": "cdn-cache/overview"`
- File: `view/cdn-cache/overview.js`
3. **ubus objects** must use `luci.` prefix
- ✅ `object: 'luci.cdn-cache'`
- ❌ `object: 'cdn-cache'`
See `CLAUDE.md` for complete documentation.

255
secubox-tools/validate-modules.sh Executable file
View File

@ -0,0 +1,255 @@
#!/bin/bash
#
# SecuBox Module Validation Script
# Validates RPCD naming, menu paths, and module structure
#
set -e
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
ERRORS=0
WARNINGS=0
echo "========================================"
echo "SecuBox Module Validation"
echo "========================================"
echo ""
# Function to print error
error() {
echo -e "${RED}❌ ERROR: $1${NC}"
((ERRORS++))
}
# Function to print warning
warn() {
echo -e "${YELLOW}⚠️ WARNING: $1${NC}"
((WARNINGS++))
}
# Function to print success
success() {
echo -e "${GREEN}$1${NC}"
}
# Check 1: RPCD script names must match ubus object names
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "1. Validating RPCD script names vs ubus objects"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
for module_dir in luci-app-*/; do
module_name=$(basename "$module_dir")
echo "Checking $module_name..."
# Find RPCD script
rpcd_dir="$module_dir/root/usr/libexec/rpcd"
if [ -d "$rpcd_dir" ]; then
rpcd_script=$(find "$rpcd_dir" -type f ! -name "*.md" 2>/dev/null | head -1)
if [ -n "$rpcd_script" ]; then
rpcd_name=$(basename "$rpcd_script")
# Extract ubus object names from JavaScript files
js_objects=$(find "$module_dir/htdocs" -name "*.js" -type f 2>/dev/null | \
xargs grep -h "object:" 2>/dev/null | \
grep -o "'[^']*'" | sort -u | tr -d "'")
if [ -n "$js_objects" ]; then
# Check if RPCD script name matches any ubus object
match_found=false
for obj in $js_objects; do
if [ "$rpcd_name" = "$obj" ]; then
match_found=true
success "$module_name: RPCD script '$rpcd_name' matches ubus object '$obj'"
break
fi
done
if [ "$match_found" = false ]; then
error "$module_name: RPCD script '$rpcd_name' does not match any ubus object(s): $js_objects"
echo " → Rename $rpcd_script to one of: $js_objects"
fi
else
warn "$module_name: No ubus object declarations found in JavaScript files"
fi
else
warn "$module_name: No RPCD script found in $rpcd_dir"
fi
else
warn "$module_name: No RPCD directory found"
fi
echo ""
done
# Check 2: Menu paths must match actual view file locations
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "2. Validating menu paths vs view file locations"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
for module_dir in luci-app-*/; do
module_name=$(basename "$module_dir")
menu_file="$module_dir/root/usr/share/luci/menu.d/${module_name}.json"
if [ -f "$menu_file" ]; then
echo "Checking $module_name menu paths..."
# Extract all view paths from menu JSON
menu_paths=$(grep -o '"path":\s*"[^"]*"' "$menu_file" | cut -d'"' -f4)
for path in $menu_paths; do
# Convert menu path to file path
view_file="$module_dir/htdocs/luci-static/resources/view/${path}.js"
if [ -f "$view_file" ]; then
success "$module_name: Menu path '$path' → file exists"
else
error "$module_name: Menu path '$path' → file NOT found at $view_file"
# Suggest possible matches
view_dir=$(dirname "$view_file")
if [ -d "$view_dir" ]; then
echo " → Possible files in $(dirname $path):"
find "$view_dir" -name "*.js" -type f | while read -r f; do
echo " - $(basename $f)"
done
fi
fi
done
echo ""
fi
done
# Check 3: View files must have corresponding menu entries
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "3. Validating view files have menu entries"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
for module_dir in luci-app-*/; do
module_name=$(basename "$module_dir")
view_dir="$module_dir/htdocs/luci-static/resources/view"
menu_file="$module_dir/root/usr/share/luci/menu.d/${module_name}.json"
if [ -d "$view_dir" ] && [ -f "$menu_file" ]; then
echo "Checking $module_name view files..."
# Find all .js view files
find "$view_dir" -name "*.js" -type f | while read -r view_file; do
# Convert file path to menu path
rel_path=$(echo "$view_file" | sed "s|$module_dir/htdocs/luci-static/resources/view/||" | sed 's|.js$||')
# Check if path exists in menu
if grep -q "\"path\":\s*\"$rel_path\"" "$menu_file"; then
success "$module_name: View '$rel_path.js' has menu entry"
else
warn "$module_name: View file '$rel_path.js' exists but has no menu entry"
fi
done
echo ""
fi
done
# Check 4: RPCD scripts must be executable
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "4. Validating RPCD script permissions"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
for module_dir in luci-app-*/; do
module_name=$(basename "$module_dir")
rpcd_dir="$module_dir/root/usr/libexec/rpcd"
if [ -d "$rpcd_dir" ]; then
find "$rpcd_dir" -type f ! -name "*.md" 2>/dev/null | while read -r script; do
if [ -x "$script" ]; then
success "$module_name: RPCD script $(basename $script) is executable"
else
error "$module_name: RPCD script $(basename $script) is NOT executable"
echo " → Run: chmod +x $script"
fi
done
fi
done
echo ""
# Check 5: JSON files must be valid
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "5. Validating JSON syntax"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
for module_dir in luci-app-*/; do
module_name=$(basename "$module_dir")
# Check menu JSON
menu_file="$module_dir/root/usr/share/luci/menu.d/${module_name}.json"
if [ -f "$menu_file" ]; then
if python3 -m json.tool "$menu_file" > /dev/null 2>&1; then
success "$module_name: menu.d JSON is valid"
else
error "$module_name: menu.d JSON is INVALID"
fi
fi
# Check ACL JSON
acl_file="$module_dir/root/usr/share/rpcd/acl.d/${module_name}.json"
if [ -f "$acl_file" ]; then
if python3 -m json.tool "$acl_file" > /dev/null 2>&1; then
success "$module_name: acl.d JSON is valid"
else
error "$module_name: acl.d JSON is INVALID"
fi
fi
done
echo ""
# Check 6: Verify ubus object naming convention
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "6. Validating ubus object naming convention"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
for module_dir in luci-app-*/; do
module_name=$(basename "$module_dir")
# Extract ubus object names from JavaScript
js_objects=$(find "$module_dir/htdocs" -name "*.js" -type f 2>/dev/null | \
xargs grep -h "object:" 2>/dev/null | \
grep -o "'[^']*'" | sort -u | tr -d "'")
if [ -n "$js_objects" ]; then
for obj in $js_objects; do
# Check if object starts with 'luci.'
if [[ $obj == luci.* ]]; then
success "$module_name: ubus object '$obj' follows naming convention (luci.* prefix)"
else
error "$module_name: ubus object '$obj' does NOT follow naming convention (missing luci. prefix)"
fi
done
fi
done
echo ""
# Summary
echo "========================================"
echo "Validation Summary"
echo "========================================"
echo ""
if [ $ERRORS -eq 0 ] && [ $WARNINGS -eq 0 ]; then
echo -e "${GREEN}✓ All checks passed!${NC}"
exit 0
elif [ $ERRORS -eq 0 ]; then
echo -e "${YELLOW}✓ All critical checks passed with $WARNINGS warning(s)${NC}"
exit 0
else
echo -e "${RED}✗ Found $ERRORS error(s) and $WARNINGS warning(s)${NC}"
echo ""
echo "Please fix the errors listed above before deploying."
exit 1
fi