United States

Managed by Servana

Platform-Agnostic Path Handling in Jenkins Pipelines

Dhruvakumar Jonnagaddala

Dhruvakumar Jonnagaddala

This guide provides practical guidance and examples for writing cross-platform Jenkins Pipelines that avoid sandbox approval issues and remain maintainable.

Platform-Agnostic Path Handling in Jenkins Pipelines

When you're shipping the same pipeline across Linux and Windows agents, the smallest thing—like a path separator; can trip you up. If you try to "fix it in Groovy" with new File(...), hudson.FilePath, or static calls like File.separator, Jenkins' Groovy Sandbox will often block those calls by default. That's on purpose and for good reasons.

This guide provides practical guidance and examples for writing cross-platform Jenkins Pipelines that avoid sandbox approval issues and remain maintainable. We avoid any methods that require @NonCPS because its presence makes the pipeline un-serializable. If Jenkins tries to pause or restart during that method, it cannot resume from the middle; it has to re-run it.


Why the Sandbox Blocks File APIs

  • Script Security: Jenkins runs untrusted Pipeline Groovy in a restricted sandbox. Calls to java.io.File or hudson.FilePath are blocked unless approved by an admin.

  • FilePath is powerful: It can run remote operations on agents or controllers—too risky to allow in untrusted Pipelines.

  • sh / bat are whitelisted: These steps spawn external processes on the agent and don't give Groovy access to Jenkins internals.


Best Practices

  1. Treat Pipelines as ephemeral– avoid persisting state.

  2. Prefer pipeline steps over APIs (findFiles, readFile, writeFile).

  3. Normalize paths only when needed (before sh /bat).

  4. Use shared libraries to abstract complexity.

  5. Handle secrets safely with withCredentials.


Examples

Simple Separator Handling

Jenkinsfile
groovy3 lines
def sep = isUnix() ? '/' : '\\'
def dmPath  = "${env.WORKSPACE}${sep}dev-tools${sep}dependency-managers"
def binPath = "${dmPath}${sep}bin"

Discover Paths with findFiles

Jenkinsfile
groovy3 lines
def matches = findFiles(glob: '**/bin/**')
def binDirs = matches.collect { it.path.replaceFirst(/\/bin\/.*$/, '/bin') }.unique()
def absPath = isUnix() ? "${env.WORKSPACE}/${binDirs[0]}" : ("${env.WORKSPACE}/${binDirs[0]}").replace('/', '\\')

Triple-Quoted Scripts

Jenkinsfile
groovy9 lines
if (isUnix()) {
  sh """
    "${absPath}/mytool" arg1
  """
} else {
  bat """
    "${absPath}\\mytool.exe" arg1
  """
}

Shared Library Helpers

Jenkinsfile
groovy1 lines
vars/osPath.groovy
4 lines
  1. def join(Object... parts) {
  2. def sep = isUnix() ? '/' : '\\'
  3. parts.findAll { it }.join(sep)
  4. }

Usage

Jenkinsfile
groovy1 lines
def binAbs = osPath.join(env.WORKSPACE, "tools", "bin")

References


Key Takeaway

Keep Groovy minimal and sandbox-friendly. Use findFiles + isUnix() for paths, normalize before calling sh/bat, and use a shared library when it gets repetitive. This ensures your pipelines remain portable, safe, and maintainable.

Testimonials

Our customers highly rate us.

© Copyright 2025 StackTrack Inc and its affiliates. All Rights Reserved.
StackTrack Inc is incorporated in Delaware, United States. Servana Managed Services Ltd is registered in England and Wales with number #10551720 and VAT registered with number GB-284560287.