Skip to content
BETAGuardrails are in beta. The library, the configuration format and the CLI command can still change.

Guardrails / Collectors

Jenkins pipelines

The Jenkinsfiles the repository carries, read in Jenkins's own vocabulary: whether each is a declarative pipeline or a scripted one, the agent it asks for, the stages in the order they are declared with the steps inside them, the timeouts its options blocks declare, the shared libraries it loads and how tightly each is pinned, and the credential ids it reaches for. A Jenkinsfile is Groovy rather than a declaration, so it is read by pattern and scanned says so. Names and ids only, never a credential, an environment value or a parameter value.

Facts keyjenkins
Versionv1
Scriptjenkins.py
Timeout60 seconds

Inputs

InputDescriptionDefaultEnvironment
jenkinsfilesComma separated globs matched against every file in the working directory and against bare file names, naming the Jenkinsfiles to read. Narrows what discovery finds; a file it matches whose name is not Jenkinsfile, Jenkinsfile.<something> or <something>.Jenkinsfile is still left out.Jenkinsfile,Jenkinsfile.*,*.JenkinsfileGUARDRAIL_INPUT_JENKINSFILES

A guardrail that declares an input of the same name passes it through, so the guardrail's configuration in buildnote.json is what decides these values.

A guardrail asks for these facts by name, and reads them back the same way:

json
{
  "collect": ["jenkins"]
}
python
jenkins = guardrail.facts("jenkins")

Facts

The document jenkins collects. A path carrying [] is an entry of the list before it, and one carrying [path] is a key of the object before it.

FactMeaning
sourcereport when a Jenkinsfile was read, none when there was none.
reasonWhy nothing was read, present only when source is none.
reportsEvery Jenkinsfile that was read, in path order.
reports[].pathPath of the Jenkinsfile, relative to the directory the CLI runs in.
reports[].modifiedWhen it was last written, ISO 8601.
reports[].formatAlways jenkins.
scannedEvery Jenkinsfile that was read by pattern, which is all of them. A Jenkinsfile is Groovy rather than a declaration, so a stage, a step or a library built by a condition, a loop or a method call is not seen. What is here was found; what is not here may still be there, so a finding is real and an absence is not proof.
pipelinesThe pipelines themselves, one entry per file that was read.
pipelines[].pathPath of the file, relative to the directory the CLI runs in.
pipelines[].styledeclarative when the file declares a top level pipeline block, scripted when it does not. Almost nothing below is readable in a scripted pipeline, where a stage is a method call inside arbitrary Groovy: stages, agent, timeout, environment, triggers and tools are all left empty for one, and only the libraries and credential ids a pattern can find are collected.
pipelines[].agentThe agent the pipeline declares, whitespace collapsed: any, none, or the body of the agent block such as label 'linux' or docker { image 'maven:3.9' }. null when it declares none, which a declarative pipeline is not allowed to do and a scripted one always does.
pipelines[].timeoutThe timeout(...) call the pipeline level options block declares, exactly as written, or null when it declares none. Jenkins imposes no timeout of its own, so null means a hung build holds its executor until somebody aborts it.
pipelines[].timeoutMinutesThe same timeout in whole minutes, or null when the pipeline declares none or writes a duration that could not be read. timeout(time: N) with no unit is minutes, which is what Jenkins defaults to.
pipelines[].environmentNames of the variables the pipeline level environment block assigns. Names only, never values: a value there is often credentials('id'), and the ids are collected separately.
pipelines[].triggersThe trigger types the triggers block declares, such as cron, pollSCM or upstream. Types only, never the schedule.
pipelines[].toolsThe tool types the tools block asks Jenkins to install, such as jdk, maven or nodejs. Types only, never the installation name they select.
pipelines[].librariesEvery shared library the file loads, from @Library(...) and from the library step, in the order they appear. A library loaded conditionally in Groovy is not here; see scanned.
pipelines[].libraries[].nameThe part of the reference before the @, which is the library name configured on the Jenkins controller.
pipelines[].libraries[].refWhat follows the @, whatever it names, or null when the reference names nothing and Jenkins resolves the default version from its own configuration.
pipelines[].libraries[].pinnedWhether ref names a fixed point by its shape: a 40 character hex commit sha, or a version such as 1.4.2 or v1.4.2. A branch name, an interpolated expression and no ref at all are not. Jenkins cannot tell a tag from a branch by name, so this reads the shape of the ref rather than what the SCM resolves it to.
pipelines[].libraries[].sourceannotation for an @Library(...) at the top of the file, step for a library '...' call inside it.
pipelines[].credentialsThe credential ids the file reaches for, from credentials('id') and from every credentialsId: a withCredentials binding names, in the order they appear. Ids only, never a credential: the facts are attached to the run event.
pipelines[].stagesEvery stage the pipeline declares, flattened in source order. A stage nested inside a parallel or a nested stages block appears after the stage holding it and names it in parent, so the tree is still readable and a parallel branch is a stage of its own.
pipelines[].stages[].nameThe name the stage(...) call gives itself, or null when it is written as an expression rather than a literal.
pipelines[].stages[].parentPosition in this list of the stage this one is nested inside, through a parallel or a nested stages block, or null for a stage declared directly under the pipeline. A position rather than a name, because a stage written as an expression has no readable name and would otherwise be indistinguishable from the pipeline itself. What a parent declares, an options timeout included, covers everything nested inside it.
pipelines[].stages[].agentThe agent the stage declares for itself, whitespace collapsed, or null when it takes the pipeline's.
pipelines[].stages[].timeoutThe timeout(...) call the stage's own options block declares, exactly as written, or null when it declares none.
pipelines[].stages[].timeoutMinutesThe same timeout in whole minutes, or null when the stage declares none or writes a duration that could not be read.
pipelines[].stages[].whenWhether a when block guards the stage, so it is skipped rather than run on some builds.
pipelines[].stages[].stepsThe steps the stage's steps block runs, flattened in source order. A step that wraps others, such as withCredentials, dir, retry or script, is recorded and so is every step inside it.
pipelines[].stages[].steps[].nameThe step as it is written, such as sh, bat, powershell, checkout, echo or withCredentials.
pipelines[].stages[].steps[].bodyThe shell body of a sh, bat, powershell or pwsh step, read as the string literal the call passes and truncated to 2000 characters. null for every other step.
counts.pipelinesFiles that were read.
counts.stagesStages across every pipeline, nested ones included.
counts.stepsSteps across every stage.
unparsedFiles that matched but were not read, because the pipeline block they open is never closed and nothing below it could be located. A file here is not a file with nothing in it: nothing was read from it and no verdict should be drawn about it.
unparsed[].pathPath of the file that was not read.
unparsed[].reasonWhat stopped the reader, and the line it gave up on.

