sysgraph 0.0.11__tar.gz

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.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Eugene Gubenkov
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,7 @@
1
+ # Include the Vite build output
2
+ recursive-include src/sysgraph/dist *
3
+
4
+ # Include top-level files
5
+ include LICENSE
6
+ include README.md
7
+ include pyproject.toml
@@ -0,0 +1,111 @@
1
+ Metadata-Version: 2.4
2
+ Name: sysgraph
3
+ Version: 0.0.11
4
+ Summary: Visualizer for processes and their interconnections
5
+ Home-page: https://github.com/gubenkoved/sysgraph
6
+ Author: Eugene Gubenkov
7
+ Author-email: gubenkoved@gmail.com
8
+ License: MIT
9
+ Project-URL: Source, https://github.com/gubenkoved/sysgraph
10
+ Project-URL: Issues, https://github.com/gubenkoved/sysgraph/issues
11
+ Keywords: process,visualization,graph,ipc,system,monitoring,linux,procfs
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3.12
14
+ Classifier: Programming Language :: Python :: 3.13
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Operating System :: POSIX :: Linux
17
+ Classifier: Topic :: System :: Monitoring
18
+ Classifier: Topic :: System :: Systems Administration
19
+ Classifier: Environment :: Web Environment
20
+ Classifier: Framework :: FastAPI
21
+ Classifier: Intended Audience :: Developers
22
+ Classifier: Intended Audience :: System Administrators
23
+ Requires-Python: >=3.12
24
+ Description-Content-Type: text/markdown
25
+ License-File: LICENSE
26
+ Requires-Dist: psutil
27
+ Requires-Dist: coloredlogs
28
+ Requires-Dist: fastapi>=0.95
29
+ Requires-Dist: uvicorn[standard]>=0.20
30
+ Dynamic: author
31
+ Dynamic: author-email
32
+ Dynamic: classifier
33
+ Dynamic: description
34
+ Dynamic: description-content-type
35
+ Dynamic: home-page
36
+ Dynamic: keywords
37
+ Dynamic: license
38
+ Dynamic: license-file
39
+ Dynamic: project-url
40
+ Dynamic: requires-dist
41
+ Dynamic: requires-python
42
+ Dynamic: summary
43
+
44
+ # sysgraph
45
+
46
+ Real-time process-graph visualizer that discovers running OS processes, their inter-process communication channels (pipes, Unix domain sockets, TCP/UDP network connections), and renders them as an interactive force-directed graph in the browser.
47
+
48
+ ![Python](https://img.shields.io/badge/python-%3E%3D3.12-blue)
49
+ ![License](https://img.shields.io/badge/license-MIT-green)
50
+
51
+ ## Features
52
+
53
+ - **Process discovery** — enumerates all running OS processes and their parent-child relationships
54
+ - **IPC visualization** — discovers pipes, Unix domain sockets, and TCP/UDP connections between processes
55
+ - **Interactive graph** — force-directed graph rendered in the browser with zoom, pan, drag, and search
56
+ - **Real-time** — fetch the latest process graph on demand via the web UI
57
+ - **Fuzzy search** — find processes by name, PID, command line, or any property
58
+ - **Adjacency filtering** — right-click a node to show only its neighbors
59
+ - **Configurable** — tune d3 force parameters, colors, and filters via the settings panel
60
+ - **Export/Import** — save and load graph snapshots as JSON
61
+
62
+ ## Requirements
63
+
64
+ - **Linux** (relies on `/proc` filesystem and the `ss` command)
65
+ - **Python ≥ 3.12**
66
+ - Root/sudo recommended for full visibility into all processes
67
+
68
+ ## Installation
69
+
70
+ ```bash
71
+ pip install sysgraph
72
+ ```
73
+
74
+ ## Usage
75
+
76
+ ```bash
77
+ # Start the web server (default: http://localhost:8000)
78
+ sysgraph
79
+
80
+ # Specify a custom port
81
+ sysgraph --port 9000
82
+
83
+ # Or run as a module
84
+ python -m sysgraph
85
+ ```
86
+
87
+ Open your browser to the displayed URL to see the interactive process graph.
88
+
89
+ For full visibility into all processes and their connections, run with elevated privileges:
90
+
91
+ ```bash
92
+ sudo sysgraph
93
+ ```
94
+
95
+ ## Docker
96
+
97
+ ```bash
98
+ docker run --rm -it --pid=host --net=host gubenkoved/sysgraph
99
+ ```
100
+
101
+ The `--pid=host` and `--net=host` flags allow the container to see host processes and network connections.
102
+
103
+ ## How It Works
104
+
105
+ 1. The **FastAPI backend** uses `psutil` and Linux-specific APIs (`/proc`, `ss`) to discover processes, pipes, Unix domain sockets, and network connections.
106
+ 2. It builds a graph of processes (nodes) and their IPC channels (edges).
107
+ 3. The **browser frontend** fetches the graph via `GET /api/graph` and renders it using [force-graph](https://github.com/vasturiano/force-graph) with d3 physics simulation.
108
+
109
+ ## License
110
+
111
+ [MIT](LICENSE)
@@ -0,0 +1,68 @@
1
+ # sysgraph
2
+
3
+ Real-time process-graph visualizer that discovers running OS processes, their inter-process communication channels (pipes, Unix domain sockets, TCP/UDP network connections), and renders them as an interactive force-directed graph in the browser.
4
+
5
+ ![Python](https://img.shields.io/badge/python-%3E%3D3.12-blue)
6
+ ![License](https://img.shields.io/badge/license-MIT-green)
7
+
8
+ ## Features
9
+
10
+ - **Process discovery** — enumerates all running OS processes and their parent-child relationships
11
+ - **IPC visualization** — discovers pipes, Unix domain sockets, and TCP/UDP connections between processes
12
+ - **Interactive graph** — force-directed graph rendered in the browser with zoom, pan, drag, and search
13
+ - **Real-time** — fetch the latest process graph on demand via the web UI
14
+ - **Fuzzy search** — find processes by name, PID, command line, or any property
15
+ - **Adjacency filtering** — right-click a node to show only its neighbors
16
+ - **Configurable** — tune d3 force parameters, colors, and filters via the settings panel
17
+ - **Export/Import** — save and load graph snapshots as JSON
18
+
19
+ ## Requirements
20
+
21
+ - **Linux** (relies on `/proc` filesystem and the `ss` command)
22
+ - **Python ≥ 3.12**
23
+ - Root/sudo recommended for full visibility into all processes
24
+
25
+ ## Installation
26
+
27
+ ```bash
28
+ pip install sysgraph
29
+ ```
30
+
31
+ ## Usage
32
+
33
+ ```bash
34
+ # Start the web server (default: http://localhost:8000)
35
+ sysgraph
36
+
37
+ # Specify a custom port
38
+ sysgraph --port 9000
39
+
40
+ # Or run as a module
41
+ python -m sysgraph
42
+ ```
43
+
44
+ Open your browser to the displayed URL to see the interactive process graph.
45
+
46
+ For full visibility into all processes and their connections, run with elevated privileges:
47
+
48
+ ```bash
49
+ sudo sysgraph
50
+ ```
51
+
52
+ ## Docker
53
+
54
+ ```bash
55
+ docker run --rm -it --pid=host --net=host gubenkoved/sysgraph
56
+ ```
57
+
58
+ The `--pid=host` and `--net=host` flags allow the container to see host processes and network connections.
59
+
60
+ ## How It Works
61
+
62
+ 1. The **FastAPI backend** uses `psutil` and Linux-specific APIs (`/proc`, `ss`) to discover processes, pipes, Unix domain sockets, and network connections.
63
+ 2. It builds a graph of processes (nodes) and their IPC channels (edges).
64
+ 3. The **browser frontend** fetches the graph via `GET /api/graph` and renders it using [force-graph](https://github.com/vasturiano/force-graph) with d3 physics simulation.
65
+
66
+ ## License
67
+
68
+ [MIT](LICENSE)
@@ -0,0 +1,19 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68.0", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [tool.ruff]
6
+ line-length = 79
7
+ target-version = "py312"
8
+ # Tune ruff rules as needed. Ruff supports many checks and can also format (`ruff format`).
9
+ # See https://beta.ruff.rs/docs/configuration/ for config options.
10
+ exclude = [".venv", "build", "dist", "__pycache__"]
11
+
12
+ [tool.isort]
13
+ profile = "black"
14
+ multi_line_output = 3
15
+ include_trailing_comma = true
16
+ force_grid_wrap = 0
17
+ use_parentheses = true
18
+ ensure_newline_before_comments = true
19
+ line_length = 88
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,91 @@
1
+ #!/usr/bin/env python
2
+ """A minimal, editable `setup.py` for the project.
3
+
4
+ This file uses a modern setuptools pattern with a `src/` layout.
5
+ Edit metadata (author, email, description, classifiers, dependencies) as needed.
6
+ """
7
+ from pathlib import Path
8
+
9
+ from setuptools import find_packages, setup
10
+
11
+ HERE = Path(__file__).parent
12
+
13
+ # Read long description from README if available
14
+ README = (HERE / "README.md").read_text(encoding="utf-8") if (HERE / "README.md").exists() else ""
15
+
16
+ # Try to read __version__ from package if present, otherwise fall back to 0.0.0
17
+ def read_version():
18
+ version_file = HERE / "src" / "sysgraph" / "__init__.py"
19
+ if version_file.exists():
20
+ for line in version_file.read_text(encoding="utf-8").splitlines():
21
+ if line.strip().startswith("__version__"):
22
+ # supports formats: __version__ = '0.1.0' or "0.1.0"
23
+ delim = '"' if '"' in line else "'"
24
+ return line.split(delim)[1]
25
+ return "0.0.0"
26
+
27
+ # Find packages in src/ (handles ordinary packages). If none found, try namespace packages.
28
+ packages = find_packages(where="src")
29
+ if not packages:
30
+ try:
31
+ from setuptools import find_namespace_packages
32
+
33
+ packages = find_namespace_packages(where="src")
34
+ except Exception:
35
+ packages = []
36
+
37
+ setup(
38
+ name="sysgraph",
39
+ version=read_version(),
40
+ description="Visualizer for processes and their interconnections",
41
+ long_description=README,
42
+ long_description_content_type="text/markdown",
43
+ author="Eugene Gubenkov",
44
+ author_email="gubenkoved@gmail.com",
45
+ url="https://github.com/gubenkoved/sysgraph",
46
+ packages=packages,
47
+ package_dir={"": "src"},
48
+ include_package_data=True,
49
+ package_data={"sysgraph": ["dist/*", "dist/**/*"]},
50
+ zip_safe=False,
51
+ python_requires=">=3.12",
52
+ install_requires=[
53
+ "psutil",
54
+ "coloredlogs",
55
+ "fastapi>=0.95",
56
+ "uvicorn[standard]>=0.20",
57
+ ],
58
+ classifiers=[
59
+ "Programming Language :: Python :: 3",
60
+ "Programming Language :: Python :: 3.12",
61
+ "Programming Language :: Python :: 3.13",
62
+ "License :: OSI Approved :: MIT License",
63
+ "Operating System :: POSIX :: Linux",
64
+ "Topic :: System :: Monitoring",
65
+ "Topic :: System :: Systems Administration",
66
+ "Environment :: Web Environment",
67
+ "Framework :: FastAPI",
68
+ "Intended Audience :: Developers",
69
+ "Intended Audience :: System Administrators",
70
+ ],
71
+ keywords=[
72
+ "process",
73
+ "visualization",
74
+ "graph",
75
+ "ipc",
76
+ "system",
77
+ "monitoring",
78
+ "linux",
79
+ "procfs",
80
+ ],
81
+ entry_points={
82
+ "console_scripts": [
83
+ "sysgraph=sysgraph.app:main",
84
+ ],
85
+ },
86
+ license="MIT",
87
+ project_urls={
88
+ "Source": "https://github.com/gubenkoved/sysgraph",
89
+ "Issues": "https://github.com/gubenkoved/sysgraph/issues",
90
+ },
91
+ )
@@ -0,0 +1 @@
1
+ __version__ = "0.0.11"
@@ -0,0 +1,3 @@
1
+ from sysgraph.app import main
2
+
3
+ main()
@@ -0,0 +1,134 @@
1
+ #!/usr/bin/env python3
2
+
3
+ import logging
4
+ import os
5
+ from contextlib import asynccontextmanager
6
+ from pathlib import Path
7
+ from typing import Any
8
+
9
+ import coloredlogs
10
+ from fastapi import FastAPI
11
+ from fastapi.middleware.gzip import GZipMiddleware
12
+ from fastapi.responses import FileResponse
13
+ from fastapi.staticfiles import StaticFiles
14
+ from pydantic import BaseModel
15
+
16
+ from sysgraph.discovery import build_graph
17
+
18
+ LOGGER = logging.getLogger(__name__)
19
+
20
+
21
+ @asynccontextmanager
22
+ async def lifespan(app):
23
+ coloredlogs.install()
24
+ logging.info(f"init for process with PID {os.getpid()}")
25
+ yield
26
+ logging.info(f"shutdown for process with PID {os.getpid()}")
27
+
28
+
29
+ app = FastAPI(title="sysgraph API", version="0.1.0", lifespan=lifespan)
30
+ app.add_middleware(GZipMiddleware, minimum_size=500)
31
+
32
+ # Vite build output — run scripts/build-ui.sh to produce it.
33
+ _dist_dir = Path(__file__).parent / "dist"
34
+
35
+ if not _dist_dir.is_dir():
36
+ LOGGER.warning(
37
+ "dist/ not found — frontend will not be served. "
38
+ "Run scripts/build-ui.sh to produce a production build."
39
+ )
40
+
41
+
42
+ # Root route serves the SPA index — defined before the catch-all mount.
43
+ @app.get("/", include_in_schema=False)
44
+ def index():
45
+ index_path = _dist_dir / "index.html"
46
+ return FileResponse(index_path)
47
+
48
+
49
+ class GraphNodeSchema(BaseModel):
50
+ id: str
51
+ type: str
52
+ properties: dict[str, Any]
53
+
54
+
55
+ class GraphEdgeSchema(BaseModel):
56
+ id: str
57
+ source_id: str
58
+ target_id: str
59
+ type: str
60
+ properties: dict[str, Any]
61
+
62
+
63
+ class GraphSchema(BaseModel):
64
+ nodes: list[GraphNodeSchema]
65
+ edges: list[GraphEdgeSchema]
66
+
67
+
68
+ @app.get("/api/health")
69
+ def health():
70
+ return {"status": "ok"}
71
+
72
+
73
+ @app.get("/api/graph", response_model=GraphSchema)
74
+ def get_graph() -> GraphSchema:
75
+ graph = build_graph()
76
+ graph_dict = graph.as_dict()
77
+
78
+ LOGGER.debug(graph_dict)
79
+
80
+ return GraphSchema(
81
+ nodes=[
82
+ GraphNodeSchema(
83
+ id=node["id"], type=node["type"], properties=node["properties"]
84
+ )
85
+ for node in graph_dict["nodes"]
86
+ ],
87
+ edges=[
88
+ GraphEdgeSchema(
89
+ id=edge["id"],
90
+ source_id=edge["source_id"],
91
+ target_id=edge["target_id"],
92
+ type=edge["type"],
93
+ properties=edge["properties"],
94
+ )
95
+ for edge in graph_dict["edges"]
96
+ ],
97
+ )
98
+
99
+
100
+ # Serve built assets (JS/CSS bundles, Shoelace icons, etc.) from the same
101
+ # directory that provides index.html. This catch-all mount MUST come after
102
+ # all explicit routes so that /api/* and / are matched first.
103
+ if _dist_dir.is_dir():
104
+ app.mount(
105
+ "/", StaticFiles(directory=str(_dist_dir)), name="static"
106
+ )
107
+
108
+
109
+ def main():
110
+ import argparse
111
+
112
+ import uvicorn
113
+
114
+ parser = argparse.ArgumentParser(description="sysgraph server")
115
+ parser.add_argument(
116
+ "-p",
117
+ "--port",
118
+ type=int,
119
+ default=int(os.environ.get("PORT", 8000)),
120
+ help="port to listen on (default: 8000, or PORT env var)",
121
+ )
122
+ args = parser.parse_args()
123
+
124
+ uvicorn.run(
125
+ "sysgraph.app:app",
126
+ host="0.0.0.0",
127
+ port=args.port,
128
+ reload=True,
129
+ log_level="info",
130
+ )
131
+
132
+
133
+ if __name__ == "__main__":
134
+ main()