Files
Gitea-Tools/docs/architecture/jenkins-readonly-build-status-design.md
T
sysadmin 74a7e8f792 docs: Jenkins read-only build status tools design (#72)
Add docs/architecture/jenkins-readonly-build-status-design.md:
implementation-ready design notes for the jenkins-mcp read-only tool set —
minimum tools (whoami, list_jobs, latest_build, build_status, get_build,
gated console_tail), safe return-field allowlist (url, number, timestamp,
duration, branch, result, commit), fail-closed failure behavior (unknown
job, unreachable, 5xx, auth, malformed JSON), bounded+redacted console tail
behind a distinct jenkins.console.read operation, per-service credential/
profile requirements (token by reference, fail closed), explicit exclusions
(build/deploy triggers, parameterized launches), job addressing with mapping
deferred to #77, and a mocked-Jenkins testing strategy.

Design only; no implementation, no code behavior changed, no Jenkins code
in mcp_server.py.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-02 14:34:18 -04:00

7.5 KiB

Jenkins Read-Only Build Status Tools — Design Notes

  • Status: Design (implementation-ready notes; no implementation in this repo)
  • Issue: #72 (parent umbrella: #75; boundary decision: ADR-0001, #71)
  • Related: #77 (repo/branch/PR → job mapping, designed separately)
  • Date: 2026-07-02

1. Purpose and scope

Define the minimum read-only Jenkins MCP tool set that lets an LLM answer: "Did the latest build for this project/branch succeed or fail?" — plus enough detail (build URL, number, timing, result) to report or investigate.

Phase 1 is strictly read-only, per ADR-0001 (adr-0001-mcp-control-plane-boundaries.md):

  • Excluded: build triggers.
  • Excluded: deploy triggers.
  • Excluded: parameterized job launches.
  • Excluded: job creation/deletion/config changes, queue manipulation, node management — any Jenkins mutation whatsoever.

2. Boundary placement

These tools belong to the jenkins-mcp package/server of the MCP Control Plane — never inside gitea-mcp (mcp_server.py in this repo). Consequences (from tool-boundaries.md, credential-isolation.md, ADR-0001):

  • jenkins-mcp runs as its own server process with its own .env.
  • Jenkins credentials never enter the Gitea MCP runtime, and Gitea credentials never enter jenkins-mcp.
  • This document lands in this repo only because the repo currently hosts the Control Plane's architecture docs; the code ships elsewhere (owner decision #1 of ADR-0001).

3. Minimum read-only tool set

Tool Purpose
jenkins_whoami Verify authenticated Jenkins identity + active profile (mirror of gitea_whoami; fail-closed identity proof before anything else)
jenkins_list_jobs List visible jobs (supports folder paths), with pagination bounds
jenkins_latest_build The primary question: latest build of a job (or job+branch for multibranch) → status summary
jenkins_build_status Status of a specific build number (job, number)
jenkins_get_build Full safe detail of a build (fields in §4)
jenkins_console_tail Bounded, redacted tail of a build's console log (§6) — optional, approval-gated addition

All tools are GET-only against the Jenkins JSON API (/api/json, .../lastBuild/api/json, .../consoleText). No tool issues POST/PUT/DELETE.

4. Return payloads (safe fields)

jenkins_latest_build / jenkins_build_status / jenkins_get_build return:

Field Source Notes
job request Fully-qualified job path (folders joined with /)
build_number number int
result result SUCCESS / FAILURE / UNSTABLE / ABORTED / NOT_BUILT; nullIN_PROGRESS when building=true
building building bool
url url Build URL
branch multibranch job name / SCM action Best-effort; omitted when unknown
timestamp timestamp ISO-8601 UTC (converted from epoch ms)
duration_seconds duration 0/omitted while building
commit_sha SCM build action Best-effort; omitted when unknown

Rules: no raw Jenkins payload passthrough (allowlist projection only); no Authorization header, token, or crumb material in any output or error (reuse the shared redaction approach of safety-model.md §3 / gitea_audit).

5. Failure behavior (fail closed, clear, safe)

Condition Behavior
Unknown job Explicit {"found": false, "job": "<path>", "error": "job not found"} — never guess or fuzzy-match a job name (hard rule; see also #77)
Jenkins unreachable (DNS/timeout/conn refused) Clear "network error contacting Jenkins: <redacted reason>"; no retry storm — mirror gitea_auth.api_request timeout + failure conversion
502/503/504 Explicit "Jenkins upstream unavailable"
401/403 "Jenkins auth failed / insufficient permissions" — without echoing credentials or the request's auth material
Malformed JSON "malformed JSON response from Jenkins" (no raw-body dump)
Missing profile/creds Fail closed before any network call (§7)

6. Console tail safety (jenkins_console_tail)

Console logs are the highest-risk surface (secrets, tokens, internal hosts routinely leak into build logs). If included at all (owner may defer it):

  • Bounded: hard server-side cap (default: last 200 lines AND ≤ 64 KiB, whichever is smaller; caller may request less, never more).
  • Redacted: pass through the shared secret redactor (token/Basic/Bearer/ password/key-value patterns) before returning; redaction failure ⇒ return an error, never the raw text.
  • Default off: summary fields (result, failing stage if cheaply available) are preferred; the tail requires an explicit allowed_operations entry (jenkins.console.read) distinct from plain jenkins.build.read.

7. Credentials and profile requirements

Follows the per-service profile model (gitea-execution-profiles.md, extended by #76):

  • Env/config: JENKINS_URL, JENKINS_USER, JENKINS_TOKEN_SOURCE_NAME (name-of-secret only — value resolved at runtime, never logged/committed).
  • Profile: e.g. jenkins-readonly with namespaced allowed_operations: ["jenkins.read", "jenkins.build.read"] (+ jenkins.console.read only if the tail tool is approved); forbidden_operations: ["jenkins.build.trigger", "jenkins.deploy", "jenkins.job.configure"] as belt-and-braces even though no mutating tool exists.
  • Missing URL/user/token/profile ⇒ fail closed with a clear message.
  • Since every tool is read-only, no confirmation gates are needed — but identity (jenkins_whoami) must still work so workflows can prove which Jenkins account they act as.

8. Job addressing and mapping

Tools accept an explicit fully-qualified job path (folder-aware: folder/subfolder/job). How a repo/branch/PR resolves to that job path is out of scope here and designed in #77, with these fixed constraints:

  • No silent guessing of job names — unmapped input returns an explicit "no mapping" result.
  • Multibranch pipelines address a branch job as <job>/<branch> with proper URL-encoding of branch names (e.g. feature%2Fx).

9. Testing strategy (for the implementing package)

Mocked-Jenkins unit tests only (no live Jenkins in unit CI), mirroring this repo's conventions (docs/developer-testing-guidelines.md):

  • Patch the HTTP client; assert method is always GET and URL shape is correct (folders, multibranch encoding).
  • Success projections: field allowlist exactly as §4; unknown fields dropped.
  • result=null + building=trueIN_PROGRESS.
  • Unknown job ⇒ found:false, no fuzzy match, no API retry.
  • Timeout/DNS/5xx/malformed-JSON ⇒ safe errors, no secret/credential leakage (explicit no-token-in-error assertions).
  • Console tail: cap enforcement (lines and bytes), redaction applied, redaction failure ⇒ error not raw text, gated behind jenkins.console.read.
  • Profile gate: missing/insufficient profile ⇒ no network call (mock_api.assert_not_called() pattern).

10. Implementation-readiness checklist

Ready to implement in jenkins-mcp once:

  1. ADR-0001 owner decision #1 (where jenkins-mcp lives) is made.
  2. #76 profile schema exists (or a minimal jenkins-readonly profile is hand-rolled to the same rules).
  3. #77 mapping design is accepted (or tools ship path-addressed only, mapping deferred).

Explicitly not unlocked by this document: build triggers, deploys, parameterized launches, any Jenkins code in mcp_server.py.