-
Type:
Bug
-
Resolution: Fixed
-
Priority:
Trivial
-
Component/s: bitbucket-branch-source-plugin
-
937.3.6
Summary
CloudWebhookManager.shouldUpdate() always triggers secret update causing webhook cache to be ineffective
- Affects Version: 937.3.2 (introduced in PR #1126 /
JENKINS-76184) - Environment: Bitbucket Cloud with hook signature enabled and webhook caching enabled
When both "Enable hook signature" and "Enable cache" are configured on the Bitbucket Cloud endpoint, the webhook cache (introduced in JENKINS-76184) is never effective. Every organization folder scan triggers a webhook update for every
repository, which immediately evicts the cache entry. The stats() output always shows "Repositories webhooks: No entry.".
Possible Root Cause
Bitbucket Cloud's REST API (GET /2.0/repositories/{owner}/{repo}/hooks) does not return the secret value in the response — it only returns "secret_set": true. The BitbucketCloudWebhook object deserialized from this response has getSecret()
== null.
In CloudWebhookManager.shouldUpdate():
if (!Objects.equal(current.getSecret(), expected.getSecret())) { current.setSecret(expected.getSecret()); logger.info(() -> "Update webhook " + current.getUuid() + " signature secret"); update = true; }
This always evaluates to !Objects.equal(null, "actual-secret-value") → true, causing:
1. An unnecessary PUT request to Bitbucket on every repo during every scan
2. Cache eviction in update() method after the PUT
3. The cache feature from JENKINS-76184 provides no benefit when hook signatures are enabled
Steps to Reproduce
1. Configure a Bitbucket Cloud endpoint with:
- "Enable hook signature" checked with a valid secret credential
- "Enable cache" checked
2. Create an organization folder pointing to a workspace with repositories
3. Trigger an organization folder scan
4. Observe logs showing "Update webhook {uuid} signature secret" for every repo
5. Check stats — shows "Repositories webhooks: No entry."
6. Trigger a second scan — same behavior repeats
Confirmation:
Calling the Bitbucket API directly confirms the secret field is null in GET responses while secret_set: true is present:
{
"uuid": "{cba5af76-...}",
"secret_set": true,
"secret": null,
...
}
Suggestions
Since the API never returns the actual secret value, there's no way to detect a credential rotation purely from the API response.
Skip comparison when secret is already set — Only push the secret if secret_set is false. Secret rotation would require clearing the cache (via the UI "Clear Caches" button or cache expiry). This is the simplest change:
if (expected.getSecret() != null && !current.isSecretSet()) { current.setSecret(expected.getSecret()); logger.info(() -> "Set webhook " + current.getUuid() + " signature secret"); update = true; }
Use cache presence as the gate — If the webhook's cache entry exists (meaning it was already processed successfully in this cache window), skip the secret comparison. After cache expiry or manual clear, the secret gets re-pushed once.
This aligns with the existing cache TTL mechanism.
Impact
Organizations with hook signatures enabled and 500+ repositories (the exact use case JENKINS-76184 was designed for) get no benefit from the caching feature and continue hitting rate limits.
Related: JENKINS-76184, PR #1126
- links to