secubox-openwrt/package/secubox/secubox-app-reporter/files/usr/sbin/secubox-reportctl
CyberMind-FR ec4aadbaa3 feat(config-vault): Add Configuration Vault system with Gitea sync
New packages:
- secubox-app-config-vault: Git-based config versioning CLI (configvaultctl)
- luci-app-config-vault: KISS-themed dashboard with status rings

Features:
- 9 configuration modules (users, network, services, security, etc.)
- Auto-commit and auto-push to private Gitea repository
- Export/import clone tarballs for device provisioning
- Commit history browser with restore capability

Also adds System Hardware Report to secubox-app-reporter:
- CPU/Memory/Disk/Temperature gauges with animations
- Environmental impact card (power/kWh/CO₂ estimates)
- Health recommendations based on system metrics
- Debug log viewer with severity highlighting

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-03-13 12:49:33 +01:00

675 lines
23 KiB
Bash

#!/bin/sh
# SecuBox Report Generator
# Generates and distributes status reports via HTML and email
# Copyright (C) 2026 CyberMind.fr
VERSION="1.0.0"
SCRIPT_DIR="/usr/share/secubox-reporter"
LIB_DIR="$SCRIPT_DIR/lib"
TPL_DIR="$SCRIPT_DIR/templates"
OUTPUT_DIR="/www/reports"
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
CYAN='\033[0;36m'
NC='\033[0m'
# Load libraries
. /lib/functions.sh
[ -f "$LIB_DIR/collectors.sh" ] && . "$LIB_DIR/collectors.sh"
[ -f "$LIB_DIR/formatters.sh" ] && . "$LIB_DIR/formatters.sh"
[ -f "$LIB_DIR/mailer.sh" ] && . "$LIB_DIR/mailer.sh"
[ -f "$LIB_DIR/system-collector.sh" ] && . "$LIB_DIR/system-collector.sh"
# Load config
config_load secubox-reporter
config_get OUTPUT_DIR global output_dir "/www/reports"
config_get THEME global theme "dark"
config_get REPO_PATH sources repo_path "/root/secubox-openwrt"
log_info() { echo -e "${CYAN}[INFO]${NC} $1"; }
log_ok() { echo -e "${GREEN}[OK]${NC} $1"; }
log_err() { echo -e "${RED}[ERROR]${NC} $1" >&2; }
log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
usage() {
cat << EOF
SecuBox Report Generator v$VERSION
Usage: secubox-reportctl <command> [options]
COMMANDS:
generate <type> Generate report (dev|services|all)
send <type> Generate and email report
schedule <type> Set cron schedule (daily|weekly|off)
status Show generator status
preview <type> Generate and output to stdout
list List generated reports
clean [days] Remove reports older than N days (default: 30)
help Show this help
REPORT TYPES:
dev Development Status Report (progress, roadmap, health)
services Distribution/Services Status Report (exposures, channels)
system System Hardware Report (CPU, memory, power, carbon impact)
meta Meta Dashboard (combined overview)
all All reports
OPTIONS:
--email Also send via email
--theme <name> Theme: dark, light, cyberpunk (default: dark)
--output <path> Custom output path
--json Output status as JSON
EXAMPLES:
secubox-reportctl generate dev
secubox-reportctl send services
secubox-reportctl schedule dev daily
secubox-reportctl generate all --theme cyberpunk
EOF
}
# Get hostname
get_hostname() {
uci -q get system.@system[0].hostname 2>/dev/null || hostname
}
# Get SecuBox version
get_version() {
cat /etc/secubox_version 2>/dev/null || echo "0.19.x"
}
# Generate development status report
generate_dev_report() {
local output_file="$1"
local theme="${2:-dark}"
log_info "Generating Development Status Report..."
mkdir -p "$(dirname "$output_file")"
local hostname=$(get_hostname)
local version=$(get_version)
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
local health_score=0
# Get health score from RPCD if available
if command -v ubus >/dev/null 2>&1; then
health_score=$(ubus call luci.secubox-core get_full_health_report 2>/dev/null | \
jsonfilter -e '@.health_score' 2>/dev/null || echo "0")
fi
[ -z "$health_score" ] && health_score=0
# Collect data from .claude files
local history_entries=""
local wip_entries=""
local roadmap_data=""
if [ -d "$REPO_PATH/.claude" ]; then
# Recent history (last 10 dated sections)
history_entries=$(collect_history "$REPO_PATH/.claude/HISTORY.md")
# WIP items
wip_entries=$(collect_wip "$REPO_PATH/.claude/WIP.md")
# Roadmap progress
roadmap_data=$(collect_roadmap "$REPO_PATH/.claude/ROADMAP.md")
else
history_entries="<p class='muted'>Repository not found at $REPO_PATH</p>"
wip_entries="<p class='muted'>Repository not found</p>"
roadmap_data="<p class='muted'>Repository not found</p>"
fi
# Generate HTML from template
if [ -f "$TPL_DIR/dev-status.html.tpl" ]; then
sed -e "s|{{HOSTNAME}}|$hostname|g" \
-e "s|{{VERSION}}|$version|g" \
-e "s|{{TIMESTAMP}}|$timestamp|g" \
-e "s|{{HEALTH_SCORE}}|$health_score|g" \
-e "s|{{THEME}}|$theme|g" \
-e "s|{{HISTORY_ENTRIES}}|$history_entries|g" \
-e "s|{{WIP_ENTRIES}}|$wip_entries|g" \
-e "s|{{ROADMAP_DATA}}|$roadmap_data|g" \
"$TPL_DIR/dev-status.html.tpl" > "$output_file"
else
# Fallback inline template
generate_dev_html_inline "$output_file" "$hostname" "$version" "$timestamp" \
"$health_score" "$history_entries" "$wip_entries" "$roadmap_data"
fi
# Ensure web-readable permissions
chmod 644 "$output_file"
log_ok "Generated: $output_file"
echo "$output_file"
}
# Generate services status report
generate_services_report() {
local output_file="$1"
local theme="${2:-dark}"
log_info "Generating Services Status Report..."
mkdir -p "$(dirname "$output_file")"
local hostname=$(get_hostname)
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
# Count services by channel
local tor_count=0
local dns_count=0
local mesh_count=0
# Tor hidden services
if [ -d /var/lib/tor/hidden_services ]; then
tor_count=$(ls -1 /var/lib/tor/hidden_services 2>/dev/null | wc -l)
fi
# HAProxy vhosts
dns_count=$(uci show haproxy 2>/dev/null | grep '=vhost$' | wc -l)
# Mesh services (from P2P if available)
if command -v secubox-p2p >/dev/null 2>&1; then
mesh_count=$(secubox-p2p shared-services 2>/dev/null | wc -l)
fi
# Collect service details
local tor_services=$(collect_tor_services)
local dns_services=$(collect_dns_services)
local mesh_services=$(collect_mesh_services)
# Health check
local health_up=0
local health_total=$((tor_count + dns_count))
# Generate HTML
if [ -f "$TPL_DIR/services-status.html.tpl" ]; then
sed -e "s|{{HOSTNAME}}|$hostname|g" \
-e "s|{{TIMESTAMP}}|$timestamp|g" \
-e "s|{{TOR_COUNT}}|$tor_count|g" \
-e "s|{{DNS_COUNT}}|$dns_count|g" \
-e "s|{{MESH_COUNT}}|$mesh_count|g" \
-e "s|{{HEALTH_UP}}|$health_up|g" \
-e "s|{{HEALTH_TOTAL}}|$health_total|g" \
-e "s|{{TOR_SERVICES}}|$tor_services|g" \
-e "s|{{DNS_SERVICES}}|$dns_services|g" \
-e "s|{{MESH_SERVICES}}|$mesh_services|g" \
-e "s|{{THEME}}|$theme|g" \
"$TPL_DIR/services-status.html.tpl" > "$output_file"
else
generate_services_html_inline "$output_file" "$hostname" "$timestamp" \
"$tor_count" "$dns_count" "$mesh_count" \
"$tor_services" "$dns_services" "$mesh_services"
fi
# Ensure web-readable permissions
chmod 644 "$output_file"
log_ok "Generated: $output_file"
echo "$output_file"
}
# Generate meta status report (combined dashboard)
generate_meta_report() {
local output_file="$1"
local theme="${2:-dark}"
log_info "Generating Meta Status Report..."
mkdir -p "$(dirname "$output_file")"
local hostname=$(get_hostname)
local version=$(get_version)
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
# Health score
local health_score=0
if command -v ubus >/dev/null 2>&1; then
health_score=$(ubus call luci.secubox-core get_full_health_report 2>/dev/null | \
jsonfilter -e '@.health_score' 2>/dev/null || echo "0")
fi
[ -z "$health_score" ] && health_score=0
# Service counts
local tor_count=0
local dns_count=0
local mesh_count=0
[ -d /var/lib/tor/hidden_services ] && tor_count=$(ls -1 /var/lib/tor/hidden_services 2>/dev/null | wc -l)
dns_count=$(uci show haproxy 2>/dev/null | grep '=vhost$' | wc -l)
command -v secubox-p2p >/dev/null 2>&1 && mesh_count=$(secubox-p2p shared-services 2>/dev/null | wc -l)
local total_services=$((tor_count + dns_count + mesh_count))
local services_pct=100
[ $total_services -gt 0 ] && services_pct=$((total_services * 100 / 300))
[ $services_pct -gt 100 ] && services_pct=100
# Calculate percentages for bars
local tor_pct=0 dns_pct=0 mesh_pct=0
[ $total_services -gt 0 ] && {
tor_pct=$((tor_count * 100 / total_services))
dns_pct=$((dns_count * 100 / total_services))
mesh_pct=$((mesh_count * 100 / total_services))
}
# System stats
local packages_count=$(opkg list-installed 2>/dev/null | wc -l)
local containers_count=$(lxc-ls 2>/dev/null | wc -w)
local uptime_pct=99
# Dev stats
local features_done=0
local wip_count=0
[ -f "$REPO_PATH/.claude/HISTORY.md" ] && features_done=$(grep -c "^\*\*" "$REPO_PATH/.claude/HISTORY.md" 2>/dev/null || echo 0)
[ -f "$REPO_PATH/.claude/WIP.md" ] && wip_count=$(grep -c "^- \*\*" "$REPO_PATH/.claude/WIP.md" 2>/dev/null || echo 0)
# Collect formatted data
local history_entries=$(collect_history "$REPO_PATH/.claude/HISTORY.md" 2>/dev/null || echo '<p class="muted">No history data</p>')
local wip_entries=$(collect_wip "$REPO_PATH/.claude/WIP.md" 2>/dev/null || echo '<p class="muted">No WIP data</p>')
local roadmap_data=$(collect_roadmap "$REPO_PATH/.claude/ROADMAP.md" 2>/dev/null || echo '<p class="muted">No roadmap data</p>')
local tor_services=$(collect_tor_services 2>/dev/null || echo '<p class="muted">No Tor services</p>')
local dns_services=$(collect_dns_services 10 2>/dev/null || echo '<p class="muted">No DNS services</p>')
# Generate from template
if [ -f "$TPL_DIR/meta-status.html.tpl" ]; then
sed -e "s|{{HOSTNAME}}|$hostname|g" \
-e "s|{{VERSION}}|$version|g" \
-e "s|{{TIMESTAMP}}|$timestamp|g" \
-e "s|{{HEALTH_SCORE}}|$health_score|g" \
-e "s|{{TOTAL_SERVICES}}|$total_services|g" \
-e "s|{{SERVICES_PCT}}|$services_pct|g" \
-e "s|{{UPTIME_PCT}}|$uptime_pct|g" \
-e "s|{{TOR_COUNT}}|$tor_count|g" \
-e "s|{{DNS_COUNT}}|$dns_count|g" \
-e "s|{{MESH_COUNT}}|$mesh_count|g" \
-e "s|{{TOR_PCT}}|$tor_pct|g" \
-e "s|{{DNS_PCT}}|$dns_pct|g" \
-e "s|{{MESH_PCT}}|$mesh_pct|g" \
-e "s|{{PACKAGES_COUNT}}|$packages_count|g" \
-e "s|{{CONTAINERS_COUNT}}|$containers_count|g" \
-e "s|{{FEATURES_DONE}}|$features_done|g" \
-e "s|{{WIP_COUNT}}|$wip_count|g" \
-e "s|{{HISTORY_ENTRIES}}|$history_entries|g" \
-e "s|{{WIP_ENTRIES}}|$wip_entries|g" \
-e "s|{{ROADMAP_DATA}}|$roadmap_data|g" \
-e "s|{{TOR_SERVICES}}|$tor_services|g" \
-e "s|{{DNS_SERVICES}}|$dns_services|g" \
"$TPL_DIR/meta-status.html.tpl" > "$output_file"
else
log_err "Meta template not found: $TPL_DIR/meta-status.html.tpl"
return 1
fi
chmod 644 "$output_file"
log_ok "Generated: $output_file"
echo "$output_file"
}
# Generate system/hardware status report
generate_system_report() {
local output_file="$1"
local theme="${2:-dark}"
log_info "Generating System Hardware Report..."
mkdir -p "$(dirname "$output_file")"
local hostname=$(get_hostname)
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
# Collect system data with defaults
local cpu_pct=$(get_cpu_usage 2>/dev/null || echo 10)
[ -z "$cpu_pct" ] && cpu_pct=10
local mem_info=$(get_memory_info 2>/dev/null || echo "512 1024")
local mem_used=$(echo "$mem_info" | awk '{print $1}')
local mem_total=$(echo "$mem_info" | awk '{print $2}')
[ -z "$mem_used" ] && mem_used=512
[ -z "$mem_total" ] && mem_total=1024
[ "$mem_total" -eq 0 ] && mem_total=1024
local mem_pct=$((mem_used * 100 / mem_total))
local disk_info=$(get_disk_info 2>/dev/null || echo "1G 8G 20")
local disk_used=$(echo "$disk_info" | awk '{print $1}')
local disk_total=$(echo "$disk_info" | awk '{print $2}')
local disk_pct=$(echo "$disk_info" | awk '{print $3}')
[ -z "$disk_pct" ] && disk_pct=20
local temp=$(get_temperature 2>/dev/null || echo 45)
[ -z "$temp" ] && temp=45
local temp_pct=$temp
local cpu_freq=$(get_cpu_freq 2>/dev/null || echo "1000 MHz")
local cpu_model=$(get_cpu_model 2>/dev/null || echo "ARM Processor")
local cpu_cores=$(get_cpu_cores 2>/dev/null || echo "4")
local device_model=$(get_device_model 2>/dev/null || echo "SecuBox")
local board=$(get_board_name 2>/dev/null || echo "secubox")
local openwrt_ver=$(get_openwrt_version 2>/dev/null || echo "23.05")
local kernel=$(get_kernel_version 2>/dev/null || echo "6.1")
local arch=$(get_architecture 2>/dev/null || echo "aarch64")
local uptime=$(get_uptime_formatted 2>/dev/null || echo "1h 0m")
local load_avg=$(get_load_average 2>/dev/null || echo "0.5 0.3 0.2")
local process_count=$(get_process_count 2>/dev/null || echo "50")
# Status classes
local cpu_class=$(get_status_class "$cpu_pct" 2>/dev/null || echo "")
local mem_class=$(get_status_class "$mem_pct" 2>/dev/null || echo "")
local disk_class=$(get_status_class "$disk_pct" 2>/dev/null || echo "")
local temp_class=$(get_status_class "$temp" temp 2>/dev/null || echo "")
# Power calculations
local power_watts=$(estimate_power_watts "$cpu_pct" 2>/dev/null || echo 8)
[ -z "$power_watts" ] && power_watts=8
local daily_kwh="0.19"
local monthly_kwh="5.8"
local co2_monthly="2.3"
# Read template
local template="$TPL_DIR/system-status.html.tpl"
if [ ! -f "$template" ]; then
log_err "Template not found: $template"
return 1
fi
# Generate dynamic content to temp files
local tmpdir="/tmp/sysreport-$$"
mkdir -p "$tmpdir"
get_top_processes > "$tmpdir/procs.html" 2>/dev/null || echo "<tr><td colspan='5'>No process data</td></tr>" > "$tmpdir/procs.html"
get_network_stats > "$tmpdir/network.html" 2>/dev/null || echo "<div class='info-item'><div class='info-label'>N/A</div></div>" > "$tmpdir/network.html"
generate_cpu_histogram > "$tmpdir/histogram.html" 2>/dev/null || echo "" > "$tmpdir/histogram.html"
generate_recommendations "$cpu_pct" "$mem_pct" "$disk_pct" "$temp" > "$tmpdir/recs.html" 2>/dev/null || echo "" > "$tmpdir/recs.html"
get_debug_log > "$tmpdir/debug.html" 2>/dev/null || echo "<div class='line'>No log data</div>" > "$tmpdir/debug.html"
# Simple substitutions first
sed -e "s|{{HOSTNAME}}|$hostname|g" \
-e "s|{{TIMESTAMP}}|$timestamp|g" \
-e "s|{{DEVICE_MODEL}}|$device_model|g" \
-e "s|{{UPTIME}}|$uptime|g" \
-e "s|{{CPU_PCT}}|$cpu_pct|g" \
-e "s|{{CPU_CLASS}}|$cpu_class|g" \
-e "s|{{MEM_PCT}}|$mem_pct|g" \
-e "s|{{MEM_CLASS}}|$mem_class|g" \
-e "s|{{DISK_PCT}}|$disk_pct|g" \
-e "s|{{DISK_CLASS}}|$disk_class|g" \
-e "s|{{TEMP_VAL}}|$temp|g" \
-e "s|{{TEMP_PCT}}|$temp_pct|g" \
-e "s|{{TEMP_CLASS}}|$temp_class|g" \
-e "s|{{CPU_FREQ}}|$cpu_freq|g" \
-e "s|{{MEM_USED}}|${mem_used}MB|g" \
-e "s|{{MEM_TOTAL}}|${mem_total}MB|g" \
-e "s|{{DISK_USED}}|$disk_used|g" \
-e "s|{{DISK_TOTAL}}|$disk_total|g" \
-e "s|{{PROCESS_COUNT}}|$process_count|g" \
-e "s|{{CPU_MODEL}}|$cpu_model|g" \
-e "s|{{CPU_CORES}}|$cpu_cores|g" \
-e "s|{{ARCH}}|$arch|g" \
-e "s|{{KERNEL}}|$kernel|g" \
-e "s|{{BOARD}}|$board|g" \
-e "s|{{OPENWRT_VER}}|$openwrt_ver|g" \
-e "s|{{LOAD_AVG}}|$load_avg|g" \
-e "s|{{POWER_WATTS}}|$power_watts|g" \
-e "s|{{DAILY_KWH}}|$daily_kwh|g" \
-e "s|{{MONTHLY_KWH}}|$monthly_kwh|g" \
-e "s|{{CO2_MONTHLY}}|$co2_monthly|g" \
"$template" > "$tmpdir/step1.html"
# Replace multiline placeholders using awk
awk '
/\{\{CPU_HISTOGRAM\}\}/ { while ((getline line < "'"$tmpdir/histogram.html"'") > 0) print line; next }
/\{\{TOP_PROCESSES\}\}/ { while ((getline line < "'"$tmpdir/procs.html"'") > 0) print line; next }
/\{\{NETWORK_STATS\}\}/ { while ((getline line < "'"$tmpdir/network.html"'") > 0) print line; next }
/\{\{RECOMMENDATIONS\}\}/ { while ((getline line < "'"$tmpdir/recs.html"'") > 0) print line; next }
/\{\{DEBUG_LOG\}\}/ { while ((getline line < "'"$tmpdir/debug.html"'") > 0) print line; next }
{ print }
' "$tmpdir/step1.html" > "$output_file"
# Cleanup
rm -rf "$tmpdir"
chmod 644 "$output_file"
log_ok "Generated: $output_file"
echo "$output_file"
}
# Command: generate
cmd_generate() {
local report_type="$1"
local theme="$THEME"
local output_path="$OUTPUT_DIR"
shift
while [ $# -gt 0 ]; do
case "$1" in
--theme) theme="$2"; shift 2 ;;
--output) output_path="$2"; shift 2 ;;
*) shift ;;
esac
done
local timestamp=$(date '+%Y%m%d-%H%M%S')
case "$report_type" in
dev)
generate_dev_report "$output_path/dev-status-$timestamp.html" "$theme"
;;
services)
generate_services_report "$output_path/services-status-$timestamp.html" "$theme"
;;
meta)
generate_meta_report "$output_path/meta-status-$timestamp.html" "$theme"
;;
system)
generate_system_report "$output_path/system-status-$timestamp.html" "$theme"
;;
all)
generate_dev_report "$output_path/dev-status-$timestamp.html" "$theme"
generate_services_report "$output_path/services-status-$timestamp.html" "$theme"
generate_meta_report "$output_path/meta-status-$timestamp.html" "$theme"
generate_system_report "$output_path/system-status-$timestamp.html" "$theme"
;;
*)
log_err "Unknown report type: $report_type"
echo "Valid types: dev, services, meta, system, all"
return 1
;;
esac
}
# Command: send
cmd_send() {
local report_type="$1"
shift
# Generate report first
local report_file=$(cmd_generate "$report_type" "$@")
if [ -z "$report_file" ] || [ ! -f "$report_file" ]; then
log_err "Failed to generate report"
return 1
fi
# Send via email
local recipient=""
config_get recipient email recipient ""
if [ -z "$recipient" ]; then
log_warn "No email recipient configured. Report saved to: $report_file"
return 0
fi
log_info "Sending report to $recipient..."
if send_report_email "$report_type" "$(cat "$report_file")" "$recipient"; then
log_ok "Report sent to $recipient"
else
log_err "Failed to send email"
return 1
fi
}
# Command: schedule
cmd_schedule() {
local report_type="$1"
local frequency="$2"
local cron_file="/etc/cron.d/secubox-reporter"
case "$frequency" in
daily)
sed -i "s/^#DAILY_${report_type^^}#//" "$cron_file" 2>/dev/null
uci set secubox-reporter.schedule.$report_type='daily'
;;
weekly)
sed -i "s/^#WEEKLY_${report_type^^}#//" "$cron_file" 2>/dev/null
uci set secubox-reporter.schedule.$report_type='weekly'
;;
off)
# Re-comment the lines
sed -i "/secubox-reportctl.*$report_type/s/^[^#]/#DISABLED#/" "$cron_file" 2>/dev/null
uci set secubox-reporter.schedule.$report_type='off'
;;
*)
log_err "Invalid frequency: $frequency"
echo "Valid: daily, weekly, off"
return 1
;;
esac
uci commit secubox-reporter
/etc/init.d/cron restart 2>/dev/null || true
log_ok "Schedule set: $report_type = $frequency"
}
# Command: status
cmd_status() {
local json_output=0
[ "$1" = "--json" ] && json_output=1
local hostname=$(get_hostname)
local version=$(get_version)
local dev_schedule=$(uci -q get secubox-reporter.schedule.dev || echo "off")
local services_schedule=$(uci -q get secubox-reporter.schedule.services || echo "off")
local recipient=$(uci -q get secubox-reporter.email.recipient || echo "")
local report_count=$(ls -1 "$OUTPUT_DIR"/*.html 2>/dev/null | wc -l)
if [ $json_output -eq 1 ]; then
cat << EOF
{"hostname":"$hostname","version":"$version","schedules":{"dev":"$dev_schedule","services":"$services_schedule"},"email_recipient":"$recipient","report_count":$report_count}
EOF
else
echo "SecuBox Report Generator v$VERSION"
echo "=================================="
echo "Hostname: $hostname"
echo "Version: $version"
echo "Output Dir: $OUTPUT_DIR"
echo "Reports: $report_count files"
echo ""
echo "Schedules:"
echo " Dev: $dev_schedule"
echo " Services: $services_schedule"
echo ""
echo "Email: ${recipient:-Not configured}"
fi
}
# Command: list
cmd_list() {
local json_output=0
[ "$1" = "--json" ] && json_output=1
if [ $json_output -eq 1 ]; then
echo '{"reports":['
local first=1
for f in $(ls -1t "$OUTPUT_DIR"/*.html 2>/dev/null); do
[ $first -eq 0 ] && echo ","
first=0
local name=$(basename "$f")
local size=$(stat -c%s "$f" 2>/dev/null || echo 0)
local mtime=$(stat -c%Y "$f" 2>/dev/null || echo 0)
echo "{\"name\":\"$name\",\"size\":$size,\"mtime\":$mtime}"
done
echo ']}'
else
echo "Generated Reports:"
echo "=================="
ls -lh "$OUTPUT_DIR"/*.html 2>/dev/null || echo "No reports found"
fi
}
# Command: clean
cmd_clean() {
local days="${1:-30}"
log_info "Removing reports older than $days days..."
local count=$(find "$OUTPUT_DIR" -name "*.html" -mtime +$days 2>/dev/null | wc -l)
find "$OUTPUT_DIR" -name "*.html" -mtime +$days -delete 2>/dev/null
log_ok "Removed $count old reports"
}
# Command: preview
cmd_preview() {
local report_type="$1"
local tmpfile="/tmp/secubox-report-preview-$$.html"
case "$report_type" in
dev)
generate_dev_report "$tmpfile" "$THEME" >/dev/null
;;
services)
generate_services_report "$tmpfile" "$THEME" >/dev/null
;;
*)
log_err "Unknown report type: $report_type"
return 1
;;
esac
cat "$tmpfile"
rm -f "$tmpfile"
}
# Main
case "$1" in
generate)
shift
cmd_generate "$@"
;;
send)
shift
cmd_send "$@"
;;
schedule)
shift
cmd_schedule "$@"
;;
status)
shift
cmd_status "$@"
;;
list)
shift
cmd_list "$@"
;;
clean)
shift
cmd_clean "$@"
;;
preview)
shift
cmd_preview "$@"
;;
help|--help|-h|"")
usage
;;
*)
log_err "Unknown command: $1"
usage
exit 1
;;
esac