container-host-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.
Files changed (74) hide show
  1. container_host_aiops-0.1.0/.github/workflows/publish.yml +26 -0
  2. container_host_aiops-0.1.0/.gitignore +7 -0
  3. container_host_aiops-0.1.0/CHANGELOG.md +60 -0
  4. container_host_aiops-0.1.0/LICENSE +21 -0
  5. container_host_aiops-0.1.0/PKG-INFO +96 -0
  6. container_host_aiops-0.1.0/README.md +80 -0
  7. container_host_aiops-0.1.0/RELEASE_NOTES.md +59 -0
  8. container_host_aiops-0.1.0/SECURITY.md +83 -0
  9. container_host_aiops-0.1.0/container_host_aiops/__init__.py +9 -0
  10. container_host_aiops-0.1.0/container_host_aiops/cli/__init__.py +9 -0
  11. container_host_aiops-0.1.0/container_host_aiops/cli/_common.py +78 -0
  12. container_host_aiops-0.1.0/container_host_aiops/cli/_root.py +70 -0
  13. container_host_aiops-0.1.0/container_host_aiops/cli/analyze.py +55 -0
  14. container_host_aiops-0.1.0/container_host_aiops/cli/container.py +85 -0
  15. container_host_aiops-0.1.0/container_host_aiops/cli/doctor.py +21 -0
  16. container_host_aiops-0.1.0/container_host_aiops/cli/image.py +61 -0
  17. container_host_aiops-0.1.0/container_host_aiops/cli/init.py +126 -0
  18. container_host_aiops-0.1.0/container_host_aiops/cli/manage.py +192 -0
  19. container_host_aiops-0.1.0/container_host_aiops/cli/network.py +38 -0
  20. container_host_aiops-0.1.0/container_host_aiops/cli/overview.py +16 -0
  21. container_host_aiops-0.1.0/container_host_aiops/cli/secret.py +108 -0
  22. container_host_aiops-0.1.0/container_host_aiops/cli/stack.py +48 -0
  23. container_host_aiops-0.1.0/container_host_aiops/cli/system.py +60 -0
  24. container_host_aiops-0.1.0/container_host_aiops/cli/volume.py +48 -0
  25. container_host_aiops-0.1.0/container_host_aiops/config.py +198 -0
  26. container_host_aiops-0.1.0/container_host_aiops/connection.py +227 -0
  27. container_host_aiops-0.1.0/container_host_aiops/doctor.py +98 -0
  28. container_host_aiops-0.1.0/container_host_aiops/governance/__init__.py +40 -0
  29. container_host_aiops-0.1.0/container_host_aiops/governance/audit.py +377 -0
  30. container_host_aiops-0.1.0/container_host_aiops/governance/budget.py +225 -0
  31. container_host_aiops-0.1.0/container_host_aiops/governance/decorators.py +474 -0
  32. container_host_aiops-0.1.0/container_host_aiops/governance/paths.py +23 -0
  33. container_host_aiops-0.1.0/container_host_aiops/governance/patterns.py +378 -0
  34. container_host_aiops-0.1.0/container_host_aiops/governance/policy.py +411 -0
  35. container_host_aiops-0.1.0/container_host_aiops/governance/sanitize.py +39 -0
  36. container_host_aiops-0.1.0/container_host_aiops/governance/undo.py +218 -0
  37. container_host_aiops-0.1.0/container_host_aiops/ops/__init__.py +1 -0
  38. container_host_aiops-0.1.0/container_host_aiops/ops/_metrics.py +83 -0
  39. container_host_aiops-0.1.0/container_host_aiops/ops/_util.py +90 -0
  40. container_host_aiops-0.1.0/container_host_aiops/ops/analyses.py +311 -0
  41. container_host_aiops-0.1.0/container_host_aiops/ops/containers.py +173 -0
  42. container_host_aiops-0.1.0/container_host_aiops/ops/images.py +124 -0
  43. container_host_aiops-0.1.0/container_host_aiops/ops/networks.py +53 -0
  44. container_host_aiops-0.1.0/container_host_aiops/ops/overview.py +45 -0
  45. container_host_aiops-0.1.0/container_host_aiops/ops/stacks.py +69 -0
  46. container_host_aiops-0.1.0/container_host_aiops/ops/system.py +163 -0
  47. container_host_aiops-0.1.0/container_host_aiops/ops/volumes.py +72 -0
  48. container_host_aiops-0.1.0/container_host_aiops/ops/writes.py +209 -0
  49. container_host_aiops-0.1.0/container_host_aiops/platform.py +146 -0
  50. container_host_aiops-0.1.0/container_host_aiops/secretstore.py +302 -0
  51. container_host_aiops-0.1.0/mcp_server/__init__.py +1 -0
  52. container_host_aiops-0.1.0/mcp_server/_shared.py +104 -0
  53. container_host_aiops-0.1.0/mcp_server/server.py +38 -0
  54. container_host_aiops-0.1.0/mcp_server/tools/__init__.py +1 -0
  55. container_host_aiops-0.1.0/mcp_server/tools/analyses.py +93 -0
  56. container_host_aiops-0.1.0/mcp_server/tools/containers.py +88 -0
  57. container_host_aiops-0.1.0/mcp_server/tools/images.py +57 -0
  58. container_host_aiops-0.1.0/mcp_server/tools/networks.py +32 -0
  59. container_host_aiops-0.1.0/mcp_server/tools/stacks.py +50 -0
  60. container_host_aiops-0.1.0/mcp_server/tools/system.py +75 -0
  61. container_host_aiops-0.1.0/mcp_server/tools/volumes.py +44 -0
  62. container_host_aiops-0.1.0/mcp_server/tools/writes.py +260 -0
  63. container_host_aiops-0.1.0/pyproject.toml +59 -0
  64. container_host_aiops-0.1.0/server.json +21 -0
  65. container_host_aiops-0.1.0/skills/container-host-aiops/SKILL.md +109 -0
  66. container_host_aiops-0.1.0/skills/container-host-aiops/references/capabilities.md +93 -0
  67. container_host_aiops-0.1.0/skills/container-host-aiops/references/cli-reference.md +106 -0
  68. container_host_aiops-0.1.0/skills/container-host-aiops/references/setup-guide.md +108 -0
  69. container_host_aiops-0.1.0/smithery.yaml +9 -0
  70. container_host_aiops-0.1.0/tests/test_platform.py +144 -0
  71. container_host_aiops-0.1.0/tests/test_reads.py +305 -0
  72. container_host_aiops-0.1.0/tests/test_secretstore.py +99 -0
  73. container_host_aiops-0.1.0/tests/test_smoke.py +273 -0
  74. container_host_aiops-0.1.0/uv.lock +962 -0
