Re-resolve cached scan credentials after a TTL - #1561
Open
ysmaoui wants to merge 3 commits into
Open
Conversation
GitHubSCMSource and GitHubSCMNavigator keep the credentials object they resolved and only re-resolve it when a full scan asks them to. Every per-build path passes forceRefresh=false, so a credential whose content changed is picked up only after a rescan, a config save or a restart. Bound the reuse to 60s, configurable through org.jenkinsci.plugins.github_branch_source.Connector.credentialsTtlSeconds, 0 to resolve on every use.
Both getCredentials methods stay private, as asked for in the review of jenkinsci#787; the test reaches them by reflection instead. The tests forced a refresh by setting the TTL to 0, which short-circuits before the clock comparison, leaving it uncovered. They now let a real TTL elapse, and the contract itself is asserted directly. A negative TTL now reuses the credentials object indefinitely, an exact opt-out for anyone who wants the previous behaviour.
A scan passing forceRefresh=true must resolve even inside the TTL, and a negative credentialsTtlSeconds must map to no expiry. Neither was asserted.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
GitHubSCMSourceandGitHubSCMNavigatorcache the credentials object they resolved in atransient volatilefield and only resolve it again when the caller asks for a refresh. Only the full-scan paths do that (GitHubSCMSource#retrievewhen the observer is notSCMHeadObserver.Any, andGitHubSCMNavigator#visitSources); every per-build and per-head path passesforceRefresh=false.The field has no expiry, so its lifetime is the source or navigator object: until the job configuration is saved or Jenkins restarts. A credential whose content changed under the same ID is therefore never picked up by builds on its own. A rescan is the only routine operation that clears it.
This is most visible with credentials backed by an external store (Azure Key Vault, HashiCorp Vault, AWS Secrets Manager), where refreshing the provider replaces the credentials object wholesale. Rotating a GitHub App there and reloading the provider cache leaves builds authenticating as the old app, with no indication that anything is stale: the credentials page shows the new value while builds keep using the old one. It also applies to plain stored credentials, where editing a secret in the UI creates a new object that cached references never see.
This bounds the reuse instead of removing it.
Connector.credentialsTtlMillisdefaults to 60 seconds and is configurable through the system propertyorg.jenkinsci.plugins.github_branch_source.Connector.credentialsTtlSeconds;0resolves on every use, a negative value reuses indefinitely and so restores today's behaviour exactly. During a scan that means a handful of lookups per source rather than one per branch or PR, so the throughput win from [JENKINS-73172] / #787 is kept, while staleness is capped at a minute instead of unbounded.Two notes for reviewers of #787 in particular:
getCredentialsmethods stay private, per the review nits on that PR. The test reaches them by reflection rather than widening them; happy to swap that for package-private visibility if you prefer.apiUri,credentialsIdorrepoOwneron a live source is not noticed either. A TTL is not the keyed lookup suggested there, but it does put a bound on it.AppInstallationTokencache inGitHubAppCredentials, so a new installation token is minted at most once per TTL per source. Providers that cache internally (Azure Key Vault, HashiCorp Vault) return a stable object and are unaffected. Raising the default is easy if you think that trade is wrong.Submitter checklist
No JIRA ticket filed yet, happy to open one if maintainers prefer that before review.
CredentialsRefreshTestcovers both classes: resolve, replace the stored credential under the same ID, assert the cached object is still reused inside the TTL, then assert the new one is resolved once a real TTL has elapsed. Both fail without the production change. A third test asserts theisCredentialsStalecontract directly, including the zero and negative settings.Manual test:
githuband a multibranch project using it.Reviewer checklist
Documentation changes
Users/aliases to notify
@Dohbedoh, as the author of #787.