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.
- cicd_aiops-0.1.0/.github/workflows/mcp-publish.yml +55 -0
- cicd_aiops-0.1.0/.github/workflows/publish.yml +26 -0
- cicd_aiops-0.1.0/.gitignore +8 -0
- cicd_aiops-0.1.0/CHANGELOG.md +30 -0
- cicd_aiops-0.1.0/LICENSE +21 -0
- cicd_aiops-0.1.0/PKG-INFO +196 -0
- cicd_aiops-0.1.0/README.md +180 -0
- cicd_aiops-0.1.0/RELEASE_NOTES.md +34 -0
- cicd_aiops-0.1.0/SECURITY.md +49 -0
- cicd_aiops-0.1.0/cicd_aiops/__init__.py +14 -0
- cicd_aiops-0.1.0/cicd_aiops/cli/__init__.py +9 -0
- cicd_aiops-0.1.0/cicd_aiops/cli/_common.py +78 -0
- cicd_aiops-0.1.0/cicd_aiops/cli/_root.py +65 -0
- cicd_aiops-0.1.0/cicd_aiops/cli/artifacts.py +65 -0
- cicd_aiops-0.1.0/cicd_aiops/cli/doctor.py +22 -0
- cicd_aiops-0.1.0/cicd_aiops/cli/init.py +149 -0
- cicd_aiops-0.1.0/cicd_aiops/cli/overview.py +34 -0
- cicd_aiops-0.1.0/cicd_aiops/cli/pipelines.py +128 -0
- cicd_aiops-0.1.0/cicd_aiops/cli/rca.py +98 -0
- cicd_aiops-0.1.0/cicd_aiops/cli/runners.py +88 -0
- cicd_aiops-0.1.0/cicd_aiops/cli/secret.py +105 -0
- cicd_aiops-0.1.0/cicd_aiops/cli/undo.py +62 -0
- cicd_aiops-0.1.0/cicd_aiops/config.py +152 -0
- cicd_aiops-0.1.0/cicd_aiops/connection.py +188 -0
- cicd_aiops-0.1.0/cicd_aiops/doctor.py +105 -0
- cicd_aiops-0.1.0/cicd_aiops/governance/__init__.py +40 -0
- cicd_aiops-0.1.0/cicd_aiops/governance/audit.py +377 -0
- cicd_aiops-0.1.0/cicd_aiops/governance/budget.py +225 -0
- cicd_aiops-0.1.0/cicd_aiops/governance/decorators.py +482 -0
- cicd_aiops-0.1.0/cicd_aiops/governance/paths.py +23 -0
- cicd_aiops-0.1.0/cicd_aiops/governance/patterns.py +378 -0
- cicd_aiops-0.1.0/cicd_aiops/governance/policy.py +430 -0
- cicd_aiops-0.1.0/cicd_aiops/governance/sanitize.py +45 -0
- cicd_aiops-0.1.0/cicd_aiops/governance/undo.py +218 -0
- cicd_aiops-0.1.0/cicd_aiops/ops/__init__.py +1 -0
- cicd_aiops-0.1.0/cicd_aiops/ops/_util.py +96 -0
- cicd_aiops-0.1.0/cicd_aiops/ops/analysis.py +527 -0
- cicd_aiops-0.1.0/cicd_aiops/ops/artifacts.py +88 -0
- cicd_aiops-0.1.0/cicd_aiops/ops/overview.py +56 -0
- cicd_aiops-0.1.0/cicd_aiops/ops/pipelines.py +116 -0
- cicd_aiops-0.1.0/cicd_aiops/ops/projects.py +68 -0
- cicd_aiops-0.1.0/cicd_aiops/ops/repos.py +124 -0
- cicd_aiops-0.1.0/cicd_aiops/ops/runners.py +65 -0
- cicd_aiops-0.1.0/cicd_aiops/ops/server.py +43 -0
- cicd_aiops-0.1.0/cicd_aiops/ops/writes.py +226 -0
- cicd_aiops-0.1.0/cicd_aiops/platform.py +289 -0
- cicd_aiops-0.1.0/cicd_aiops/secretstore.py +304 -0
- cicd_aiops-0.1.0/mcp_server/__init__.py +1 -0
- cicd_aiops-0.1.0/mcp_server/_shared.py +106 -0
- cicd_aiops-0.1.0/mcp_server/server.py +40 -0
- cicd_aiops-0.1.0/mcp_server/tools/__init__.py +1 -0
- cicd_aiops-0.1.0/mcp_server/tools/analysis.py +199 -0
- cicd_aiops-0.1.0/mcp_server/tools/artifacts.py +23 -0
- cicd_aiops-0.1.0/mcp_server/tools/pipelines.py +75 -0
- cicd_aiops-0.1.0/mcp_server/tools/projects.py +38 -0
- cicd_aiops-0.1.0/mcp_server/tools/repos.py +68 -0
- cicd_aiops-0.1.0/mcp_server/tools/runners.py +42 -0
- cicd_aiops-0.1.0/mcp_server/tools/system.py +47 -0
- cicd_aiops-0.1.0/mcp_server/tools/undo.py +121 -0
- cicd_aiops-0.1.0/mcp_server/tools/writes.py +276 -0
- cicd_aiops-0.1.0/pyproject.toml +60 -0
- cicd_aiops-0.1.0/server.json +21 -0
- cicd_aiops-0.1.0/skills/cicd-aiops/SKILL.md +151 -0
- cicd_aiops-0.1.0/skills/cicd-aiops/references/capabilities.md +77 -0
- cicd_aiops-0.1.0/skills/cicd-aiops/references/cli-reference.md +79 -0
- cicd_aiops-0.1.0/skills/cicd-aiops/references/setup-guide.md +100 -0
- cicd_aiops-0.1.0/smithery.yaml +9 -0
- cicd_aiops-0.1.0/tests/conftest.py +34 -0
- cicd_aiops-0.1.0/tests/test_analysis.py +251 -0
- cicd_aiops-0.1.0/tests/test_cli_writes.py +116 -0
- cicd_aiops-0.1.0/tests/test_doctor.py +225 -0
- cicd_aiops-0.1.0/tests/test_governance_persistence.py +177 -0
- cicd_aiops-0.1.0/tests/test_init.py +149 -0
- cicd_aiops-0.1.0/tests/test_platform.py +189 -0
- cicd_aiops-0.1.0/tests/test_reads.py +314 -0
- cicd_aiops-0.1.0/tests/test_secretstore.py +99 -0
- cicd_aiops-0.1.0/tests/test_smoke.py +153 -0
- cicd_aiops-0.1.0/tests/test_undo_executor.py +138 -0
- cicd_aiops-0.1.0/tests/test_writes.py +339 -0
- 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,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).
|
cicd_aiops-0.1.0/LICENSE
ADDED
|
@@ -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"
|