Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Merge pull request #278 from MarkEWaite/use-git-terminal-prompt-env
[JENKINS-35959] Don't prompt for credentials
  • Loading branch information
MarkEWaite committed Oct 14, 2017
2 parents 5c9f28d + c29628b commit ad9024d
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 86 deletions.
34 changes: 34 additions & 0 deletions src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java
Expand Up @@ -86,6 +86,33 @@ public class CliGitAPIImpl extends LegacyCompatibleGitAPIImpl {
*/
public static final boolean USE_SETSID = Boolean.valueOf(System.getProperty(CliGitAPIImpl.class.getName() + ".useSETSID", "false"));

/**
* Set promptForAuthentication=true if you must allow command line git
* versions 2.3 and later to prompt the user for authentication.
*
* Command line git prompting for authentication should be rare, since
* Jenkins credentials should be managed through the credentials plugin.
*
* Command line git 2.3 and later read the environment variable
* GIT_TERMINAL_PROMPT. If it has the value 0, then git will not prompt the
* user for authentication, even if a terminal is available (as when running
* a Jenkins agent from the Windows desktop, or when running it
* interactively from the command line, or from a Docker image). If a
* terminal is not available (most services on Windows and Linux), then
* command line git will not prompt for authentication, whether or not
* GIT_TERMINAL_PROMPT is set.
*
* GCM_INTERACTIVE=never is the environment variable which should
* cause the git credential manager for windows to never prompt
* for credentials.
*
* Credential prompting could happen on multiple platforms, but is
* more common on Windows computers because many Windows agents
* run from the desktop environment. Agents running on the
* desktop are much less common in the Unix environments.
*/
private static final boolean PROMPT_FOR_AUTHENTICATION = Boolean.valueOf(System.getProperty(CliGitAPIImpl.class.getName() + ".promptForAuthentication", "false"));

/**
* CALL_SETSID decides if command line git can use the setsid program
* during ssh based authentication to detach git from its controlling
Expand Down Expand Up @@ -1581,6 +1608,13 @@ private String launchCommandWithCredentials(ArgumentListBuilder args, File workD
File pass = null;
File askpass = null;
EnvVars env = environment;
if (!PROMPT_FOR_AUTHENTICATION && isAtLeastVersion(2, 3, 0, 0)) {
env = new EnvVars(env);
env.put("GIT_TERMINAL_PROMPT", "0"); // Don't prompt for auth from command line git
if (isWindows()) {
env.put("GCM_INTERACTIVE", "never"); // Don't prompt for auth from git credentials manager for windows
}
}
try {
if (credentials instanceof SSHUserPrivateKey) {
SSHUserPrivateKey sshUser = (SSHUserPrivateKey) credentials;
Expand Down
88 changes: 2 additions & 86 deletions src/test/java/org/jenkinsci/plugins/gitclient/CredentialsTest.java
Expand Up @@ -8,7 +8,6 @@
import com.cloudbees.plugins.credentials.impl.UsernamePasswordCredentialsImpl;
import com.google.common.io.Files;
import hudson.model.Fingerprint;
import hudson.plugins.git.GitException;
import hudson.util.LogTaskListener;
import hudson.util.StreamTaskListener;
import java.io.File;
Expand All @@ -17,7 +16,6 @@
import java.io.IOException;
import java.io.PrintStream;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collection;
Expand All @@ -30,9 +28,6 @@
import java.util.regex.Pattern;
import org.apache.commons.lang.StringUtils;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.transport.RefSpec;
import org.eclipse.jgit.transport.RemoteConfig;
import org.eclipse.jgit.transport.URIish;
import static org.hamcrest.Matchers.*;
import org.junit.After;
import static org.junit.Assert.*;
Expand Down Expand Up @@ -159,7 +154,7 @@ public void setUp() throws IOException, InterruptedException {
addExpectedLogSubstring("> git fetch ");
addExpectedLogSubstring("> git checkout -b master ");
}
addExpectedLogSubstring("Using reference repository: ");
addExpectedLogSubstring("Using reference repository: ");

assertTrue("Bad username, password, privateKey combo: '" + username + "', '" + password + "'",
(password == null || password.isEmpty()) ^ (privateKey == null || !privateKey.exists()));
Expand Down Expand Up @@ -330,21 +325,10 @@ public static Collection gitRepoUrls() throws MalformedURLException, FileNotFoun
}
}
Collections.shuffle(repos); // randomize test order
int toIndex = Math.min(repos.size(), TEST_ALL_CREDENTIALS ? 90 : 6); // Don't run more than 90 variations of test - about 12 minutes
int toIndex = Math.min(repos.size(), TEST_ALL_CREDENTIALS ? 90 : 6); // Don't run more than 90 variations of test - about 3 minutes
return repos.subList(0, toIndex);
}

private String listDir(File dir) {
File[] files = repo.listFiles();
StringBuilder fileList = new StringBuilder();
for (File file : files) {
fileList.append(file.getName());
fileList.append(',');
}
fileList.deleteCharAt(fileList.length() - 1);
return fileList.toString();
}

private void addCredential(String username, String password, File privateKey) throws IOException {
if (random.nextBoolean()) {
git.addDefaultCredentials(testedCredential);
Expand All @@ -353,74 +337,6 @@ private void addCredential(String username, String password, File privateKey) th
}
}

// @Test
public void testFetchWithCredentials() throws URISyntaxException, GitException, InterruptedException, MalformedURLException, IOException {
File clonedFile = new File(repo, fileToCheck);
String origin = "origin";
List<RefSpec> refSpecs = new ArrayList<>();
refSpecs.add(new RefSpec("+refs/heads/master:refs/remotes/" + origin + "/master"));
git.init_().workspace(repo.getAbsolutePath()).execute();
assertFalse("file " + fileToCheck + " in " + repo + ", has " + listDir(repo), clonedFile.exists());
addCredential(username, password, privateKey);
/* Save some bandwidth with shallow clone for CliGit, not yet available for JGit */
FetchCommand cmd = git.fetch_().from(new URIish(gitRepoURL), refSpecs).tags(false);
if (gitImpl.equals("git")) {
// Reduce network transfer by using shallow clone
// JGit does not support shallow clone
cmd.shallow(true).depth(1);
}
cmd.execute();
git.setRemoteUrl(origin, gitRepoURL);
ObjectId master = git.getHeadRev(gitRepoURL, "master");
log().println("Checking out " + master.getName() + " from " + gitRepoURL);
git.checkout().branch("master").ref(master.getName()).deleteBranchIfExist(true).execute();
if (submodules) {
log().println("Initializing submodules from " + gitRepoURL);
git.submoduleInit();
SubmoduleUpdateCommand subcmd = git.submoduleUpdate().parentCredentials(useParentCreds);
subcmd.execute();
}
assertTrue("master: " + master + " not in repo", git.isCommitInRepo(master));
assertEquals("Master != HEAD", master, git.getRepository().getRef("master").getObjectId());
assertEquals("Wrong branch", "master", git.getRepository().getBranch());
assertTrue("No file " + fileToCheck + ", has " + listDir(repo), clonedFile.exists());
/* prune opens a remote connection to list remote branches */
git.prune(new RemoteConfig(git.getRepository().getConfig(), origin));
checkExpectedLogSubstring();
}