@@ -0,0 +1,26 @@
1
+ name: Publish to PyPI
2
+
3
+ # Trusted Publishing (OIDC) — publishes from GitHub's runners with no API token,
4
+ # sidestepping the local-IP / account new-project rate limit. Configure a matching
5
+ # "trusted publisher" for this package on PyPI (see the repo release notes).
6
+ on:
7
+ release:
8
+ types: [published]
9
+ workflow_dispatch:
10
+
11
+ permissions:
12
+ contents: read
13
+
14
+ jobs:
15
+ publish:
16
+ runs-on: ubuntu-latest
17
+ permissions:
18
+ id-token: write # required for PyPI Trusted Publishing (OIDC)
19
+ steps:
20
+ - uses: actions/checkout@v4
21
+ - name: Set up uv
22
+ uses: astral-sh/setup-uv@v5
23
+ - name: Build sdist + wheel
24
+ run: uv build
25
+ - name: Publish to PyPI (Trusted Publishing)
26
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,7 @@
1
+ .venv/
2
+ dist/
3
+ __pycache__/
4
+ *.pyc
5
+ .pytest_cache/
6
+ .ruff_cache/
7
+ *.egg-info/
@@ -0,0 +1,60 @@
1
+ # Changelog
2
+
3
+ All notable changes to container-host-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 **non-orchestrator container hosts**
9
+ across the **Docker Engine API** (unix socket or TCP) and **Portainer** (its
10
+ management API, which also proxies Docker), with a bundled governance harness. One
11
+ config can span many hosts; a per-target `platform` field selects the API shape.
12
+ **Mock-validated only — not yet verified against a live Docker daemon or Portainer
13
+ server.**
14
+
15
+ ### Added
16
+
17
+ - **34 MCP tools** (26 read, 8 write), every one wrapped with the bundled
18
+ `@governed_tool` harness (audit, policy, token/runaway budget, undo,
19
+ risk-tiers):
20
+ - **Overview** — `overview` (one-shot host health: version + container state
21
+ rollup + disk headline).
22
+ - **Containers (read)** — `list_containers`, `inspect_container`,
23
+ `container_logs` (tail N), `container_stats` (CPU%/mem%), `container_top`,
24
+ `container_restart_summary`.
25
+ - **Images (read)** — `list_images`, `inspect_image` (with history/layers),
26
+ `dangling_images`, `image_disk_usage`.
27
+ - **Volumes (read)** — `list_volumes`, `inspect_volume`, `dangling_volumes`.
28
+ - **Networks (read)** — `list_networks`, `inspect_network`.
29
+ - **System (read)** — `system_info`, `system_version`, `system_df`,
30
+ `system_events`.
31
+ - **Stacks (Portainer, read)** — `list_endpoints`, `list_stacks`,
32
+ `stack_detail`.
33
+ - **Flagship analyses (read)** — `restart_loop_rca` (crash-looping containers +
34
+ cause/action from exit code + log tail), `resource_pressure_analysis`
35
+ (CPU/memory vs limits + recommendation), `image_and_volume_bloat` (dangling
36
+ images + volumes + build cache → prune candidates with reclaimable bytes).
37
+ - **Writes** — `restart_container` (med), `stop_container` (med, undo→start),
38
+ `start_container` (med, undo→stop), `update_container` (med, undo restores
39
+ prior CPU/memory limits), `remove_container` (**high**, captures full inspect
40
+ first), `prune_images` (**high**, dry-run lists candidates), `prune_volumes`
41
+ (**high**, dry-run lists candidates), `recreate_stack` (**high**, Portainer).
42
+ - **Connection layer** — Docker over a unix socket (`httpx.HTTPTransport(uds=...)`)
43
+ or a TCP host; Portainer over HTTPS with an `X-API-Key` token that also proxies
44
+ the Docker API of a managed endpoint (`/api/endpoints/{id}/docker/...`).
45
+ - **Encrypted secret store** — the Portainer API token is stored encrypted in
46
+ `~/.container-host-aiops/secrets.enc` (Fernet + scrypt); never plaintext on disk.
47
+ A direct Docker socket needs no secret. Legacy `CONTAINER_HOST_<TARGET>_TOKEN`
48
+ env var honoured as a fallback.
49
+ - **CLI** (`container-host-aiops`) — `init` platform-picking wizard, `overview`,
50
+ `container`, `image`, `volume`, `network`, `system`, `stack`, `analyze`,
51
+ `manage` (guarded writes with `--dry-run` + double-confirm), `secret`
52
+ management, and a platform-aware `doctor`.
53
+
54
+ ### Known limitations
55
+
56
+ - Preview / mock-only: the Docker Engine + Portainer API responses are mocked and
57
+ need live verification against a real daemon / server. `container-host-aiops
58
+ doctor` is the fastest live check.
59
+ - Single-host focus by design: cluster orchestrators, hypervisors, storage
60
+ appliances, and backup products are out of scope (separate AIops-tools).
@@ -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,96 @@
1
+ Metadata-Version: 2.4
2
+ Name: container-host-aiops
3
+ Version: 0.1.0
4
+ Summary: Governed AI-ops for Docker + Portainer container hosts: container/image/volume/network/system reads, restart-loop and resource-pressure and bloat analyses, and guarded lifecycle + prune writes 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/container-host-aiops -->
18
+
19
+ # Container Host AIops (preview)
20
+
21
+ > **Disclaimer**: Community-maintained open-source project. **Not affiliated with, endorsed by, or sponsored by Docker, Inc., Portainer.io, or any container-platform vendor.** "Docker", "Portainer" and all product/trademark names belong to their respective owners. MIT licensed.
22
+
23
+ Governed AI-ops for **non-orchestrator container hosts** — the **Docker Engine API** (over a local unix socket or a TCP host) and **Portainer** (its management API, which also proxies Docker) — with a **built-in governance harness**: unified audit log, policy engine, token/runaway budget guard, undo-token recording, and graduated-autonomy risk tiers. **Multi-platform by construction**: a registry keyed by `platform` means a per-target `platform` field (`docker` / `portainer`) selects the API shape, and another host family could be added later without touching the ops/CLI/MCP layers. **Preview — mock-validated only, not verified against a live Docker daemon or Portainer server.**
24
+
25
+ ## What it does
26
+
27
+ Three flagship signature analyses, plus the guarded reads and writes around them:
28
+
29
+ - **Restart-loop RCA** — inspect containers for restart count + exit code, flag the crash-looping ones (restartCount over threshold, or restarting/dead, or a non-zero exit), and map each to a likely cause + action from the exit code (137 OOM/SIGKILL, 143 SIGTERM, 139 segfault, 127 bad entrypoint, …), with a tail of logs. Every ranking carries its numbers, not a black-box verdict.
30
+ - **Resource-pressure analysis** — a one-shot CPU%/memory% sample per running container vs its configured limits, flagging each "near" (≥ 80% of a threshold) or "over", with a recommendation (raise a limit, set a missing memory limit, scale out).
31
+ - **Image & volume bloat** — dangling images + dangling volumes + build cache from `system/df`, totalled into prune candidates with reclaimable bytes.
32
+
33
+ ## What works
34
+
35
+ - **CLI** (`container-host-aiops ...`): `init`, `overview`, `container`, `image`, `volume`, `network`, `system`, `stack`, `analyze`, `manage`, `secret`, `doctor`, `mcp`.
36
+ - **MCP server** (`container-host-aiops mcp` or `container-host-aiops-mcp`): **34 tools** (26 read, 8 write), every one wrapped with the bundled `@governed_tool` harness.
37
+ - **Connection layer**: Docker over a **unix socket** (`httpx.HTTPTransport(uds=...)`) or a TCP host; Portainer over HTTPS with an `X-API-Key` token that also proxies the Docker API of a managed endpoint. A local Docker socket needs **no secret** — the socket's file permissions are the boundary.
38
+ - **Encrypted credentials**: the Portainer API token lives in an encrypted store `~/.container-host-aiops/secrets.enc` (Fernet + scrypt) — **never plaintext on disk**. Unlock with a master password from `CONTAINER_HOST_AIOPS_MASTER_PASSWORD` (MCP/CI) or an interactive prompt (CLI).
39
+ - **Reversibility**: mutating writes fetch the **real before-state first** and record a faithful inverse (`stop`↔`start`; `update_container` restores prior CPU/memory limits). Irreversible ops (`remove_container`, `prune_images`, `prune_volumes`, `recreate_stack`) capture the before-state for audit but declare no undo.
40
+ - **Safety**: every state-changing CLI op supports `--dry-run` and requires double confirmation; every write MCP tool takes a `dry_run` preview — and prune previews **list what would be removed + reclaimable bytes** before doing it.
41
+
42
+ ## Capability matrix (34 MCP tools)
43
+
44
+ | Domain | Tools | Count | R/W |
45
+ |--------|-------|:-----:|:---:|
46
+ | **Overview** | `overview` | 1 | read |
47
+ | **Containers** | `list_containers`, `inspect_container`, `container_logs`, `container_stats`, `container_top`, `container_restart_summary` | 6 | read |
48
+ | **Images** | `list_images`, `inspect_image`, `dangling_images`, `image_disk_usage` | 4 | read |
49
+ | **Volumes** | `list_volumes`, `inspect_volume`, `dangling_volumes` | 3 | read |
50
+ | **Networks** | `list_networks`, `inspect_network` | 2 | read |
51
+ | **System** | `system_info`, `system_version`, `system_df`, `system_events` | 4 | read |
52
+ | **Stacks (Portainer)** | `list_endpoints`, `list_stacks`, `stack_detail` | 3 | read |
53
+ | **Analyses (flagship)** | `restart_loop_rca`, `resource_pressure_analysis`, `image_and_volume_bloat` | 3 | read |
54
+ | **Writes** | `remove_container`, `prune_images`, `prune_volumes`, `recreate_stack` | 4 | write (high) |
55
+ | | `restart_container`, `stop_container`, `start_container`, `update_container` | 4 | write (medium) |
56
+
57
+ The three analyses accept injected data for offline analysis, or pull live from a configured target. Stacks/endpoints require a `portainer` target.
58
+
59
+ ## Quick start
60
+
61
+ ```bash
62
+ uv tool install container-host-aiops # or: pipx install container-host-aiops
63
+ container-host-aiops init # wizard: add a Docker socket or Portainer target
64
+ container-host-aiops doctor # verify config, secrets, connectivity
65
+ container-host-aiops overview # one-shot host health
66
+ container-host-aiops analyze restart-loop # crash-looping containers + cause/action
67
+ container-host-aiops container list --running # running containers
68
+ ```
69
+
70
+ Run as an MCP server (stdio):
71
+
72
+ ```bash
73
+ export CONTAINER_HOST_AIOPS_MASTER_PASSWORD=... # only needed for Portainer targets
74
+ container-host-aiops-mcp
75
+ ```
76
+
77
+ ## Governance
78
+
79
+ Every MCP tool passes through the bundled `@governed_tool` harness:
80
+
81
+ - **Audit** — every call (params, result, status, duration, risk tier, approver, rationale) is logged to `~/.container-host-aiops/audit.db` (relocatable via `CONTAINER_HOST_AIOPS_HOME`).
82
+ - **Budget / runaway guard** — token and call budgets trip a circuit breaker.
83
+ - **Risk tiers** — graduated autonomy; high-risk ops (remove / prune / recreate) can require a named approver.
84
+ - **Undo recording** — reversible writes record an inverse descriptor built from the fetched before-state.
85
+
86
+ ## Scope
87
+
88
+ This is the **container-host** member of the AIops-tools family (governed AI-ops with audit + budget + undo + risk tiers), for **single-host Docker / Portainer**. It is deliberately **NOT** for a cluster orchestrator, a hypervisor, a storage appliance, a backup product, or OT / industrial edge — those are separate tools/lines.
89
+
90
+ ## Missing a capability?
91
+
92
+ Coverage is intentionally a curated subset of the Docker Engine + Portainer APIs. Missing a call, or want another container host family? **Open an issue or PR** — contributions welcome.
93
+
94
+ ## Status
95
+
96
+ **Preview — mock-validated only, not verified against a live Docker daemon or Portainer server.** The API paths are modelled from the public API shape and need live verification. `container-host-aiops doctor` is the fastest live check.
@@ -0,0 +1,80 @@
1
+ <!-- mcp-name: io.github.AIops-tools/container-host-aiops -->
2
+
3
+ # Container Host AIops (preview)
4
+
5
+ > **Disclaimer**: Community-maintained open-source project. **Not affiliated with, endorsed by, or sponsored by Docker, Inc., Portainer.io, or any container-platform vendor.** "Docker", "Portainer" and all product/trademark names belong to their respective owners. MIT licensed.
6
+
7
+ Governed AI-ops for **non-orchestrator container hosts** — the **Docker Engine API** (over a local unix socket or a TCP host) and **Portainer** (its management API, which also proxies Docker) — with a **built-in governance harness**: unified audit log, policy engine, token/runaway budget guard, undo-token recording, and graduated-autonomy risk tiers. **Multi-platform by construction**: a registry keyed by `platform` means a per-target `platform` field (`docker` / `portainer`) selects the API shape, and another host family could be added later without touching the ops/CLI/MCP layers. **Preview — mock-validated only, not verified against a live Docker daemon or Portainer server.**
8
+
9
+ ## What it does
10
+
11
+ Three flagship signature analyses, plus the guarded reads and writes around them:
12
+
13
+ - **Restart-loop RCA** — inspect containers for restart count + exit code, flag the crash-looping ones (restartCount over threshold, or restarting/dead, or a non-zero exit), and map each to a likely cause + action from the exit code (137 OOM/SIGKILL, 143 SIGTERM, 139 segfault, 127 bad entrypoint, …), with a tail of logs. Every ranking carries its numbers, not a black-box verdict.
14
+ - **Resource-pressure analysis** — a one-shot CPU%/memory% sample per running container vs its configured limits, flagging each "near" (≥ 80% of a threshold) or "over", with a recommendation (raise a limit, set a missing memory limit, scale out).
15
+ - **Image & volume bloat** — dangling images + dangling volumes + build cache from `system/df`, totalled into prune candidates with reclaimable bytes.
16
+
17
+ ## What works
18
+
19
+ - **CLI** (`container-host-aiops ...`): `init`, `overview`, `container`, `image`, `volume`, `network`, `system`, `stack`, `analyze`, `manage`, `secret`, `doctor`, `mcp`.
20
+ - **MCP server** (`container-host-aiops mcp` or `container-host-aiops-mcp`): **34 tools** (26 read, 8 write), every one wrapped with the bundled `@governed_tool` harness.
21
+ - **Connection layer**: Docker over a **unix socket** (`httpx.HTTPTransport(uds=...)`) or a TCP host; Portainer over HTTPS with an `X-API-Key` token that also proxies the Docker API of a managed endpoint. A local Docker socket needs **no secret** — the socket's file permissions are the boundary.
22
+ - **Encrypted credentials**: the Portainer API token lives in an encrypted store `~/.container-host-aiops/secrets.enc` (Fernet + scrypt) — **never plaintext on disk**. Unlock with a master password from `CONTAINER_HOST_AIOPS_MASTER_PASSWORD` (MCP/CI) or an interactive prompt (CLI).
23
+ - **Reversibility**: mutating writes fetch the **real before-state first** and record a faithful inverse (`stop`↔`start`; `update_container` restores prior CPU/memory limits). Irreversible ops (`remove_container`, `prune_images`, `prune_volumes`, `recreate_stack`) capture the before-state for audit but declare no undo.
24
+ - **Safety**: every state-changing CLI op supports `--dry-run` and requires double confirmation; every write MCP tool takes a `dry_run` preview — and prune previews **list what would be removed + reclaimable bytes** before doing it.
25
+
26
+ ## Capability matrix (34 MCP tools)
27
+
28
+ | Domain | Tools | Count | R/W |
29
+ |--------|-------|:-----:|:---:|
30
+ | **Overview** | `overview` | 1 | read |
31
+ | **Containers** | `list_containers`, `inspect_container`, `container_logs`, `container_stats`, `container_top`, `container_restart_summary` | 6 | read |
32
+ | **Images** | `list_images`, `inspect_image`, `dangling_images`, `image_disk_usage` | 4 | read |
33
+ | **Volumes** | `list_volumes`, `inspect_volume`, `dangling_volumes` | 3 | read |
34
+ | **Networks** | `list_networks`, `inspect_network` | 2 | read |
35
+ | **System** | `system_info`, `system_version`, `system_df`, `system_events` | 4 | read |
36
+ | **Stacks (Portainer)** | `list_endpoints`, `list_stacks`, `stack_detail` | 3 | read |
37
+ | **Analyses (flagship)** | `restart_loop_rca`, `resource_pressure_analysis`, `image_and_volume_bloat` | 3 | read |
38
+ | **Writes** | `remove_container`, `prune_images`, `prune_volumes`, `recreate_stack` | 4 | write (high) |
39
+ | | `restart_container`, `stop_container`, `start_container`, `update_container` | 4 | write (medium) |
40
+
41
+ The three analyses accept injected data for offline analysis, or pull live from a configured target. Stacks/endpoints require a `portainer` target.
42
+
43
+ ## Quick start
44
+
45
+ ```bash
46
+ uv tool install container-host-aiops # or: pipx install container-host-aiops
47
+ container-host-aiops init # wizard: add a Docker socket or Portainer target
48
+ container-host-aiops doctor # verify config, secrets, connectivity
49
+ container-host-aiops overview # one-shot host health
50
+ container-host-aiops analyze restart-loop # crash-looping containers + cause/action
51
+ container-host-aiops container list --running # running containers
52
+ ```
53
+
54
+ Run as an MCP server (stdio):
55
+
56
+ ```bash
57
+ export CONTAINER_HOST_AIOPS_MASTER_PASSWORD=... # only needed for Portainer targets
58
+ container-host-aiops-mcp
59
+ ```
60
+
61
+ ## Governance
62
+
63
+ Every MCP tool passes through the bundled `@governed_tool` harness:
64
+
65
+ - **Audit** — every call (params, result, status, duration, risk tier, approver, rationale) is logged to `~/.container-host-aiops/audit.db` (relocatable via `CONTAINER_HOST_AIOPS_HOME`).
66
+ - **Budget / runaway guard** — token and call budgets trip a circuit breaker.
67
+ - **Risk tiers** — graduated autonomy; high-risk ops (remove / prune / recreate) can require a named approver.
68
+ - **Undo recording** — reversible writes record an inverse descriptor built from the fetched before-state.
69
+
70
+ ## Scope
71
+
72
+ This is the **container-host** member of the AIops-tools family (governed AI-ops with audit + budget + undo + risk tiers), for **single-host Docker / Portainer**. It is deliberately **NOT** for a cluster orchestrator, a hypervisor, a storage appliance, a backup product, or OT / industrial edge — those are separate tools/lines.
73
+
74
+ ## Missing a capability?
75
+
76
+ Coverage is intentionally a curated subset of the Docker Engine + Portainer APIs. Missing a call, or want another container host family? **Open an issue or PR** — contributions welcome.
77
+
78
+ ## Status
79
+
80
+ **Preview — mock-validated only, not verified against a live Docker daemon or Portainer server.** The API paths are modelled from the public API shape and need live verification. `container-host-aiops doctor` is the fastest live check.
@@ -0,0 +1,59 @@
1
+ # Container Host AIops v0.1.0 — preview
2
+
3
+ Governed AI-ops for **non-orchestrator container hosts** across the **Docker
4
+ Engine API** (unix socket or TCP) and **Portainer** (its management API, which
5
+ also proxies Docker) for AI agents, with a built-in governance harness (audit,
6
+ policy, token/runaway budget, undo-token recording, graduated risk tiers) and an
7
+ encrypted credential store. Standalone — no external skill-family dependency. One
8
+ config can span many hosts; a per-target `platform` field selects the API shape.
9
+
10
+ > **Preview / mock-only.** All behaviour is validated against mocked Docker /
11
+ > Portainer responses; it has not been run against a live daemon or server. The
12
+ > fastest live check is `container-host-aiops doctor`.
13
+
14
+ ## Highlights
15
+
16
+ - **34 MCP tools** (26 read, 8 write), every one wrapped with `@governed_tool`.
17
+ - **Overview** — `overview` (host version + container state rollup + disk).
18
+ - **Containers** — `list_containers`, `inspect_container`, `container_logs`,
19
+ `container_stats`, `container_top`, `container_restart_summary`.
20
+ - **Images** — `list_images`, `inspect_image`, `dangling_images`,
21
+ `image_disk_usage`.
22
+ - **Volumes / Networks** — `list_volumes`, `inspect_volume`, `dangling_volumes`;
23
+ `list_networks`, `inspect_network`.
24
+ - **System** — `system_info`, `system_version`, `system_df`, `system_events`.
25
+ - **Stacks (Portainer)** — `list_endpoints`, `list_stacks`, `stack_detail`.
26
+ - **Writes** — `restart_container`, `stop_container`/`start_container`,
27
+ `update_container`, `remove_container`, `prune_images`/`prune_volumes`,
28
+ `recreate_stack`.
29
+ - **Three flagship analyses** — `restart_loop_rca` (crash-looping containers +
30
+ cause/action from exit code + log tail), `resource_pressure_analysis` (CPU/memory
31
+ vs limits + recommendation), `image_and_volume_bloat` (prune candidates +
32
+ reclaimable bytes). Each accepts injected data for offline analysis or pulls live.
33
+ - **Connection layer** — Docker over a unix socket (`httpx.HTTPTransport(uds=...)`)
34
+ or a TCP host; Portainer over HTTPS with an `X-API-Key` token that proxies the
35
+ Docker API of a managed endpoint. A local Docker socket needs no secret.
36
+ - **Encrypted secret store** (`~/.container-host-aiops/secrets.enc`, Fernet + scrypt)
37
+ — the Portainer API token, never plaintext on disk; legacy
38
+ `CONTAINER_HOST_<TARGET>_TOKEN` env fallback.
39
+ - **Guarded writes** — destructive ops (`remove_container`, `prune_images`,
40
+ `prune_volumes`, `recreate_stack`) require dry-run + double-confirm; prune
41
+ previews list what would be removed + reclaimable bytes first. Reversible writes
42
+ capture before-state and record an inverse undo descriptor.
43
+ - **CLI** with an `init` platform-picking wizard, `secret` management, and a
44
+ platform-aware `doctor`.
45
+
46
+ ## Install
47
+
48
+ ```bash
49
+ uv tool install container-host-aiops
50
+ container-host-aiops init # pick platform (docker/portainer) + connect
51
+ container-host-aiops doctor
52
+ ```
53
+
54
+ ## Caveats
55
+
56
+ - Preview / mock-only: the Docker Engine + Portainer API responses are mocked and
57
+ need live verification.
58
+ - Single-host focus by design: cluster orchestrators, hypervisors, storage
59
+ appliances, and backup products are out of scope (separate AIops-tools).
@@ -0,0 +1,83 @@
1
+ # Security Policy
2
+
3
+ ## Disclaimer
4
+
5
+ Community-maintained open-source project. **Not affiliated with, endorsed by, or
6
+ sponsored by Docker, Inc. or Portainer.io.** Product and trademark names (Docker,
7
+ Portainer) belong to their owners. Source is auditable under the MIT license.
8
+
9
+ ## Reporting Vulnerabilities
10
+
11
+ Report privately via a GitHub Security Advisory on
12
+ [github.com/AIops-tools/Container-Host-AIops](https://github.com/AIops-tools/Container-Host-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
+ - The only secret is the **Portainer API token**. It lives **encrypted** in
20
+ `~/.container-host-aiops/secrets.enc` (Fernet/AES-128 + scrypt-derived key; chmod
21
+ 600), never in `config.yaml` and never in source. The master password is never
22
+ stored — only a per-store random salt and the ciphertext are on disk.
23
+ - A **direct Docker socket** target needs no secret at all — the unix socket's
24
+ file permissions are the trust boundary. Treat access to `/var/run/docker.sock`
25
+ as root-equivalent on the host and scope it accordingly.
26
+ - A legacy plaintext env var `CONTAINER_HOST_<TARGET_NAME_UPPER>_TOKEN` is still
27
+ honoured as a fallback with a deprecation warning (migrate with
28
+ `container-host-aiops secret migrate`).
29
+ - The token is held only in memory and never logged or echoed; it is sent in the
30
+ `X-API-Key` request header at call time. The config file holds only platform,
31
+ socket path / host, port, endpoint id, and TLS settings.
32
+
33
+ ### Governed Operations
34
+ Every MCP tool runs through the bundled `@governed_tool` harness
35
+ (`container_host_aiops.governance`):
36
+ - **Audit** — every call logged to a local SQLite DB under `~/.container-host-aiops/`
37
+ (relocatable via `CONTAINER_HOST_AIOPS_HOME`), agent-attributed, secret-redacted.
38
+ - **Token/runaway budget** — hard ceilings (`CONTAINER_HOST_MAX_TOOL_CALLS` /
39
+ `CONTAINER_HOST_MAX_TOOL_SECONDS` — the env-var names the bundled harness reads)
40
+ plus an on-by-default guard that trips a tight poll/retry loop, preventing
41
+ unbounded API consumption.
42
+ - **Graduated risk tiers** — `~/.container-host-aiops/rules.yaml` `risk_tiers` gate
43
+ writes by environment/tag; the highest tiers require a recorded approver.
44
+ - **Undo-token recording** — reversible writes capture the BEFORE state and
45
+ record an inverse descriptor (e.g. `stop_container`→`start_container`,
46
+ `update_container`→restore prior limits) so the change can be rolled back.
47
+
48
+ ### State-Changing Operations
49
+ Destructive writes — `remove_container`, `prune_images`, `prune_volumes`,
50
+ `recreate_stack` — are `risk_level=high`, accept a `dry_run` preview (prune
51
+ previews **list what would be removed + reclaimable bytes** first), and (under
52
+ `risk_tiers`) require a recorded approver (`CONTAINER_HOST_AUDIT_APPROVED_BY` +
53
+ `CONTAINER_HOST_AUDIT_RATIONALE` — the env-var names the bundled harness reads).
54
+ Lifecycle writes (`restart_container`, `stop_container`, `start_container`,
55
+ `update_container`) are `risk_level=medium`; reversible ones capture before-state
56
+ and record an undo token. `remove_container` captures the full inspect JSON
57
+ before deletion for the audit trail.
58
+
59
+ ### SSL/TLS Verification
60
+ `verify_ssl` defaults to true; disable only for a self-signed Portainer / TLS
61
+ Docker daemon in a lab. A unix-socket Docker target does not use TLS.
62
+
63
+ ### Prompt-Injection Protection
64
+ All host-returned text (container names, image tags, log lines, event text,
65
+ volume/network names) is passed through a `sanitize()` truncate +
66
+ control-character strip before reaching the agent, bounded in depth and length.
67
+
68
+ ### Network Scope
69
+ No webhooks, no telemetry, no outbound calls beyond the configured Docker socket /
70
+ TCP host or the Portainer API base URL. No post-install scripts or background
71
+ services.
72
+
73
+ ## Static Analysis
74
+
75
+ ```bash
76
+ uvx bandit -r container_host_aiops/ mcp_server/
77
+ uv run ruff check .
78
+ ```
79
+
80
+ ## Supported Versions
81
+
82
+ The latest released version receives security fixes. This is a preview (0.x);
83
+ pin a version in production.
@@ -0,0 +1,9 @@
1
+ """container-host-aiops — governed Docker + Portainer container-host ops 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 ``container_host_aiops.governance`` — this package has no external
6
+ skill-family dependency. Preview: not yet full-coverage, mock-validated only.
7
+ """
8
+
9
+ __version__ = "0.1.0"
@@ -0,0 +1,9 @@
1
+ """CLI package for container-host-aiops.
2
+
3
+ Re-exports ``app`` so the pyproject entry point
4
+ ``container-host-aiops = "container_host_aiops.cli:app"`` works unchanged.
5
+ """
6
+
7
+ from container_host_aiops.cli._root import app
8
+
9
+ __all__ = ["app"]
@@ -0,0 +1,78 @@
1
+ """Shared helpers for container-host-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 container_host_aiops.connection import ContainerHostApiError
28
+
29
+ return (ContainerHostApiError, 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 container_host_aiops.config import load_config
54
+ from container_host_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,70 @@
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 container_host_aiops.cli._common import cli_errors
8
+ from container_host_aiops.cli.analyze import analyze_app
9
+ from container_host_aiops.cli.container import container_app
10
+ from container_host_aiops.cli.doctor import doctor_cmd
11
+ from container_host_aiops.cli.image import image_app
12
+ from container_host_aiops.cli.init import init_cmd
13
+ from container_host_aiops.cli.manage import manage_app
14
+ from container_host_aiops.cli.network import network_app
15
+ from container_host_aiops.cli.overview import overview_cmd
16
+ from container_host_aiops.cli.secret import secret_app
17
+ from container_host_aiops.cli.stack import stack_app
18
+ from container_host_aiops.cli.system import system_app
19
+ from container_host_aiops.cli.volume import volume_app
20
+
21
+ app = typer.Typer(
22
+ name="container-host-aiops",
23
+ help="Governed AI-ops for Docker + Portainer container hosts: container / "
24
+ "image / volume / network / system reads, flagship analyses, and guarded "
25
+ "lifecycle + prune writes with a built-in governance harness.",
26
+ no_args_is_help=True,
27
+ )
28
+
29
+ app.add_typer(container_app, name="container")
30
+ app.add_typer(image_app, name="image")
31
+ app.add_typer(volume_app, name="volume")
32
+ app.add_typer(network_app, name="network")
33
+ app.add_typer(system_app, name="system")
34
+ app.add_typer(stack_app, name="stack")
35
+ app.add_typer(analyze_app, name="analyze")
36
+ app.add_typer(manage_app, name="manage")
37
+ app.add_typer(secret_app, name="secret")
38
+ app.command("init")(init_cmd)
39
+ app.command("overview")(overview_cmd)
40
+ app.command("doctor")(doctor_cmd)
41
+
42
+
43
+ @app.command("mcp")
44
+ @cli_errors
45
+ def mcp_cmd() -> None:
46
+ """Start the MCP server (stdio transport).
47
+
48
+ Single-command entry point for MCP clients (does not go through uvx/PyPI
49
+ resolution at launch):
50
+ container-host-aiops mcp
51
+ """
52
+ import sys
53
+
54
+ if sys.version_info < (3, 11):
55
+ typer.echo(
56
+ f"ERROR: container-host-aiops requires Python >= 3.11 "
57
+ f"(got {sys.version_info.major}.{sys.version_info.minor}).\n"
58
+ f"Fix: uv python install 3.12 && "
59
+ f"uv tool install --python 3.12 --force container-host-aiops",
60
+ err=True,
61
+ )
62
+ raise typer.Exit(2)
63
+
64
+ from mcp_server.server import main as _mcp_main
65
+
66
+ _mcp_main()
67
+
68
+
69
+ if __name__ == "__main__":
70
+ app()