Trusted Libraries and Versioned APIs

Scenario: A mutable trusted library changes all production builds without application commits.

A "shared library" can mean "shared root access"

Here's the part of shared libraries that genuinely deserves caution: a library marked as globally trusted can call the same privileged Jenkins and JVM APIs that would normally require an administrator's permission - regardless of what folder-level permissions the person merely using that library actually has. That's a much bigger deal than it sounds at first.

Analogy: Think of a trusted shared library like a master key that's been duplicated and handed to a locksmith who services many different offices in a building - except the locksmith's own key-cutting shop, not the individual offices, is what actually controls what that master key can open. If someone breaks into the locksmith's shop and re-cuts that master key to open a few extra doors, every single office relying on "the locksmith's usual key" is now compromised at once, even though none of those individual offices did anything wrong themselves. Protecting a trusted library's own source repository is exactly as important as protecting the Jenkins controller itself - because in a real sense, whoever controls that repository effectively controls every consumer of it.

This is why the rest of this section is about trust and versioning discipline specifically - not just "how do I use a library," which the previous section already covered.

Pipeline example

@Library('delivery-lib@v3') _
companyDeploy artifact: env.DIGEST, environment: 'staging'

Trust extends controller-level authority, silently

A globally trusted library may call Jenkins internals and JVM APIs entirely outside Groovy's normal sandboxing restrictions. This means anyone able to push a commit to that library's referenced branch can effectively gain controller-level authority across every single Pipeline that loads it - completely independent of whatever ordinary folder-level permissions that person happens to have. Protect a trusted library's source repository accordingly: require code review, use immutable release tags rather than a moving branch reference, isolate who's allowed to maintain it, and audit its configuration changes as carefully as you'd audit changes to the Jenkins controller's own configuration. Folder-scoped or explicitly untrusted libraries, by contrast, remain sandboxed under ordinary Groovy restrictions and are perfectly appropriate for convenience code shared just within one team, without needing this same elevated level of scrutiny.

Pinning is only meaningful if the reference is actually immutable

Pinning a library to a specific version is only genuinely reproducible if the underlying SCM reference itself is immutable - pinning to @v3 where v3 is a moving branch that keeps getting new commits pushed to it is not real pinning, even though it looks like a pinned version number in the Jenkinsfile. A moving branch like this can distribute bug fixes centrally and automatically - which is genuinely convenient - but it also means every consumer's build behavior can change with zero corresponding commit in their own application repository, which is exactly the kind of silent, hard-to-trace change this whole track keeps warning about.

[Pipeline] Loading library delivery-lib@v3
Resolved to commit e4a1b90 (branch v3, HEAD at time of build)

Compare this to the earlier, tag-pinned example (@3.4.1 resolving to a fixed commit): here, @v3 resolves to "whatever HEAD of the v3 branch happened to be at the moment this specific build ran" - rerun the exact same Jenkinsfile next week, and it may silently resolve to a completely different commit, with different behavior, even though nothing in the consuming repository changed at all.

Evolve the library as a real product, with a real contract

Use immutable release tags for anything meant to be a genuine, reproducible release; use curated, deliberately "moving" channels only where managed, opt-in adoption of upstream fixes is actually the intended design; and maintain an explicit revocation path for when a vulnerable or broken version needs to be actively blocked from further use, not just quietly deprecated. Document every step's arguments, defaults, validation rules, expected return values, credentials it needs, and any side effects it causes - a shared library with undocumented behavior is exactly as risky as an undocumented internal API, just spread across every repository that happens to use it. Add new features in a backward-compatible way within a major version line, and publish clear migration guidance for any genuinely breaking change. Test the library against the specific Jenkins core and plugin versions it's actually meant to support, since library step behavior can depend on plugin APIs that change - and remember that a Pipeline already running (possibly paused mid-execution, per the CPS module) may resume execution after a Jenkins upgrade has happened underneath it.

A pitfall: a "small fix" that goes out to every consumer at once, untested

Canary a new library revision across a small set of representative consumer repositories before rolling it out broadly - the exact same discipline you'd apply to any other piece of shared production infrastructure, because that's genuinely what a trusted shared library is. Log the resolved library SHA in every build that uses it, and keep the previous known-good, immutable version readily available to roll back to. Maintain an actual inventory of which repositories import which library versions, so that if a faulty central release does slip out, you can identify and directly contact every affected consumer quickly - rather than having to guess, repository by repository, who might be impacted while an incident is actively ongoing.

Goal: Practice the concrete behavior in jenkins-declarative-rescue. Learn sections have no Jenkins terminal; the Jenkins lab opens the real shared service in a new full-screen tab inside your private folder.