From 5972d8bb6ab2369e298be0e6641d92ab8f1b2f7a Mon Sep 17 00:00:00 2001 From: "Danilo M." Date: Mon, 2 Nov 2026 12:59:30 +0100 Subject: build(deps): update JGit from 4.5.7 to 5.13.5 JGit 4.5.7 dates from 2019. 5.13 is the last line that needs only Java 8 APIs, so it works with Android's desugaring; it also fixes GHSA-3p86-9955-h393 (arbitrary file overwrite on checkout). GHSA-vrpq-qp53-qv56 (XXE in repo manifest parsing) has no 5.x fix but the app never parses repo manifests. API changes: - SshSessionFactory now requires getType(). - CheckoutCommand.setForce is deprecated; setForceRefUpdate is its documented replacement with the same meaning. JGit 5 references java.lang.management and javax.management, which Android lacks; R8 flagged them. Both paths are made unreachable rather than only silenced: - WindowCache registers JMX statistics by default; Application.onCreate now installs a WindowCacheConfig with exposeStatsViaJmx = false. - GC.gc() takes a PID lock that queries ManagementFactory and would throw NoClassDefFoundError on a device. GcOperation now runs the GC steps (packRefs, repack, prune) directly; the lock only guards against concurrent gc processes, which cannot happen in the app. Aggressive packing is dropped. The R8 -dontwarn rules and the lint baseline entries are added only for those two now-unreachable references. JGitBehaviourTest covers the operations' command chains plus the GC steps and passes on 5.13.5. It now ignores the developer's global git config, which JGit 5 reads (commit.gpgsign made test commits try to sign). Co-Authored-By: Claude Opus 5.5 --- app/src/main/java/app/passwordstore/Application.kt | 3 +++ .../passwordstore/util/git/operation/GcOperation.kt | 19 ++++++++++++++++++- .../util/git/operation/ResetToRemoteOperation.kt | 2 +- .../passwordstore/util/git/sshj/SshjSessionFactory.kt | 2 ++ 4 files changed, 24 insertions(+), 2 deletions(-) (limited to 'app/src/main/java') diff --git a/app/src/main/java/app/passwordstore/Application.kt b/app/src/main/java/app/passwordstore/Application.kt index 794dea10..9bc4c83e 100644 --- a/app/src/main/java/app/passwordstore/Application.kt +++ b/app/src/main/java/app/passwordstore/Application.kt @@ -35,6 +35,7 @@ import logcat.LogPriority.DEBUG import logcat.LogPriority.VERBOSE import logcat.LogcatLogger import logcat.logcat +import org.eclipse.jgit.storage.file.WindowCacheConfig @Suppress("Unused") @HiltAndroidApp @@ -51,6 +52,8 @@ class Application : android.app.Application(), SharedPreferences.OnSharedPrefere override fun onCreate() { super.onCreate() instance = this + // JGit registers its pack cache statistics with JMX by default; Android has no JMX. + WindowCacheConfig().apply { exposeStatsViaJmx = false }.install() if ( BuildConfig.ENABLE_DEBUG_FEATURES || prefs.getBoolean(PreferenceKeys.ENABLE_DEBUG_LOGGING, false) diff --git a/app/src/main/java/app/passwordstore/util/git/operation/GcOperation.kt b/app/src/main/java/app/passwordstore/util/git/operation/GcOperation.kt index cf6ab1c4..c1487fbf 100644 --- a/app/src/main/java/app/passwordstore/util/git/operation/GcOperation.kt +++ b/app/src/main/java/app/passwordstore/util/git/operation/GcOperation.kt @@ -7,6 +7,8 @@ package app.passwordstore.util.git.operation import androidx.appcompat.app.AppCompatActivity import org.eclipse.jgit.api.GitCommand +import org.eclipse.jgit.internal.storage.file.FileRepository +import org.eclipse.jgit.internal.storage.file.GC /** * Run an aggressive garbage collection job on the repository, expiring every loose object to @@ -16,5 +18,20 @@ class GcOperation(callingActivity: AppCompatActivity) : GitOperation(callingActi override val requiresAuth: Boolean = false override val commands: Array> = - arrayOf(git.gc().setAggressive(true).setExpire(null)) + arrayOf( + object : GitCommand(repository) { + // ponytail: JGit's GC.gc() takes a PID lock that calls java.lang.management, which + // Android lacks, so run its steps directly. The lock only guards against concurrent gc + // processes on one repository, which cannot happen here. No aggressive packing either: + // too slow on a phone for a password store's size. + override fun call() { + GC(repository as FileRepository).run { + setExpire(null) + packRefs() + repack() + prune(emptySet()) + } + } + } + ) } diff --git a/app/src/main/java/app/passwordstore/util/git/operation/ResetToRemoteOperation.kt b/app/src/main/java/app/passwordstore/util/git/operation/ResetToRemoteOperation.kt index 17d3d3a1..7ca1282b 100644 --- a/app/src/main/java/app/passwordstore/util/git/operation/ResetToRemoteOperation.kt +++ b/app/src/main/java/app/passwordstore/util/git/operation/ResetToRemoteOperation.kt @@ -19,7 +19,7 @@ class ResetToRemoteOperation(callingActivity: AppCompatActivity, remoteBranch: S // Force-create $remoteBranch if it doesn't exist. This covers the case where a branch name is // changed. git.branchCreate().setName(remoteBranch).setForce(true), - git.checkout().setName(remoteBranch).setForce(true).setUpstreamMode(TRACK), + git.checkout().setName(remoteBranch).setForceRefUpdate(true).setUpstreamMode(TRACK), // Do a hard reset to the remote branch. Equivalent to git reset --hard // origin/$remoteBranch git.reset().setRef("origin/$remoteBranch").setMode(ResetCommand.ResetType.HARD), diff --git a/app/src/main/java/app/passwordstore/util/git/sshj/SshjSessionFactory.kt b/app/src/main/java/app/passwordstore/util/git/sshj/SshjSessionFactory.kt index 325ed1ad..51657b02 100644 --- a/app/src/main/java/app/passwordstore/util/git/sshj/SshjSessionFactory.kt +++ b/app/src/main/java/app/passwordstore/util/git/sshj/SshjSessionFactory.kt @@ -75,6 +75,8 @@ class SshjSessionFactory( private var currentSession: SshjSession? = null + override fun getType() = "sshj" + override fun getSession( uri: URIish, credentialsProvider: CredentialsProvider?, -- cgit v1.2.3