cicd-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 (80) hide show
  1. cicd_aiops-0.1.0/.github/workflows/mcp-publish.yml +55 -0
  2. cicd_aiops-0.1.0/.github/workflows/publish.yml +26 -0
  3. cicd_aiops-0.1.0/.gitignore +8 -0
  4. cicd_aiops-0.1.0/CHANGELOG.md +30 -0
  5. cicd_aiops-0.1.0/LICENSE +21 -0
  6. cicd_aiops-0.1.0/PKG-INFO +196 -0
  7. cicd_aiops-0.1.0/README.md +180 -0
  8. cicd_aiops-0.1.0/RELEASE_NOTES.md +34 -0
  9. cicd_aiops-0.1.0/SECURITY.md +49 -0
  10. cicd_aiops-0.1.0/cicd_aiops/__init__.py +14 -0
  11. cicd_aiops-0.1.0/cicd_aiops/cli/__init__.py +9 -0
  12. cicd_aiops-0.1.0/cicd_aiops/cli/_common.py +78 -0
  13. cicd_aiops-0.1.0/cicd_aiops/cli/_root.py +65 -0
  14. cicd_aiops-0.1.0/cicd_aiops/cli/artifacts.py +65 -0
  15. cicd_aiops-0.1.0/cicd_aiops/cli/doctor.py +22 -0
  16. cicd_aiops-0.1.0/cicd_aiops/cli/init.py +149 -0
  17. cicd_aiops-0.1.0/cicd_aiops/cli/overview.py +34 -0
  18. cicd_aiops-0.1.0/cicd_aiops/cli/pipelines.py +128 -0
  19. cicd_aiops-0.1.0/cicd_aiops/cli/rca.py +98 -0
  20. cicd_aiops-0.1.0/cicd_aiops/cli/runners.py +88 -0
  21. cicd_aiops-0.1.0/cicd_aiops/cli/secret.py +105 -0
  22. cicd_aiops-0.1.0/cicd_aiops/cli/undo.py +62 -0
  23. cicd_aiops-0.1.0/cicd_aiops/config.py +152 -0
  24. cicd_aiops-0.1.0/cicd_aiops/connection.py +188 -0
  25. cicd_aiops-0.1.0/cicd_aiops/doctor.py +105 -0
  26. cicd_aiops-0.1.0/cicd_aiops/governance/__init__.py +40 -0
  27. cicd_aiops-0.1.0/cicd_aiops/governance/audit.py +377 -0
  28. cicd_aiops-0.1.0/cicd_aiops/governance/budget.py +225 -0
  29. cicd_aiops-0.1.0/cicd_aiops/governance/decorators.py +482 -0
  30. cicd_aiops-0.1.0/cicd_aiops/governance/paths.py +23 -0
  31. cicd_aiops-0.1.0/cicd_aiops/governance/patterns.py +378 -0
  32. cicd_aiops-0.1.0/cicd_aiops/governance/policy.py +430 -0
  33. cicd_aiops-0.1.0/cicd_aiops/governance/sanitize.py +45 -0
  34. cicd_aiops-0.1.0/cicd_aiops/governance/undo.py +218 -0
  35. cicd_aiops-0.1.0/cicd_aiops/ops/__init__.py +1 -0
  36. cicd_aiops-0.1.0/cicd_aiops/ops/_util.py +96 -0
  37. cicd_aiops-0.1.0/cicd_aiops/ops/analysis.py +527 -0
  38. cicd_aiops-0.1.0/cicd_aiops/ops/artifacts.py +88 -0
  39. cicd_aiops-0.1.0/cicd_aiops/ops/overview.py +56 -0
  40. cicd_aiops-0.1.0/cicd_aiops/ops/pipelines.py +116 -0
  41. cicd_aiops-0.1.0/cicd_aiops/ops/projects.py +68 -0
  42. cicd_aiops-0.1.0/cicd_aiops/ops/repos.py +124 -0
  43. cicd_aiops-0.1.0/cicd_aiops/ops/runners.py +65 -0
  44. cicd_aiops-0.1.0/cicd_aiops/ops/server.py +43 -0
  45. cicd_aiops-0.1.0/cicd_aiops/ops/writes.py +226 -0
  46. cicd_aiops-0.1.0/cicd_aiops/platform.py +289 -0
  47. cicd_aiops-0.1.0/cicd_aiops/secretstore.py +304 -0
  48. cicd_aiops-0.1.0/mcp_server/__init__.py +1 -0
  49. cicd_aiops-0.1.0/mcp_server/_shared.py +106 -0
  50. cicd_aiops-0.1.0/mcp_server/server.py +40 -0
  51. cicd_aiops-0.1.0/mcp_server/tools/__init__.py +1 -0
  52. cicd_aiops-0.1.0/mcp_server/tools/analysis.py +199 -0
  53. cicd_aiops-0.1.0/mcp_server/tools/artifacts.py +23 -0
  54. cicd_aiops-0.1.0/mcp_server/tools/pipelines.py +75 -0
  55. cicd_aiops-0.1.0/mcp_server/tools/projects.py +38 -0
  56. cicd_aiops-0.1.0/mcp_server/tools/repos.py +68 -0
  57. cicd_aiops-0.1.0/mcp_server/tools/runners.py +42 -0
  58. cicd_aiops-0.1.0/mcp_server/tools/system.py +47 -0
  59. cicd_aiops-0.1.0/mcp_server/tools/undo.py +121 -0
  60. cicd_aiops-0.1.0/mcp_server/tools/writes.py +276 -0
  61. cicd_aiops-0.1.0/pyproject.toml +60 -0
  62. cicd_aiops-0.1.0/server.json +21 -0
  63. cicd_aiops-0.1.0/skills/cicd-aiops/SKILL.md +151 -0
  64. cicd_aiops-0.1.0/skills/cicd-aiops/references/capabilities.md +77 -0
  65. cicd_aiops-0.1.0/skills/cicd-aiops/references/cli-reference.md +79 -0
  66. cicd_aiops-0.1.0/skills/cicd-aiops/references/setup-guide.md +100 -0
  67. cicd_aiops-0.1.0/smithery.yaml +9 -0
  68. cicd_aiops-0.1.0/tests/conftest.py +34 -0
  69. cicd_aiops-0.1.0/tests/test_analysis.py +251 -0
  70. cicd_aiops-0.1.0/tests/test_cli_writes.py +116 -0
  71. cicd_aiops-0.1.0/tests/test_doctor.py +225 -0
  72. cicd_aiops-0.1.0/tests/test_governance_persistence.py +177 -0
  73. cicd_aiops-0.1.0/tests/test_init.py +149 -0
  74. cicd_aiops-0.1.0/tests/test_platform.py +189 -0
  75. cicd_aiops-0.1.0/tests/test_reads.py +314 -0
  76. cicd_aiops-0.1.0/tests/test_secretstore.py +99 -0
  77. cicd_aiops-0.1.0/tests/test_smoke.py +153 -0
  78. cicd_aiops-0.1.0/tests/test_undo_executor.py +138 -0
  79. cicd_aiops-0.1.0/tests/test_writes.py +339 -0
  80. cicd_aiops-0.1.0/uv.lock +1121 -0
