@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/claude-marketplace/plugins/agent-board/.claude-plugin/plugin.json +2 -2
- package/dist/assets.json +4 -4
- package/dist/cli.d.ts +5 -2
- package/dist/cli.js +39 -12
- package/dist/doctor.d.ts +82 -2
- package/dist/doctor.js +170 -4
- package/dist/identity_writer.d.ts +1 -46
- package/dist/identity_writer.js +5 -174
- package/dist/keyslot_status.d.ts +17 -0
- package/dist/keyslot_status.js +108 -2
- package/dist/setup.d.ts +112 -5
- package/dist/setup.js +287 -61
- package/dist/setup_all.d.ts +51 -0
- package/dist/setup_all.js +164 -0
- package/dist/setup_storage.d.ts +39 -1
- package/dist/setup_storage.js +99 -37
- package/dist/setup_writers.d.ts +7 -0
- package/dist/setup_writers.js +11 -2
- package/keyslot/lib.sh +88 -47
- package/keyslot/status.sh +411 -246
- package/package.json +2 -2
package/keyslot/status.sh
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
|
-
# status.sh --harness <h> [--slot <s>] [--json] [--scan-cache fresh|use|only] [--scan-timeout <s>]
|
|
2
|
+
# status.sh --harness <h> [--slot <s>] [--json] [--scan-cache fresh|use|only] [--scan-timeout <s>]
|
|
3
|
+
# or status.sh --slots <a,b,...> --json [--scan-cache fresh|use|only] [--scan-timeout <s>]:
|
|
3
4
|
# what does slot <s> hold, measured, and is it chained and loaded? (IF-0-KEYSEAL-3,
|
|
4
5
|
# IF-0-KEYSEAL-6). <s> defaults to <h>.
|
|
5
6
|
#
|
|
@@ -11,6 +12,17 @@
|
|
|
11
12
|
# scan stage runs under one `timeout` (--scan-timeout, default 1800 s); a scan that gives up is
|
|
12
13
|
# exit 2 `scan_timed_out` and is never cached. Progress goes to stderr; stdout stays JSON.
|
|
13
14
|
#
|
|
15
|
+
# --slots <a,b,...> (#552-ONBOARD-SL3, IF-0-ONBOARD-1 "a key scan at most once per host"): judge N
|
|
16
|
+
# slots in one run. Checks 1-5 run per slot, unchanged; check 6 walks the filesystem ONCE for
|
|
17
|
+
# every slot named (one `find`/`xargs`/`grep` stage under one `timeout`), then classifies each
|
|
18
|
+
# slot's candidates separately against that single walk's output, so N slots never cost N walks.
|
|
19
|
+
# `--slots` requires --json and cannot combine with --harness/--slot; each name is both the
|
|
20
|
+
# harness and the slot. Output is one JSON object per line, in the order given, each carrying its
|
|
21
|
+
# own "exit"; the process exit is the worst of the per-slot exits (1 beats 2 beats 0, as below). A
|
|
22
|
+
# single name behaves exactly as --harness <name>: N=1 is "N slots sharing one walk" with N=1, so
|
|
23
|
+
# it is the SAME code path, not a special case, and its output and cache are byte-identical to
|
|
24
|
+
# today's.
|
|
25
|
+
#
|
|
14
26
|
# MODE, from provenance only, never from what provision was asked (A1):
|
|
15
27
|
# sealed <s>.cred + <s>.pub, the pin derives from a PIPED decrypt of the blob, no
|
|
16
28
|
# <s>.key, no opt-in
|
|
@@ -54,21 +66,41 @@ here=${BASH_SOURCE[0]%/*}
|
|
|
54
66
|
# shellcheck source=lib.sh
|
|
55
67
|
. "$here/lib.sh"
|
|
56
68
|
|
|
57
|
-
harness= slot= json=no scan_cache=fresh scan_timeout=$KEYSEAL_SCAN_TIMEOUT_S
|
|
58
|
-
usage="usage: status.sh --harness <h> [--slot <s>] [--json] [--scan-cache fresh|use|only] [--scan-timeout <s>]"
|
|
69
|
+
harness= slot= slots_arg= json=no scan_cache=fresh scan_timeout=$KEYSEAL_SCAN_TIMEOUT_S
|
|
70
|
+
usage="usage: status.sh --harness <h> [--slot <s>] [--json] [--scan-cache fresh|use|only] [--scan-timeout <s>] | status.sh --slots <a,b,...> --json [--scan-cache fresh|use|only] [--scan-timeout <s>]"
|
|
59
71
|
while (($#)); do
|
|
60
72
|
case $1 in
|
|
61
73
|
--harness) harness=${2-}; shift 2 || keyseal_die "usage: --harness <h>" ;;
|
|
62
74
|
--slot) slot=${2-}; shift 2 || keyseal_die "usage: --slot <s>" ;;
|
|
75
|
+
--slots) slots_arg=${2-}; shift 2 || keyseal_die "usage: --slots <a,b,...>" ;;
|
|
63
76
|
--json) json=yes; shift ;;
|
|
64
77
|
--scan-cache) scan_cache=${2-}; shift 2 || keyseal_die "$usage" ;;
|
|
65
78
|
--scan-timeout) scan_timeout=${2-}; shift 2 || keyseal_die "$usage" ;;
|
|
66
79
|
*) keyseal_die "$usage" ;;
|
|
67
80
|
esac
|
|
68
81
|
done
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
[[
|
|
82
|
+
|
|
83
|
+
slots=() harness_of=()
|
|
84
|
+
if [[ -n $slots_arg ]]; then
|
|
85
|
+
[[ -z $harness && -z $slot ]] || keyseal_die "usage: --slots cannot combine with --harness/--slot"
|
|
86
|
+
[[ $json == yes ]] || keyseal_die "usage: --slots requires --json"
|
|
87
|
+
IFS=, read -ra slots <<<"$slots_arg"
|
|
88
|
+
((${#slots[@]} >= 1)) || keyseal_die "usage: --slots <a,b,...>"
|
|
89
|
+
declare -A seen_slot=()
|
|
90
|
+
for s in "${slots[@]}"; do
|
|
91
|
+
[[ $s =~ $KEYSEAL_SLOT_RE ]] || keyseal_die "bad_slot: $s"
|
|
92
|
+
[[ -z ${seen_slot[$s]-} ]] || keyseal_die "duplicate_slot: $s"
|
|
93
|
+
seen_slot[$s]=1
|
|
94
|
+
done
|
|
95
|
+
harness_of=("${slots[@]}")
|
|
96
|
+
else
|
|
97
|
+
[[ $harness =~ $KEYSEAL_SLOT_RE ]] || keyseal_die "bad_harness"
|
|
98
|
+
slot=${slot:-$harness}
|
|
99
|
+
[[ $slot =~ $KEYSEAL_SLOT_RE ]] || keyseal_die "bad_slot"
|
|
100
|
+
slots=("$slot")
|
|
101
|
+
harness_of=("$harness")
|
|
102
|
+
fi
|
|
103
|
+
n=${#slots[@]}
|
|
72
104
|
[[ $scan_cache == fresh || $scan_cache == use || $scan_cache == only ]] || keyseal_die "bad_scan_cache: $usage"
|
|
73
105
|
[[ $scan_timeout =~ ^[1-9][0-9]{0,6}$ ]] || keyseal_die "bad_scan_timeout: $usage"
|
|
74
106
|
[[ -n ${XDG_RUNTIME_DIR-} ]] || keyseal_die "runtime_dir_unset: XDG_RUNTIME_DIR is unset, so the slot's agent socket cannot be located; run from a login session or export XDG_RUNTIME_DIR=/run/user/$(id -u)"
|
|
@@ -79,14 +111,14 @@ trap keyseal_scan_cleanup EXIT
|
|
|
79
111
|
trap 'exit 130' INT
|
|
80
112
|
trap 'exit 143' TERM
|
|
81
113
|
|
|
82
|
-
K=$(keyseal_key_dir)
|
|
83
|
-
cred=$K/$slot.cred pub=$K/$slot.pub key=$K/$slot.key optin=$K/$slot.unsealed-optin
|
|
84
|
-
base_unit=$KEYSEAL_BASE_UNIT@$slot.service
|
|
85
|
-
load_unit=$KEYSEAL_LOAD_UNIT@$slot.service
|
|
86
|
-
declare -A ok detail
|
|
87
|
-
exit2=()
|
|
88
114
|
has() { [[ -e $1 || -L $1 ]]; }
|
|
89
115
|
str_or_null() { if [[ -n $1 ]]; then keyseal_json_str "$1"; else printf null; fi; }
|
|
116
|
+
bool() { if [[ $1 == yes ]]; then printf true; else printf false; fi; }
|
|
117
|
+
state() { "$SYSTEMCTL" --user "$1" "$2" 2>/dev/null || true; }
|
|
118
|
+
|
|
119
|
+
# ---- host-level, computed at most once per run (IF-0-ONBOARD-1) --------------------------------
|
|
120
|
+
|
|
121
|
+
K=$(keyseal_key_dir)
|
|
90
122
|
|
|
91
123
|
probe_out=$("$here/probe.sh" --json 2>/dev/null) && probe_rc=0 || probe_rc=$?
|
|
92
124
|
outcome=error
|
|
@@ -94,262 +126,395 @@ outcome=error
|
|
|
94
126
|
round_trip=unknown
|
|
95
127
|
[[ $probe_out =~ \"round_trip\":\"([a-z_]+)\" ]] && round_trip=${BASH_REMATCH[1]}
|
|
96
128
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
fi
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
129
|
+
boot_id=$(</proc/sys/kernel/random/boot_id)
|
|
130
|
+
machine_id=$(keyseal_machine_id) || machine_id=
|
|
131
|
+
seam_j=$(keyseal_seam_json)
|
|
132
|
+
host_j=$(keyseal_json_str "$(uname -n)")
|
|
133
|
+
uid_j=$(keyseal_uid)
|
|
134
|
+
machine_id_j=$(str_or_null "$machine_id")
|
|
135
|
+
boot_id_j=$(keyseal_json_str "$boot_id")
|
|
136
|
+
|
|
137
|
+
stale_temp=$(keyseal_scan_stale_temp)
|
|
138
|
+
keyseal_scan_roots
|
|
139
|
+
scope_sha_j=$(keyseal_json_str "$(keyseal_sha256_str "$(keyseal_scan_scope_json)")")
|
|
140
|
+
scanner_sha_j=$(str_or_null "$(keyseal_files_sha "$here" lib.sh status.sh || true)")
|
|
141
|
+
|
|
142
|
+
linger=$(keyseal_linger)
|
|
143
|
+
if [[ $linger == yes ]]; then ok_linger=true detail_linger=""; else ok_linger=false detail_linger="linger is $linger"; fi
|
|
144
|
+
|
|
145
|
+
# ---- phase A: checks 1-5 and the cache judge, per slot ------------------------------------------
|
|
146
|
+
|
|
147
|
+
declare -a A_MODE=() A_PIN=() A_EXEMPT=() A_EXEMPT_J=() A_PINSHA_J=() A_BLOBSHA_J=()
|
|
148
|
+
declare -a A_OK_COMMITTED=() A_DET_COMMITTED=()
|
|
149
|
+
declare -a A_OK_CHAIN=() A_DET_CHAIN=() A_CHAIN_LEGACY=() A_LEGACY=() A_LOADER_STATE=() A_LOADER_REC=() A_LOADER_RUN=()
|
|
150
|
+
declare -a A_OK_UNITS=() A_DET_UNITS=()
|
|
151
|
+
declare -a A_OK_AGENT=() A_DET_AGENT=() A_AGENT_EMPTY=()
|
|
152
|
+
declare -a A_OPTIN_J=() A_UPGRADE=() A_EXIT2=()
|
|
153
|
+
declare -a A_CACHE_TOKEN=() A_CACHE_STATE=() A_CACHE_REASON=() A_CACHE_SCAN=() A_CACHE_SCANNED_AT=() A_CACHE_DURATION=() A_CACHE_LAST=()
|
|
154
|
+
declare -a A_NEEDS_SCAN=()
|
|
155
|
+
|
|
156
|
+
for i in "${!slots[@]}"; do
|
|
157
|
+
slot=${slots[i]}
|
|
158
|
+
cred=$K/$slot.cred pub=$K/$slot.pub key=$K/$slot.key optin=$K/$slot.unsealed-optin
|
|
159
|
+
base_unit=$KEYSEAL_BASE_UNIT@$slot.service
|
|
160
|
+
load_unit=$KEYSEAL_LOAD_UNIT@$slot.service
|
|
161
|
+
|
|
162
|
+
# 1 committed: the provenance table. The pin is read whatever the provenance, so a
|
|
163
|
+
# contradiction still scans for copies of the pinned key (review round 1, Opus S3).
|
|
164
|
+
contra=()
|
|
165
|
+
mode=undetermined optin_json=null
|
|
166
|
+
pin=$(keyseal_read_pin "$pub") || pin=
|
|
167
|
+
has "$cred" && has "$key" && contra+=("a sealed blob and an unsealed key are both present")
|
|
168
|
+
has "$cred" && has "$optin" && contra+=("an opt-in record beside a sealed blob")
|
|
169
|
+
has "$optin" && ! has "$key" && contra+=("an opt-in record without $slot.key")
|
|
170
|
+
if has "$optin"; then
|
|
171
|
+
optin_ok=true
|
|
172
|
+
optin_problems=$(keyseal_optin_check "$slot") || optin_ok=false
|
|
173
|
+
plist=
|
|
174
|
+
while IFS= read -r line; do [[ -n $line ]] && plist+="${plist:+,}$(keyseal_json_str "$line")"; done <<<"$optin_problems"
|
|
175
|
+
optin_json="{\"ok\":$optin_ok,\"problems\":[$plist]}"
|
|
176
|
+
fi
|
|
177
|
+
if has "$key" && ! has "$optin"; then contra+=("$slot.key without an opt-in record"); fi
|
|
178
|
+
if has "$K/$slot.cred.staging" || has "$K/$slot.pub.staging" || has "$K/$slot.unsealed-optin.staging"; then
|
|
179
|
+
contra+=("staging file present")
|
|
180
|
+
fi
|
|
181
|
+
exit2_i=()
|
|
182
|
+
if ((${#contra[@]} == 0)); then
|
|
183
|
+
if ! has "$cred" && ! has "$pub" && ! has "$key" && ! has "$optin"; then
|
|
184
|
+
exit2_i+=(nothing_committed)
|
|
185
|
+
elif has "$key"; then
|
|
186
|
+
# The loader's own predicate (optin.sh): what it would refuse to load is a contradiction.
|
|
187
|
+
if problems=$(keyseal_unsealed_check "$slot"); then mode=unsealed
|
|
188
|
+
else contra+=("the unsealed slot does not verify: ${problems//$'\n'/; }")
|
|
189
|
+
fi
|
|
190
|
+
elif ! has "$cred"; then contra+=("blob missing")
|
|
191
|
+
elif [[ -z $pin ]]; then contra+=("pin missing or malformed")
|
|
133
192
|
else
|
|
134
|
-
|
|
193
|
+
drc=0
|
|
194
|
+
derived=$(keyseal_derive_pub "$slot") || drc=$?
|
|
195
|
+
if ((drc == 0)); then
|
|
196
|
+
if [[ $derived == "$pin" ]]; then mode=sealed; else contra+=("pin does not derive from the blob"); fi
|
|
197
|
+
elif [[ $outcome == capable ]]; then
|
|
198
|
+
contra+=("the blob does not decrypt to a key, though sealing works here")
|
|
199
|
+
else
|
|
200
|
+
exit2_i+=(undeterminable)
|
|
201
|
+
fi
|
|
135
202
|
fi
|
|
136
203
|
fi
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
fi
|
|
204
|
+
if ((${#contra[@]})); then
|
|
205
|
+
mode=contradiction ok_committed_i=false
|
|
206
|
+
detail_committed_i=$(printf '%s; ' "${contra[@]}")
|
|
207
|
+
detail_committed_i=${detail_committed_i%; }
|
|
208
|
+
else
|
|
209
|
+
ok_committed_i=true detail_committed_i=""
|
|
210
|
+
fi
|
|
145
211
|
|
|
146
|
-
# 2 chain, including the slot's loader version
|
|
147
|
-
if keyseal_chain_check "$slot" "$here"; then
|
|
148
|
-
else
|
|
149
|
-
fi
|
|
150
|
-
|
|
151
|
-
if [[ $KEYSEAL_CHAIN_LEGACY == yes ]] || keyseal_legacy_present; then
|
|
152
|
-
if [[ $KEYSEAL_CHAIN_LEGACY == no ]]; then
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
212
|
+
# 2 chain, including the slot's loader version
|
|
213
|
+
if keyseal_chain_check "$slot" "$here"; then ok_chain_i=true detail_chain_i=""
|
|
214
|
+
else ok_chain_i=false detail_chain_i=${KEYSEAL_CHAIN_PROBLEMS%$'\n'}
|
|
215
|
+
fi
|
|
216
|
+
legacy_i=no
|
|
217
|
+
if [[ $KEYSEAL_CHAIN_LEGACY == yes ]] || keyseal_legacy_present; then legacy_i=yes exit2_i+=(legacy_loader_present); fi
|
|
218
|
+
if [[ $KEYSEAL_CHAIN_LEGACY == no ]]; then
|
|
219
|
+
case $KEYSEAL_LOADER_STATE in
|
|
220
|
+
outdated) exit2_i+=(loader_outdated) ;;
|
|
221
|
+
unrecorded) exit2_i+=(loader_unrecorded) ;;
|
|
222
|
+
esac
|
|
223
|
+
fi
|
|
224
|
+
|
|
225
|
+
# 3 units
|
|
226
|
+
sub=$("$SYSTEMCTL" --user show -p SubState "$load_unit" 2>/dev/null || true)
|
|
227
|
+
if [[ $(state is-enabled "$base_unit") == enabled && $(state is-enabled "$load_unit") == enabled &&
|
|
228
|
+
$(state is-active "$base_unit") == active && $(state is-active "$load_unit") == active && $sub == SubState=exited ]]; then
|
|
229
|
+
ok_units_i=true detail_units_i=""
|
|
230
|
+
else
|
|
231
|
+
ok_units_i=false detail_units_i="base $(state is-enabled "$base_unit")/$(state is-active "$base_unit"), loader $(state is-enabled "$load_unit")/$(state is-active "$load_unit") ${sub#SubState=}"
|
|
232
|
+
fi
|
|
233
|
+
|
|
234
|
+
# 4 agent: exactly one identity, and it is the pin. `empty` is told apart from a wrong or
|
|
235
|
+
# extra key: an empty agent can be the CONSEQUENCE of an exit-2 cause (below).
|
|
236
|
+
agent_empty=no
|
|
237
|
+
if [[ -n $pin ]] && keyseal_agent_holds_exactly "$slot" "$pin"; then ok_agent_i=true detail_agent_i=""
|
|
238
|
+
else
|
|
239
|
+
held=$(keyseal_agent_keys "$slot" 2>/dev/null) || held="?"
|
|
240
|
+
if [[ -z $held ]]; then agent_empty=yes; fi
|
|
241
|
+
nheld=$(printf '%s' "$held" | "$KEYSEAL_BIN_GREP" -c . || true)
|
|
242
|
+
[[ $held == "?" ]] && nheld=
|
|
243
|
+
ok_agent_i=false detail_agent_i="the slot agent holds ${nheld:-an unreadable set of} identities, not exactly the pin"
|
|
244
|
+
fi
|
|
245
|
+
|
|
246
|
+
# 5 linger (shared, host-level), and capability for the measured mode
|
|
247
|
+
[[ $linger == yes ]] || exit2_i+=(linger_off)
|
|
248
|
+
upgrade_i=no
|
|
249
|
+
case $mode in
|
|
250
|
+
sealed) [[ $outcome == capable ]] || exit2_i+=("capability_$outcome") ;;
|
|
251
|
+
unsealed)
|
|
252
|
+
if [[ $outcome == capable ]]; then upgrade_i=yes exit2_i+=(upgrade_available)
|
|
253
|
+
elif [[ $outcome != incapable ]]; then exit2_i+=("capability_$outcome")
|
|
254
|
+
fi
|
|
255
|
+
;;
|
|
156
256
|
esac
|
|
157
|
-
fi
|
|
158
257
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
if [[ $(state is-enabled "$base_unit") == enabled && $(state is-enabled "$load_unit") == enabled &&
|
|
163
|
-
$(state is-active "$base_unit") == active && $(state is-active "$load_unit") == active && $sub == SubState=exited ]]; then
|
|
164
|
-
ok[units]=true detail[units]=""
|
|
165
|
-
else
|
|
166
|
-
ok[units]=false detail[units]="base $(state is-enabled "$base_unit")/$(state is-active "$base_unit"), loader $(state is-enabled "$load_unit")/$(state is-active "$load_unit") ${sub#SubState=}"
|
|
167
|
-
fi
|
|
258
|
+
pin_sha=null blob_sha=null
|
|
259
|
+
[[ -n $pin ]] && pin_sha=$(keyseal_json_str "$(keyseal_sha256_str "$pin")")
|
|
260
|
+
[[ -f $cred ]] && blob_sha=$(keyseal_json_str "$(keyseal_sha256_file "$cred")")
|
|
168
261
|
|
|
169
|
-
#
|
|
170
|
-
#
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
else
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
262
|
+
# 6 scan setup: the unsealed slot's own key file is the one exemption. Judge the cache now (IF-
|
|
263
|
+
# 552-2); the walk, shared across every slot needing one, runs once after this loop.
|
|
264
|
+
exempt=
|
|
265
|
+
[[ $mode == unsealed ]] && exempt=$key
|
|
266
|
+
exempt_j=$(if [[ -n $exempt ]]; then keyseal_json_str "$(keyseal_sha256_str "$exempt")"; else printf null; fi)
|
|
267
|
+
KEYSEAL_INPUT=(
|
|
268
|
+
[seam]=$seam_j
|
|
269
|
+
[uid]=$uid_j
|
|
270
|
+
[machine_id]=$machine_id_j
|
|
271
|
+
[slot]=$(keyseal_json_str "$slot")
|
|
272
|
+
[mode]=$(keyseal_json_str "$mode")
|
|
273
|
+
[exempt]=$exempt_j
|
|
274
|
+
[pin_sha256]=$pin_sha
|
|
275
|
+
[blob_sha256]=$blob_sha
|
|
276
|
+
[scope_sha256]=$scope_sha_j
|
|
277
|
+
[scanner_sha256]=$scanner_sha_j
|
|
278
|
+
)
|
|
279
|
+
keyseal_cache_read "$slot" "$scan_cache"
|
|
180
280
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
upgrade=no
|
|
185
|
-
case $mode in
|
|
186
|
-
sealed) [[ $outcome == capable ]] || exit2+=("capability_$outcome") ;;
|
|
187
|
-
unsealed)
|
|
188
|
-
if [[ $outcome == capable ]]; then upgrade=yes exit2+=(upgrade_available)
|
|
189
|
-
elif [[ $outcome != incapable ]]; then exit2+=("capability_$outcome")
|
|
190
|
-
fi
|
|
191
|
-
;;
|
|
192
|
-
esac
|
|
281
|
+
needs_scan=no
|
|
282
|
+
if [[ $KEYSEAL_CACHE_STATE != hit && $scan_cache != only ]]; then needs_scan=yes; fi
|
|
283
|
+
[[ $KEYSEAL_CACHE_STATE != hit && $scan_cache == only ]] && exit2_i+=(scan_not_cached)
|
|
193
284
|
|
|
194
|
-
|
|
195
|
-
[[
|
|
196
|
-
[[
|
|
197
|
-
|
|
285
|
+
A_MODE[i]=$mode A_PIN[i]=$pin A_EXEMPT[i]=$exempt A_EXEMPT_J[i]=$exempt_j
|
|
286
|
+
A_PINSHA_J[i]=$pin_sha A_BLOBSHA_J[i]=$blob_sha
|
|
287
|
+
A_OK_COMMITTED[i]=$ok_committed_i A_DET_COMMITTED[i]=$detail_committed_i
|
|
288
|
+
A_OK_CHAIN[i]=$ok_chain_i A_DET_CHAIN[i]=$detail_chain_i
|
|
289
|
+
A_CHAIN_LEGACY[i]=$KEYSEAL_CHAIN_LEGACY A_LEGACY[i]=$legacy_i
|
|
290
|
+
A_LOADER_STATE[i]=$KEYSEAL_LOADER_STATE A_LOADER_REC[i]=$KEYSEAL_LOADER_RECORDED A_LOADER_RUN[i]=$KEYSEAL_LOADER_RUNNING
|
|
291
|
+
A_OK_UNITS[i]=$ok_units_i A_DET_UNITS[i]=$detail_units_i
|
|
292
|
+
A_OK_AGENT[i]=$ok_agent_i A_DET_AGENT[i]=$detail_agent_i A_AGENT_EMPTY[i]=$agent_empty
|
|
293
|
+
A_OPTIN_J[i]=$optin_json A_UPGRADE[i]=$upgrade_i
|
|
294
|
+
A_EXIT2[i]="${exit2_i[*]-}"
|
|
295
|
+
A_CACHE_TOKEN[i]=$KEYSEAL_CACHE_TOKEN A_CACHE_STATE[i]=$KEYSEAL_CACHE_STATE A_CACHE_REASON[i]=$KEYSEAL_CACHE_REASON
|
|
296
|
+
A_CACHE_SCAN[i]=$KEYSEAL_CACHE_SCAN A_CACHE_SCANNED_AT[i]=$KEYSEAL_CACHE_SCANNED_AT
|
|
297
|
+
A_CACHE_DURATION[i]=$KEYSEAL_CACHE_DURATION A_CACHE_LAST[i]=$KEYSEAL_CACHE_LAST
|
|
298
|
+
A_NEEDS_SCAN[i]=$needs_scan
|
|
299
|
+
done
|
|
198
300
|
|
|
199
|
-
#
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
[scope_sha256]=$(keyseal_json_str "$(keyseal_sha256_str "$(keyseal_scan_scope_json)")")
|
|
215
|
-
[scanner_sha256]=$(str_or_null "$(keyseal_files_sha "$here" lib.sh status.sh || true)")
|
|
216
|
-
)
|
|
217
|
-
keyseal_cache_read "$slot" "$scan_cache"
|
|
218
|
-
cache_read="$KEYSEAL_CACHE_STATE:$KEYSEAL_CACHE_REASON"
|
|
219
|
-
cache_last=null
|
|
220
|
-
[[ -n $KEYSEAL_CACHE_LAST ]] && cache_last=$(keyseal_json_str "$(keyseal_iso "$KEYSEAL_CACHE_LAST")")
|
|
221
|
-
scan_source=none scan_scanned_at=null scan_age=null scan_duration=null scan_core=
|
|
222
|
-
scan_judged=yes scan_timed_out=no
|
|
223
|
-
if [[ $KEYSEAL_CACHE_STATE == hit ]]; then
|
|
224
|
-
scan_source=cached scan_core=$KEYSEAL_CACHE_SCAN
|
|
225
|
-
scan_now=$(keyseal_now) || scan_now=$KEYSEAL_CACHE_SCANNED_AT
|
|
226
|
-
scan_scanned_at=$(keyseal_json_str "$(keyseal_iso "$KEYSEAL_CACHE_SCANNED_AT")")
|
|
227
|
-
scan_age=$((scan_now - KEYSEAL_CACHE_SCANNED_AT)) scan_duration=$KEYSEAL_CACHE_DURATION
|
|
228
|
-
elif [[ $scan_cache == only ]]; then
|
|
229
|
-
scan_judged=no
|
|
230
|
-
detail[scan]="not judged: no valid scan cache ($KEYSEAL_CACHE_STATE:$KEYSEAL_CACHE_REASON)"
|
|
231
|
-
exit2+=(scan_not_cached)
|
|
232
|
-
else
|
|
301
|
+
# ---- the ONE shared walk, for every slot phase A marked needs_scan=yes --------------------------
|
|
302
|
+
|
|
303
|
+
scan_idx=()
|
|
304
|
+
for i in "${!slots[@]}"; do
|
|
305
|
+
[[ ${A_NEEDS_SCAN[i]} == yes ]] && scan_idx+=("$i")
|
|
306
|
+
done
|
|
307
|
+
|
|
308
|
+
scan_start=0 scan_duration=0
|
|
309
|
+
if ((${#scan_idx[@]})); then
|
|
310
|
+
KEYSEAL_SCAN_PINS=() KEYSEAL_SCAN_EXEMPTS=()
|
|
311
|
+
for k in "${!scan_idx[@]}"; do
|
|
312
|
+
i=${scan_idx[k]}
|
|
313
|
+
KEYSEAL_SCAN_PINS[k]=${A_PIN[i]}
|
|
314
|
+
KEYSEAL_SCAN_EXEMPTS[k]=${A_EXEMPT[i]}
|
|
315
|
+
done
|
|
233
316
|
# scanned_at is the scan's START: a file created after it may be missed.
|
|
234
317
|
scan_start=$(keyseal_now) || scan_start=0
|
|
235
|
-
|
|
236
|
-
|
|
318
|
+
for k in "${!scan_idx[@]}"; do
|
|
319
|
+
i=${scan_idx[k]}
|
|
320
|
+
if ((n > 1)); then
|
|
321
|
+
printf 'status: scan: starting (%s:%s) slot=%s\n' "${A_CACHE_STATE[i]}" "${A_CACHE_REASON[i]}" "${slots[i]}" >&2
|
|
322
|
+
else
|
|
323
|
+
printf 'status: scan: starting (%s:%s)\n' "${A_CACHE_STATE[i]}" "${A_CACHE_REASON[i]}" >&2
|
|
324
|
+
fi
|
|
325
|
+
done
|
|
326
|
+
keyseal_scan_run "$scan_timeout"
|
|
237
327
|
scan_end=$(keyseal_now) || scan_end=$scan_start
|
|
238
328
|
scan_duration=$((scan_end - scan_start))
|
|
239
329
|
((scan_duration >= 0)) || scan_duration=0
|
|
240
|
-
case $KEYSEAL_SCAN_OUTCOME in
|
|
241
|
-
ok)
|
|
242
|
-
scan_source=fresh scan_core=$(keyseal_scan_core_json)
|
|
243
|
-
scan_scanned_at=$(keyseal_json_str "$(keyseal_iso "$scan_start")") scan_age=$scan_duration
|
|
244
|
-
;;
|
|
245
|
-
timed_out)
|
|
246
|
-
scan_judged=no scan_timed_out=yes
|
|
247
|
-
detail[scan]="not judged: the scan gave up after $scan_timeout s (scan_timed_out)"
|
|
248
|
-
exit2+=(scan_timed_out)
|
|
249
|
-
KEYSEAL_CACHE_STATE=not_written KEYSEAL_CACHE_REASON=timed_out
|
|
250
|
-
;;
|
|
251
|
-
*)
|
|
252
|
-
detail[scan]="the scan did not run to completion"
|
|
253
|
-
KEYSEAL_CACHE_STATE=not_written KEYSEAL_CACHE_REASON=incomplete
|
|
254
|
-
;;
|
|
255
|
-
esac
|
|
256
330
|
fi
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
331
|
+
|
|
332
|
+
# ---- phase B: interpret the scan, commit the cache and emit, per slot ---------------------------
|
|
333
|
+
|
|
334
|
+
saw1=no saw2=no
|
|
335
|
+
for i in "${!slots[@]}"; do
|
|
336
|
+
slot=${slots[i]} harness=${harness_of[i]} mode=${A_MODE[i]}
|
|
337
|
+
read -ra exit2_i <<<"${A_EXIT2[i]:-}"
|
|
338
|
+
cache_read_i="${A_CACHE_STATE[i]}:${A_CACHE_REASON[i]}"
|
|
339
|
+
cache_state=${A_CACHE_STATE[i]} cache_reason=${A_CACHE_REASON[i]}
|
|
340
|
+
base_unit=$KEYSEAL_BASE_UNIT@$slot.service
|
|
341
|
+
load_unit=$KEYSEAL_LOAD_UNIT@$slot.service
|
|
342
|
+
|
|
343
|
+
KEYSEAL_INPUT=(
|
|
344
|
+
[seam]=$seam_j
|
|
345
|
+
[uid]=$uid_j
|
|
346
|
+
[machine_id]=$machine_id_j
|
|
347
|
+
[slot]=$(keyseal_json_str "$slot")
|
|
348
|
+
[mode]=$(keyseal_json_str "$mode")
|
|
349
|
+
[exempt]=${A_EXEMPT_J[i]}
|
|
350
|
+
[pin_sha256]=${A_PINSHA_J[i]}
|
|
351
|
+
[blob_sha256]=${A_BLOBSHA_J[i]}
|
|
352
|
+
[scope_sha256]=$scope_sha_j
|
|
353
|
+
[scanner_sha256]=$scanner_sha_j
|
|
354
|
+
)
|
|
355
|
+
|
|
356
|
+
scan_source=none scan_scanned_at=null scan_age=null scan_dur=null scan_core=
|
|
357
|
+
scan_judged=yes scan_timed_out=no detail_scan=""
|
|
358
|
+
if [[ $cache_state == hit ]]; then
|
|
359
|
+
scan_source=cached scan_core=${A_CACHE_SCAN[i]}
|
|
360
|
+
scan_now=$(keyseal_now) || scan_now=${A_CACHE_SCANNED_AT[i]}
|
|
361
|
+
scan_scanned_at=$(keyseal_json_str "$(keyseal_iso "${A_CACHE_SCANNED_AT[i]}")")
|
|
362
|
+
scan_age=$((scan_now - A_CACHE_SCANNED_AT[i]))
|
|
363
|
+
scan_dur=${A_CACHE_DURATION[i]}
|
|
364
|
+
elif [[ ${A_NEEDS_SCAN[i]} == no ]]; then
|
|
365
|
+
scan_judged=no
|
|
366
|
+
detail_scan="not judged: no valid scan cache ($cache_state:$cache_reason)"
|
|
367
|
+
else
|
|
368
|
+
case $KEYSEAL_SCAN_OUTCOME in
|
|
369
|
+
ok)
|
|
370
|
+
k=-1
|
|
371
|
+
for kk in "${!scan_idx[@]}"; do [[ ${scan_idx[kk]} == "$i" ]] && k=$kk && break; done
|
|
372
|
+
scan_source=fresh scan_core=$(keyseal_scan_core_json "$k")
|
|
373
|
+
scan_scanned_at=$(keyseal_json_str "$(keyseal_iso "$scan_start")") scan_age=$scan_duration
|
|
374
|
+
scan_dur=$scan_duration
|
|
375
|
+
;;
|
|
376
|
+
timed_out)
|
|
377
|
+
scan_judged=no scan_timed_out=yes
|
|
378
|
+
detail_scan="not judged: the scan gave up after $scan_timeout s (scan_timed_out)"
|
|
379
|
+
exit2_i+=(scan_timed_out)
|
|
380
|
+
cache_state=not_written cache_reason=timed_out
|
|
381
|
+
;;
|
|
382
|
+
*)
|
|
383
|
+
detail_scan="the scan did not run to completion"
|
|
384
|
+
cache_state=not_written cache_reason=incomplete
|
|
385
|
+
;;
|
|
386
|
+
esac
|
|
260
387
|
fi
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
388
|
+
if [[ -n $scan_core ]]; then
|
|
389
|
+
if [[ $scan_core == *'"plaintext_matches":[]'* ]]; then ok_scan=true detail_scan=""
|
|
390
|
+
else ok_scan=false detail_scan="plaintext copy of the slot key found"
|
|
391
|
+
fi
|
|
392
|
+
else
|
|
393
|
+
ok_scan=false
|
|
394
|
+
fi
|
|
395
|
+
# A match is never cached: it writes a tombstone. Only a clean, completed, fresh scan commits.
|
|
396
|
+
if [[ $scan_source == fresh ]]; then
|
|
397
|
+
KEYSEAL_CACHE_TOKEN=${A_CACHE_TOKEN[i]}
|
|
398
|
+
if [[ $ok_scan == true ]]; then keyseal_cache_commit_clean "$slot" "$scan_start" "$scan_duration" "$scan_core"
|
|
399
|
+
else keyseal_cache_commit_tombstone "$slot" "$harness"
|
|
400
|
+
fi
|
|
401
|
+
cache_state=$KEYSEAL_CACHE_STATE cache_reason=$KEYSEAL_CACHE_REASON
|
|
268
402
|
fi
|
|
269
|
-
fi
|
|
270
|
-
if [[ $scan_source == fresh ]]; then
|
|
271
|
-
n_matches=0 n_candidates=0
|
|
272
|
-
[[ $scan_core =~ \"candidates\":([0-9]+) ]] && n_candidates=${BASH_REMATCH[1]}
|
|
273
|
-
[[ ${ok[scan]} == true ]] || n_matches=$(printf '%s' "$scan_core" | keyseal_node count-matches 2>/dev/null || printf '?')
|
|
274
|
-
printf 'status: scan: done in %s s (%s folders, %s candidates, %s matches)\n' "$scan_duration" "$KEYSEAL_SCAN_FOLDERS" "$n_candidates" "$n_matches" >&2
|
|
275
|
-
elif [[ $scan_source == none && $scan_judged == yes || $scan_timed_out == yes ]]; then
|
|
276
|
-
printf 'status: scan: done in %s s (%s folders): %s\n' "$scan_duration" "$KEYSEAL_SCAN_FOLDERS" "${detail[scan]}" >&2
|
|
277
|
-
fi
|
|
278
|
-
scan_meta="\"source\":\"$scan_source\",\"scanned_at\":$scan_scanned_at,\"age_s\":$scan_age,\"duration_s\":$scan_duration,\"inputs\":$(keyseal_cache_inputs_json),\"stale_temp\":$stale_temp,\"cache\":{\"mode\":\"$scan_cache\",\"state\":\"$KEYSEAL_CACHE_STATE\",\"reason\":$(str_or_null "$KEYSEAL_CACHE_REASON"),\"read\":$(keyseal_json_str "$cache_read"),\"last_scanned_at\":$cache_last}"
|
|
279
|
-
# A scan that was not judged still names the scope it would have scanned.
|
|
280
|
-
if [[ -n $scan_core ]]; then scan=$(keyseal_scan_with_headers "${scan_core%\}},$scan_meta}")
|
|
281
|
-
else scan="{\"roots\":$(keyseal_json_list ${KEYSEAL_ROOTS[@]+"${KEYSEAL_ROOTS[@]}"}),\"roots_skipped\":$KEYSEAL_ROOTS_SKIPPED_JSON,$scan_meta}"
|
|
282
|
-
fi
|
|
283
403
|
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
[[ $
|
|
287
|
-
|
|
288
|
-
if
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
fi
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
404
|
+
if [[ $scan_source == fresh ]]; then
|
|
405
|
+
n_matches=0 n_candidates=0
|
|
406
|
+
[[ $scan_core =~ \"candidates\":([0-9]+) ]] && n_candidates=${BASH_REMATCH[1]}
|
|
407
|
+
[[ $ok_scan == true ]] || n_matches=$(printf '%s' "$scan_core" | keyseal_node count-matches 2>/dev/null || printf '?')
|
|
408
|
+
if ((n > 1)); then
|
|
409
|
+
printf 'status: scan: done in %s s (%s folders, %s candidates, %s matches) slot=%s\n' "$scan_duration" "$KEYSEAL_SCAN_FOLDERS" "$n_candidates" "$n_matches" "$slot" >&2
|
|
410
|
+
else
|
|
411
|
+
printf 'status: scan: done in %s s (%s folders, %s candidates, %s matches)\n' "$scan_duration" "$KEYSEAL_SCAN_FOLDERS" "$n_candidates" "$n_matches" >&2
|
|
412
|
+
fi
|
|
413
|
+
elif [[ $scan_source == none && $scan_judged == yes || $scan_timed_out == yes ]]; then
|
|
414
|
+
if ((n > 1)); then
|
|
415
|
+
printf 'status: scan: done in %s s (%s folders) slot=%s: %s\n' "$scan_duration" "$KEYSEAL_SCAN_FOLDERS" "$slot" "$detail_scan" >&2
|
|
416
|
+
else
|
|
417
|
+
printf 'status: scan: done in %s s (%s folders): %s\n' "$scan_duration" "$KEYSEAL_SCAN_FOLDERS" "$detail_scan" >&2
|
|
418
|
+
fi
|
|
419
|
+
fi
|
|
420
|
+
|
|
421
|
+
cache_last=null
|
|
422
|
+
[[ -n ${A_CACHE_LAST[i]} ]] && cache_last=$(keyseal_json_str "$(keyseal_iso "${A_CACHE_LAST[i]}")")
|
|
423
|
+
scan_meta="\"source\":\"$scan_source\",\"scanned_at\":$scan_scanned_at,\"age_s\":$scan_age,\"duration_s\":$scan_dur,\"inputs\":$(keyseal_cache_inputs_json),\"stale_temp\":$stale_temp,\"cache\":{\"mode\":\"$scan_cache\",\"state\":\"$cache_state\",\"reason\":$(str_or_null "$cache_reason"),\"read\":$(keyseal_json_str "$cache_read_i"),\"last_scanned_at\":$cache_last}"
|
|
424
|
+
if [[ -n $scan_core ]]; then scan_json=$(keyseal_scan_with_headers "${scan_core%\}},$scan_meta}")
|
|
425
|
+
else scan_json="{\"roots\":$(keyseal_json_list ${KEYSEAL_ROOTS[@]+"${KEYSEAL_ROOTS[@]}"}),\"roots_skipped\":$KEYSEAL_ROOTS_SKIPPED_JSON,$scan_meta}"
|
|
426
|
+
fi
|
|
427
|
+
|
|
428
|
+
# Nothing committed is 2 by the provenance table: there is no unit, agent or chain to judge.
|
|
429
|
+
hard=(committed chain units agent scan)
|
|
430
|
+
[[ "${exit2_i[*]-}" == *nothing_committed* ]] && hard=(committed scan)
|
|
431
|
+
# A scan that was not judged (no valid cache under `only`, or the deadline) is 2, never 1.
|
|
432
|
+
if [[ $scan_judged == no ]]; then
|
|
433
|
+
judged=()
|
|
434
|
+
for c in "${hard[@]}"; do [[ $c == scan ]] || judged+=("$c"); done
|
|
435
|
+
hard=("${judged[@]}")
|
|
436
|
+
fi
|
|
437
|
+
soft=no
|
|
438
|
+
for r in "${exit2_i[@]}"; do
|
|
439
|
+
case $r in
|
|
440
|
+
undeterminable) soft=yes ;;
|
|
441
|
+
capability_error | capability_incapable) [[ $mode == sealed ]] && soft=yes ;;
|
|
442
|
+
capability_incapable-for-keyslot) [[ $mode == sealed && $round_trip != equal ]] && soft=yes ;;
|
|
443
|
+
esac
|
|
444
|
+
done
|
|
445
|
+
if [[ $soft == yes ]]; then
|
|
446
|
+
still_hard=()
|
|
447
|
+
for c in "${hard[@]}"; do
|
|
448
|
+
case $c in
|
|
449
|
+
agent) [[ ${A_OK_AGENT[i]} == true || ${A_AGENT_EMPTY[i]} == yes ]] || still_hard+=(agent) ;;
|
|
450
|
+
units)
|
|
451
|
+
[[ ${A_OK_UNITS[i]} == true ]] ||
|
|
452
|
+
{ [[ $(state is-enabled "$base_unit") == enabled && $(state is-enabled "$load_unit") == enabled ]] || still_hard+=(units); }
|
|
453
|
+
;;
|
|
454
|
+
*) still_hard+=("$c") ;;
|
|
455
|
+
esac
|
|
456
|
+
done
|
|
457
|
+
hard=("${still_hard[@]}")
|
|
458
|
+
fi
|
|
459
|
+
rc=0
|
|
312
460
|
for c in "${hard[@]}"; do
|
|
313
461
|
case $c in
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
*) still_hard+=("$c") ;;
|
|
462
|
+
committed) v=${A_OK_COMMITTED[i]} ;;
|
|
463
|
+
chain) v=${A_OK_CHAIN[i]} ;;
|
|
464
|
+
units) v=${A_OK_UNITS[i]} ;;
|
|
465
|
+
agent) v=${A_OK_AGENT[i]} ;;
|
|
466
|
+
scan) v=$ok_scan ;;
|
|
320
467
|
esac
|
|
468
|
+
[[ $v == true ]] || rc=1
|
|
321
469
|
done
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
rc=
|
|
325
|
-
for c in "${hard[@]}"; do [[ ${ok[$c]} == true ]] || rc=1; done
|
|
326
|
-
if ((rc == 0 && ${#exit2[@]})); then rc=2; fi
|
|
470
|
+
if ((rc == 0 && ${#exit2_i[@]})); then rc=2; fi
|
|
471
|
+
((rc == 1)) && saw1=yes
|
|
472
|
+
((rc == 2)) && saw2=yes
|
|
327
473
|
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
reasons=
|
|
331
|
-
for r in "${
|
|
332
|
-
|
|
333
|
-
[[ $
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
474
|
+
outdated_i=no
|
|
475
|
+
[[ "${exit2_i[*]-}" == *loader_outdated* ]] && outdated_i=yes
|
|
476
|
+
reasons=
|
|
477
|
+
for r in "${exit2_i[@]}"; do reasons+="${reasons:+,}$(keyseal_json_str "$r")"; done
|
|
478
|
+
|
|
479
|
+
if [[ $json == yes ]]; then
|
|
480
|
+
checks=
|
|
481
|
+
for c in committed chain units agent linger scan; do
|
|
482
|
+
case $c in
|
|
483
|
+
committed) cok=${A_OK_COMMITTED[i]} cdet=${A_DET_COMMITTED[i]} ;;
|
|
484
|
+
chain) cok=${A_OK_CHAIN[i]} cdet=${A_DET_CHAIN[i]} ;;
|
|
485
|
+
units) cok=${A_OK_UNITS[i]} cdet=${A_DET_UNITS[i]} ;;
|
|
486
|
+
agent) cok=${A_OK_AGENT[i]} cdet=${A_DET_AGENT[i]} ;;
|
|
487
|
+
linger) cok=$ok_linger cdet=$detail_linger ;;
|
|
488
|
+
scan) cok=$ok_scan cdet=$detail_scan ;;
|
|
489
|
+
esac
|
|
490
|
+
checks+="${checks:+,}\"$c\":{\"ok\":$cok,\"detail\":$(keyseal_json_str "$cdet")}"
|
|
491
|
+
done
|
|
492
|
+
printf '{"tool":"status","seam":%s,"host":%s,"uid":%s,"machine_id":%s,"harness":%s,"slot":%s,"mode":%s,"boot_id":%s,"pin_sha256":%s,"blob_sha256":%s,"capability_probe_exit":%s,"probe_outcome":%s,"optin":%s,"loader":{"recorded_sha256":%s,"running_sha256":%s,"state":%s},"upgrade_available":%s,"loader_outdated":%s,"legacy_loader_present":%s,"exit2_reasons":[%s],"checks":{%s},"scan":%s,"exit":%s}\n' \
|
|
493
|
+
"$seam_j" "$host_j" "$uid_j" "$machine_id_j" \
|
|
494
|
+
"$(keyseal_json_str "$harness")" "$(keyseal_json_str "$slot")" "$(keyseal_json_str "$mode")" \
|
|
495
|
+
"$boot_id_j" "${A_PINSHA_J[i]}" "${A_BLOBSHA_J[i]}" "$probe_rc" "$(keyseal_json_str "$outcome")" "${A_OPTIN_J[i]}" \
|
|
496
|
+
"$(str_or_null "${A_LOADER_REC[i]}")" "$(str_or_null "${A_LOADER_RUN[i]}")" \
|
|
497
|
+
"$(keyseal_json_str "$([[ ${A_CHAIN_LEGACY[i]} == yes ]] && echo legacy || echo "${A_LOADER_STATE[i]}")")" \
|
|
498
|
+
"$(bool "${A_UPGRADE[i]}")" "$(bool "$outdated_i")" "$(bool "${A_LEGACY[i]}")" "$reasons" "$checks" "$scan_json" "$rc"
|
|
499
|
+
else
|
|
500
|
+
for c in committed chain units agent linger scan; do
|
|
501
|
+
case $c in
|
|
502
|
+
committed) cok=${A_OK_COMMITTED[i]} cdet=${A_DET_COMMITTED[i]} ;;
|
|
503
|
+
chain) cok=${A_OK_CHAIN[i]} cdet=${A_DET_CHAIN[i]} ;;
|
|
504
|
+
units) cok=${A_OK_UNITS[i]} cdet=${A_DET_UNITS[i]} ;;
|
|
505
|
+
agent) cok=${A_OK_AGENT[i]} cdet=${A_DET_AGENT[i]} ;;
|
|
506
|
+
linger) cok=$ok_linger cdet=$detail_linger ;;
|
|
507
|
+
scan) cok=$ok_scan cdet=$detail_scan ;;
|
|
508
|
+
esac
|
|
509
|
+
printf '%-9s %s %s\n' "$c" "$([[ $cok == true ]] && echo ok || echo FAIL)" "$cdet"
|
|
510
|
+
done
|
|
511
|
+
printf 'mode %s\n' "$mode"
|
|
512
|
+
((${#exit2_i[@]})) && printf 'exit 2 %s\n' "${exit2_i[*]}"
|
|
513
|
+
printf 'status: exit %s (seam=%s)\n' "$rc" "$seam_j"
|
|
514
|
+
fi
|
|
515
|
+
done
|
|
516
|
+
|
|
517
|
+
if [[ $saw1 == yes ]]; then exit 1
|
|
518
|
+
elif [[ $saw2 == yes ]]; then exit 2
|
|
519
|
+
else exit 0
|
|
354
520
|
fi
|
|
355
|
-
exit "$rc"
|