feat: stream CLI log transcripts and run status to Socket backend#201
Draft
Benjamin Barslev Nielsen (barslev) wants to merge 4 commits into
Draft
feat: stream CLI log transcripts and run status to Socket backend#201Benjamin Barslev Nielsen (barslev) wants to merge 4 commits into
Benjamin Barslev Nielsen (barslev) wants to merge 4 commits into
Conversation
Buffer the CLI's own log records and POST them in 5s batches to a new register/upload/finalize lifecycle so the admin dashboard renders what the user saw in their terminal alongside the run's terminal status. New modules: - core/cli_run.py — register_cli_run / finalize_cli_run helpers - core/log_uploader.py — BatchedLogUploader (daemon-thread flusher, chunked under the 256KB cap, swallows network errors, drains on shutdown) and UploadingLogHandler routing log records to it - core/streaming.py — setup_streaming() wires both into the socketcli and socketdev loggers, forces them to DEBUG so uploads capture the full history regardless of local terminal verbosity, and returns a teardown callable for the caller to register with atexit - set_run_status() propagates the terminal status through the teardown; socketcli.py exception handlers call it for KeyboardInterrupt (cancelled), uncaught Exception (failure), and any SystemExit with a non-zero code (failure) so sys.exit() paths inside main_code surface correctly instead of defaulting to success Best-effort end-to-end: registration failures fall back to no-streaming and never block the scan. Opt out with --disable-server-log-streaming. Tested against local depscan with the matching /v0/python-cli-runs/* endpoints; 173 unit tests pass.
|
❌ Version Check Failed Please increment... |
|
🚀 Preview package published! Install with: pip install --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple socketsecurity==2.2.86.dev10Docker image: |
The 256 KB ceiling I added speculatively when the server cap was 256 KB no longer matches the reference implementation we're mirroring, which sends each flush as a single POST regardless of size. With the server cap now well above any plausible single-flush volume, chunking is unnecessary and divergent — drop it. Removes _chunk_by_size, _MAX_BATCH_BYTES, and the four chunking tests. _flush now POSTs the entire buffered batch as one request.
The server-side handler now rejects unknown fields and the integration column has been removed from the schema (it was plumbed end-to-end but never displayed, filtered, or grouped on). Stop sending it. Removes the integration parameter from register_cli_run and setup_streaming, drops the corresponding wiring in socketcli.py, and prunes the now-pointless test_register_cli_run_omits_integration_when_falsy case.
The depscan side now joins cli_run → full_scans → repositories via the report_run_id field to surface the scanned repo in the admin dashboard view of each CLI run. Wire the CLI to send the full_scan_id (== the report_run_id depscan expects) when it has one. - finalize_cli_run accepts an optional report_run_id and includes it (nullable) in the POST body. - streaming.py adds a module-level _report_run_id holder and a set_report_run_id() setter; teardown passes it through to finalize. - socketcli.py captures diff.id at a single chokepoint after the diff-producing branches converge, guarded against the NO_DIFF_RAN / NO_SCAN_RAN sentinel values. The field is nullable end-to-end so CLI invocations that fail before producing a diff (or are run in modes that don't create one) still finalize cleanly.
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.
Adds a streaming log channel between the Python CLI and the Socket
backend so the CLI run's terminal status (
in_progress/success/failure/cancelled) and a transcript of its own log output arevisible in the Socket admin views.
Why?
The Socket backend currently has no visibility into what happens
inside a CLI invocation — there's no record of whether a scan ran
to completion or what was logged along the way. This PR opens a
bounded, opt-out side-channel that uploads the CLI's own log
records to the backend and reports the run's terminal status,
without changing any existing CLI request on the wire.
Changes
New modules
socketsecurity/core/cli_run.py—register_cli_run/finalize_cli_runlifecycle helpers, both best-effort.socketsecurity/core/log_uploader.py—BatchedLogUploader(daemon-thread flusher, 5s flush interval, single-batch
size-chunked under a 256 KB request cap, swallows all network
errors and drops batches at-most-once, drains on shutdown) plus
UploadingLogHandler— alogging.Handlerthat routes recordsto the uploader. Includes a thread-local recursion guard so the
uploader's own request-error logs aren't re-enqueued mid-flush.
socketsecurity/core/streaming.py—setup_streaming()wiresthe uploader and a terminal handler into the
socketcliandsocketdevloggers, forces both loggers toDEBUGso the uploadcaptures the full history regardless of
--enable-debugstate,and returns a teardown callable for the caller to register with
atexit.set_run_status()is the module-level setter thatpropagates the terminal status into
finalize_cli_run.Existing files
socketsecurity/config.py— adds--disable-server-log-streaming/--disable_server_log_streamingopt-out flag (advanced group, default off, mirrors the existing
--disable-*flag style).socketsecurity/socketcli.py— callssetup_streaming()afterCliClientinit, registers the teardown viaatexit. Exceptionhandlers in
cli()now callset_run_status(...):KeyboardInterrupt→cancelledSystemExitwith non-zero code →failureException→failuresuccessThe
SystemExithandling is load-bearing: several failure pathsin
main_code()callsys.exit(3)directly, which bypassesexcept Exception(sinceSystemExitis aBaseExceptionsubclass, not
Exception).Test plan
uv run pytest tests/unit— 173 unit tests pass (including 39new tests across
test_cli_run.py,test_log_uploader.py,test_streaming.py)endpoints applied:
status: successRuntimeError→ run reportsstatus: failure, logcaptured up to the crash
intervals while the CLI is still running
--disable-server-log-streaming→ CLI emits no streaming-relatedrequests; scan otherwise unchanged
degrades, scan continues normally, no exception surfaces
Public Changelog
The CLI now reports a per-run status (
in_progress/success/failure/cancelled) and a transcript of its own log output to the Socket backend. The transcript is captured regardless of the local--enable-debugstate; the existing terminal verbosity is unchanged. Opt out with--disable-server-log-streaming.