jenkinsci / jenkinsci/github-branch-source-plugin

`GitHubSCMProbe.cache` grows unbounded for short-lived tokens delivered as standard (username/password) credentials

Open
#1,541 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
Java
Stars
217
Forks
398
Avg merge
30m
Merged PRs (30d)
1

Description

### Summary

On-disk API caches under `$JENKINS_HOME/org.jenkinsci.plugins.github_branch_source.GitHubSCMProbe.cache` accumulate without bound when a multibranch/SCM source authenticates with a **rotating token supplied as a standard `UsernamePasswordCredentials`** (rather than the plugin's native `GitHubAppCredentials`). This is the same disk/inode exhaustion described in JENKINS-63711, but for a credential type the JENKINS-63711 fix (#341) deliberately left out of scope.

### Environment

- github-branch-source: `1967.1970.vd86979736546`
- Jenkins: `2.568.1`
- Auth: GitHub App **installation tokens issued externally** (in our case via HashiCorp Vault + [`vault-plugin-secrets-github`](https://github.com/martinbaillie/vault-plugin-secrets-github)), token TTL **1 hour**, delivered into Jenkins as a `UsernamePasswordCredentials` (secret text / username-password), **not** as `GitHubAppCredentials`.

### Root cause (from current `master`)

Two behaviors combine:

1. **Cache directory name is keyed on the secret value.** `Connector.getCache()` names the cache subdirectory as `SHA-256(apiUrl "::" username "::" authHash)`, where `authHash` is a digest of the credential secret. A token that rotates hourly therefore produces a **new cache directory every rotation, per repo**.

2. **Automatic cleanup is gated on the concrete credential class.** `UnusedConnectionDestroyer` deletes a cache folder only when `cleanupCacheFolder == true`, which is set exclusively via:

```java
new GitHubConnection(gb.build(), cache, credentials instanceof GitHubAppCredentials)
```

For a `UsernamePasswordCredentials` this is `false`, so the hourly orphaned directories are **never reclaimed**.

Net effect: one new, never-deleted cache directory per repo per hour → unbounded directory/inode growth. PR #341 explicitly scoped its cleanup to `GitHubAppCredentials` ("Behavior for non-GitHubAppCredential connections is unchanged to preserve the advantages of the existing behavior for standard credentials"), which is reasonable for *stable* standard credentials but breaks down for externally-issued short-lived tokens — an increasingly common pattern (Vault, IRSA/OIDC brokers, other secret managers).

### Impact

Operators in this configuration must run an out-of-band cron job to periodically delete the cache directory (we've maintained one for ~3 years), or disable caching entirely via `-Dorg.jenkinsci.plugins.github_branch_source.GitHubSCMSource.cacheSize=0` at the cost of losing conditional-request (ETag/304) rate-limit savings.

### Suggested directions (any one would resolve it)

- **Size/age-based eviction** of the cache root (e.g. LRU trim to `cacheSize`, or delete entries idle beyond a threshold) that is independent of credential class — this fixes the general case rather than special-casing one credential type.
- **Cleanup based on token rotation, not credential class:** treat any connection whose `authHash` is no longer referenced as eligible for folder deletion in `UnusedConnectionDestroyer`.
- **Decouple the cache key from the secret** where a stable identity is available (e.g. key on username / app-id + apiUrl rather than the rotating token), so rotation reuses one directory instead of spawning new ones.

### References

- JENKINS-63711 / PR #341 — original unbounded-growth report and the App-credentials-only cleanup.

Contributor guide

Open the contributing guide

Research direction

Start with Connector.getCache(), UnusedConnectionDestroyer, and GitHubConnection to trace cache naming, credential-class cleanup, and references from GitHubSCMProbe.cache. Reproduce the behavior with rotating UsernamePasswordCredentials and inspect PR #341 and JENKINS-63711 for existing constraints. Done means cache growth is bounded for rotating standard credentials without regressing stable-credential behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
github, java
Domain
backend, devops
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.