A collector that cannot finish prints what it had along with an incomplete key saying why, so the facts below the point it stopped are absent. A check that cares reads incomplete before the rest.

Example facts

The example facts collected by jenkins collector:

json
{
  "source": "report",
  "reports": [
    {
      "path": "Jenkinsfile",
      "modified": "2026-03-04T10:15:00Z",
      "format": "jenkins"
    }
  ],
  "scanned": [
    "Jenkinsfile"
  ],
  "pipelines": [
    {
      "path": "Jenkinsfile",
      "style": "declarative",
      "agent": "docker { image 'maven:3.9.6-eclipse-temurin-21' }",
      "timeout": "timeout(time: 30, unit: 'MINUTES')",
      "timeoutMinutes": 30,
      "environment": [
        "GRADLE_OPTS",
        "SONAR_TOKEN"
      ],
      "triggers": [
        "cron"
      ],
      "tools": [
        "jdk"
      ],
      "libraries": [
        {
          "name": "acme-pipeline",
          "ref": "1.4.2",
          "pinned": true,
          "source": "annotation"
        }
      ],
      "credentials": [
        "sonar-token",
        "registry"
      ],
      "stages": [
        {
          "name": "Build",
          "parent": null,
          "agent": null,
          "timeout": null,
          "timeoutMinutes": null,
          "when": false,
          "steps": [
            {
              "name": "checkout",
              "body": null
            },
            {
              "name": "sh",
              "body": "./gradlew --no-daemon build"
            }
          ]
        },
        {
          "name": "Verify",
          "parent": null,
          "agent": null,
          "timeout": null,
          "timeoutMinutes": null,
          "when": false,
          "steps": []
        },
        {
          "name": "Test",
          "parent": 1,
          "agent": null,
          "timeout": null,
          "timeoutMinutes": null,
          "when": false,
          "steps": [
            {
              "name": "sh",
              "body": "./gradlew --no-daemon test"
            }
          ]
        },
        {
          "name": "Lint",
          "parent": 1,
          "agent": null,
          "timeout": "timeout(time: 5, unit: 'MINUTES')",
          "timeoutMinutes": 5,
          "when": false,
          "steps": [
            {
              "name": "sh",
              "body": "./gradlew --no-daemon detekt"
            }
          ]
        },
        {
          "name": "Publish",
          "parent": null,
          "agent": null,
          "timeout": "timeout(time: 10, unit: 'MINUTES')",
          "timeoutMinutes": 10,
          "when": true,
          "steps": [
            {
              "name": "withCredentials",
              "body": null
            },
            {
              "name": "sh",
              "body": "./gradlew --no-daemon publish"
            }
          ]
        }
      ]
    }
  ],
  "counts": {
    "pipelines": 1,
    "stages": 5,
    "steps": 6
  },
  "unparsed": []
}

Collected for

GuardrailCategoryInputs
jenkins/job-timeout-setjenkinsjenkinsfiles
jenkins/shared-library-pinnedjenkinsjenkinsfiles

All collectors

Buildnote Limited
Registered in England and Wales, Reg: 16140412