# Read results and save reports Wait for completion, inspect the native exit code, and download the files you need. ## 1. Follow a run Set `RUN_ID` to the ID returned by submission. Use the first example to print events as the run progresses. Save `next_cursor` after each page and pass it as `after` on the next request so you do not repeat events. ## 2. Check the terminal result Read `state`, `result.exit_code` and `cleanup_status`. A successful invocation does not mean “no vulnerabilities”: the tool’s report says what it found. If the run is `outcome_unknown`, review retained output before deciding whether to run it again. ## 3. Download outputs The second example saves the returned files under `results/RUN_ID` and verifies their SHA-256 values. To get a tool-generated report, request its path in `invocation.outputs` when submitting the run. Stdout and stderr are returned separately. ## 4. Check for incomplete output Inspect `stdout_truncated`, `stderr_truncated`, `outputs_truncated` and `output_errors`. If a report is too large, narrow the tool’s output or request fewer files and run it again. Events show command progress and captured output. For process, file or kernel-event collection, use an explicit [Sysmon](https://www.security.run/docs/tool-sysmon.html) or [Tetragon](https://www.security.run/docs/tool-tetragon.html) run. Those events are not automatically collected by every tool. ## Follow a run ```python import os import httpx api = httpx.Client( base_url=os.environ["SECURITY_RUN_URL"].rstrip("/"), headers={"Authorization": "Bearer " + os.environ["SECURITY_RUN_API_KEY"]}, timeout=30, ) import time run_id = os.environ["RUN_ID"] cursor = 0 terminal = {"succeeded", "failed", "timed_out", "cancelled", "outcome_unknown"} while True: response = api.get(f"/v1/tool-runs/{run_id}/events", params={"after": cursor, "limit": 100}) response.raise_for_status() page = response.json() for event in page["events"]: print(event["kind"], event["data"]) cursor = page["next_cursor"] response = api.get(f"/v1/tool-runs/{run_id}") response.raise_for_status() if response.json()["state"] in terminal and not page["events"]: break time.sleep(0.5) ``` ## Save and verify outputs ```python import os import httpx api = httpx.Client( base_url=os.environ["SECURITY_RUN_URL"].rstrip("/"), headers={"Authorization": "Bearer " + os.environ["SECURITY_RUN_API_KEY"]}, timeout=30, ) import hashlib from pathlib import Path run_id = os.environ["RUN_ID"] response = api.get(f"/v1/tool-runs/{run_id}") response.raise_for_status() run = response.json() print("State:", run["state"]) print("Cleanup:", run["cleanup_status"]) print("Exit code:", (run.get("result") or {}).get("exit_code")) folder = Path("results") / run_id folder.mkdir(parents=True, exist_ok=True) for output in run["outputs"]: response = api.get(output["download_url"]) response.raise_for_status() data = response.content assert hashlib.sha256(data).hexdigest() == output["sha256"] path = folder / Path(output["name"]).name path.write_bytes(data) print(path) ```