|
51 | 51 | cat >"$stub_bin/systemctl" <<'STUB' |
52 | 52 | #!/bin/bash |
53 | 53 | printf 'systemctl <%s>\n' "$*" >>"$CALLS" |
54 | | -if [[ $* == "is-enabled --quiet usbguard.service" ]]; then |
| 54 | +if [[ $* == "show usbguard.service --property=InvocationID --value" ]]; then |
| 55 | + printf '%s\n' "${TEST_DAEMON_INVOCATION:-11111111111111111111111111111111}" |
| 56 | +elif [[ $* == "is-enabled --quiet usbguard.service" ]]; then |
55 | 57 | exit 1 |
56 | 58 | fi |
57 | 59 | STUB |
@@ -97,6 +99,9 @@ list-rules) |
97 | 99 | printf 'usbguard' >>"$CALLS" |
98 | 100 | printf ' <%s>' "$@" >>"$CALLS" |
99 | 101 | printf '\n' >>"$CALLS" |
| 102 | + if [[ $1 == "watch" && -n ${TEST_WATCH_ID_FILE:-} ]]; then |
| 103 | + printf '%s\n' "$OMARCHY_USB_AUTHORIZATION_WATCH_ID" >"$TEST_WATCH_ID_FILE" |
| 104 | + fi |
100 | 105 | if [[ $1 == "allow-device" && ${!#} == block* ]]; then |
101 | 106 | [[ ${APPROVAL_EXIT_FAIL:-0} == 0 ]] || exit 1 |
102 | 107 | if [[ ${APPROVAL_SILENT_FAIL:-0} == 0 ]]; then |
@@ -506,6 +511,63 @@ wait "$scan_pid" |
506 | 511 | fail "overlapping scan and policy events must not duplicate pending prompts" |
507 | 512 | pass "USB reconnect scans and policy events deduplicate pending requests" |
508 | 513 |
|
| 514 | +# Dismissing/canceling a notification leaves its request, even after the shell |
| 515 | +# discards the archived action. Reusing the ID after daemon restart must prompt. |
| 516 | +notification_count=$(grep -c '^notification' "$calls") |
| 517 | +export TEST_DAEMON_INVOCATION=22222222222222222222222222222222 |
| 518 | +USBGUARD_IPC_SIGNAL=IPC.Connected "$ROOT/bin/omarchy-usb-authorization-event" & |
| 519 | +scan_pid=$! |
| 520 | +USBGUARD_IPC_SIGNAL=Device.PolicyApplied \ |
| 521 | + USBGUARD_DEVICE_ID=17 \ |
| 522 | + USBGUARD_DEVICE_TARGET_NEW=block \ |
| 523 | + USBGUARD_DEVICE_RULE="$malicious_rule" \ |
| 524 | + "$ROOT/bin/omarchy-usb-authorization-event" |
| 525 | +wait "$scan_pid" |
| 526 | +[[ $(grep -c '^notification' "$calls") == $((notification_count + 1)) ]] || |
| 527 | + fail "reused IDs must get exactly one new notification after daemon restart" |
| 528 | +[[ -f $request ]] || fail "the recovered notification must have a reviewable request" |
| 529 | + |
| 530 | +# Starting another watcher/session also expires old notification deduplication. |
| 531 | +notification_count=$(grep -c '^notification' "$calls") |
| 532 | +export OMARCHY_USB_AUTHORIZATION_WATCH_ID=new-session |
| 533 | +USBGUARD_IPC_SIGNAL=IPC.Connected "$ROOT/bin/omarchy-usb-authorization-event" |
| 534 | +[[ $(grep -c '^notification' "$calls") == $((notification_count + 1)) ]] || |
| 535 | + fail "a new watcher must recover an orphaned approval action" |
| 536 | +USBGUARD_IPC_SIGNAL=IPC.Connected "$ROOT/bin/omarchy-usb-authorization-event" |
| 537 | +[[ $(grep -c '^notification' "$calls") == $((notification_count + 1)) ]] || |
| 538 | + fail "same-generation scans must still deduplicate" |
| 539 | + |
| 540 | +# A removal that arrives late must not erase a new connection's request. |
| 541 | +USBGUARD_IPC_SIGNAL=Device.PresenceChanged USBGUARD_DEVICE_EVENT=Remove \ |
| 542 | + USBGUARD_DEVICE_ID=17 USBGUARD_DEVICE_RULE="$malicious_rule" \ |
| 543 | + "$ROOT/bin/omarchy-usb-authorization-event" |
| 544 | +[[ -f $request ]] || fail "delayed removal must preserve a currently blocked device's request" |
| 545 | +BLOCKED_DEVICE_PRESENT=0 \ |
| 546 | + USBGUARD_IPC_SIGNAL=Device.PresenceChanged USBGUARD_DEVICE_EVENT=Remove \ |
| 547 | + USBGUARD_DEVICE_ID=17 USBGUARD_DEVICE_RULE="${malicious_rule/#block/allow}" \ |
| 548 | + "$ROOT/bin/omarchy-usb-authorization-event" |
| 549 | +[[ ! -e $request ]] || fail "device removal must clean up its pending request" |
| 550 | +USBGUARD_IPC_SIGNAL=IPC.Connected "$ROOT/bin/omarchy-usb-authorization-event" |
| 551 | +[[ $(grep -c '^notification' "$calls") == $((notification_count + 2)) ]] || |
| 552 | + fail "a reappeared device must receive a fresh notification" |
| 553 | + |
| 554 | +# Upgrade from requests written before generations existed, and remove stale |
| 555 | +# requests for devices no longer in the inventory. |
| 556 | +jq 'del(.generation)' "$request" >"$scratch/legacy-request" |
| 557 | +mv "$scratch/legacy-request" "$request" |
| 558 | +legacy_orphan="${request%/*}/request-$(printf '%064d' 0).json" |
| 559 | +printf '{"id":"99","rule":"block id 0000:0000"}\n' >"$legacy_orphan" |
| 560 | +USBGUARD_IPC_SIGNAL=IPC.Connected "$ROOT/bin/omarchy-usb-authorization-event" |
| 561 | +[[ $(grep -c '^notification' "$calls") == $((notification_count + 3)) ]] || |
| 562 | + fail "legacy request markers must not suppress notification recovery" |
| 563 | +[[ ! -e $legacy_orphan ]] || fail "reconnect must clean up old-generation orphan requests" |
| 564 | + |
| 565 | +TEST_WATCH_ID_FILE="$scratch/watch-one" "$ROOT/bin/omarchy-usb-authorization-watch" |
| 566 | +TEST_WATCH_ID_FILE="$scratch/watch-two" "$ROOT/bin/omarchy-usb-authorization-watch" |
| 567 | +[[ -s $scratch/watch-one && $(<"$scratch/watch-one") != "$(<"$scratch/watch-two")" ]] || |
| 568 | + fail "each watcher must export a fresh lifetime identifier" |
| 569 | +pass "USB prompts recover across daemon and session generations and device removal" |
| 570 | + |
509 | 571 | GUM_CHOICE='Allow once' "$ROOT/bin/omarchy-usb-authorization-review" "$token" >"$scratch/review-once-output" |
510 | 572 | grep -Fqx "usbguard <allow-device> <$malicious_rule>" "$calls" || fail "review can allow the exact device once" |
511 | 573 | [[ ! -e $request ]] || fail "a completed review consumes its request" |
|
0 commit comments