New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
JENKINS-70275 git scm owner is reinitialized if null whenever accessi… #374
JENKINS-70275 git scm owner is reinitialized if null whenever accessi… #374
Conversation
…ng in BitbucketSCMSource
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for digging into and fixing this @mhenschke-atl !
@@ -181,6 +181,9 @@ public BitbucketSCMRepository getBitbucketSCMRepository() { | |||
CustomGitSCMSource getAndInitializeGitSCMSourceIfNull() { | |||
if (gitSCMSource == null) { | |||
initializeGitScmSource(); | |||
} | |||
if (getOwner() != null && gitSCMSource.getOwner() == null) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this only have to happen after the scm source is initialized or are there other scenarios where we might need to set the owner? If the former, should we put this code as part of initializeGitScmSource
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The GitSCMSource always needs an owner, so it does need to be in the initialization too. It's done as part of constructing the new source:
gitSCMSource = new CustomGitSCMSource(remoteConfig.getUrl(), repository);
gitSCMSource.setBrowser(new BitbucketServer(selfLink));
gitSCMSource.setCredentialsId(repository.getCloneCredentialsId());
gitSCMSource.setOwner(getOwner());
gitSCMSource.setTraits(traits);
gitSCMSource.setId(getId() + "-git-scm");
One thing to note here is we also set a browser which is not serialized with the rest of the source. I'm actually not 100% sure of what that browser is doing- theoretically it generates links out to source browsers but we already do that manually with BitbucketLink
. That said I'm happy to include a null check for it as well, for completeness.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The browser provides the links for when you view the changeset in Jenkins. Would be good to include it as well. Either in this PR or in a separate PR
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The browser is a slightly trickier task, as it relies on the self-link which we don't currently persist anywhere. I might tackle this in a separate PR, it's a larger change and unrelated to this issue.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am slightly concerned that we're removing the browser
but... I think we can address that in a separate PR before release.
@@ -178,9 +178,13 @@ public BitbucketSCMRepository getBitbucketSCMRepository() { | |||
return repository; | |||
} | |||
|
|||
CustomGitSCMSource getAndInitializeGitSCMSourceIfNull() { | |||
CustomGitSCMSource getFullyInitializedGitSCMSource() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had a go at renaming this method to make it more reflective of what it's actually doing
I'm wondering if the recent JENKINS-60490 reopening is related to this issue too- will perform a local test on it before this merges |
This issue can be replicated locally by taking the following steps:
The result is a stack trace in the Jenkins logs related to a 401 on checkout. Inspecting the request in Bitbucket reveals Jenkins has sent a pair of garbled strings instead of real credentials, which probably isn't great but is ultimately a red herring.
This issue relates closely to JENKINS-65541, and has to do with the way we wrap the GitSCMSource. We provide a credential id to the git scm when attempting a retrieve rather than a full credential- it then uses it's owner context (which refers to the containing job or folder) so it can only retrieve credentials it has access to. All items have global access. However, our GitSCMSource doesn't have an owner, as it's wrapped in the BitbucketSCMSource, so the solution to this bug was to ensure we added the same owner when the GitSCMSource is initialized.
The problem comes when Jenkins restarts. We added the setOwner check in the git initialization code, that's called whenever a BitbucketSCMSource is created, but upon restart Jenkins doesn't create a new SCMSource, it deserializes it from the job's config.xml file. An example is shown below:
Notice that the GitSCMSource serializes the credential id fine, but not the owner- which is why the credential is passed through with no problems to the SCM which attempts to fetch the credential and fails. Hence, the authentication check with Bitbucket fails and the job cannot succeed until the user has re-saved the config, this creating the SCMSource anew with the appropriate owner.
This bug will reoccur every time Jenkins restarts.
You may be asking is "why doesn't this happen with the BitbucketSCMSource as well"? Unlike the GitSCMSource, the Bitbucket source has a real owner- a multibranch pipeline. These extend
Item
, which exposes anonLoad
method- a method called as part of deserialization of the config file, where any implied information (such as the owner) can be added dynamically. You can see the workings inMultiBranchProject#init2
- it cycles over all deserialized SCMSources it knows about and simply adds itself to them as owner manually. Our GitSCMSource is not in this list, so it is omitted and we have to do it ourself. It would be really convenient if SCMSource exposed anonLoad
method, but it doesn't because this sort of dynamic setting is designed to be done by Projects, not SCMs- which is one more compelling reason to do away with the GitSCMSource in the future.