fix(P16): aggregate.sh JSON injection + drift-gate fix (REQ-131, F11, F18)
---ci--- project: orca phase: 16 milestone: v0.12 status: execute ---/ci--- orca-aggregate.sh: peer output validated via jq before JSON interpolation (prevents injection from malicious peer). Peer name escaped. Fallback: JSON shape validation via grep. orca-pull.sh: R-020 drift gate now uses jq for accurate JSON parsing (replaces fragile grep-based parsing). Fallback to grep if jq absent. Build green.
This commit is contained in:
@@ -69,7 +69,25 @@ while IFS= read -r peer; do
|
||||
orca_log_warn "aggregate" "$peer" "skipped" "failed to read state snapshot"
|
||||
continue
|
||||
fi
|
||||
printf '{"peer":"%s","state":%s}\n' "$peer" "$snapshot" >>"$merge_tmp"
|
||||
# REQ-131 / F11: use jq to safely construct JSON (prevents JSON
|
||||
# injection from malicious peer output). $peer is sanitized; $snapshot
|
||||
# is parsed as raw JSON by jq, so control chars can't break out.
|
||||
if command -v jq >/dev/null 2>&1; then
|
||||
snapshot_json="$(printf '%s' "$snapshot" | jq -c '.' 2>/dev/null)" || {
|
||||
orca_log_warn "aggregate" "$peer" "skipped" "peer returned invalid JSON"
|
||||
continue
|
||||
}
|
||||
peer_escaped="${peer//\"/\\\"}"
|
||||
printf '{"peer":"%s","state":%s}\n' "$peer_escaped" "$snapshot_json" >>"$merge_tmp"
|
||||
else
|
||||
# Fallback: validate $snapshot looks like JSON before interpolation.
|
||||
if ! printf '%s' "$snapshot" | grep -qE '^\s*\{.*\}\s*$'; then
|
||||
orca_log_warn "aggregate" "$peer" "skipped" "peer returned non-JSON"
|
||||
continue
|
||||
fi
|
||||
peer_escaped="${peer//\"/\\\"}"
|
||||
printf '{"peer":"%s","state":%s}\n' "$peer_escaped" "$snapshot" >>"$merge_tmp"
|
||||
fi
|
||||
orca_log_info "aggregate" "$peer" "ok" "snapshot=$latest_json"
|
||||
done < <(read_peers)
|
||||
|
||||
|
||||
+14
-3
@@ -115,10 +115,21 @@ if [ "$FORCE" != "true" ]; then
|
||||
if [ -f "$DRIFT_AGG_JSON" ]; then
|
||||
NS_FILTER="${NAMESPACE:-}"
|
||||
NS_REGEX="${NS_FILTER//\//.}"
|
||||
if [ -n "$NS_FILTER" ]; then
|
||||
DRIFT_HITS="$(grep -o '"path"[[:space:]]*:[[:space:]]*"[^"]*"' "$DRIFT_AGG_JSON" 2>/dev/null | sed 's/.*: *"//;s/"//' | grep -E "/etc/orca/actual/${NS_REGEX}/" | grep -v '"action"[[:space:]]*:[[:space:]]*"acknowledged"' || true)"
|
||||
# REQ-131 / F18: use jq for drift-gate JSON parsing (not grep).
|
||||
if command -v jq >/dev/null 2>&1; then
|
||||
if [ -n "$NS_FILTER" ]; then
|
||||
DRIFT_HITS="$(jq -r --arg ns "$NS_FILTER" '[.events[]? | select((.path|test("/etc/orca/actual/\($ns)/")) and (.action != "acknowledged"))] | length' "$DRIFT_AGG_JSON" 2>/dev/null || true)"
|
||||
else
|
||||
DRIFT_HITS="$(jq -r '[.events[]? | select(.drift_confirmed == true and .action != "acknowledged")] | length' "$DRIFT_AGG_JSON" 2>/dev/null || true)"
|
||||
fi
|
||||
else
|
||||
DRIFT_HITS="$(grep -o '"drift_confirmed"[[:space:]]*:[[:space:]]*true' "$DRIFT_AGG_JSON" 2>/dev/null || true)"
|
||||
# Fallback: grep (less accurate; the ack filter may not
|
||||
# match the same line as the path filter).
|
||||
if [ -n "$NS_FILTER" ]; then
|
||||
DRIFT_HITS="$(grep -o '"path"[[:space:]]*:[[:space:]]*"[^"]*"' "$DRIFT_AGG_JSON" 2>/dev/null | sed 's/.*: *"//;s/"//' | grep -E "/etc/orca/actual/${NS_REGEX}/" || true)"
|
||||
else
|
||||
DRIFT_HITS="$(grep -o '"drift_confirmed"[[:space:]]*:[[:space:]]*true' "$DRIFT_AGG_JSON" 2>/dev/null || true)"
|
||||
fi
|
||||
fi
|
||||
if [ -n "$DRIFT_HITS" ]; then
|
||||
orca_log_error "orca-pull" "$TXN_DIR" "drift-detected" "namespace=${NAMESPACE:-cluster-wide}"
|
||||
|
||||
Reference in New Issue
Block a user