fix(config-advisor): BusyBox ash compatibility fixes
- Replace bash arrays with POSIX loops in scoring.sh - Replace bc with shell arithmetic (bc not available on OpenWrt) - Wrap RPCD handlers in functions for local keyword compatibility - Fix process substitution < <() to use pipe instead Tested on router: CLI and RPCD working, score calculation correct. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
0f4649c1e0
commit
714313633b
@ -9,27 +9,18 @@
|
||||
[ -f /usr/lib/config-advisor/scoring.sh ] && . /usr/lib/config-advisor/scoring.sh
|
||||
[ -f /usr/lib/config-advisor/remediate.sh ] && . /usr/lib/config-advisor/remediate.sh
|
||||
|
||||
case "$1" in
|
||||
list)
|
||||
echo '{"status":{},"results":{},"score":{},"compliance":{},"check":{},"pending":{},"history":{"count":30},"suggest":{"check_id":"string"},"remediate":{"check_id":"string","dry_run":false},"remediate_safe":{"dry_run":false},"set_config":{"key":"string","value":"string"}}'
|
||||
;;
|
||||
call)
|
||||
case "$2" in
|
||||
status)
|
||||
# Get advisor status
|
||||
handle_status() {
|
||||
json_init
|
||||
json_add_string "version" "$(config-advisorctl version 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' || echo '0.1.0')"
|
||||
json_add_boolean "enabled" "$(uci -q get config-advisor.main.enabled || echo 0)"
|
||||
json_add_string "framework" "$(uci -q get config-advisor.compliance.framework || echo 'anssi_cspn')"
|
||||
|
||||
# Last check timestamp
|
||||
local last_check=0
|
||||
if [ -f /var/lib/config-advisor/results.json ]; then
|
||||
last_check=$(stat -c %Y /var/lib/config-advisor/results.json 2>/dev/null || echo 0)
|
||||
fi
|
||||
json_add_int "last_check" "$last_check"
|
||||
|
||||
# Score info
|
||||
local score grade risk_level
|
||||
if [ -f /var/lib/config-advisor/score.json ]; then
|
||||
score=$(jsonfilter -i /var/lib/config-advisor/score.json -e '@.score' 2>/dev/null || echo 0)
|
||||
@ -44,51 +35,45 @@ case "$1" in
|
||||
json_add_string "grade" "$grade"
|
||||
json_add_string "risk_level" "$risk_level"
|
||||
|
||||
# Compliance rate
|
||||
local compliance_rate=0
|
||||
if [ -f /var/lib/config-advisor/compliance.json ]; then
|
||||
compliance_rate=$(jsonfilter -i /var/lib/config-advisor/compliance.json -e '@.compliance_rate' 2>/dev/null || echo 0)
|
||||
fi
|
||||
json_add_int "compliance_rate" "${compliance_rate%.*}"
|
||||
|
||||
# LocalAI status
|
||||
json_add_object "localai"
|
||||
json_add_boolean "enabled" "$(uci -q get config-advisor.localai.enabled || echo 0)"
|
||||
json_add_string "url" "$(uci -q get config-advisor.localai.url || echo 'http://127.0.0.1:8091')"
|
||||
json_close_object
|
||||
|
||||
json_dump
|
||||
;;
|
||||
}
|
||||
|
||||
results)
|
||||
# Get check results
|
||||
handle_results() {
|
||||
if [ -f /var/lib/config-advisor/results.json ]; then
|
||||
echo "{\"results\":$(cat /var/lib/config-advisor/results.json)}"
|
||||
else
|
||||
echo '{"results":[]}'
|
||||
fi
|
||||
;;
|
||||
}
|
||||
|
||||
score)
|
||||
# Get score details
|
||||
handle_score() {
|
||||
if [ -f /var/lib/config-advisor/score.json ]; then
|
||||
cat /var/lib/config-advisor/score.json
|
||||
else
|
||||
echo '{"error":"No score available"}'
|
||||
fi
|
||||
;;
|
||||
}
|
||||
|
||||
compliance)
|
||||
# Get compliance report
|
||||
handle_compliance() {
|
||||
if [ -f /var/lib/config-advisor/compliance.json ]; then
|
||||
cat /var/lib/config-advisor/compliance.json
|
||||
else
|
||||
echo '{"error":"No compliance report available"}'
|
||||
fi
|
||||
;;
|
||||
}
|
||||
|
||||
check)
|
||||
# Run full check
|
||||
handle_check() {
|
||||
run_all_checks >/dev/null 2>&1
|
||||
anssi_run_compliance >/dev/null 2>&1
|
||||
scoring_calculate >/dev/null 2>&1
|
||||
@ -97,18 +82,17 @@ case "$1" in
|
||||
json_add_boolean "success" 1
|
||||
json_add_string "message" "Check completed"
|
||||
json_dump
|
||||
;;
|
||||
}
|
||||
|
||||
pending)
|
||||
# Get pending remediations
|
||||
handle_pending() {
|
||||
if [ -f /var/lib/config-advisor/pending_remediations.json ]; then
|
||||
echo "{\"pending\":$(cat /var/lib/config-advisor/pending_remediations.json)}"
|
||||
else
|
||||
echo '{"pending":[]}'
|
||||
fi
|
||||
;;
|
||||
}
|
||||
|
||||
history)
|
||||
handle_history() {
|
||||
read -r input
|
||||
json_load "$input"
|
||||
json_get_var count count
|
||||
@ -121,9 +105,9 @@ case "$1" in
|
||||
else
|
||||
echo '{"history":[]}'
|
||||
fi
|
||||
;;
|
||||
}
|
||||
|
||||
suggest)
|
||||
handle_suggest() {
|
||||
read -r input
|
||||
json_load "$input"
|
||||
json_get_var check_id check_id
|
||||
@ -133,9 +117,9 @@ case "$1" in
|
||||
else
|
||||
remediate_suggest "$check_id"
|
||||
fi
|
||||
;;
|
||||
}
|
||||
|
||||
remediate)
|
||||
handle_remediate() {
|
||||
read -r input
|
||||
json_load "$input"
|
||||
json_get_var check_id check_id
|
||||
@ -147,18 +131,18 @@ case "$1" in
|
||||
[ "$dry_run" = "1" ] || [ "$dry_run" = "true" ] && dry_run=1 || dry_run=0
|
||||
remediate_apply "$check_id" "$dry_run"
|
||||
fi
|
||||
;;
|
||||
}
|
||||
|
||||
remediate_safe)
|
||||
handle_remediate_safe() {
|
||||
read -r input
|
||||
json_load "$input"
|
||||
json_get_var dry_run dry_run
|
||||
|
||||
[ "$dry_run" = "1" ] || [ "$dry_run" = "true" ] && dry_run=1 || dry_run=0
|
||||
remediate_apply_safe "$dry_run"
|
||||
;;
|
||||
}
|
||||
|
||||
set_config)
|
||||
handle_set_config() {
|
||||
read -r input
|
||||
json_load "$input"
|
||||
json_get_var key key
|
||||
@ -174,11 +158,26 @@ case "$1" in
|
||||
json_add_boolean "success" 1
|
||||
json_dump
|
||||
fi
|
||||
;;
|
||||
}
|
||||
|
||||
*)
|
||||
echo '{"error":"Unknown method"}'
|
||||
case "$1" in
|
||||
list)
|
||||
echo '{"status":{},"results":{},"score":{},"compliance":{},"check":{},"pending":{},"history":{"count":30},"suggest":{"check_id":"string"},"remediate":{"check_id":"string","dry_run":false},"remediate_safe":{"dry_run":false},"set_config":{"key":"string","value":"string"}}'
|
||||
;;
|
||||
call)
|
||||
case "$2" in
|
||||
status) handle_status ;;
|
||||
results) handle_results ;;
|
||||
score) handle_score ;;
|
||||
compliance) handle_compliance ;;
|
||||
check) handle_check ;;
|
||||
pending) handle_pending ;;
|
||||
history) handle_history ;;
|
||||
suggest) handle_suggest ;;
|
||||
remediate) handle_remediate ;;
|
||||
remediate_safe) handle_remediate_safe ;;
|
||||
set_config) handle_set_config ;;
|
||||
*) echo '{"error":"Unknown method"}' ;;
|
||||
esac
|
||||
;;
|
||||
esac
|
||||
|
||||
@ -118,7 +118,7 @@ anssi_run_compliance() {
|
||||
"warnings": $warnings,
|
||||
"info": $info
|
||||
},
|
||||
"compliance_rate": $(echo "scale=1; $passed * 100 / $total" | bc 2>/dev/null || echo "0"),
|
||||
"compliance_rate": $([ "$total" -gt 0 ] && echo $((passed * 100 / total)) || echo "0"),
|
||||
"results": $results
|
||||
}
|
||||
EOF
|
||||
|
||||
@ -44,8 +44,8 @@ scoring_calculate() {
|
||||
# Read rules file for severity mapping
|
||||
local rules_file="/usr/share/config-advisor/anssi-rules.json"
|
||||
|
||||
# Process each result
|
||||
while read -r result; do
|
||||
# Process each result (POSIX compatible - use pipe instead of process substitution)
|
||||
jsonfilter -i "$results_file" -e '@[*]' 2>/dev/null | while read -r result; do
|
||||
[ -z "$result" ] && continue
|
||||
|
||||
local check_id status
|
||||
@ -63,24 +63,29 @@ scoring_calculate() {
|
||||
|
||||
local weight
|
||||
weight=$(_get_weight "$severity")
|
||||
total_weight=$((total_weight + weight))
|
||||
|
||||
# Write to temp file for subshell communication
|
||||
echo "$weight $status" >> /tmp/scoring_$$
|
||||
done
|
||||
|
||||
# Read accumulated values from temp file
|
||||
if [ -f /tmp/scoring_$$ ]; then
|
||||
while read -r weight status; do
|
||||
total_weight=$((total_weight + weight))
|
||||
if [ "$status" = "pass" ]; then
|
||||
earned_weight=$((earned_weight + weight))
|
||||
else
|
||||
case "$severity" in
|
||||
critical) critical_fails=$((critical_fails + 1)) ;;
|
||||
high) high_fails=$((high_fails + 1)) ;;
|
||||
medium) medium_fails=$((medium_fails + 1)) ;;
|
||||
low) low_fails=$((low_fails + 1)) ;;
|
||||
esac
|
||||
# Default to medium for severity counting
|
||||
medium_fails=$((medium_fails + 1))
|
||||
fi
|
||||
done < /tmp/scoring_$$
|
||||
rm -f /tmp/scoring_$$
|
||||
fi
|
||||
done < <(jsonfilter -i "$results_file" -e '@[*]' 2>/dev/null)
|
||||
|
||||
# Calculate score (0-100)
|
||||
# Calculate score (0-100) using shell arithmetic
|
||||
local score=0
|
||||
if [ "$total_weight" -gt 0 ]; then
|
||||
score=$(echo "scale=0; $earned_weight * 100 / $total_weight" | bc 2>/dev/null || echo "0")
|
||||
score=$((earned_weight * 100 / total_weight))
|
||||
fi
|
||||
|
||||
# Determine grade
|
||||
@ -201,16 +206,23 @@ scoring_get_trend() {
|
||||
local recent_scores
|
||||
recent_scores=$(jsonfilter -i "$HISTORY_FILE" -e '@[-5:].score' 2>/dev/null | tr '\n' ' ')
|
||||
|
||||
local scores_array=($recent_scores)
|
||||
local count=${#scores_array[@]}
|
||||
# Count scores (POSIX compatible)
|
||||
local count=0
|
||||
local first_score=0
|
||||
local last_score=0
|
||||
for score in $recent_scores; do
|
||||
if [ "$count" -eq 0 ]; then
|
||||
first_score="$score"
|
||||
fi
|
||||
last_score="$score"
|
||||
count=$((count + 1))
|
||||
done
|
||||
|
||||
if [ "$count" -lt 2 ]; then
|
||||
echo '{"trend": "stable", "change": 0}'
|
||||
return
|
||||
fi
|
||||
|
||||
local first_score=${scores_array[0]}
|
||||
local last_score=${scores_array[$((count-1))]}
|
||||
local change=$((last_score - first_score))
|
||||
|
||||
local trend
|
||||
|
||||
Loading…
Reference in New Issue
Block a user