@@ -0,0 +1,55 @@
1
+ name: mcp-publish
2
+
3
+ on:
4
+ workflow_dispatch:
5
+ release:
6
+ types: [published]
7
+
8
+ permissions:
9
+ id-token: write
10
+ contents: read
11
+
12
+ jobs:
13
+ publish-mcp:
14
+ runs-on: ubuntu-latest
15
+ steps:
16
+ - uses: actions/checkout@v4
17
+ - name: Wait for PyPI
18
+ # The release event also triggers the PyPI publish workflow; the MCP
19
+ # registry validates that the package version exists on PyPI, so poll
20
+ # until it has propagated (every 15s, up to 10 minutes).
21
+ run: |
22
+ python3 - <<'EOF'
23
+ import json
24
+ import sys
25
+ import time
26
+ import urllib.error
27
+ import urllib.request
28
+
29
+ with open("server.json", encoding="utf-8") as f:
30
+ package = json.load(f)["packages"][0]
31
+ name, version = package["identifier"], package["version"]
32
+ url = f"https://pypi.org/pypi/{name}/{version}/json"
33
+ deadline = time.monotonic() + 600
34
+ while True:
35
+ try:
36
+ with urllib.request.urlopen(url, timeout=10):
37
+ print(f"{name}=={version} is available on PyPI.")
38
+ sys.exit(0)
39
+ except (urllib.error.URLError, OSError) as exc:
40
+ print(f"{name}=={version} not on PyPI yet ({exc}); "
41
+ "retrying in 15s...")
42
+ if time.monotonic() >= deadline:
43
+ sys.exit(f"Timed out after 10 minutes waiting for "
44
+ f"{name}=={version} to appear on PyPI. "
45
+ "Check the PyPI publish workflow, then re-run "
46
+ "this workflow via workflow_dispatch.")
47
+ time.sleep(15)
48
+ EOF
49
+ - name: Install mcp-publisher
50
+ run: |
51
+ curl -sL "https://github.com/modelcontextprotocol/registry/releases/latest/download/mcp-publisher_$(uname -s | tr '[:upper:]' '[:lower:]')_$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/').tar.gz" | tar xz mcp-publisher
52
+ - name: Login to MCP Registry (GitHub OIDC)
53
+ run: ./mcp-publisher login github-oidc
54
+ - name: Publish server.json
55
+ run: ./mcp-publisher publish
@@ -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,8 @@
1
+ .venv/
2
+ dist/
3
+ __pycache__/
4
+ *.pyc
5
+ .pytest_cache/
6
+ .ruff_cache/
7
+ *.egg-info/
8
+ .coverage
@@ -0,0 +1,30 @@
1
+ # Changelog
2
+
3
+ ## v0.1.0 — 2026-07-17
4
+
5
+ Initial preview release.
6
+
7
+ - **Platforms**: self-managed GitLab (REST API v4, `PRIVATE-TOKEN`) and
8
+ self-hosted Gitea (API v1, `Authorization: token`) behind a name-keyed
9
+ platform registry; unsupported surfaces raise teaching errors.
10
+ - **Reads (16)**: server version + token identity + overview; projects with
11
+ storage statistics; pipelines/runs, jobs, trace tails; runner fleet
12
+ (GitLab); merge/pull requests, branches, protection rules, releases;
13
+ artifact inventories with expiry.
14
+ - **Flagship analyses (4)**: `pipeline_failure_rca` (test-failure /
15
+ dependency-network / runner-timeout / oom / script-error with evidence),
16
+ `runner_health_rca` (offline/stale/paused, queue waits, tag saturation),
17
+ `artifact_storage_bloat_analysis` (ranked storage + reclaimable bytes),
18
+ `stale_work_audit` (idle MRs/branches, protection gaps).
19
+ - **Governed writes (6)**: `retry_pipeline` / `cancel_pipeline` (priorState
20
+ status), `pause_runner` / `resume_runner` (reversible undo pair),
21
+ `delete_artifacts` (risk=high, priorState bytes/count, irreversible),
22
+ `update_branch_protection` (undo replays prior settings). All with
23
+ `dry_run` previews; CLI writes double-confirm and run through the governed
24
+ path (audited).
25
+ - **Governance harness** bundled: audit (`~/.cicd-aiops/audit.db`), policy
26
+ engine with secure-by-default dual-control for high risk, token/runaway
27
+ budgets, undo store, injection-safe output sanitisation.
28
+ - **Secrets**: encrypted store (`secrets.enc`, Fernet + scrypt), `init`
29
+ wizard, `secret` commands; TLS verification defaults ON.
30
+ - 114 tests, mock-only (no live server validation yet).
@@ -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,196 @@
1
+ Metadata-Version: 2.4
2
+ Name: cicd-aiops
3
+ Version: 0.1.0
4
+ Summary: Governed AI-ops for self-managed GitLab + Gitea CI/CD: pipelines, jobs, runners, artifacts, repo hygiene, flagship RCA analyses (pipeline failures, runner health, storage bloat, stale work), and governed writes (retry/cancel, pause/resume, artifact deletion, branch protection) 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
+ # CICD AIops
18
+
19
+ **Governed AI-ops for self-managed GitLab and self-hosted Gitea.**
20
+
21
+ `cicd-aiops` is for the team running its *own* CI/CD forge — a GitLab instance
22
+ or a Gitea server on your hardware, in your lab, behind your VPN — who want an
23
+ AI agent that can answer "why did the pipeline fail?", "which runner is
24
+ wedged?", "where did 40 GB of artifact storage go?" and "what work went
25
+ stale?" and then act (retry, cancel, pause, delete, protect) **only** through
26
+ an audited, budgeted, risk-tiered, undo-recorded governance harness. It is not
27
+ a SaaS integration: it speaks the GitLab REST API v4 and the Gitea API v1
28
+ directly against your server, with credentials encrypted at rest.
29
+
30
+ > **Preview / mock-only**: modelled from each project's public API docs and
31
+ > exercised against mocked HTTP responses; not yet validated against live
32
+ > servers. `cicd-aiops doctor` is the fastest live check.
33
+
34
+ > **Routing**: Do NOT use this for Kubernetes deploy state — use k8s-aiops.
35
+ > This tool ends at the CI/CD server's API (pipelines, runners, artifacts,
36
+ > repo hygiene).
37
+
38
+ ## Quick start
39
+
40
+ ```bash
41
+ uv tool install cicd-aiops # or: pip install cicd-aiops
42
+
43
+ cicd-aiops init # wizard: base URL + token (encrypted) + TLS verify
44
+ cicd-aiops doctor # connectivity + token-scope probe per target
45
+ cicd-aiops overview # version, identity, projects, runners at a glance
46
+ ```
47
+
48
+ Then the interesting parts:
49
+
50
+ ```bash
51
+ cicd-aiops rca pipelines dev/api # classify recent failed pipelines
52
+ cicd-aiops rca runners # offline/stale runners, tag saturation
53
+ cicd-aiops rca storage # artifact/repo bloat, reclaimable bytes
54
+ cicd-aiops rca stale dev/api # stale MRs/branches, protection gaps
55
+
56
+ cicd-aiops pipelines retry dev/api 42 --dry-run
57
+ cicd-aiops artifacts delete dev/api --older-than-days 30 --dry-run
58
+ ```
59
+
60
+ Every write has `--dry-run` and a double confirmation, and executes through
61
+ the same governed path the MCP tools use — so CLI writes are audited too.
62
+
63
+ ## Support scope
64
+
65
+ | Surface | GitLab (REST v4, self-managed) | Gitea (API v1, self-hosted) |
66
+ |---|---|---|
67
+ | Server version + token identity | ✅ | ✅ |
68
+ | Projects + storage statistics | ✅ (`statistics=true`) | ✅ (repo `size`) |
69
+ | Pipelines / runs, jobs, trace tails | ✅ | ✅ (Actions runs/jobs/logs) |
70
+ | Runner fleet (list/detail) | ✅ | ❌ teaching error (no API v1 equivalent) |
71
+ | Merge/pull requests, branches, protection, releases | ✅ | ✅ |
72
+ | Artifact inventory | ✅ (via jobs) | ✅ (Actions artifacts) |
73
+ | `retry_pipeline` / `cancel_pipeline` | ✅ | ❌ teaching error |
74
+ | `pause_runner` / `resume_runner` | ✅ | ❌ teaching error |
75
+ | `delete_artifacts` | ✅ | ❌ teaching error |
76
+ | `update_branch_protection` | ✅ | ✅ |
77
+
78
+ Where a platform lacks a surface, the platform registry raises a *teaching
79
+ error* naming the resources that **are** available — the agent learns instead
80
+ of hitting a mystery 404. GitLab.com / Gitea Cloud SaaS accounts are out of
81
+ scope by design: this tool targets self-managed instances.
82
+
83
+ ## Flagship analyses (the reason this tool exists)
84
+
85
+ 1. **`pipeline_failure_rca`** — pulls recent failed pipelines with failed-job
86
+ trace tails and classifies each failure: *test-failure /
87
+ dependency-network / runner-timeout / oom / script-error*, with the matched
88
+ evidence, a cause, and an action per pipeline.
89
+ 2. **`runner_health_rca`** — offline/stale/paused runners (contact-age
90
+ threshold), jobs queued past a threshold, and per-tag saturation (queued
91
+ jobs vs online runners).
92
+ 3. **`artifact_storage_bloat_analysis`** — projects ranked by repo + artifact
93
+ bytes, expired-but-kept artifacts, and a reclaimable-bytes estimate that
94
+ feeds straight into `delete_artifacts --dry-run`.
95
+ 4. **`stale_work_audit`** — merge/pull requests idle past N days, branches
96
+ with no commits for N days, and protection gaps (unprotected default
97
+ branch, force-push allowed).
98
+
99
+ All four are transparent heuristics: thresholds are named parameters and every
100
+ flag carries its numbers.
101
+
102
+ ## Governance (built in, always on)
103
+
104
+ Every MCP tool and every CLI write runs through the vendored harness in
105
+ `cicd_aiops/governance/`:
106
+
107
+ - **Audit** — every call (including denials and errors) lands in
108
+ `~/.cicd-aiops/audit.db` with params, status, risk level, and approver.
109
+ - **Budget** — call/time budgets and a runaway breaker
110
+ (`CICD_MAX_TOOL_CALLS`, `CICD_MAX_TOOL_SECONDS`, `CICD_RUNAWAY_MAX`).
111
+ - **Risk tiers, secure by default** — reads are `low`; mutating writes are
112
+ `medium`; `delete_artifacts` is `high`. With no `rules.yaml`, high-risk
113
+ writes are **denied unless a named approver** is set
114
+ (`CICD_AUDIT_APPROVED_BY`, plus `CICD_AUDIT_RATIONALE`). `init` seeds a
115
+ starter `rules.yaml` with that dual-control tier spelled out.
116
+ - **Undo** — reversible writes record a replayable inverse in
117
+ `~/.cicd-aiops/undo.db`, built from the *fetched* before-state:
118
+ `pause_runner` ⇄ `resume_runner`, and `update_branch_protection` replays the
119
+ prior settings. Irreversible writes (`retry_pipeline`, `cancel_pipeline`,
120
+ `delete_artifacts`) record `priorState` (status / bytes+count) instead.
121
+ - **Dry-run everywhere** — every write takes `dry_run=True` (MCP) /
122
+ `--dry-run` (CLI) and previews without calling the server.
123
+ - **Sanitize** — all server-returned text is folded through an
124
+ injection-safe normaliser (bounded strings, capped depth) before an agent
125
+ sees it; all path parameters are percent-encoded so an identifier can never
126
+ rewrite a URL.
127
+
128
+ ### Secrets
129
+
130
+ Tokens live in `~/.cicd-aiops/secrets.enc` — Fernet-encrypted, key derived
131
+ from a master password via scrypt. Never plaintext on disk. Set
132
+ `CICD_AIOPS_MASTER_PASSWORD` for non-interactive/MCP use, and manage with
133
+ `cicd-aiops secret set|list|remove|migrate`. TLS verification defaults ON
134
+ (the init wizard asks before turning it off for lab certs).
135
+
136
+ ## MCP server
137
+
138
+ 26 governed tools (20 reads incl. the four flagship analyses, 6 writes).
139
+
140
+ ```json
141
+ {
142
+ "mcpServers": {
143
+ "cicd-aiops": {
144
+ "command": "uvx",
145
+ "args": ["--from", "cicd-aiops", "cicd-aiops-mcp"],
146
+ "env": {
147
+ "CICD_AIOPS_MASTER_PASSWORD": "your-master-password"
148
+ }
149
+ }
150
+ }
151
+ }
152
+ ```
153
+
154
+ > **Env-block caveat**: MCP clients launch the server with a *minimal*
155
+ > environment — your shell profile is not sourced. Anything the server needs
156
+ > (`CICD_AIOPS_MASTER_PASSWORD`, `CICD_AIOPS_HOME`, `CICD_AUDIT_APPROVED_BY`
157
+ > for high-risk writes) must be set in the `env` block above, not in
158
+ > `~/.zshrc`.
159
+
160
+ Alternatively: `cicd-aiops mcp` (same server, CLI entry point).
161
+
162
+ ## Configuration
163
+
164
+ `~/.cicd-aiops/config.yaml` (the wizard writes this):
165
+
166
+ ```yaml
167
+ targets:
168
+ - name: gl1
169
+ platform: gitlab # or: gitea
170
+ base_url: https://git.example.com
171
+ verify_ssl: true # default ON; set false only for lab certs
172
+ ```
173
+
174
+ The token for each target is stored encrypted under the target's name.
175
+ Relocate all state (config, audit, undo, secrets) with `CICD_AIOPS_HOME`.
176
+
177
+ ## Development
178
+
179
+ ```bash
180
+ uv sync
181
+ uv run pytest -q
182
+ uv run ruff check .
183
+ ```
184
+
185
+ ## 缺功能?
186
+
187
+ 缺功能提 issue/PR 欢迎留言 — if a GitLab/Gitea surface you need is missing
188
+ (runner administration on newer Gitea, per-job retry, scheduled pipelines,
189
+ group-level rollups…), open an issue or PR at
190
+ https://github.com/AIops-tools/CICD-AIops. The platform registry is designed
191
+ so a new resource is one path-map entry, not a refactor.
192
+
193
+ ## License
194
+
195
+ MIT. GitLab is a trademark of GitLab Inc.; Gitea is a trademark of its
196
+ project owners. This project is independent and not affiliated with either.
@@ -0,0 +1,180 @@
1
+ # CICD AIops
2
+
3
+ **Governed AI-ops for self-managed GitLab and self-hosted Gitea.**
4
+
5
+ `cicd-aiops` is for the team running its *own* CI/CD forge — a GitLab instance
6
+ or a Gitea server on your hardware, in your lab, behind your VPN — who want an
7
+ AI agent that can answer "why did the pipeline fail?", "which runner is
8
+ wedged?", "where did 40 GB of artifact storage go?" and "what work went
9
+ stale?" and then act (retry, cancel, pause, delete, protect) **only** through
10
+ an audited, budgeted, risk-tiered, undo-recorded governance harness. It is not
11
+ a SaaS integration: it speaks the GitLab REST API v4 and the Gitea API v1
12
+ directly against your server, with credentials encrypted at rest.
13
+
14
+ > **Preview / mock-only**: modelled from each project's public API docs and
15
+ > exercised against mocked HTTP responses; not yet validated against live
16
+ > servers. `cicd-aiops doctor` is the fastest live check.
17
+
18
+ > **Routing**: Do NOT use this for Kubernetes deploy state — use k8s-aiops.
19
+ > This tool ends at the CI/CD server's API (pipelines, runners, artifacts,
20
+ > repo hygiene).
21
+
22
+ ## Quick start
23
+
24
+ ```bash
25
+ uv tool install cicd-aiops # or: pip install cicd-aiops
26
+
27
+ cicd-aiops init # wizard: base URL + token (encrypted) + TLS verify
28
+ cicd-aiops doctor # connectivity + token-scope probe per target
29
+ cicd-aiops overview # version, identity, projects, runners at a glance
30
+ ```
31
+
32
+ Then the interesting parts:
33
+
34
+ ```bash
35
+ cicd-aiops rca pipelines dev/api # classify recent failed pipelines
36
+ cicd-aiops rca runners # offline/stale runners, tag saturation
37
+ cicd-aiops rca storage # artifact/repo bloat, reclaimable bytes
38
+ cicd-aiops rca stale dev/api # stale MRs/branches, protection gaps
39
+
40
+ cicd-aiops pipelines retry dev/api 42 --dry-run
41
+ cicd-aiops artifacts delete dev/api --older-than-days 30 --dry-run
42
+ ```
43
+
44
+ Every write has `--dry-run` and a double confirmation, and executes through
45
+ the same governed path the MCP tools use — so CLI writes are audited too.
46
+
47
+ ## Support scope
48
+
49
+ | Surface | GitLab (REST v4, self-managed) | Gitea (API v1, self-hosted) |
50
+ |---|---|---|
51
+ | Server version + token identity | ✅ | ✅ |
52
+ | Projects + storage statistics | ✅ (`statistics=true`) | ✅ (repo `size`) |
53
+ | Pipelines / runs, jobs, trace tails | ✅ | ✅ (Actions runs/jobs/logs) |
54
+ | Runner fleet (list/detail) | ✅ | ❌ teaching error (no API v1 equivalent) |
55
+ | Merge/pull requests, branches, protection, releases | ✅ | ✅ |
56
+ | Artifact inventory | ✅ (via jobs) | ✅ (Actions artifacts) |
57
+ | `retry_pipeline` / `cancel_pipeline` | ✅ | ❌ teaching error |
58
+ | `pause_runner` / `resume_runner` | ✅ | ❌ teaching error |
59
+ | `delete_artifacts` | ✅ | ❌ teaching error |
60
+ | `update_branch_protection` | ✅ | ✅ |
61
+
62
+ Where a platform lacks a surface, the platform registry raises a *teaching
63
+ error* naming the resources that **are** available — the agent learns instead
64
+ of hitting a mystery 404. GitLab.com / Gitea Cloud SaaS accounts are out of
65
+ scope by design: this tool targets self-managed instances.
66
+
67
+ ## Flagship analyses (the reason this tool exists)
68
+
69
+ 1. **`pipeline_failure_rca`** — pulls recent failed pipelines with failed-job
70
+ trace tails and classifies each failure: *test-failure /
71
+ dependency-network / runner-timeout / oom / script-error*, with the matched
72
+ evidence, a cause, and an action per pipeline.
73
+ 2. **`runner_health_rca`** — offline/stale/paused runners (contact-age
74
+ threshold), jobs queued past a threshold, and per-tag saturation (queued
75
+ jobs vs online runners).
76
+ 3. **`artifact_storage_bloat_analysis`** — projects ranked by repo + artifact
77
+ bytes, expired-but-kept artifacts, and a reclaimable-bytes estimate that
78
+ feeds straight into `delete_artifacts --dry-run`.
79
+ 4. **`stale_work_audit`** — merge/pull requests idle past N days, branches
80
+ with no commits for N days, and protection gaps (unprotected default
81
+ branch, force-push allowed).
82
+
83
+ All four are transparent heuristics: thresholds are named parameters and every
84
+ flag carries its numbers.
85
+
86
+ ## Governance (built in, always on)
87
+
88
+ Every MCP tool and every CLI write runs through the vendored harness in
89
+ `cicd_aiops/governance/`:
90
+
91
+ - **Audit** — every call (including denials and errors) lands in
92
+ `~/.cicd-aiops/audit.db` with params, status, risk level, and approver.
93
+ - **Budget** — call/time budgets and a runaway breaker
94
+ (`CICD_MAX_TOOL_CALLS`, `CICD_MAX_TOOL_SECONDS`, `CICD_RUNAWAY_MAX`).
95
+ - **Risk tiers, secure by default** — reads are `low`; mutating writes are
96
+ `medium`; `delete_artifacts` is `high`. With no `rules.yaml`, high-risk
97
+ writes are **denied unless a named approver** is set
98
+ (`CICD_AUDIT_APPROVED_BY`, plus `CICD_AUDIT_RATIONALE`). `init` seeds a
99
+ starter `rules.yaml` with that dual-control tier spelled out.
100
+ - **Undo** — reversible writes record a replayable inverse in
101
+ `~/.cicd-aiops/undo.db`, built from the *fetched* before-state:
102
+ `pause_runner` ⇄ `resume_runner`, and `update_branch_protection` replays the
103
+ prior settings. Irreversible writes (`retry_pipeline`, `cancel_pipeline`,
104
+ `delete_artifacts`) record `priorState` (status / bytes+count) instead.
105
+ - **Dry-run everywhere** — every write takes `dry_run=True` (MCP) /
106
+ `--dry-run` (CLI) and previews without calling the server.
107
+ - **Sanitize** — all server-returned text is folded through an
108
+ injection-safe normaliser (bounded strings, capped depth) before an agent
109
+ sees it; all path parameters are percent-encoded so an identifier can never
110
+ rewrite a URL.
111
+
112
+ ### Secrets
113
+
114
+ Tokens live in `~/.cicd-aiops/secrets.enc` — Fernet-encrypted, key derived
115
+ from a master password via scrypt. Never plaintext on disk. Set
116
+ `CICD_AIOPS_MASTER_PASSWORD` for non-interactive/MCP use, and manage with
117
+ `cicd-aiops secret set|list|remove|migrate`. TLS verification defaults ON
118
+ (the init wizard asks before turning it off for lab certs).
119
+
120
+ ## MCP server
121
+
122
+ 26 governed tools (20 reads incl. the four flagship analyses, 6 writes).
123
+
124
+ ```json
125
+ {
126
+ "mcpServers": {
127
+ "cicd-aiops": {
128
+ "command": "uvx",
129
+ "args": ["--from", "cicd-aiops", "cicd-aiops-mcp"],
130
+ "env": {
131
+ "CICD_AIOPS_MASTER_PASSWORD": "your-master-password"
132
+ }
133
+ }
134
+ }
135
+ }
136
+ ```
137
+
138
+ > **Env-block caveat**: MCP clients launch the server with a *minimal*
139
+ > environment — your shell profile is not sourced. Anything the server needs
140
+ > (`CICD_AIOPS_MASTER_PASSWORD`, `CICD_AIOPS_HOME`, `CICD_AUDIT_APPROVED_BY`
141
+ > for high-risk writes) must be set in the `env` block above, not in
142
+ > `~/.zshrc`.
143
+
144
+ Alternatively: `cicd-aiops mcp` (same server, CLI entry point).
145
+
146
+ ## Configuration
147
+
148
+ `~/.cicd-aiops/config.yaml` (the wizard writes this):
149
+
150
+ ```yaml
151
+ targets:
152
+ - name: gl1
153
+ platform: gitlab # or: gitea
154
+ base_url: https://git.example.com
155
+ verify_ssl: true # default ON; set false only for lab certs
156
+ ```
157
+
158
+ The token for each target is stored encrypted under the target's name.
159
+ Relocate all state (config, audit, undo, secrets) with `CICD_AIOPS_HOME`.
160
+
161
+ ## Development
162
+
163
+ ```bash
164
+ uv sync
165
+ uv run pytest -q
166
+ uv run ruff check .
167
+ ```
168
+
169
+ ## 缺功能?
170
+
171
+ 缺功能提 issue/PR 欢迎留言 — if a GitLab/Gitea surface you need is missing
172
+ (runner administration on newer Gitea, per-job retry, scheduled pipelines,
173
+ group-level rollups…), open an issue or PR at
174
+ https://github.com/AIops-tools/CICD-AIops. The platform registry is designed
175
+ so a new resource is one path-map entry, not a refactor.
176
+
177
+ ## License
178
+
179
+ MIT. GitLab is a trademark of GitLab Inc.; Gitea is a trademark of its
180
+ project owners. This project is independent and not affiliated with either.
@@ -0,0 +1,34 @@
1
+ # cicd-aiops v0.1.0 — release notes
2
+
3
+ First preview of **cicd-aiops**: governed AI-ops for self-managed GitLab and
4
+ self-hosted Gitea CI/CD servers.
5
+
6
+ ## Highlights
7
+
8
+ - **26 governed MCP tools** (20 reads incl. 4 flagship RCAs, 6 writes), every
9
+ one wrapped with the bundled audit / budget / risk-tier / undo harness.
10
+ - **Pipeline-failure RCA**: failed jobs classified from failure_reason +
11
+ trace-tail markers — test-failure, dependency/network, runner-timeout, OOM,
12
+ script error — each with matched evidence, cause, and action.
13
+ - **Runner health & queue RCA**: offline/stale/paused runners, long-queued
14
+ jobs, per-tag saturation.
15
+ - **Artifact/storage bloat**: projects ranked by repo + artifact bytes,
16
+ expired-but-kept artifacts, reclaimable estimate → feeds
17
+ `delete_artifacts --dry-run`.
18
+ - **Stale-work audit**: idle MRs/branches and protection gaps (unprotected
19
+ default branch, force-push allowed).
20
+ - **Writes with faithful before-state**: pause/resume runner is a true undo
21
+ pair; branch protection undo replays prior settings; pipeline retry/cancel
22
+ and artifact deletion record priorState (irreversible, artifact deletion is
23
+ risk=high behind the approver gate).
24
+ - **Encrypted secrets** (Fernet + scrypt), TLS verify default ON, friendly
25
+ `init` wizard, `doctor` with version + token-scope probes.
26
+
27
+ ## Known limits (v0.1)
28
+
29
+ - Preview / mock-only: modelled from public API docs, exercised against
30
+ mocked HTTP; not yet validated on live servers.
31
+ - Runner administration, pipeline retry/cancel, and artifact deletion are
32
+ GitLab surfaces; on Gitea they raise a teaching error (no API v1
33
+ equivalent).
34
+ - Self-managed instances only — GitLab.com / Gitea Cloud are out of scope.
@@ -0,0 +1,49 @@
1
+ # Security Policy
2
+
3
+ Community-maintained open-source project, **not affiliated with, endorsed by, or
4
+ sponsored by GitLab Inc. or the Gitea project.**
5
+ Product and trademark names (GitLab, Gitea) belong to their owners.
6
+
7
+ ## Reporting a vulnerability
8
+
9
+ Open a private security advisory on GitHub
10
+ (https://github.com/AIops-tools/CICD-AIops/security/advisories) or email
11
+ zhouwei008@gmail.com. Please do not open public issues for exploitable bugs.
12
+
13
+ ## Credential handling
14
+
15
+ - Per-target secrets — the GitLab personal/project access token or the Gitea
16
+ access token — are stored **encrypted** in `~/.cicd-aiops/secrets.enc`
17
+ (Fernet/AES-128-CBC+HMAC, key derived from a master password via scrypt),
18
+ file mode 600. Never plaintext on disk.
19
+ - The token is presented as a `PRIVATE-TOKEN` header (GitLab) or an
20
+ `Authorization: token` header (Gitea) at request time and held only in
21
+ memory; secrets are never logged, echoed, or included in tool output.
22
+ - A legacy plaintext env var (`CICD_<TARGET>_SECRET`) is honoured as a
23
+ fallback with a deprecation warning — migrate with
24
+ `cicd-aiops secret migrate`.
25
+ - TLS verification defaults ON; disabling it is an explicit per-target,
26
+ wizard-confirmed choice intended for lab certs only.
27
+
28
+ ## Blast-radius controls
29
+
30
+ - Every MCP tool and every CLI write runs through the `@governed_tool`
31
+ harness: audit log (`~/.cicd-aiops/audit.db`), call/time budgets, a runaway
32
+ breaker, graduated risk tiers, and undo-token recording.
33
+ - Secure by default: with no `rules.yaml`, high-risk writes
34
+ (`delete_artifacts`) are denied unless `CICD_AUDIT_APPROVED_BY` names a
35
+ human approver.
36
+ - Every write supports `dry_run`; the CLI double-confirms destructive
37
+ operations.
38
+
39
+ ## Input/output hardening
40
+
41
+ - All server-returned text (job traces, MR titles, branch names, runner
42
+ descriptions) is folded through an injection-safe normaliser — bounded
43
+ string length, capped nesting depth — before an agent sees it.
44
+ - All URL path parameters are percent-encoded; Gitea's `owner/repo` values
45
+ are validated per segment (empty/`.`/`..` rejected) so an agent-supplied
46
+ identifier can never rewrite a request path.
47
+
48
+ No webhooks, no telemetry, no outbound calls beyond the configured GitLab /
49
+ Gitea REST API.
@@ -0,0 +1,14 @@
1
+ """cicd-aiops — governed GitLab + Gitea CI/CD operations for AI agents.
2
+
3
+ Standalone and self-contained: the governance harness (audit, token budget,
4
+ undo-token recording, graduated risk tiers, output sanitize) is
5
+ bundled under ``cicd_aiops.governance`` — this package has no external
6
+ skill-family dependency. Preview: not yet full-coverage.
7
+ """
8
+
9
+ from importlib.metadata import PackageNotFoundError, version
10
+
11
+ try:
12
+ __version__ = version("cicd-aiops")
13
+ except PackageNotFoundError: # running from an uninstalled source tree
14
+ __version__ = "0.0.0+unknown"
@@ -0,0 +1,9 @@
1
+ """CLI package for cicd-aiops.
2
+
3
+ Re-exports ``app`` so the pyproject entry point
4
+ ``cicd-aiops = "cicd_aiops.cli:app"`` works unchanged.
5
+ """
6
+
7
+ from cicd_aiops.cli._root import app
8
+
9
+ __all__ = ["app"]