@Test
public void testCloneWithCredentials() throws URISyntaxException, GitException, InterruptedException, MalformedURLException, IOException {
File clonedFile = new File(repo, fileToCheck);
String origin = "origin";
List<RefSpec> refSpecs = new ArrayList<>();
refSpecs.add(new RefSpec("+refs/heads/master:refs/remotes/" + origin + "/master"));
addCredential(username, password, privateKey);
CloneCommand cmd = git.clone_().url(gitRepoURL).repositoryName(origin).refspecs(refSpecs).reference(CURR_DIR.getAbsolutePath());
if (gitImpl.equals("git")) {
// Reduce network transfer
// Use shallow clone, JGit does not support shallow clone
cmd.shallow().depth(1);
}
cmd.execute();
ObjectId master = git.getHeadRev(gitRepoURL, "master");
log().println("Checking out " + master + " from " + gitRepoURL);
git.checkout().branch("master").ref(origin + "/master").deleteBranchIfExist(true).execute();
if (submodules) {
log().println("Initializing submodules from " + gitRepoURL);
git.submoduleInit();
SubmoduleUpdateCommand subcmd = git.submoduleUpdate();
subcmd.execute();
}
assertTrue("master: " + master + " not in repo", git.isCommitInRepo(master));
assertEquals("Master != HEAD", master, git.getRepository().getRef("master").getObjectId());
assertEquals("Wrong branch", "master", git.getRepository().getBranch());
assertTrue("No file " + fileToCheck + " in " + repo + ", has " + listDir(repo), clonedFile.exists());
/* prune opens a remote connection to list remote branches */
git.prune(new RemoteConfig(git.getRepository().getConfig(), origin));
checkExpectedLogSubstring();
}

@Test
public void testRemoteReferencesWithCredentials() throws Exception {
addCredential(username, password, privateKey);
Expand Down

0 comments on commit ad9024d

Please sign in to comment.