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:
parent
16ad6d6a43
commit
92f3318729
163
CLAUDE.md
163
CLAUDE.md
@ -38,6 +38,9 @@ opkg install /tmp/luci-app-*.ipk
|
|||||||
### Validation
|
### Validation
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
# Run comprehensive module validation (RECOMMENDED)
|
||||||
|
./secubox-tools/validate-modules.sh
|
||||||
|
|
||||||
# Validate shell scripts (RPCD backends)
|
# Validate shell scripts (RPCD backends)
|
||||||
shellcheck luci-app-*/root/usr/libexec/rpcd/*
|
shellcheck luci-app-*/root/usr/libexec/rpcd/*
|
||||||
|
|
||||||
@ -71,7 +74,8 @@ luci-app-<module-name>/
|
|||||||
└── root/
|
└── root/
|
||||||
├── etc/config/<module-name> # UCI configuration (optional)
|
├── etc/config/<module-name> # UCI configuration (optional)
|
||||||
└── usr/
|
└── usr/
|
||||||
├── libexec/rpcd/<module-name> # RPCD backend script
|
├── libexec/rpcd/
|
||||||
|
│ └── luci.<module-name> # RPCD backend script (MUST use luci. prefix!)
|
||||||
└── share/
|
└── share/
|
||||||
├── luci/menu.d/ # Menu JSON definition
|
├── luci/menu.d/ # Menu JSON definition
|
||||||
│ └── luci-app-<module-name>.json
|
│ └── luci-app-<module-name>.json
|
||||||
@ -99,6 +103,93 @@ luci-app-<module-name>/
|
|||||||
- Defines access control for ubus methods
|
- Defines access control for ubus methods
|
||||||
- Maps read/write permissions to user groups
|
- 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
|
### Makefile Structure
|
||||||
|
|
||||||
Each package Makefile must define:
|
Each package Makefile must define:
|
||||||
@ -244,11 +335,49 @@ x86: x86-64, x86-generic
|
|||||||
|
|
||||||
## Common Issues and Solutions
|
## 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
|
### RPCD Not Responding
|
||||||
|
|
||||||
After installing/updating a package:
|
After installing/updating a package:
|
||||||
```bash
|
```bash
|
||||||
/etc/init.d/rpcd restart
|
/etc/init.d/rpcd restart
|
||||||
|
/etc/init.d/uhttpd restart
|
||||||
```
|
```
|
||||||
|
|
||||||
### Menu Not Appearing
|
### Menu Not Appearing
|
||||||
@ -257,30 +386,46 @@ Check that:
|
|||||||
1. Menu JSON is valid: `jsonlint root/usr/share/luci/menu.d/*.json`
|
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`
|
2. ACL grants access: Check `root/usr/share/rpcd/acl.d/*.json`
|
||||||
3. Dependencies are installed: Check Makefile `LUCI_DEPENDS`
|
3. Dependencies are installed: Check Makefile `LUCI_DEPENDS`
|
||||||
|
4. Menu path matches view file location (see above)
|
||||||
|
|
||||||
### Build Failures
|
### Build Failures
|
||||||
|
|
||||||
Common causes:
|
Common causes:
|
||||||
1. Missing fields in Makefile (PKG_NAME, LUCI_TITLE, etc.)
|
1. Missing fields in Makefile (PKG_NAME, LUCI_TITLE, etc.)
|
||||||
2. Invalid JSON syntax in menu.d or acl.d
|
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`)
|
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`
|
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
|
## Development Workflow
|
||||||
|
|
||||||
1. Make changes to module files
|
1. Make changes to module files
|
||||||
2. Test JSON syntax: `jsonlint <file>.json`
|
2. **Run validation checks** (CRITICAL):
|
||||||
3. Test shell scripts: `shellcheck <script>`
|
```bash
|
||||||
4. Build package: `make package/luci-app-<name>/compile V=s`
|
./secubox-tools/validate-modules.sh
|
||||||
5. Install on test router and verify functionality
|
```
|
||||||
6. Run repair tool if needed: `./secubox-tools/secubox-repair.sh`
|
3. Test JSON syntax: `jsonlint <file>.json`
|
||||||
7. Commit changes and push (triggers CI validation)
|
4. Test shell scripts: `shellcheck <script>`
|
||||||
8. Create tag for release: `git tag -a v1.0.0 -m "Release 1.0.0"`
|
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
|
## 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
|
- All modules use Apache-2.0 license
|
||||||
- RPCD backends must be executable (chmod +x)
|
- RPCD backends must be executable (chmod +x)
|
||||||
- JavaScript files use strict mode: `'use strict';`
|
- JavaScript files use strict mode: `'use strict';`
|
||||||
|
|||||||
130
secubox-tools/README.md
Normal file
130
secubox-tools/README.md
Normal 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
255
secubox-tools/validate-modules.sh
Executable 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
|
||||||
Loading…
Reference in New Issue
Block a user