endpoint-aiops 0.1.0__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.
- endpoint_aiops-0.1.0/.gitignore +22 -0
- endpoint_aiops-0.1.0/CHANGELOG.md +45 -0
- endpoint_aiops-0.1.0/LICENSE +21 -0
- endpoint_aiops-0.1.0/PKG-INFO +108 -0
- endpoint_aiops-0.1.0/README.md +92 -0
- endpoint_aiops-0.1.0/RELEASE_NOTES.md +43 -0
- endpoint_aiops-0.1.0/SECURITY.md +75 -0
- endpoint_aiops-0.1.0/endpoint_aiops/__init__.py +9 -0
- endpoint_aiops-0.1.0/endpoint_aiops/cli/__init__.py +9 -0
- endpoint_aiops-0.1.0/endpoint_aiops/cli/_common.py +78 -0
- endpoint_aiops-0.1.0/endpoint_aiops/cli/_root.py +58 -0
- endpoint_aiops-0.1.0/endpoint_aiops/cli/doctor.py +21 -0
- endpoint_aiops-0.1.0/endpoint_aiops/cli/drift.py +45 -0
- endpoint_aiops-0.1.0/endpoint_aiops/cli/endpoint.py +90 -0
- endpoint_aiops-0.1.0/endpoint_aiops/cli/init.py +101 -0
- endpoint_aiops-0.1.0/endpoint_aiops/cli/overview.py +16 -0
- endpoint_aiops-0.1.0/endpoint_aiops/cli/secret.py +103 -0
- endpoint_aiops-0.1.0/endpoint_aiops/cli/session.py +47 -0
- endpoint_aiops-0.1.0/endpoint_aiops/config.py +131 -0
- endpoint_aiops-0.1.0/endpoint_aiops/connection.py +163 -0
- endpoint_aiops-0.1.0/endpoint_aiops/doctor.py +84 -0
- endpoint_aiops-0.1.0/endpoint_aiops/governance/__init__.py +40 -0
- endpoint_aiops-0.1.0/endpoint_aiops/governance/audit.py +377 -0
- endpoint_aiops-0.1.0/endpoint_aiops/governance/budget.py +225 -0
- endpoint_aiops-0.1.0/endpoint_aiops/governance/decorators.py +474 -0
- endpoint_aiops-0.1.0/endpoint_aiops/governance/paths.py +23 -0
- endpoint_aiops-0.1.0/endpoint_aiops/governance/patterns.py +378 -0
- endpoint_aiops-0.1.0/endpoint_aiops/governance/policy.py +411 -0
- endpoint_aiops-0.1.0/endpoint_aiops/governance/sanitize.py +39 -0
- endpoint_aiops-0.1.0/endpoint_aiops/governance/undo.py +218 -0
- endpoint_aiops-0.1.0/endpoint_aiops/ops/__init__.py +1 -0
- endpoint_aiops-0.1.0/endpoint_aiops/ops/_util.py +26 -0
- endpoint_aiops-0.1.0/endpoint_aiops/ops/drift.py +123 -0
- endpoint_aiops-0.1.0/endpoint_aiops/ops/inventory.py +101 -0
- endpoint_aiops-0.1.0/endpoint_aiops/ops/remediation.py +56 -0
- endpoint_aiops-0.1.0/endpoint_aiops/ops/sessions.py +184 -0
- endpoint_aiops-0.1.0/endpoint_aiops/secretstore.py +302 -0
- endpoint_aiops-0.1.0/mcp_server/__init__.py +1 -0
- endpoint_aiops-0.1.0/mcp_server/_shared.py +99 -0
- endpoint_aiops-0.1.0/mcp_server/server.py +33 -0
- endpoint_aiops-0.1.0/mcp_server/tools/__init__.py +1 -0
- endpoint_aiops-0.1.0/mcp_server/tools/drift.py +65 -0
- endpoint_aiops-0.1.0/mcp_server/tools/inventory.py +47 -0
- endpoint_aiops-0.1.0/mcp_server/tools/remediation.py +62 -0
- endpoint_aiops-0.1.0/mcp_server/tools/sessions.py +69 -0
- endpoint_aiops-0.1.0/pyproject.toml +59 -0
- endpoint_aiops-0.1.0/server.json +21 -0
- endpoint_aiops-0.1.0/skills/endpoint-aiops/SKILL.md +103 -0
- endpoint_aiops-0.1.0/skills/endpoint-aiops/references/capabilities.md +35 -0
- endpoint_aiops-0.1.0/skills/endpoint-aiops/references/cli-reference.md +47 -0
- endpoint_aiops-0.1.0/skills/endpoint-aiops/references/setup-guide.md +78 -0
- endpoint_aiops-0.1.0/smithery.yaml +9 -0
- endpoint_aiops-0.1.0/tests/test_secretstore.py +99 -0
- endpoint_aiops-0.1.0/tests/test_smoke.py +331 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*.egg-info/
|
|
5
|
+
.pytest_cache/
|
|
6
|
+
.ruff_cache/
|
|
7
|
+
|
|
8
|
+
# Virtual envs / build
|
|
9
|
+
.venv/
|
|
10
|
+
dist/
|
|
11
|
+
build/
|
|
12
|
+
|
|
13
|
+
# uv
|
|
14
|
+
uv.lock
|
|
15
|
+
|
|
16
|
+
# Local config / secrets (never commit)
|
|
17
|
+
*.env
|
|
18
|
+
.env
|
|
19
|
+
config.yaml
|
|
20
|
+
|
|
21
|
+
# OS
|
|
22
|
+
.DS_Store
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to endpoint-aiops are documented here. This project adheres
|
|
4
|
+
to [Semantic Versioning](https://semver.org/).
|
|
5
|
+
|
|
6
|
+
## [0.1.0] — preview
|
|
7
|
+
|
|
8
|
+
Initial preview release: governed AI-ops for managed-endpoint fleets (thin
|
|
9
|
+
clients / VDI) with a bundled governance harness. **Mock-validated only — not
|
|
10
|
+
yet verified against a live endpoint-management server.**
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- **9 MCP tools** (7 read, 2 write), every one wrapped with the bundled
|
|
15
|
+
`@governed_tool` harness (audit, policy, token/runaway budget, undo,
|
|
16
|
+
risk-tiers):
|
|
17
|
+
- **Overview** — `overview` (fleet health: online/offline, stale endpoints,
|
|
18
|
+
agent/patch spread).
|
|
19
|
+
- **Inventory** — `endpoint_list`, `endpoint_get`.
|
|
20
|
+
- **Sessions** — `session_list`; `login_storm_analysis` — detect login storms
|
|
21
|
+
(bursts of concurrent logins in a sliding window) and rank the slowest
|
|
22
|
+
login/boot contributors.
|
|
23
|
+
- **Drift** — `drift_report` (endpoints deviating from a per-field baseline,
|
|
24
|
+
fleet-majority derived when none is given); `patch_status` (patch-level
|
|
25
|
+
distribution + endpoints behind the target).
|
|
26
|
+
- **Remediation** — `endpoint_assign_profile` (write, high, reversible:
|
|
27
|
+
captures the prior profile, records an inverse reassign undo descriptor);
|
|
28
|
+
`endpoint_reboot` (write, medium, no safe inverse, captures before-state).
|
|
29
|
+
- **Pure/offline analysis** — `login_storm_analysis`, `drift_report`, and
|
|
30
|
+
`patch_status` accept injected records for analysis without a live server.
|
|
31
|
+
- **Encrypted secret store** — the management-server API key is stored encrypted
|
|
32
|
+
in `~/.endpoint-aiops/secrets.enc` (Fernet + scrypt); never plaintext on disk.
|
|
33
|
+
Legacy `ENDPOINT_<TARGET>_APIKEY` env var honoured as a fallback.
|
|
34
|
+
- **CLI** (`endpoint-aiops`) — `init` wizard, `secret` management, `doctor`,
|
|
35
|
+
`overview`, and the `endpoint` / `session` / `drift` sub-commands.
|
|
36
|
+
- **Bearer-auth REST connection layer** over a generic endpoint-management REST
|
|
37
|
+
API with centralised teaching error translation (`EndpointApiError`).
|
|
38
|
+
|
|
39
|
+
### Known limitations
|
|
40
|
+
|
|
41
|
+
- Preview / mock-only: the REST paths (`/endpoints`, `/sessions`, `/version`,
|
|
42
|
+
`/endpoints/{id}/profile`, `/endpoints/{id}/reboot`) are modelled generically
|
|
43
|
+
and need live verification against a real management server.
|
|
44
|
+
- Out of scope by design: enrollment/de-enrollment, image/OTA management, and
|
|
45
|
+
any bulk destructive operation.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 wei <zhouwei008@gmail.com>
|
|
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,108 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: endpoint-aiops
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Governed AI-ops for managed-endpoint fleets (thin clients / VDI): login-storm & drift analysis with a built-in governance harness (audit, budget, undo, risk tiers)
|
|
5
|
+
Author-email: wei <zhouwei008@gmail.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
License-File: LICENSE
|
|
8
|
+
Requires-Python: >=3.11
|
|
9
|
+
Requires-Dist: cryptography>=42.0
|
|
10
|
+
Requires-Dist: httpx<1.0,>=0.27
|
|
11
|
+
Requires-Dist: mcp[cli]<2.0,>=1.10
|
|
12
|
+
Requires-Dist: pyyaml<7.0,>=6.0
|
|
13
|
+
Requires-Dist: rich<16.0,>=13.0
|
|
14
|
+
Requires-Dist: typer<1.0,>=0.12
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
|
|
17
|
+
<!-- mcp-name: io.github.AIops-tools/endpoint-aiops -->
|
|
18
|
+
|
|
19
|
+
# Endpoint AIops (preview)
|
|
20
|
+
|
|
21
|
+
> **Disclaimer**: Community-maintained open-source project. **Not affiliated with, endorsed by, or sponsored by any endpoint-management vendor.** Product and trademark names belong to their owners. MIT licensed.
|
|
22
|
+
|
|
23
|
+
Governed AI-ops for **managed-endpoint fleets** — thin clients, VDI endpoints,
|
|
24
|
+
and other centrally-managed devices — with a **built-in governance harness**:
|
|
25
|
+
unified audit log, policy engine, token/runaway budget guard, undo-token
|
|
26
|
+
recording, and graduated-autonomy risk tiers. Vendor-neutral: it talks to an
|
|
27
|
+
endpoint-management server's REST API (Bearer auth). Self-contained: no
|
|
28
|
+
dependencies beyond `httpx` and the MCP SDK. **Preview — mock-validated only,
|
|
29
|
+
not yet verified against a live management server.**
|
|
30
|
+
|
|
31
|
+
## What it does
|
|
32
|
+
|
|
33
|
+
Two signature analyses, plus the guarded reads and writes around them:
|
|
34
|
+
|
|
35
|
+
- **Login-storm analysis** — during a "everyone logs in at 9am" incident,
|
|
36
|
+
detect the storm (bursts of concurrent logins in a sliding window) and rank
|
|
37
|
+
the endpoints/users dragging login and boot times. Every flag is reported
|
|
38
|
+
with its number, not a black-box verdict.
|
|
39
|
+
- **Patch / config drift** — find endpoints that have drifted from the fleet
|
|
40
|
+
(outdated patch level, stray agent version, divergent OS build or config
|
|
41
|
+
profile). With no declared baseline it derives one by fleet majority, so it
|
|
42
|
+
works before a gold image exists.
|
|
43
|
+
|
|
44
|
+
## What works
|
|
45
|
+
|
|
46
|
+
- **CLI** (`endpoint-aiops ...`): `init`, `overview`, `endpoint list/get/assign-profile/reboot`, `session list/storm`, `drift report/patch`, `secret set/list/rm/migrate/rotate-password`, `doctor`, `mcp`.
|
|
47
|
+
- **MCP server** (`endpoint-aiops mcp` or `endpoint-aiops-mcp`): **9 tools** (7 read, 2 write), every one wrapped with the bundled `@governed_tool` harness.
|
|
48
|
+
- **Encrypted credentials**: the management-server API key lives in an encrypted store `~/.endpoint-aiops/secrets.enc` (Fernet + scrypt) — **never plaintext on disk**. Unlock with a master password from `ENDPOINT_AIOPS_MASTER_PASSWORD` (MCP/CI) or an interactive prompt (CLI).
|
|
49
|
+
- **Reversibility**: `endpoint_assign_profile` (`high` risk) captures the prior profile and records an inverse "reassign the prior profile" undo descriptor. `endpoint_reboot` (`medium` risk) captures the prior online state for the audit record but declares no undo (a reboot has no safe inverse).
|
|
50
|
+
- **Safety**: state-changing CLI ops (`endpoint assign-profile`, `endpoint reboot`) require double confirmation and support `--dry-run`.
|
|
51
|
+
|
|
52
|
+
## Capability matrix (9 MCP tools)
|
|
53
|
+
|
|
54
|
+
| Category | Tools | Count | R/W |
|
|
55
|
+
|----------|-------|:-----:|:---:|
|
|
56
|
+
| **Overview** | `overview` | 1 | read |
|
|
57
|
+
| **Inventory** | `endpoint_list`, `endpoint_get` | 2 | read |
|
|
58
|
+
| **Sessions** | `session_list`, `login_storm_analysis` | 2 | read |
|
|
59
|
+
| **Drift** | `drift_report`, `patch_status` | 2 | read |
|
|
60
|
+
| **Remediation** | `endpoint_assign_profile` | 1 | write (high) |
|
|
61
|
+
| | `endpoint_reboot` | 1 | write (medium) |
|
|
62
|
+
|
|
63
|
+
The analysis tools (`login_storm_analysis`, `drift_report`, `patch_status`)
|
|
64
|
+
accept injected records for pure/offline analysis, or pull live from a
|
|
65
|
+
configured target.
|
|
66
|
+
|
|
67
|
+
## Quick start
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
uv tool install endpoint-aiops # or: pipx install endpoint-aiops
|
|
71
|
+
endpoint-aiops init # wizard: add a target + store its API key (encrypted)
|
|
72
|
+
endpoint-aiops doctor # verify config, secrets, connectivity
|
|
73
|
+
endpoint-aiops overview # one-shot fleet health
|
|
74
|
+
endpoint-aiops session storm # detect a login storm + slow contributors
|
|
75
|
+
endpoint-aiops drift report # endpoints drifted from the fleet baseline
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Run as an MCP server (stdio):
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
export ENDPOINT_AIOPS_MASTER_PASSWORD=... # unlock secrets non-interactively
|
|
82
|
+
endpoint-aiops-mcp
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Governance
|
|
86
|
+
|
|
87
|
+
Every MCP tool passes through the bundled `@governed_tool` harness:
|
|
88
|
+
|
|
89
|
+
- **Audit** — every call (params, result, status, duration, risk tier,
|
|
90
|
+
approver, rationale) is logged to `~/.endpoint-aiops/audit.db` (relocatable
|
|
91
|
+
via `ENDPOINT_AIOPS_HOME`).
|
|
92
|
+
- **Budget / runaway guard** — token and call budgets trip a circuit breaker.
|
|
93
|
+
- **Risk tiers** — graduated autonomy; high-risk ops can require a named
|
|
94
|
+
approver (`ENDPOINT_AUDIT_APPROVED_BY` / `ENDPOINT_AUDIT_RATIONALE`).
|
|
95
|
+
- **Undo recording** — reversible writes record an inverse descriptor.
|
|
96
|
+
|
|
97
|
+
## Scope
|
|
98
|
+
|
|
99
|
+
This is the **IT-endpoint** member of the AIops-tools family (governed AI-ops
|
|
100
|
+
with audit + budget + undo + risk tiers). For **OT / industrial edge**
|
|
101
|
+
(Modbus, OPC-UA, PROFINET, …) see the separate `industrial-aiops` line.
|
|
102
|
+
|
|
103
|
+
## Status
|
|
104
|
+
|
|
105
|
+
**Preview — mock-validated only.** The endpoint-management REST paths are
|
|
106
|
+
modelled generically (`/endpoints`, `/sessions`, `/version`) and need live
|
|
107
|
+
verification against a real server. Missing a capability or a server dialect?
|
|
108
|
+
Open an issue or PR — contributions welcome.
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
<!-- mcp-name: io.github.AIops-tools/endpoint-aiops -->
|
|
2
|
+
|
|
3
|
+
# Endpoint AIops (preview)
|
|
4
|
+
|
|
5
|
+
> **Disclaimer**: Community-maintained open-source project. **Not affiliated with, endorsed by, or sponsored by any endpoint-management vendor.** Product and trademark names belong to their owners. MIT licensed.
|
|
6
|
+
|
|
7
|
+
Governed AI-ops for **managed-endpoint fleets** — thin clients, VDI endpoints,
|
|
8
|
+
and other centrally-managed devices — with a **built-in governance harness**:
|
|
9
|
+
unified audit log, policy engine, token/runaway budget guard, undo-token
|
|
10
|
+
recording, and graduated-autonomy risk tiers. Vendor-neutral: it talks to an
|
|
11
|
+
endpoint-management server's REST API (Bearer auth). Self-contained: no
|
|
12
|
+
dependencies beyond `httpx` and the MCP SDK. **Preview — mock-validated only,
|
|
13
|
+
not yet verified against a live management server.**
|
|
14
|
+
|
|
15
|
+
## What it does
|
|
16
|
+
|
|
17
|
+
Two signature analyses, plus the guarded reads and writes around them:
|
|
18
|
+
|
|
19
|
+
- **Login-storm analysis** — during a "everyone logs in at 9am" incident,
|
|
20
|
+
detect the storm (bursts of concurrent logins in a sliding window) and rank
|
|
21
|
+
the endpoints/users dragging login and boot times. Every flag is reported
|
|
22
|
+
with its number, not a black-box verdict.
|
|
23
|
+
- **Patch / config drift** — find endpoints that have drifted from the fleet
|
|
24
|
+
(outdated patch level, stray agent version, divergent OS build or config
|
|
25
|
+
profile). With no declared baseline it derives one by fleet majority, so it
|
|
26
|
+
works before a gold image exists.
|
|
27
|
+
|
|
28
|
+
## What works
|
|
29
|
+
|
|
30
|
+
- **CLI** (`endpoint-aiops ...`): `init`, `overview`, `endpoint list/get/assign-profile/reboot`, `session list/storm`, `drift report/patch`, `secret set/list/rm/migrate/rotate-password`, `doctor`, `mcp`.
|
|
31
|
+
- **MCP server** (`endpoint-aiops mcp` or `endpoint-aiops-mcp`): **9 tools** (7 read, 2 write), every one wrapped with the bundled `@governed_tool` harness.
|
|
32
|
+
- **Encrypted credentials**: the management-server API key lives in an encrypted store `~/.endpoint-aiops/secrets.enc` (Fernet + scrypt) — **never plaintext on disk**. Unlock with a master password from `ENDPOINT_AIOPS_MASTER_PASSWORD` (MCP/CI) or an interactive prompt (CLI).
|
|
33
|
+
- **Reversibility**: `endpoint_assign_profile` (`high` risk) captures the prior profile and records an inverse "reassign the prior profile" undo descriptor. `endpoint_reboot` (`medium` risk) captures the prior online state for the audit record but declares no undo (a reboot has no safe inverse).
|
|
34
|
+
- **Safety**: state-changing CLI ops (`endpoint assign-profile`, `endpoint reboot`) require double confirmation and support `--dry-run`.
|
|
35
|
+
|
|
36
|
+
## Capability matrix (9 MCP tools)
|
|
37
|
+
|
|
38
|
+
| Category | Tools | Count | R/W |
|
|
39
|
+
|----------|-------|:-----:|:---:|
|
|
40
|
+
| **Overview** | `overview` | 1 | read |
|
|
41
|
+
| **Inventory** | `endpoint_list`, `endpoint_get` | 2 | read |
|
|
42
|
+
| **Sessions** | `session_list`, `login_storm_analysis` | 2 | read |
|
|
43
|
+
| **Drift** | `drift_report`, `patch_status` | 2 | read |
|
|
44
|
+
| **Remediation** | `endpoint_assign_profile` | 1 | write (high) |
|
|
45
|
+
| | `endpoint_reboot` | 1 | write (medium) |
|
|
46
|
+
|
|
47
|
+
The analysis tools (`login_storm_analysis`, `drift_report`, `patch_status`)
|
|
48
|
+
accept injected records for pure/offline analysis, or pull live from a
|
|
49
|
+
configured target.
|
|
50
|
+
|
|
51
|
+
## Quick start
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
uv tool install endpoint-aiops # or: pipx install endpoint-aiops
|
|
55
|
+
endpoint-aiops init # wizard: add a target + store its API key (encrypted)
|
|
56
|
+
endpoint-aiops doctor # verify config, secrets, connectivity
|
|
57
|
+
endpoint-aiops overview # one-shot fleet health
|
|
58
|
+
endpoint-aiops session storm # detect a login storm + slow contributors
|
|
59
|
+
endpoint-aiops drift report # endpoints drifted from the fleet baseline
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Run as an MCP server (stdio):
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
export ENDPOINT_AIOPS_MASTER_PASSWORD=... # unlock secrets non-interactively
|
|
66
|
+
endpoint-aiops-mcp
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Governance
|
|
70
|
+
|
|
71
|
+
Every MCP tool passes through the bundled `@governed_tool` harness:
|
|
72
|
+
|
|
73
|
+
- **Audit** — every call (params, result, status, duration, risk tier,
|
|
74
|
+
approver, rationale) is logged to `~/.endpoint-aiops/audit.db` (relocatable
|
|
75
|
+
via `ENDPOINT_AIOPS_HOME`).
|
|
76
|
+
- **Budget / runaway guard** — token and call budgets trip a circuit breaker.
|
|
77
|
+
- **Risk tiers** — graduated autonomy; high-risk ops can require a named
|
|
78
|
+
approver (`ENDPOINT_AUDIT_APPROVED_BY` / `ENDPOINT_AUDIT_RATIONALE`).
|
|
79
|
+
- **Undo recording** — reversible writes record an inverse descriptor.
|
|
80
|
+
|
|
81
|
+
## Scope
|
|
82
|
+
|
|
83
|
+
This is the **IT-endpoint** member of the AIops-tools family (governed AI-ops
|
|
84
|
+
with audit + budget + undo + risk tiers). For **OT / industrial edge**
|
|
85
|
+
(Modbus, OPC-UA, PROFINET, …) see the separate `industrial-aiops` line.
|
|
86
|
+
|
|
87
|
+
## Status
|
|
88
|
+
|
|
89
|
+
**Preview — mock-validated only.** The endpoint-management REST paths are
|
|
90
|
+
modelled generically (`/endpoints`, `/sessions`, `/version`) and need live
|
|
91
|
+
verification against a real server. Missing a capability or a server dialect?
|
|
92
|
+
Open an issue or PR — contributions welcome.
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Endpoint AIops v0.1.0 — preview
|
|
2
|
+
|
|
3
|
+
Governed AI-ops for **managed-endpoint fleets** (thin clients / VDI) for AI
|
|
4
|
+
agents, with a built-in governance harness (audit, policy, token/runaway
|
|
5
|
+
budget, undo-token recording, graduated risk tiers) and an encrypted credential
|
|
6
|
+
store. Standalone — no external skill-family dependency.
|
|
7
|
+
|
|
8
|
+
> **Preview / mock-only.** All behaviour is validated against mocked REST
|
|
9
|
+
> responses; it has not been run against a live endpoint-management server. The
|
|
10
|
+
> fastest live check is `endpoint-aiops doctor`.
|
|
11
|
+
|
|
12
|
+
## Highlights
|
|
13
|
+
|
|
14
|
+
- **9 MCP tools** (7 read, 2 write), every one wrapped with `@governed_tool`.
|
|
15
|
+
- Read: fleet `overview`; inventory (`endpoint_list`, `endpoint_get`);
|
|
16
|
+
sessions (`session_list`, `login_storm_analysis`); drift (`drift_report`,
|
|
17
|
+
`patch_status`).
|
|
18
|
+
- Write: `endpoint_assign_profile` (high, reversible — records an inverse
|
|
19
|
+
reassign undo), `endpoint_reboot` (medium, no safe inverse, captures
|
|
20
|
+
before-state).
|
|
21
|
+
- **Two signature analyses** — login-storm detection + slow login/boot ranking,
|
|
22
|
+
and patch/config drift vs a fleet-majority (or explicit) baseline. Both accept
|
|
23
|
+
injected records for offline analysis.
|
|
24
|
+
- **Encrypted API key store** (`~/.endpoint-aiops/secrets.enc`, Fernet + scrypt)
|
|
25
|
+
— never plaintext on disk; legacy `ENDPOINT_<TARGET>_APIKEY` env fallback.
|
|
26
|
+
- **CLI** with an `init` onboarding wizard, `secret` management, and `doctor`.
|
|
27
|
+
- **Bearer-auth REST connection layer** over a generic endpoint-management REST
|
|
28
|
+
API with teaching error translation (`EndpointApiError`).
|
|
29
|
+
|
|
30
|
+
## Install
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
uv tool install endpoint-aiops
|
|
34
|
+
endpoint-aiops init
|
|
35
|
+
endpoint-aiops doctor
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Caveats
|
|
39
|
+
|
|
40
|
+
- The REST paths are modelled generically (`/endpoints`, `/sessions`,
|
|
41
|
+
`/version`, `/endpoints/{id}/profile|reboot`) and need live verification.
|
|
42
|
+
- Out of scope by design: enrollment/de-enrollment, image/OTA management, and
|
|
43
|
+
any bulk destructive operation.
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# Security Policy
|
|
2
|
+
|
|
3
|
+
## Disclaimer
|
|
4
|
+
|
|
5
|
+
Community-maintained open-source project. **Not affiliated with, endorsed by, or
|
|
6
|
+
sponsored by any endpoint-management vendor.** Product and trademark names
|
|
7
|
+
belong to their owners. Source is publicly auditable under the MIT license.
|
|
8
|
+
|
|
9
|
+
## Reporting Vulnerabilities
|
|
10
|
+
|
|
11
|
+
Report privately via a GitHub Security Advisory on
|
|
12
|
+
[github.com/AIops-tools/Endpoint-AIops](https://github.com/AIops-tools/Endpoint-AIops/security/advisories)
|
|
13
|
+
or email zhouwei008@gmail.com. Please do not open public issues for security
|
|
14
|
+
reports.
|
|
15
|
+
|
|
16
|
+
## Security Design
|
|
17
|
+
|
|
18
|
+
### Credential Management
|
|
19
|
+
- Per-target Endpoint API keys live **encrypted** in
|
|
20
|
+
`~/.endpoint-aiops/secrets.enc` (Fernet/AES-128 + scrypt-derived key; chmod
|
|
21
|
+
600), never in `config.yaml` and never in source. The master password is
|
|
22
|
+
never stored — only a per-store random salt and the ciphertext are on disk.
|
|
23
|
+
- A legacy plaintext env var `ENDPOINT_<TARGET_NAME_UPPER>_APIKEY` is still
|
|
24
|
+
honoured as a fallback with a deprecation warning (migrate with
|
|
25
|
+
`endpoint-aiops secret migrate`).
|
|
26
|
+
- The API key is sent as an `Authorization: Bearer` header at request time and
|
|
27
|
+
held only in memory. Keys are never logged or echoed; the config file holds
|
|
28
|
+
only host, port, api_path, and TLS settings.
|
|
29
|
+
|
|
30
|
+
### Governed Operations
|
|
31
|
+
Every MCP tool runs through the bundled `@governed_tool` harness
|
|
32
|
+
(`endpoint_aiops.governance`):
|
|
33
|
+
- **Audit** — every call logged to a local SQLite DB under `~/.endpoint-aiops/`
|
|
34
|
+
(relocatable via `ENDPOINT_AIOPS_HOME`), agent-attributed, secret-redacted.
|
|
35
|
+
- **Token/runaway budget** — hard ceilings (`ENDPOINT_MAX_TOOL_CALLS` /
|
|
36
|
+
`ENDPOINT_MAX_TOOL_SECONDS`) plus an on-by-default guard that trips a tight
|
|
37
|
+
poll/retry loop, preventing unbounded API consumption (e.g. polling a slow
|
|
38
|
+
session).
|
|
39
|
+
- **Graduated risk tiers** — `~/.endpoint-aiops/rules.yaml` `risk_tiers` gate
|
|
40
|
+
writes by environment/tag; the highest tiers require a recorded approver.
|
|
41
|
+
- **Undo-token recording** — `endpoint_assign_profile` captures the prior
|
|
42
|
+
profile and records an inverse "reassign the prior profile" descriptor so the
|
|
43
|
+
change can be rolled back.
|
|
44
|
+
|
|
45
|
+
### State-Changing Operations
|
|
46
|
+
`endpoint assign-profile` and `endpoint reboot` require double confirmation at
|
|
47
|
+
the CLI layer and support `--dry-run`. `endpoint_assign_profile` is
|
|
48
|
+
`risk_level=high` and reversible (captures the prior profile, records an undo
|
|
49
|
+
descriptor); `endpoint_reboot` is `risk_level=medium` and has no safe inverse
|
|
50
|
+
(captures the before-state for the audit record, records no undo token).
|
|
51
|
+
|
|
52
|
+
### SSL/TLS Verification
|
|
53
|
+
`verify_ssl` defaults to true; disable only for self-signed lab certificates.
|
|
54
|
+
|
|
55
|
+
### Prompt-Injection Protection
|
|
56
|
+
All server-returned text (hostnames, usernames, profile ids, session fields) is
|
|
57
|
+
passed through a `sanitize()` truncate + control-character strip before reaching
|
|
58
|
+
the agent.
|
|
59
|
+
|
|
60
|
+
### Network Scope
|
|
61
|
+
No webhooks, no telemetry, no outbound calls beyond the configured
|
|
62
|
+
endpoint-management REST API endpoint. No post-install scripts or background
|
|
63
|
+
services.
|
|
64
|
+
|
|
65
|
+
## Static Analysis
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
uvx bandit -r endpoint_aiops/ mcp_server/
|
|
69
|
+
uv run ruff check .
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Supported Versions
|
|
73
|
+
|
|
74
|
+
The latest released version receives security fixes. This is a preview (0.x);
|
|
75
|
+
pin a version in production.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"""endpoint-aiops — governed Endpoint SCALE operations for AI agents.
|
|
2
|
+
|
|
3
|
+
Standalone and self-contained: the governance harness (audit, token budget,
|
|
4
|
+
undo-token recording, graduated risk tiers, prompt-injection sanitize) is
|
|
5
|
+
bundled under ``endpoint_aiops.governance`` — this package has no external
|
|
6
|
+
skill-family dependency. Preview: not yet full-coverage.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
__version__ = "0.1.0"
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"""Shared helpers for endpoint-aiops CLI sub-modules."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import functools
|
|
6
|
+
from collections.abc import Callable
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from typing import Annotated, Any
|
|
9
|
+
|
|
10
|
+
import typer
|
|
11
|
+
from rich.console import Console
|
|
12
|
+
|
|
13
|
+
console = Console()
|
|
14
|
+
|
|
15
|
+
# ─── Shared Option types ───────────────────────────────────────────────────
|
|
16
|
+
|
|
17
|
+
TargetOption = Annotated[
|
|
18
|
+
str | None, typer.Option("--target", "-t", help="Target name from config")
|
|
19
|
+
]
|
|
20
|
+
DryRunOption = Annotated[
|
|
21
|
+
bool, typer.Option("--dry-run", help="Print the API call without executing")
|
|
22
|
+
]
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def _cli_error_types() -> tuple[type[BaseException], ...]:
|
|
26
|
+
"""Exceptions translated to a one-line teaching error instead of a traceback."""
|
|
27
|
+
from endpoint_aiops.connection import EndpointApiError
|
|
28
|
+
|
|
29
|
+
return (EndpointApiError, KeyError, OSError, ValueError)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def cli_errors(fn: Callable) -> Callable:
|
|
33
|
+
"""Translate known exceptions into one red line + exit code 1."""
|
|
34
|
+
|
|
35
|
+
@functools.wraps(fn)
|
|
36
|
+
def wrapper(*args: Any, **kwargs: Any) -> Any:
|
|
37
|
+
try:
|
|
38
|
+
return fn(*args, **kwargs)
|
|
39
|
+
except (typer.Exit, typer.Abort):
|
|
40
|
+
raise
|
|
41
|
+
except _cli_error_types() as e:
|
|
42
|
+
message = str(e)
|
|
43
|
+
if isinstance(e, KeyError):
|
|
44
|
+
message = f"Missing required key or environment variable: {message}"
|
|
45
|
+
console.print(f"[red]Error: {message}[/]")
|
|
46
|
+
raise typer.Exit(1) from e
|
|
47
|
+
|
|
48
|
+
return wrapper
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def get_connection(target: str | None, config_path: Path | None = None):
|
|
52
|
+
"""Return a (conn, config) tuple for the given target."""
|
|
53
|
+
from endpoint_aiops.config import load_config
|
|
54
|
+
from endpoint_aiops.connection import ConnectionManager
|
|
55
|
+
|
|
56
|
+
cfg = load_config(config_path)
|
|
57
|
+
mgr = ConnectionManager(cfg)
|
|
58
|
+
return mgr.connect(target), cfg
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def dry_run_print(*, operation: str, api_call: str, parameters: dict | None = None) -> None:
|
|
62
|
+
"""Print a dry-run preview of the API call that would be made."""
|
|
63
|
+
console.print("\n[bold magenta][DRY-RUN] No changes will be made.[/]")
|
|
64
|
+
console.print(f"[magenta] Operation: {operation}[/]")
|
|
65
|
+
console.print(f"[magenta] API Call: {api_call}[/]")
|
|
66
|
+
for k, v in (parameters or {}).items():
|
|
67
|
+
console.print(f"[magenta] Param: {k} = {v}[/]")
|
|
68
|
+
console.print("[magenta] Run without --dry-run to execute.[/]\n")
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def double_confirm(action: str, resource: str) -> None:
|
|
72
|
+
"""Require two confirmations for a destructive operation."""
|
|
73
|
+
console.print(f"[bold yellow]⚠️ About to: {action} '{resource}'[/]")
|
|
74
|
+
typer.confirm(f"Confirm 1/2: {action} '{resource}'?", abort=True)
|
|
75
|
+
typer.confirm(
|
|
76
|
+
f"Confirm 2/2: really {action} '{resource}'? This may be irreversible.",
|
|
77
|
+
abort=True,
|
|
78
|
+
)
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"""Top-level Typer app: assembles sub-apps and top-level commands."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import typer
|
|
6
|
+
|
|
7
|
+
from endpoint_aiops.cli._common import cli_errors
|
|
8
|
+
from endpoint_aiops.cli.doctor import doctor_cmd
|
|
9
|
+
from endpoint_aiops.cli.drift import drift_app
|
|
10
|
+
from endpoint_aiops.cli.endpoint import endpoint_app
|
|
11
|
+
from endpoint_aiops.cli.init import init_cmd
|
|
12
|
+
from endpoint_aiops.cli.overview import overview_cmd
|
|
13
|
+
from endpoint_aiops.cli.secret import secret_app
|
|
14
|
+
from endpoint_aiops.cli.session import session_app
|
|
15
|
+
|
|
16
|
+
app = typer.Typer(
|
|
17
|
+
name="endpoint-aiops",
|
|
18
|
+
help="Governed AI-ops for managed-endpoint fleets (thin clients / VDI).",
|
|
19
|
+
no_args_is_help=True,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
app.add_typer(endpoint_app, name="endpoint")
|
|
23
|
+
app.add_typer(session_app, name="session")
|
|
24
|
+
app.add_typer(drift_app, name="drift")
|
|
25
|
+
app.add_typer(secret_app, name="secret")
|
|
26
|
+
app.command("init")(init_cmd)
|
|
27
|
+
app.command("overview")(overview_cmd)
|
|
28
|
+
app.command("doctor")(doctor_cmd)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@app.command("mcp")
|
|
32
|
+
@cli_errors
|
|
33
|
+
def mcp_cmd() -> None:
|
|
34
|
+
"""Start the MCP server (stdio transport).
|
|
35
|
+
|
|
36
|
+
Single-command entry point for MCP clients (does not go through uvx/PyPI
|
|
37
|
+
resolution at launch):
|
|
38
|
+
endpoint-aiops mcp
|
|
39
|
+
"""
|
|
40
|
+
import sys
|
|
41
|
+
|
|
42
|
+
if sys.version_info < (3, 11):
|
|
43
|
+
typer.echo(
|
|
44
|
+
f"ERROR: endpoint-aiops requires Python >= 3.11 "
|
|
45
|
+
f"(got {sys.version_info.major}.{sys.version_info.minor}).\n"
|
|
46
|
+
f"Fix: uv python install 3.12 && "
|
|
47
|
+
f"uv tool install --python 3.12 --force endpoint-aiops",
|
|
48
|
+
err=True,
|
|
49
|
+
)
|
|
50
|
+
raise typer.Exit(2)
|
|
51
|
+
|
|
52
|
+
from mcp_server.server import main as _mcp_main
|
|
53
|
+
|
|
54
|
+
_mcp_main()
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
if __name__ == "__main__":
|
|
58
|
+
app()
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"""Doctor top-level command: environment and connectivity check."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Annotated
|
|
6
|
+
|
|
7
|
+
import typer
|
|
8
|
+
|
|
9
|
+
from endpoint_aiops.cli._common import cli_errors
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@cli_errors
|
|
13
|
+
def doctor_cmd(
|
|
14
|
+
skip_auth: Annotated[
|
|
15
|
+
bool, typer.Option("--skip-auth", help="Skip connectivity check (faster)")
|
|
16
|
+
] = False,
|
|
17
|
+
) -> None:
|
|
18
|
+
"""Check environment, config, secrets, and connectivity."""
|
|
19
|
+
from endpoint_aiops.doctor import run_doctor
|
|
20
|
+
|
|
21
|
+
raise typer.Exit(run_doctor(skip_auth=skip_auth))
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"""``endpoint-aiops drift`` — patch/config drift + patch-level status."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
from typing import Annotated
|
|
7
|
+
|
|
8
|
+
import typer
|
|
9
|
+
|
|
10
|
+
from endpoint_aiops.cli._common import TargetOption, cli_errors, console, get_connection
|
|
11
|
+
|
|
12
|
+
drift_app = typer.Typer(
|
|
13
|
+
name="drift",
|
|
14
|
+
help="Fleet drift: config/patch deviation vs a baseline, patch-level status.",
|
|
15
|
+
no_args_is_help=True,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@drift_app.command("report")
|
|
20
|
+
@cli_errors
|
|
21
|
+
def drift_report(target: TargetOption = None) -> None:
|
|
22
|
+
"""Report endpoints drifted from the fleet-majority baseline."""
|
|
23
|
+
from endpoint_aiops.ops import drift as ops
|
|
24
|
+
from endpoint_aiops.ops import inventory as inv
|
|
25
|
+
|
|
26
|
+
conn, _ = get_connection(target)
|
|
27
|
+
console.print_json(json.dumps(ops.config_drift(inv.list_endpoints(conn))))
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@drift_app.command("patch")
|
|
31
|
+
@cli_errors
|
|
32
|
+
def drift_patch(
|
|
33
|
+
target_patch: Annotated[
|
|
34
|
+
str | None, typer.Option("--target-patch", help="Desired patch level")
|
|
35
|
+
] = None,
|
|
36
|
+
target: TargetOption = None,
|
|
37
|
+
) -> None:
|
|
38
|
+
"""Patch-level distribution + which endpoints are behind the target."""
|
|
39
|
+
from endpoint_aiops.ops import drift as ops
|
|
40
|
+
from endpoint_aiops.ops import inventory as inv
|
|
41
|
+
|
|
42
|
+
conn, _ = get_connection(target)
|
|
43
|
+
console.print_json(
|
|
44
|
+
json.dumps(ops.patch_status(inv.list_endpoints(conn), target_patch=target_patch))
|
|
45
|
+
)
|