Add on-demand CPU/network observation window (Phase 5-1) - #72
Merged
Conversation
New "CPU·네트워크 관찰" section on the Activity page: the owner picks a window (30s-5min) and triggers idle_cpu.sh and network_watch.sh concurrently over the same period, showing real CPU deltas and any newly-appeared connections/listening ports. Scoped this as synchronous and user-triggered rather than a scheduled background watch after investigating the existing options: schedule.sh is entirely hardcoded to one job (storage-watch's own label/plist), not a generic scheduler, so extending it would mean building new scheduling infrastructure in the most security-sensitive part of the codebase. CPU/network are also fast, bursty signals where a fixed hourly sample would almost always just catch them idle -- unlike free disk space, which changes slowly enough for that cadence to make sense. Windows' own scripts/monitor.ps1 is the existing cross-platform precedent for this shape: synchronous, foreground, user-triggered, never scheduled. New scripts/network_watch.sh mirrors idle_cpu.sh's two-sample delta pattern: identity for established connections is (process, remote host:port), ignoring the local ephemeral port, so an ordinary reconnect to an already-seen server isn't reported as "new" -- proven with a fixture and a revert/restore of the fix (it also caught the "no changes" case, not just the one it targeted). idle_cpu.sh needed no changes at all; it's invoked with a longer window than the scan's own 3s default, same script either way. Verified end-to-end in the actual signed app (built via build_macos_swift_app.sh, after #71 fixed the runtime bundle): the window picker, in-flight state, and results all render correctly, and triggering it for real over a 30s window surfaced genuine CPU usage and network connections happening on this machine during the run.
network_watch.sh checks uname -s before its PCH_TEST_MODE branch, same as idle_cpu.sh -- the injection path is unreachable on Linux, so these tests need the same skipif guard test_macos_idle_cpu.py already uses for its own analogous tests. Missed this the first time; the argument- validation test doesn't need it since that check runs before the platform gate.
4 tasks
heznpc
added a commit
that referenced
this pull request
Aug 13, 2026
…73) Two bugs in lsof output handling, both confirmed against this machine's real output rather than hypothesized: 1. lsof escapes a space inside a COMMAND name as literal "\x20" ("Codex " -> "Codex\x20") -- that escaping is what keeps whitespace field-splitting correct, but passed through verbatim it leaked into the UI: the main scan's network/listeningPorts sections (present since the JXA port, "Codex\x20"/"Manus\x20" in this machine's real scan_result.json) and network_watch.sh's rows (#72). Both now unescape it, and drop the trailing space left by lsof's 9-character truncation -- invisible in the UI while still splitting dedup keys. 2. network_watch.sh's awk used the FNR==NR idiom to separate the two samples. With an empty first sample -- a real shape, since lsof exits 1 with no output both on failure and on zero matches, and `|| true` swallows it -- FNR==NR misreads the second file as the first, so every connection made during the window was registered as "already seen" and reporting went silent. Found because the new escaping test's fixture happened to use an empty first listen sample. Replaced with POSIX inter-file variable assignment (building=1 file1 building=0 file2), which holds even for empty files; with no baseline, over-reporting is the safe direction. All three new tests proven against the pre-fix code via stash/restore. Co-authored-by: Heznpc <[email protected]>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
idle_cpu.shandnetwork_watch.shconcurrently over the same period, showing real CPU deltas and any newly-appeared connections/listening ports.storage_watch.sh/schedule.sh/idle_cpu.sh/network.shand Windows'monitor.ps1):schedule.shis entirely hardcoded to one job (storage-watch's own label/plist/wrapper) -- not a generic multi-job scheduler. Extending it to CPU/network would mean building new scheduling infrastructure in the most security-sensitive part of the codebase (launchd install, SHA-256 script pinning, owner-approval gates), for signals (CPU/network) that are fast and bursty, unlike free disk space which changes slowly enough for an hourly cadence to make sense.scripts/monitor.ps1is the existing cross-platform precedent for "CPU monitoring" in this app, and it's synchronous/foreground/user-triggered too -- confirmed via grep, no scheduling mechanism exists there either.idle_cpu.shcompletely unchanged (just a longer--windowthan the scan's own 3s default).scripts/network_watch.shmirrorsidle_cpu.sh's two-sample delta pattern. Identity for established connections is(process, remote host:port), deliberately ignoring the local ephemeral port -- an ordinary reconnect to an already-seen server assigns a new local port every time, and counting that as a "new connection" would be noise, not signal. Listening ports use the bound address:port directly since that itself is the signal.Test plan
pytest tests/-- 358 passed (incl. 5 newtest_macos_network_watch.pycases)swift test-- 157 passed (incl. 5 newObservationServiceTests)python3 scripts/release_smoke.py --check-only--{"ok": true}build_macos_swift_app.sh(after Fix build_macos_swift_app.sh silently omitting shipped scripts #71 fixed the runtime bundle, without which this couldn't have worked at all), launched it, triggered a real 30-second observation, and confirmed genuine results -- real CPU usage from processes actually running on this machine, and real new connections detected (a local loopback connection from a dev tool, an HTTPS connection to a real external endpoint), correctly rendered with the right icons and labels.Depends on
#71 (fixed the app's runtime bundle, which this PR's own scripts need to actually ship)
🤖 Generated with Claude Code