Skip to content

Rebuild-button (which redirects to Replay) can cause inconsistent Shared Lib usage when user miss Run/Build->Replay permission #1745

Description

@MicroDoc-RRU

Jenkins and plugins versions report

Besides we observed this on multiple of our self-hosted instances, it can be reproduced with an up-to-date fresh Docker-Jenkins installation:

  • jenkins/jenkins:lts-jdk21 - which gave me Jenkins Version 2.541.2 at the time of writing (Feb. 2026)
  • Go through the installation without installing any additional plugins (i used 'Folders', but it's not needed for this case)
  • Matrix Authorization Strategy Plugin Version 3.2.9

What Operating System are you using (both controller, and any agents involved in the problem)?

  • RHEL 9 based
  • Debian based (see default Docker image jenkins/jenkins_lts-jdk21)

Reproduction steps

  • Start a new container of the Jenkins image

  • Follow the setup, do not install any suggested plugins

  • After finishing the installation, install the 'Matrix Authorization Strategy' plugin

  • Your account will stay administrator

  • Set up a very basic Shared Library with

    • resources/endpoints.txt , with the content
    Singing in the rain.
    
    • vars/dumpUtil.groovy with the content
    void dumpSomething() {
      println '### Mambo No 7'
    }
    
  • the Shared library will be accessible under the name dancefloor

  • Have a very simple pipeline which is using both the resources

@Library('dancefloor') _

pipeline {
  agent any
  parameters {
    choice(
      name: 'parChoice',
      choices: ['a', 'b', 'c'],
      description: '''Your choice
      ''',
    )
  } // parameters
  stages {
    stage('Test') {
      steps {
        script {
          println "* ${STAGE_NAME} - Begin"

          println "** Var dump"
          println "*** parChoice: [${parChoice}]"

          final String txtContent = libraryResource 'endpoints.txt'
          println "*** Shared Lib entry: [${txtContent}]"

          dumpUtil.dumpSomething()

          println "* ${STAGE_NAME} - End"
        } // script
      } // steps
    } // stage
  } // stages
} // pipeline
  • Create a new account for Dummy-User 'Fred'
  • Configure the job with the Matrix Auth plugin so that the user is not having Run/Build -> Replay permissions
  • In a new private window of your browser, log in as 'Fred' and continue
  • Trigger a new build of the job. The console log will show you:
    • the chosen parameter
    • content of resources/endpoints.txt
    • content dumped by vars/dumpUtil.groovy
    *** parChoice: [b]
    *** Shared Lib entry: [Singing in the rain.
    ]
    ### Mambo No 7
    
  • Now provide a new version of the Shared Library, where both files are edited
    • resources/endpoints.txt with the content
    Singing in the sun.
    
    • vars/dumpUtil.groovy with the content
    void dumpSomething() {
      println '### Mambo No 5'
    }
    
  • Now as Fred, hit the 'Rebuild-which-is-pointing-to-Replay'-Button -> 'Run'
  • In the console log, you will find
*** parChoice: [b]
*** Shared Lib entry: [Singing in the sun.
]
### Mambo No 7

Expected Results

If the user is missing the Run/Build -> Replay permission

  • do not show the button at all instead of renaming it to 'Rebuild' and limit the modification possibilities
  • block the /replay URL and show and error message / go back link / ... so that the user can not work around the missing button

If the 'Rebuild'-functionality is needed, the 'Rebuilder'-plugin can be installed.
It is a slim, save, peaceful, MIT-licensed plugin with no known side effects with other plugins.
In my opinion, it is OK to suggest this as an alternative.

Reason:
If the user is missing the Run/Build -> Replay permission, it makes no sense to provide the 'Rebuild"-Button which is basically doing a Replay without the ability of modifying the sources.
It is correct that the user is not able to do modifications, but selling the blocked 'Replay' as 'Rebuild' is bad in my eyes. The reason is that like this now, it is possible to create builds with a quite undefined state of the Shared Library(s) used. That can also be dangerous and is at least unpredictable and hard to reproduce.

The purpose is clear and good: provide functionality so that a user can at least perform the part from the 'Replay' which allows him / her to trigger a build with the same parameters as for an already run build.
Honestly, this is exactly what the 'Rebuilder'-plugin is for.
Plus, if the 'Replay'-Button would simply be hidden if the permissions are missing, it would also solve
https://issues.jenkins.io/browse/JENKINS-76292 - Non-admin users see "Rebuild" button twice when Rebuilder plugin is installed

Actual Results

See above;

The output of the Shared Library is mixed, as the vars and src contents are taken from the non-modifyable 'Replay' section, but resources is coming from the latest version of the Shared Library.
That produces a missmatch.

Anything else?

Scenario / Example:

  • Have a user Fred with missing permissions of 'Run/Build -> Replay'
  • Have a build #1, using version A of a Shared Library
    • Version A of Shared Library is providing a method uploadArtifacts somewhere under vars, which is collecting artifacts from the build and uploads it to an external Artifactory
    • The endpoint definition of the external Artifactory is defined in the Shared Library under resources/endpoints.json
  • Build #1 uploads artifacts to the endpoint defined in resources/endpoints.json
  • The company switched the provider of the external Artifactory, a new version B of the Shared Library was created
    • resources/endpoints.json was adapted to point to the new endpoint
    • vars/uploadUtil#uploadArtifacts was extended with a filter mechanism so that some artifacts are skipped during upload
  • Now Fred hits Rebuild (which is, as said, Replay without the possibility to modify the Shared-Lib contents) on Build #1

What is now happening is that:

  • Upload to new endpoint as defined in resources/endpoints.json (because this is taken from the latest Shared lib version available) -> Shared Lib version B
  • vars/uploadUtil#uploadArtifacts is still the same logic as in build #1, missing the filter mechanism -> Shared Lib version A

This example shows that it is quite easy to use a totally inconsistant, hard to debug Shared Library version.
I consider this being a bug as the behaviour can be unpredictable and it should not be possible to mix up 'CICD logic' as a user that easy.

Are you interested in contributing a fix?

No response

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions