🌴 Sync 2026-09-27 20:55:59

This commit is contained in:
github-actions[bot] committed 2026-09-27 20:56:00 +08:00
1 parent 5c90f0aed1
commit 13668feb29
77 files changed
+2076 -94

No files matched your search

@@ -116,7 +116,11 @@ fwlive_adaptive_state_dir_ok() {
[ -d "$_dir" ] || return 1
# shellcheck disable=SC3067
[ -O "$_dir" ] || return 1
return 0
# Same group/other-write refuse as wan_log_lock_dir_safe: the
# PID-predictable ${STATE}.tmp.$$ + mv is a symlink-write if the
# dir is world-writable.
_writable=$(find "$_dir" -prune \( -perm -020 -o -perm -002 \) -print 2>/dev/null) || return 1
[ -z "$_writable" ]
}
# Extract a decimal integer field from a one-line JSON object (builtin only).
@@ -5,7 +5,8 @@
# source: core/fwlive-log.js CLASSIFY_SPEC
# Shared isFirewallEvent parity logic (shell). Sourced by fwlive-log-filter.sh and tests.
# Sourced library: do not add set -euo here; callers own strict mode.
# One awk process classifies a batch (MODE=json/json_reply) or one message (default).
# MODE=json prints matching records comma-joined, with no array wrapper or trailing newline.
# MODE=json_reply wraps a poll reply; default MODE=msg classifies one message.
# The caller sets FILTER_DIR when this file is sourced. Resolve the asset
# once, not once per classification call.
@@ -411,8 +411,18 @@ maybe_snapshot_wan_log_baseline() {
zone="$1"
path="$(wan_log_baseline_path)"
[ -n "$zone" ] || return 1
[ -L "$path" ] && return 1
[ -f "$path" ] && return 0
mkdir -p "$(dirname "$path")" 2>/dev/null || return 1
_dir=$(dirname "$path")
[ -n "$_dir" ] || return 1
[ -L "$_dir" ] && return 1
mkdir -p "$_dir" 2>/dev/null || return 1
[ -L "$_dir" ] && return 1
[ -L "$path" ] && return 1
# Production path only: tests relocate WAN_LOG_BASELINE_FILE.
if [ -z "${FWLIVE_WAN_LOG_BASELINE_FILE:-}" ] && [ "$path" = /etc/fwlive/wan-log-baseline ]; then
wan_log_lock_dir_safe "$_dir" || return 1
fi
current=$(wan_zone_log_value "$zone")
printf '%s' "$current" >"$path" 2>/dev/null || return 1
return 0
+13 -2
View File
@@ -66,6 +66,9 @@ slug_key() {
# Cap rules JSON size so a huge ruleset cannot unbound an rpcd reply.
RULES_MAP_MAX_KEYS=512
RULES_MAP_MAX_BYTES=65536
# First-wins dups never increment _map_keys, so they would otherwise walk
# the whole dump. Bound map_prefix_with_label calls independently.
RULES_MAP_MAX_LINES=512
map_add() {
key="$1"
@@ -111,10 +114,12 @@ map_add() {
uci_rule_names() {
# uci missing / empty firewall config is "no names", not fatal.
# pipefail + set -e cannot apply to this pipeline.
# One show dump; named-section names still use uci get.
_firewall_show=$(uci -q show firewall 2>/dev/null || true)
{
uci -q show firewall 2>/dev/null |
printf '%s\n' "$_firewall_show" |
sed -n "s/^firewall\.@rule\[[0-9]*\]\.name='\(.*\)'$/\1/p" || true
uci -q show firewall 2>/dev/null |
printf '%s\n' "$_firewall_show" |
sed -n 's/^firewall\.\([A-Za-z0-9_-]*\)=rule$/\1/p' |
while IFS= read -r section; do
uci -q get "firewall.${section}.name" 2>/dev/null || true
@@ -152,6 +157,11 @@ read_rpc_input() {
map_prefix_with_label() {
prefix="$1"
label="$2"
if [ "${_map_lines:-0}" -ge "$RULES_MAP_MAX_LINES" ]; then
_map_overflow=1
return 0
fi
_map_lines=$(( ${_map_lines:-0} + 1 ))
prefix=$(normalize_log_prefix "$prefix")
[ -n "$prefix" ] || return 0
slug=$(slug_key "$prefix")
@@ -496,6 +506,7 @@ enrich_rules_dump() {
build_rules_map() {
OUT=''
_map_keys=0
_map_lines=0
_map_overflow=''
_enrich_error=''
backend=unknown