Files
Gitea-Tools/docs/architecture/jenkins-readonly-build-status-design.md
T
sysadminandClaude Opus 4.8 b4e04f4dfb docs: separate Jenkins trigger onto jenkins-write-mcp boundary (#152)
Document that build triggers live on the gated jenkins-write-mcp server,
not the read-only jenkins-mcp surface. Add registration and safety-model
cross-links plus doc tests that fail if trigger tools reappear on the read
boundary.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2026-07-06 13:26:58 -04:00

8.4 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

Note on naming: This design used historical jenkins-readonly skill name in Gitea-Tools. Actual package/server is jenkins-mcp (see mcp-control-plane registration in #55). The read server boundary remains read-only; gated triggers live on the separate jenkins-write-mcp / jenkins_mcp.write_server boundary (see #56 / #152). Client registration and reload instructions live in ../mcp-client-registration.md.

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 primarily read-only, per ADR-0001 (adr-0001-mcp-control-plane-boundaries.md):

  • Build triggers are outside this read-only surface and require the separate jenkins-write-mcp boundary, a dedicated profile, exact confirmation, and fail-closed mutation audit (landed in #4, boundary correction in #56 / #152).
  • Excluded: deploy triggers.
  • Excluded: parameterized job launches.
  • Excluded: job creation/deletion/config changes, queue manipulation, node management — any Jenkins mutation whatsoever unless explicitly configured.

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 on jenkins-mcp 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 operate through jenkins-mcp once:

  1. The MCP client registers the external server under the exact jenkins-mcp name and is reconnected/reloaded.
  2. Tool discoverability proves the expected jenkins_* read tools are visible; if the server is enabled but exposes no usable tools, report SKIPPED and stop.
  3. #76 profile schema exists (or a minimal jenkins-readonly profile is hand-rolled to the same rules).
  4. #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.