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 key | jenkins |
| Version | v1 |
| Script | jenkins.py |
| Timeout | 60 seconds |
Inputs
| Input | Description | Default | Environment |
|---|---|---|---|
jenkinsfiles | Comma 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.*,*.Jenkinsfile | GUARDRAIL_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:
{
"collect": ["jenkins"]
}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.
| Fact | Meaning |
|---|---|
source | report when a Jenkinsfile was read, none when there was none. |
reason | Why nothing was read, present only when source is none. |
reports | Every Jenkinsfile that was read, in path order. |
reports[].path | Path of the Jenkinsfile, relative to the directory the CLI runs in. |
reports[].modified | When it was last written, ISO 8601. |
reports[].format | Always jenkins. |
scanned | Every 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. |
pipelines | The pipelines themselves, one entry per file that was read. |
pipelines[].path | Path of the file, relative to the directory the CLI runs in. |
pipelines[].style | declarative 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[].agent | The 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[].timeout | The 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[].timeoutMinutes | The 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[].environment | Names 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[].triggers | The trigger types the triggers block declares, such as cron, pollSCM or upstream. Types only, never the schedule. |
pipelines[].tools | The tool types the tools block asks Jenkins to install, such as jdk, maven or nodejs. Types only, never the installation name they select. |
pipelines[].libraries | Every 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[].name | The part of the reference before the @, which is the library name configured on the Jenkins controller. |
pipelines[].libraries[].ref | What follows the @, whatever it names, or null when the reference names nothing and Jenkins resolves the default version from its own configuration. |
pipelines[].libraries[].pinned | Whether 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[].source | annotation for an @Library(...) at the top of the file, step for a library '...' call inside it. |
pipelines[].credentials | The 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[].stages | Every 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[].name | The name the stage(...) call gives itself, or null when it is written as an expression rather than a literal. |
pipelines[].stages[].parent | Position 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[].agent | The agent the stage declares for itself, whitespace collapsed, or null when it takes the pipeline's. |
pipelines[].stages[].timeout | The timeout(...) call the stage's own options block declares, exactly as written, or null when it declares none. |
pipelines[].stages[].timeoutMinutes | The same timeout in whole minutes, or null when the stage declares none or writes a duration that could not be read. |
pipelines[].stages[].when | Whether a when block guards the stage, so it is skipped rather than run on some builds. |
pipelines[].stages[].steps | The 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[].name | The step as it is written, such as sh, bat, powershell, checkout, echo or withCredentials. |
pipelines[].stages[].steps[].body | The 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.pipelines | Files that were read. |
counts.stages | Stages across every pipeline, nested ones included. |
counts.steps | Steps across every stage. |
unparsed | Files 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[].path | Path of the file that was not read. |
unparsed[].reason | What 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:
{
"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
| Guardrail | Category | Inputs |
|---|---|---|
jenkins/job-timeout-set | jenkins | jenkinsfiles |
jenkins/shared-library-pinned | jenkins | jenkinsfiles |