@consiliency/agent-board-cli 1.28.0 → 1.29.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/keyslot/lib.sh CHANGED
@@ -732,14 +732,42 @@ keyseal_scan_mktemp() {
732
732
  printf -v "$1" '%s' "$f"
733
733
  }
734
734
 
735
+ # The parent pid of pid $1, from /proc (the field after the state). rc 1 when $1 is gone.
736
+ keyseal_ppid_of() {
737
+ local s
738
+ s=$(cat -- "/proc/$1/stat" 2>/dev/null) || return 1
739
+ s=${s##*) }
740
+ # shellcheck disable=SC2086
741
+ set -- $s
742
+ printf '%s' "$2"
743
+ }
744
+
745
+ # The pgid of pid $1, from /proc (the fields after the command name: state ppid pgrp).
746
+ keyseal_pgid_of() {
747
+ local s
748
+ s=$(cat -- "/proc/$1/stat" 2>/dev/null) || return 1
749
+ s=${s##*) }
750
+ # shellcheck disable=SC2086
751
+ set -- $s
752
+ printf '%s' "$3"
753
+ }
754
+
735
755
  # The scan stage: ONE child of `timeout`, run as `bash -c` so the deadline covers find, xargs,
736
- # grep AND the classifier (IF-552-2 "Self-bound"). Args: rc file, json file, count file, pruned
737
- # file, list file, uid, exempt path, roots...; the pin is in KEYSEAL_SCAN_PIN. It writes its
738
- # results to files; status.sh reads them only when the stage completed.
756
+ # grep AND every slot's classifier (IF-552-2 "Self-bound"; extended by #552-ONBOARD-SL3 so N
757
+ # slots share this ONE walk — the walk itself never depends on a pin or an exempt path). Args: rc
758
+ # file, count file, pruned file, list file, uid, slot count n, then n groups of (json file, pin,
759
+ # exempt path), then `--`, then the roots. It writes its results to files; status.sh reads them
760
+ # only when the stage completed.
739
761
  keyseal_scan_stage() {
740
- local rcf=$1 jsonf=$2 count=$3 pruned=$4 list=$5 uid=$6 exempt=$7 find grep i=0 h
741
- shift 7
742
- local -a expr greps
762
+ local rcf=$1 count=$2 pruned=$3 list=$4 uid=$5 n=$6 find grep i=0 h j
763
+ shift 6
764
+ local -a jsonfs=() pins=() exempts=() expr greps
765
+ for ((j = 0; j < n; j++)); do
766
+ jsonfs+=("$1"); pins+=("$2"); exempts+=("$3")
767
+ shift 3
768
+ done
769
+ [[ ${1-} == -- ]] || exit 3
770
+ shift
743
771
  find=$(seam_resolve KEYSEAL_TEST_FIND "$KEYSEAL_BIN_FIND") || exit 3
744
772
  grep=$(seam_resolve KEYSEAL_TEST_GREP "$KEYSEAL_BIN_GREP") || exit 3
745
773
  # One clause per prune entry, in report order; each writes its INDEX, never the path. The
@@ -752,36 +780,27 @@ keyseal_scan_stage() {
752
780
  for h in "${KEYSEAL_SCAN_HEADERS[@]}"; do greps+=(-e "$h" -e "$h"$'\r'); done
753
781
  "$find" -H "$@" "${expr[@]}" 2>/dev/null \
754
782
  | "$KEYSEAL_BIN_XARGS" -0 -r "$grep" -lsZ -x -F "${greps[@]}" -- >"$list"
755
- local rc_find=${PIPESTATUS[0]} rc_xargs=${PIPESTATUS[1]} rc_node=-
783
+ local rc_find=${PIPESTATUS[0]} rc_xargs=${PIPESTATUS[1]}
784
+ local -a rc_nodes=()
756
785
  # find: 0, or 1 when some directory was unreadable. xargs: 0, or 123 when some grep found
757
- # nothing. Anything else means the scan did not run to completion.
786
+ # nothing. Anything else means the scan did not run to completion, for every slot alike.
758
787
  if ((rc_find <= 1)) && ((rc_xargs == 0 || rc_xargs == 123)); then
759
788
  local delay=
760
789
  seam_active && delay=${KEYSEAL_TEST_CLASSIFY_DELAY_MS-}
761
- KEYSEAL_SCAN_DELAY_MS=$delay keyseal_node classify "$list" "$uid" "$KEYSEAL_SCAN_MAX_BYTES" "$exempt" "$pruned" \
762
- "${KEYSEAL_SCAN_PRUNE_NAMES[@]}" "${KEYSEAL_SCAN_PRUNE_PATHS[@]}" >"$jsonf" && rc_node=0 || rc_node=$?
790
+ for ((j = 0; j < n; j++)); do
791
+ local rc_node
792
+ KEYSEAL_SCAN_DELAY_MS=$delay KEYSEAL_SCAN_PIN=${pins[j]} keyseal_node classify "$list" "$uid" "$KEYSEAL_SCAN_MAX_BYTES" "${exempts[j]}" "$pruned" \
793
+ "${KEYSEAL_SCAN_PRUNE_NAMES[@]}" "${KEYSEAL_SCAN_PRUNE_PATHS[@]}" >"${jsonfs[j]}" && rc_node=0 || rc_node=$?
794
+ rc_nodes+=("$rc_node")
795
+ done
796
+ else
797
+ for ((j = 0; j < n; j++)); do rc_nodes+=(-); done
763
798
  fi
764
- printf '%s %s %s\n' "$rc_find" "$rc_xargs" "$rc_node" >"$rcf"
765
- }
766
-
767
- # The parent pid of pid $1, from /proc (the field after the state). rc 1 when $1 is gone.
768
- keyseal_ppid_of() {
769
- local s
770
- s=$(cat -- "/proc/$1/stat" 2>/dev/null) || return 1
771
- s=${s##*) }
772
- # shellcheck disable=SC2086
773
- set -- $s
774
- printf '%s' "$2"
775
- }
776
-
777
- # The pgid of pid $1, from /proc (the fields after the command name: state ppid pgrp).
778
- keyseal_pgid_of() {
779
- local s
780
- s=$(cat -- "/proc/$1/stat" 2>/dev/null) || return 1
781
- s=${s##*) }
782
- # shellcheck disable=SC2086
783
- set -- $s
784
- printf '%s' "$3"
799
+ {
800
+ printf '%s %s' "$rc_find" "$rc_xargs"
801
+ for j in "${rc_nodes[@]}"; do printf ' %s' "$j"; done
802
+ printf '\n'
803
+ } >"$rcf"
785
804
  }
786
805
 
787
806
  # The stage group led by `timeout` (pid $1) is gone within the grace, else KILLed group-wide
@@ -883,14 +902,25 @@ keyseal_scan_cleanup() {
883
902
  if [[ -n $KEYSEAL_CACHE_TMP ]]; then rm -f -- "$KEYSEAL_CACHE_TMP"; fi
884
903
  }
885
904
 
886
- # Run the scan stage under one deadline. $1 pin, $2 exempt path, $3 deadline (s). Sets
887
- # KEYSEAL_SCAN_OUTCOME (ok | incomplete | timed_out), KEYSEAL_SCAN_CLASSIFIED (the classifier's
888
- # JSON when ok) and KEYSEAL_SCAN_FOLDERS (directories entered, from the count file's size).
905
+ # Run the scan stage under one deadline, for every slot named in the caller's parallel arrays
906
+ # KEYSEAL_SCAN_PINS[] / KEYSEAL_SCAN_EXEMPTS[] (at least one entry; #552-ONBOARD-SL3: N slots
907
+ # share this ONE walk, never one walk per slot). $1 deadline (s). Sets KEYSEAL_SCAN_OUTCOME (ok |
908
+ # incomplete | timed_out, for the whole stage: one deadline covers every slot alike),
909
+ # KEYSEAL_SCAN_CLASSIFIED[] (index-parallel to the inputs: each slot's classifier JSON, only when
910
+ # ok) and KEYSEAL_SCAN_FOLDERS (directories entered, from the count file's size).
889
911
  keyseal_scan_run() {
890
- local pin=$1 exempt=$2 deadline=$3 list count pruned rcf jsonf trc=0 period rcs
891
- KEYSEAL_SCAN_OUTCOME=incomplete KEYSEAL_SCAN_CLASSIFIED= KEYSEAL_SCAN_FOLDERS=0
912
+ local deadline=$1 list count pruned rcf trc=0 period rcs n i pat
913
+ n=${#KEYSEAL_SCAN_PINS[@]}
914
+ KEYSEAL_SCAN_OUTCOME=incomplete KEYSEAL_SCAN_CLASSIFIED=() KEYSEAL_SCAN_FOLDERS=0
915
+ ((n >= 1)) || return 0
892
916
  keyseal_scan_mktemp list && keyseal_scan_mktemp count && keyseal_scan_mktemp pruned &&
893
- keyseal_scan_mktemp rcf && keyseal_scan_mktemp jsonf || return 0
917
+ keyseal_scan_mktemp rcf || return 0
918
+ local -a jsonfs=()
919
+ for ((i = 0; i < n; i++)); do
920
+ local jf
921
+ keyseal_scan_mktemp jf || return 0
922
+ jsonfs+=("$jf")
923
+ done
894
924
  if seam_active && [[ ${KEYSEAL_TEST_COUNT_FIFO-} == 1 ]]; then
895
925
  # SC-16's seam: a FIFO with no reader, so the REAL find blocks opening it.
896
926
  rm -f -- "$count" && "$KEYSEAL_BIN_MKFIFO" -m 0600 -- "$count" || return 0
@@ -903,9 +933,12 @@ keyseal_scan_run() {
903
933
  # GNU runner can prove what only uutils would otherwise expose (#552 review r3).
904
934
  local timeout_bin
905
935
  timeout_bin=$(seam_resolve KEYSEAL_TEST_TIMEOUT "$KEYSEAL_BIN_TIMEOUT") || return 0
906
- KEYSEAL_SCAN_PIN=$pin "$timeout_bin" --kill-after="$KEYSEAL_SCAN_KILL_AFTER_S" "$deadline" \
936
+ local -a stage_args=("$rcf" "$count" "$pruned" "$list" "$(id -u)" "$n")
937
+ for ((i = 0; i < n; i++)); do stage_args+=("${jsonfs[i]}" "${KEYSEAL_SCAN_PINS[i]}" "${KEYSEAL_SCAN_EXEMPTS[i]}"); done
938
+ stage_args+=(--)
939
+ "$timeout_bin" --kill-after="$KEYSEAL_SCAN_KILL_AFTER_S" "$deadline" \
907
940
  /bin/bash -c '. "$0"; keyseal_scan_stage "$@"' "$keyseal_here/lib.sh" \
908
- "$rcf" "$jsonf" "$count" "$pruned" "$list" "$(id -u)" "$exempt" "${starts[@]}" >/dev/null &
941
+ "${stage_args[@]}" "${starts[@]}" >/dev/null &
909
942
  KEYSEAL_SCAN_TPID=$!
910
943
  period=$(keyseal_seam_seconds KEYSEAL_TEST_SCAN_PROGRESS_S "$KEYSEAL_SCAN_PROGRESS_S")
911
944
  local watch=
@@ -926,22 +959,30 @@ keyseal_scan_run() {
926
959
  if ((trc == 124 || trc == 137)); then KEYSEAL_SCAN_OUTCOME=timed_out; return 0; fi
927
960
  ((trc == 0)) || return 0
928
961
  rcs=$(<"$rcf") || return 0
929
- [[ $rcs =~ ^[01]\ (0|123)\ 0$ ]] || return 0
930
- KEYSEAL_SCAN_CLASSIFIED=$(<"$jsonf") || return 0
931
- [[ $KEYSEAL_SCAN_CLASSIFIED == \{* ]] || return 0
962
+ pat="^[01] (0|123)"
963
+ for ((i = 0; i < n; i++)); do pat+=" 0"; done
964
+ pat+='$'
965
+ [[ $rcs =~ $pat ]] || return 0
966
+ for ((i = 0; i < n; i++)); do
967
+ local c
968
+ c=$(<"${jsonfs[i]}") || return 0
969
+ [[ $c == \{* ]] || return 0
970
+ KEYSEAL_SCAN_CLASSIFIED[i]=$c
971
+ done
932
972
  KEYSEAL_SCAN_OUTCOME=ok
933
973
  }
934
974
 
935
- # The scan object's fixed part: scope, positive prune report and verdicts. This is what a cache
936
- # stores, WITHOUT `headers`: the cache file lives under $HOME, and the PEM header strings are never
937
- # written there at all. scope_sha256 covers the headers, so a hit re-adds the current ones
938
- # (keyseal_scan_with_headers) and a cached report is shape-identical to a fresh one.
975
+ # The scan object's fixed part for slot index $1: scope, positive prune report and verdicts. This
976
+ # is what a cache stores, WITHOUT `headers`: the cache file lives under $HOME, and the PEM header
977
+ # strings are never written there at all. scope_sha256 covers the headers, so a hit re-adds the
978
+ # current ones (keyseal_scan_with_headers) and a cached report is shape-identical to a fresh one.
939
979
  keyseal_scan_core_json() {
980
+ local i=$1
940
981
  printf '{"roots":%s,"roots_skipped":%s,"pruned":%s,"max_bytes":%s,"not_detected":%s,%s' \
941
982
  "$(keyseal_json_list ${KEYSEAL_ROOTS[@]+"${KEYSEAL_ROOTS[@]}"})" "$KEYSEAL_ROOTS_SKIPPED_JSON" \
942
983
  "$(keyseal_json_list "${KEYSEAL_SCAN_PRUNE_NAMES[@]}" "${KEYSEAL_SCAN_PRUNE_PATHS[@]}")" \
943
984
  "$KEYSEAL_SCAN_MAX_BYTES" \
944
- "$(keyseal_json_list "${KEYSEAL_SCAN_NOT_DETECTED[@]}")" "${KEYSEAL_SCAN_CLASSIFIED#\{}"
985
+ "$(keyseal_json_list "${KEYSEAL_SCAN_NOT_DETECTED[@]}")" "${KEYSEAL_SCAN_CLASSIFIED[i]#\{}"
945
986
  }
946
987
  keyseal_scan_with_headers() { printf '{"headers":%s,%s' "$(keyseal_json_list "${KEYSEAL_SCAN_HEADERS[@]}")" "${1#\{}"; }
947
988