mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[git] Fixed caching git-trusted failure (IJPL-254472)
(cherry picked from commit a11ab71c33694546ac840e02f6de59bf48a78d92) (cherry picked from commit 5cef50f116adffe45a73a92c0cc8ca6c6928b418) IJ-MR-222169 GitOrigin-RevId: d111f26b7b4d53b3de78db64949c8b76a6b5d9b0
This commit is contained in:
committed by
intellij-monorepo-bot
parent
21d6cd5ebf
commit
57933ab7d4
@@ -97,6 +97,9 @@ git4idea.commands.Git
|
||||
- a:runCommand(com.intellij.openapi.util.Computable):git4idea.commands.GitCommandResult
|
||||
- a:runCommand(git4idea.commands.GitLineHandler):git4idea.commands.GitCommandResult
|
||||
- a:runCommandWithoutCollectingOutput(git4idea.commands.GitLineHandler):git4idea.commands.GitCommandResult
|
||||
f:git4idea.commands.GitCommandNotTrustedException
|
||||
- java.lang.IllegalStateException
|
||||
- <init>(java.lang.String):V
|
||||
c:git4idea.commands.GitCommandResult
|
||||
- s:error(java.lang.String):git4idea.commands.GitCommandResult
|
||||
- getOutputOrThrow(I[]):java.lang.String
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
// Copyright 2000-2026 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package git4idea.commands;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* Thrown when the project is not trusted.
|
||||
* <p>
|
||||
* This reflects the trust state of the caller, not a property of the git executable. A cache
|
||||
* keyed by the executable, such as {@code git4idea.config.GitExecutableFileTester}, must not
|
||||
* store this failure: the same executable can succeed for a later, trusted caller.
|
||||
*/
|
||||
public final class GitCommandNotTrustedException extends IllegalStateException {
|
||||
public GitCommandNotTrustedException(@NotNull String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -465,12 +465,12 @@ public abstract class GitHandler {
|
||||
|
||||
private void start() throws IOException {
|
||||
if (myProject == null && !TrustedProjects.isProjectTrusted(Objects.requireNonNull(getWorkingDirectory()))) {
|
||||
throw new IllegalStateException("Shouldn't be possible to run a Git command in potentially untrusted project. " +
|
||||
"Pass Project to GitHandler constructor if applicable.");
|
||||
throw new GitCommandNotTrustedException("Shouldn't be possible to run a Git command in potentially untrusted project. " +
|
||||
"Pass Project to GitHandler constructor if applicable.");
|
||||
}
|
||||
|
||||
if (myProject != null && !myProject.isDefault() && !TrustedProjects.isProjectTrusted(myProject)) {
|
||||
throw new IllegalStateException("Shouldn't be possible to run a Git command in the safe mode");
|
||||
throw new GitCommandNotTrustedException("Shouldn't be possible to run a Git command in the safe mode");
|
||||
}
|
||||
|
||||
if (isStarted()) {
|
||||
|
||||
@@ -18,6 +18,7 @@ import com.intellij.platform.ide.impl.wsl.WslEelDescriptor;
|
||||
import com.intellij.util.concurrency.AppJavaExecutorUtil;
|
||||
import git4idea.commands.Git;
|
||||
import git4idea.commands.GitCommand;
|
||||
import git4idea.commands.GitCommandNotTrustedException;
|
||||
import git4idea.commands.GitCommandResult;
|
||||
import git4idea.commands.GitLineHandler;
|
||||
import git4idea.i18n.GitBundle;
|
||||
@@ -60,13 +61,27 @@ class GitExecutableFileTester {
|
||||
LOG.warn(e);
|
||||
|
||||
result = new TestResult(e, currentLastModificationDate);
|
||||
myTestMap.put(executable, result);
|
||||
if (!isProjectTrustFailure(e)) {
|
||||
myTestMap.put(executable, result);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* A {@link GitCommandNotTrustedException} reflects the trust state of the caller, not a
|
||||
* property of {@code executable}, so it must not be cached: the same executable can be
|
||||
* retested for a different, trusted caller and succeed.
|
||||
*/
|
||||
private static boolean isProjectTrustFailure(@NotNull Throwable e) {
|
||||
for (Throwable t = e; t != null; t = t.getCause()) {
|
||||
if (t instanceof GitCommandNotTrustedException) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static @NotNull GitVersion testOrAbort(@Nullable Project project, @NotNull GitExecutable executable) throws Exception {
|
||||
int maxAttempts = 1;
|
||||
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
// Copyright 2000-2026 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package git4idea.config
|
||||
|
||||
import com.intellij.ide.trustedProjects.TrustedProjects
|
||||
import com.intellij.testFramework.junit5.SystemProperty
|
||||
import com.intellij.testFramework.junit5.TestApplication
|
||||
import com.intellij.testFramework.junit5.fixture.projectFixture
|
||||
import com.intellij.vcs.test.vcsPlatformFixture
|
||||
import git4idea.commands.GitCommandNotTrustedException
|
||||
import git4idea.config.GitSaveChangesPolicy
|
||||
import git4idea.test.GitPlatformTestContext
|
||||
import git4idea.test.gitPlatformFixture
|
||||
import org.junit.jupiter.api.Assertions.assertThrows
|
||||
import org.junit.jupiter.api.Assertions.assertTrue
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
@TestApplication
|
||||
@SystemProperty("idea.trust.headless.disabled", "false")
|
||||
internal class GitExecutableManagerTrustCacheTest {
|
||||
|
||||
private val contextFixture = projectFixture(openAfterCreation = true).let { projectFixture ->
|
||||
projectFixture
|
||||
.vcsPlatformFixture()
|
||||
.gitPlatformFixture(projectFixture, defaultSaveChangesPolicy = GitSaveChangesPolicy.SHELVE, hasRemoteGitOperation = false)
|
||||
}
|
||||
private val context: GitPlatformTestContext get() = contextFixture.get()
|
||||
|
||||
@Test
|
||||
fun `an untrusted-project failure is not cached and does not poison a later trusted call`(): Unit = with(context) {
|
||||
val manager = GitExecutableManager.getInstance()
|
||||
val executable = manager.getExecutable(project)
|
||||
|
||||
// The fixture's own setup already tested this executable and cached a success for it;
|
||||
// drop that entry so the call below genuinely re-tests under the trust state set here.
|
||||
manager.dropVersionCache(executable)
|
||||
TrustedProjects.setProjectTrusted(project, false)
|
||||
val failure = assertThrows(GitVersionIdentificationException::class.java) {
|
||||
manager.identifyVersion(project, executable)
|
||||
}
|
||||
assertTrue(failure.cause is GitCommandNotTrustedException)
|
||||
|
||||
// Without the fix, the poisoned cache entry (same GitExecutable, unchanged mtime)
|
||||
// would be replayed here even though the project is now trusted.
|
||||
TrustedProjects.setProjectTrusted(project, true)
|
||||
val version = manager.identifyVersion(project, executable)
|
||||
assertTrue(version.isSupported)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user