diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
new file mode 100644
index 0000000000000000000000000000000000000000..a7842e0f66c76f14ba418fec1d01350b48b637a8
--- /dev/null
+++ b/.github/FUNDING.yml
@@ -0,0 +1 @@
+custom: https://jenkins.io/donate/
diff --git a/.github/release-drafter.yml b/.github/release-drafter.yml
new file mode 100644
index 0000000000000000000000000000000000000000..ee1096aa39093b66c43095737d32d29225c5dd40
--- /dev/null
+++ b/.github/release-drafter.yml
@@ -0,0 +1,59 @@
+# Configuration for Release Drafter: https://github.com/toolmantim/release-drafter
+name-template: $NEXT_PATCH_VERSION
+# Uses a more common 2-digit versioning in Jenkins weekly releases.
+version-template: $MAJOR.$MINOR
+tag-template: jenkins-$NEXT_MINOR_VERSION
+
+exclude-labels:
+ - reverted
+ - no-changelog
+ - skip-changelog
+ - invalid
+change-template: |-
+ - type: todo
+ message: |-
+ $TITLE
+ pull: $NUMBER
+ authors:
+ - $AUTHOR
+
+template: |
+ **Disclaimer**: This is an automatically generated changelog draft for Jenkins weekly releases.
+ See https://jenkins.io/changelog/ for the official changelogs.
+
+ ```yaml
+ $CHANGES
+ ```
+
+# Categories will be commented out, because we use YAML
+# Now we use categories only for sorting
+categories:
+ - title: Major BUGs and regressions
+ labels:
+ - major-bug
+ - regression-fix
+ - title: Major RFE
+ label: major-rfe
+ - title: RFEs
+ label: rfe
+ - title: Bug fixes
+ label: bug
+ - title: Localization
+ label: localization
+ # TODO: consider merging category or changing emojis
+ - title: Internal/Developer changes
+ label: internal
+
+replacers:
+ - search: '/\[*JENKINS-(\d+)\]*\s*-*\s*/g'
+ replace: |-
+ issue: $1
+ message: |-
+
+ - search: |-
+ message: |-
+ issue:
+ replace: "issue:"
+
+ - search: "##"
+ replace: "#"
diff --git a/.mvn/maven.config b/.mvn/maven.config
index e54fdacfe62468e4e85ebe51890384926933b476..2a0299c4865d58b47a576f7effc4a15f3fcf4ee9 100644
--- a/.mvn/maven.config
+++ b/.mvn/maven.config
@@ -1 +1,2 @@
+-Pconsume-incrementals
-Pmight-produce-incrementals
diff --git a/Dockerfile b/Dockerfile
index d4541bdfcbaa7904cfc9264f6a823d80d1b55992..4566c7265f56fda510013ff263b911d92c6a2a3b 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -8,6 +8,8 @@ COPY cli/ /jenkins/src/cli/
COPY core/ /jenkins/src/core/
COPY src/ /jenkins/src/src/
COPY test/ /jenkins/src/test/
+COPY test-pom/ /jenkins/src/test-pom/
+COPY test-jdk8/ /jenkins/src/test-jdk8/
COPY war/ /jenkins/src/war/
COPY *.xml /jenkins/src/
COPY LICENSE.txt /jenkins/src/LICENSE.txt
diff --git a/Jenkinsfile b/Jenkinsfile
index 3cecdfcbb7b16bac414c800ad0163e37e80dbd5e..95c9becb3fd0161ff306ac7c7598634d4b8ca205 100644
--- a/Jenkinsfile
+++ b/Jenkinsfile
@@ -3,20 +3,16 @@
/*
* This Jenkinsfile is intended to run on https://ci.jenkins.io and may fail anywhere else.
* It makes assumptions about plugins being installed, labels mapping to nodes that can build what is needed, etc.
- *
- * The required labels are "java" and "docker" - "java" would be any node that can run Java builds. It doesn't need
- * to have Java installed, but some setups may have nodes that shouldn't have heavier builds running on them, so we
- * make this explicit. "docker" would be any node with docker installed.
*/
// TEST FLAG - to make it easier to turn on/off unit tests for speeding up access to later stuff.
def runTests = true
def failFast = false
-properties([buildDiscarder(logRotator(numToKeepStr: '50', artifactNumToKeepStr: '20')), durabilityHint('PERFORMANCE_OPTIMIZED')])
+properties([buildDiscarder(logRotator(numToKeepStr: '50', artifactNumToKeepStr: '3')), durabilityHint('PERFORMANCE_OPTIMIZED')])
-// see https://github.com/jenkins-infra/documentation/blob/master/ci.adoc for information on what node types are available
-def buildTypes = ['Linux', 'Windows']
+// TODO: Restore 'Windows' once https://groups.google.com/forum/#!topic/jenkinsci-dev/v9d-XosOp2s is resolved
+def buildTypes = ['Linux']
def jdks = [8, 11]
def builds = [:]
@@ -25,8 +21,8 @@ for(j = 0; j < jdks.size(); j++) {
def buildType = buildTypes[i]
def jdk = jdks[j]
builds["${buildType}-jdk${jdk}"] = {
- node(buildType.toLowerCase()) {
- timestamps {
+ // see https://github.com/jenkins-infra/documentation/blob/master/ci.adoc#node-labels for information on what node types are available
+ node(buildType == 'Linux' ? (jdk == 8 ? 'maven' : 'maven-11') : buildType.toLowerCase()) {
// First stage is actually checking out the source. Since we're using Multibranch
// currently, we can use "checkout scm".
stage('Checkout') {
@@ -42,7 +38,7 @@ for(j = 0; j < jdks.size(); j++) {
// See below for what this method does - we're passing an arbitrary environment
// variable to it so that JAVA_OPTS and MAVEN_OPTS are set correctly.
withMavenEnv(["JAVA_OPTS=-Xmx1536m -Xms512m",
- "MAVEN_OPTS=-Xmx1536m -Xms512m"], jdk) {
+ "MAVEN_OPTS=-Xmx1536m -Xms512m"], buildType, jdk) {
// Actually run Maven!
// -Dmaven.repo.local=… tells Maven to create a subdir in the temporary directory for the local Maven repository
def mvnCmd = "mvn -Pdebug -U -Dset.changelist help:evaluate -Dexpression=changelist -Doutput=$changelistF clean install ${runTests ? '-Dmaven.test.failure.ignore' : '-DskipTests'} -V -B -Dmaven.repo.local=$m2repo -s settings-azure.xml -e"
@@ -63,7 +59,7 @@ for(j = 0; j < jdks.size(); j++) {
junit healthScaleFactor: 20.0, testResults: '*/target/surefire-reports/*.xml'
archiveArtifacts allowEmptyArchive: true, artifacts: '**/target/surefire-reports/*.dumpstream'
}
- if (buildType == 'Linux') {
+ if (buildType == 'Linux' && jdk == jdks[0]) {
def changelist = readFile(changelistF)
dir(m2repo) {
archiveArtifacts artifacts: "**/*$changelist/*$changelist*",
@@ -73,12 +69,13 @@ for(j = 0; j < jdks.size(); j++) {
}
}
}
- }
}
}
}}
+// TODO: Restore ATH once https://groups.google.com/forum/#!topic/jenkinsci-dev/v9d-XosOp2s is resolved
// TODO: ATH flow now supports Java 8 only, it needs to be reworked (INFRA-1690)
+/*
builds.ath = {
node("docker&&highmem") {
// Just to be safe
@@ -100,7 +97,7 @@ builds.ath = {
runATH jenkins: fileUri, metadataFile: metadataPath
}
}
-}
+}*/
builds.failFast = failFast
parallel builds
@@ -109,7 +106,14 @@ infra.maybePublishIncrementals()
// This method sets up the Maven and JDK tools, puts them in the environment along
// with whatever other arbitrary environment variables we passed in, and runs the
// body we passed in within that environment.
-void withMavenEnv(List envVars = [], def javaVersion, def body) {
+void withMavenEnv(List envVars = [], def buildType, def javaVersion, def body) {
+ if (buildType == 'Linux') {
+ // I.e., a Maven container using ACI. No need to install tools.
+ return withEnv(envVars) {
+ body.call()
+ }
+ }
+
// The names here are currently hardcoded for my test environment. This needs
// to be made more flexible.
// Using the "tool" Workflow call automatically installs those tools on the
diff --git a/README.md b/README.md
index 7ef6c08a8ec40120d755931ce679e5ca870c5bda..ee4ed648cbcbe3526a3e8c6870de015b5d2f9f60 100644
--- a/README.md
+++ b/README.md
@@ -1,8 +1,13 @@
[![][ButlerImage]][website]
# About
+
+[![Weekly Release](https://img.shields.io/badge/dynamic/json.svg?url=https://updates.jenkins.io/update-center.actual.json&label=Weekly%20Release&query=$.core.version&color=green)](https://jenkins.io/changelog/)
+[![LTS Release](https://img.shields.io/badge/dynamic/json.svg?url=https://updates.jenkins.io/stable/update-center.actual.json&label=LTS%20Release&query=$.core.version&color=orange)](https://jenkins.io/changelog-stable/)
+[![Docker Pulls](https://img.shields.io/docker/pulls/jenkins/jenkins.svg)](https://hub.docker.com/r/jenkins/jenkins/)
+
In a nutshell, Jenkins is the leading open-source automation server.
-Built with Java, it provides over 1000 plugins to support automating virtually anything,
+Built with Java, it provides over 1600 [plugins](https://plugins.jenkins.io/) to support automating virtually anything,
so that humans can actually spend their time doing things machines cannot.
# What to Use Jenkins for and When to Use It
@@ -29,32 +34,11 @@ Follow the [contributing](CONTRIBUTING.md) file.
All information about Jenkins can be found on our [website]. Follow us on Twitter [@jenkinsci].
# License
-Jenkins is **licensed** under the **[MIT License]**. The terms of the license are as follows:
-
- The MIT License (MIT)
-
- Copyright (c) 2004 Kohsuke Kawaguchi, Sun Microsystems Inc., and a number of other contributors.
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in
- all copies or substantial portions of the Software.
+Jenkins is **licensed** under the **[MIT License]**.
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- THE SOFTWARE.
[ButlerImage]: https://jenkins.io/sites/default/files/jenkins_logo.png
-[MIT License]: https://github.com/jenkinsci/jenkins/raw/master/LICENSE.txt
+[MIT License]: https://github.com/jenkinsci/jenkins/blob/master/LICENSE.txt
[Mirrors]: http://mirrors.jenkins-ci.org
[GitHub]: https://github.com/jenkinsci/jenkins
[website]: https://jenkins.io/
diff --git a/cli/pom.xml b/cli/pom.xml
index 0a5aa6a5c328e6072e7a164f4bf974656b676cb0..5d3738bd4202853908b39d102bd1f852dfc1c819 100644
--- a/cli/pom.xml
+++ b/cli/pom.xml
@@ -58,7 +58,7 @@
org.jvnet.localizerlocalizer
- 1.24
+ 1.26org.apache.sshd
@@ -77,15 +77,10 @@
slf4j-jdk14true
-
- org.jenkins-ci
- trilead-ssh2
- build214-jenkins-1
-
- com.google.code.findbugs
- annotations
- provided
+ com.github.spotbugs
+ spotbugs-annotations
+ truecommons-lang
@@ -139,7 +134,21 @@
org.codehaus.mojo
- findbugs-maven-plugin
+ build-helper-maven-plugin
+
+
+ add-source
+ generate-sources
+
+ add-source
+
+
+
+
+
+
+
+
diff --git a/cli/src/main/java/hudson/cli/CLI.java b/cli/src/main/java/hudson/cli/CLI.java
index 0ffef53f9305a6e9d260826e092e805fe9b8465e..5b436b02b085d9ca964561828d4b2fdeafb41715 100644
--- a/cli/src/main/java/hudson/cli/CLI.java
+++ b/cli/src/main/java/hudson/cli/CLI.java
@@ -24,54 +24,25 @@
package hudson.cli;
import hudson.cli.client.Messages;
-import hudson.remoting.Channel;
-import hudson.remoting.NamingThreadFactory;
-import hudson.remoting.PingThread;
-import hudson.remoting.Pipe;
-import hudson.remoting.RemoteInputStream;
-import hudson.remoting.RemoteOutputStream;
-import hudson.remoting.SocketChannelStream;
-import hudson.remoting.SocketOutputStream;
-import javax.crypto.SecretKey;
-import javax.crypto.spec.SecretKeySpec;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
-import java.io.BufferedInputStream;
-import java.io.BufferedOutputStream;
-import java.io.BufferedReader;
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.Closeable;
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
-import java.io.PrintStream;
-import java.io.StringReader;
-import java.net.HttpURLConnection;
-import java.net.InetSocketAddress;
-import java.net.Socket;
import java.net.URL;
import java.net.URLConnection;
import java.nio.charset.Charset;
import java.security.GeneralSecurityException;
import java.security.KeyPair;
-import java.security.PublicKey;
import java.security.SecureRandom;
-import java.security.Signature;
-import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Properties;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -81,240 +52,10 @@ import org.apache.commons.lang.StringUtils;
/**
* CLI entry point to Jenkins.
- *
- * @author Kohsuke Kawaguchi
*/
-public class CLI implements AutoCloseable {
- private final ExecutorService pool;
- private final Channel channel;
- private final CliEntryPoint entryPoint;
- private final boolean ownsPool;
- private final List closables = new ArrayList(); // stuff to close in the close method
- private final String httpsProxyTunnel;
- private final String authorization;
+public class CLI {
- /**
- * For tests only.
- * @deprecated Specific to {@link Mode#REMOTING}.
- */
- @Deprecated
- public CLI(URL jenkins) throws IOException, InterruptedException {
- this(jenkins,null);
- }
-
- /**
- * @deprecated
- * Use {@link CLIConnectionFactory} to create {@link CLI}
- */
- @Deprecated
- public CLI(URL jenkins, ExecutorService exec) throws IOException, InterruptedException {
- this(jenkins,exec,null);
- }
-
- /**
- * @deprecated
- * Use {@link CLIConnectionFactory} to create {@link CLI}
- */
- @Deprecated
- public CLI(URL jenkins, ExecutorService exec, String httpsProxyTunnel) throws IOException, InterruptedException {
- this(new CLIConnectionFactory().url(jenkins).executorService(exec).httpsProxyTunnel(httpsProxyTunnel));
- }
-
- /**
- * @deprecated Specific to {@link Mode#REMOTING}.
- */
- @Deprecated
- /*package*/ CLI(CLIConnectionFactory factory) throws IOException, InterruptedException {
- URL jenkins = factory.jenkins;
- this.httpsProxyTunnel = factory.httpsProxyTunnel;
- this.authorization = factory.authorization;
- ExecutorService exec = factory.exec;
-
- ownsPool = exec==null;
- pool = exec!=null ? exec : Executors.newCachedThreadPool(new NamingThreadFactory(Executors.defaultThreadFactory(), "CLI.pool"));
-
- Channel _channel;
- try {
- _channel = connectViaCliPort(jenkins, getCliTcpPort(jenkins));
- } catch (IOException e) {
- LOGGER.log(Level.FINE, "Failed to connect via CLI port. Falling back to HTTP", e);
- try {
- _channel = connectViaHttp(jenkins);
- } catch (IOException e2) {
- e.addSuppressed(e2);
- throw e;
- }
- }
- this.channel = _channel;
-
- // execute the command
- entryPoint = (CliEntryPoint)_channel.waitForRemoteProperty(CliEntryPoint.class.getName());
-
- if(entryPoint.protocolVersion()!=CliEntryPoint.VERSION)
- throw new IOException(Messages.CLI_VersionMismatch());
- }
-
- /**
- * @deprecated Specific to {@link Mode#REMOTING}.
- */
- @Deprecated
- private Channel connectViaHttp(URL url) throws IOException {
- LOGGER.log(FINE, "Trying to connect to {0} via Remoting over HTTP", url);
-
- FullDuplexHttpStream con = new FullDuplexHttpStream(url, "cli?remoting=true", authorization);
- Channel ch = new Channel("Chunked connection to " + url,
- pool,con.getInputStream(),con.getOutputStream());
- final long interval = 15*1000;
- final long timeout = (interval * 3) / 4;
- new PingThread(ch,timeout,interval) {
- protected void onDead() {
- // noop. the point of ping is to keep the connection alive
- // as most HTTP servers have a rather short read time out
- }
- }.start();
- return ch;
- }
-
- /**
- * @deprecated Specific to {@link Mode#REMOTING}.
- */
- @Deprecated
- private Channel connectViaCliPort(URL jenkins, CliPort clip) throws IOException {
- LOGGER.log(FINE, "Trying to connect directly via Remoting over TCP/IP to {0}", clip.endpoint);
-
- if (authorization != null) {
- LOGGER.warning("-auth ignored when using JNLP agent port");
- }
-
- final Socket s = new Socket();
- // this prevents a connection from silently terminated by the router in between or the other peer
- // and that goes without unnoticed. However, the time out is often very long (for example 2 hours
- // by default in Linux) that this alone is enough to prevent that.
- s.setKeepAlive(true);
- // we take care of buffering on our own
- s.setTcpNoDelay(true);
- OutputStream out;
-
- if (httpsProxyTunnel!=null) {
- String[] tokens = httpsProxyTunnel.split(":");
- LOGGER.log(Level.FINE, "Using HTTP proxy {0}:{1} to connect to CLI port", new Object[]{tokens[0], tokens[1]});
- s.connect(new InetSocketAddress(tokens[0], Integer.parseInt(tokens[1])));
- PrintStream o = new PrintStream(s.getOutputStream());
- o.print("CONNECT " + clip.endpoint.getHostString() + ":" + clip.endpoint.getPort() + " HTTP/1.0\r\n\r\n");
-
- // read the response from the proxy
- ByteArrayOutputStream rsp = new ByteArrayOutputStream();
- while (!rsp.toString("ISO-8859-1").endsWith("\r\n\r\n")) {
- int ch = s.getInputStream().read();
- if (ch<0) throw new IOException("Failed to read the HTTP proxy response: "+rsp);
- rsp.write(ch);
- }
- String head = new BufferedReader(new StringReader(rsp.toString("ISO-8859-1"))).readLine();
-
- if (head == null) {
- throw new IOException("Unexpected empty response");
- }
- if (!(head.startsWith("HTTP/1.0 200 ") || head.startsWith("HTTP/1.1 200 "))) {
- s.close();
- LOGGER.log(Level.SEVERE, "Failed to tunnel the CLI port through the HTTP proxy. Falling back to HTTP.");
- throw new IOException("Failed to establish a connection through HTTP proxy: " + rsp);
- }
-
- // HTTP proxies (at least the one I tried --- squid) doesn't seem to do half-close very well.
- // So instead of relying on it, we'll just send the close command and then let the server
- // cut their side, then close the socket after the join.
- out = new SocketOutputStream(s) {
- @Override
- public void close() throws IOException {
- // ignore
- }
- };
- } else {
- s.connect(clip.endpoint,3000);
- out = SocketChannelStream.out(s);
- }
-
- closables.add(new Closeable() {
- public void close() throws IOException {
- s.close();
- }
- });
-
- Connection c = new Connection(SocketChannelStream.in(s),out);
-
- switch (clip.version) {
- case 1:
- DataOutputStream dos = new DataOutputStream(s.getOutputStream());
- dos.writeUTF("Protocol:CLI-connect");
- // we aren't checking greeting from the server here because I'm too lazy. It gets ignored by Channel constructor.
- break;
- case 2:
- DataInputStream dis = new DataInputStream(s.getInputStream());
- dos = new DataOutputStream(s.getOutputStream());
- dos.writeUTF("Protocol:CLI2-connect");
- String greeting = dis.readUTF();
- if (!greeting.equals("Welcome"))
- throw new IOException("Handshaking failed: "+greeting);
- try {
- byte[] secret = c.diffieHellman(false).generateSecret();
- SecretKey sessionKey = new SecretKeySpec(Connection.fold(secret,128/8),"AES");
- c = c.encryptConnection(sessionKey,"AES/CFB8/NoPadding");
-
- // validate the instance identity, so that we can be sure that we are talking to the same server
- // and there's no one in the middle.
- byte[] signature = c.readByteArray();
-
- if (clip.identity!=null) {
- Signature verifier = Signature.getInstance("SHA1withRSA");
- verifier.initVerify(clip.getIdentity());
- verifier.update(secret);
- if (!verifier.verify(signature))
- throw new IOException("Server identity signature validation failed.");
- }
-
- } catch (GeneralSecurityException e) {
- throw (IOException)new IOException("Failed to negotiate transport security").initCause(e);
- }
- }
-
- return new Channel("CLI connection to "+jenkins, pool,
- new BufferedInputStream(c.in), new BufferedOutputStream(c.out));
- }
-
- /**
- * If the server advertises CLI endpoint, returns its location.
- * @deprecated Specific to {@link Mode#REMOTING}.
- */
- @Deprecated
- protected CliPort getCliTcpPort(URL url) throws IOException {
- if (url.getHost()==null || url.getHost().length()==0) {
- throw new IOException("Invalid URL: "+url);
- }
- URLConnection head = url.openConnection();
- try {
- head.connect();
- } catch (IOException e) {
- throw (IOException)new IOException("Failed to connect to "+url).initCause(e);
- }
-
- String h = head.getHeaderField("X-Jenkins-CLI-Host");
- if (h==null) h = head.getURL().getHost();
- String p1 = head.getHeaderField("X-Jenkins-CLI-Port");
- if (p1==null) p1 = head.getHeaderField("X-Hudson-CLI-Port"); // backward compatibility
- String p2 = head.getHeaderField("X-Jenkins-CLI2-Port");
-
- String identity = head.getHeaderField("X-Instance-Identity");
-
- flushURLConnection(head);
- if (p1==null && p2==null) {
- verifyJenkinsConnection(head);
-
- throw new IOException("No X-Jenkins-CLI2-Port among " + head.getHeaderFields().keySet());
- }
-
- if (p2!=null) return new CliPort(new InetSocketAddress(h,Integer.parseInt(p2)),identity,2);
- else return new CliPort(new InetSocketAddress(h,Integer.parseInt(p1)),identity,1);
- }
+ private CLI() {}
/**
* Make sure the connection is open against Jenkins server.
@@ -337,91 +78,6 @@ public class CLI implements AutoCloseable {
}
}
- /**
- * Flush the supplied {@link URLConnection} input and close the
- * connection nicely.
- * @param conn the connection to flush/close
- */
- private void flushURLConnection(URLConnection conn) {
- byte[] buf = new byte[1024];
- try {
- InputStream is = conn.getInputStream();
- while (is.read(buf) >= 0) {
- // Ignore
- }
- is.close();
- } catch (IOException e) {
- try {
- InputStream es = ((HttpURLConnection)conn).getErrorStream();
- if (es!=null) {
- while (es.read(buf) >= 0) {
- // Ignore
- }
- es.close();
- }
- } catch (IOException ex) {
- // Ignore
- }
- }
- }
-
- /**
- * Shuts down the channel and closes the underlying connection.
- */
- public void close() throws IOException, InterruptedException {
- channel.close();
- channel.join();
- if(ownsPool)
- pool.shutdown();
- for (Closeable c : closables)
- c.close();
- }
-
- public int execute(List args, InputStream stdin, OutputStream stdout, OutputStream stderr) {
- return entryPoint.main(args, Locale.getDefault(),
- new RemoteInputStream(stdin),
- new RemoteOutputStream(stdout),
- new RemoteOutputStream(stderr));
- }
-
- public int execute(List args) {
- return execute(args, System.in, System.out, System.err);
- }
-
- public int execute(String... args) {
- return execute(Arrays.asList(args));
- }
-
- /**
- * Returns true if the named command exists.
- */
- public boolean hasCommand(String name) {
- return entryPoint.hasCommand(name);
- }
-
- /**
- * Accesses the underlying communication channel.
- * @since 1.419
- */
- public Channel getChannel() {
- return channel;
- }
-
- /**
- * Attempts to lift the security restriction on the underlying channel.
- * This requires the administer privilege on the server.
- *
- * @throws SecurityException
- * If we fail to upgrade the connection.
- */
- public void upgrade() {
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- if (execute(Arrays.asList("groovy", "="),
- new ByteArrayInputStream("hudson.remoting.Channel.current().setRestricted(false)".getBytes()),
- out,out)!=0)
- throw new SecurityException(out.toString()); // failed to upgrade
- }
-
public static void main(final String[] _args) throws Exception {
try {
System.exit(_main(_args));
@@ -435,12 +91,10 @@ public class CLI implements AutoCloseable {
}
}
- private enum Mode {HTTP, SSH, REMOTING}
+ private enum Mode {HTTP, SSH}
public static int _main(String[] _args) throws Exception {
List args = Arrays.asList(_args);
PrivateKeyProvider provider = new PrivateKeyProvider();
- boolean sshAuthRequestedExplicitly = false;
- String httpProxy=null;
String url = System.getenv("JENKINS_URL");
@@ -484,13 +138,8 @@ public class CLI implements AutoCloseable {
continue;
}
if (head.equals("-remoting")) {
- if (mode != null) {
- printUsage("-remoting clashes with previously defined mode " + mode);
- return -1;
- }
- mode = Mode.REMOTING;
- args = args.subList(1, args.size());
- continue;
+ printUsage("-remoting mode is no longer supported");
+ return -1;
}
if(head.equals("-s") && args.size()>=2) {
url = args.get(1);
@@ -526,7 +175,6 @@ public class CLI implements AutoCloseable {
provider.readFrom(f);
args = args.subList(2,args.size());
- sshAuthRequestedExplicitly = true;
continue;
}
if (head.equals("-strictHostKey")) {
@@ -544,11 +192,6 @@ public class CLI implements AutoCloseable {
args = args.subList(2, args.size());
continue;
}
- if(head.equals("-p") && args.size()>=2) {
- httpProxy = args.get(1);
- args = args.subList(2,args.size());
- continue;
- }
if (head.equals("-logger") && args.size() >= 2) {
Level level = parse(args.get(1));
for (Handler h : Logger.getLogger("").getHandlers()) {
@@ -616,7 +259,7 @@ public class CLI implements AutoCloseable {
LOGGER.warning("Warning: -user ignored unless using -ssh");
}
- CLIConnectionFactory factory = new CLIConnectionFactory().url(url).httpsProxyTunnel(httpProxy);
+ CLIConnectionFactory factory = new CLIConnectionFactory();
String userInfo = new URL(url).getUserInfo();
if (userInfo != null) {
factory = factory.basicAuth(userInfo);
@@ -628,39 +271,7 @@ public class CLI implements AutoCloseable {
return plainHttpConnection(url, args, factory);
}
- CLI cli = factory.connect();
- try {
- if (provider.hasKeys()) {
- try {
- // TODO: server verification
- cli.authenticate(provider.getKeys());
- } catch (IllegalStateException e) {
- if (sshAuthRequestedExplicitly) {
- LOGGER.warning("The server doesn't support public key authentication");
- return -1;
- }
- } catch (UnsupportedOperationException e) {
- if (sshAuthRequestedExplicitly) {
- LOGGER.warning("The server doesn't support public key authentication");
- return -1;
- }
- } catch (GeneralSecurityException e) {
- if (sshAuthRequestedExplicitly) {
- LOGGER.log(WARNING, null, e);
- return -1;
- }
- LOGGER.warning("Failed to authenticate with your SSH keys. Proceeding as anonymous");
- LOGGER.log(FINE, null, e);
- }
- }
-
- // execute the command
- // Arrays.asList is not serializable --- see 6835580
- args = new ArrayList(args);
- return cli.execute(args, System.in, System.out, System.err);
- } finally {
- cli.close();
- }
+ throw new AssertionError();
}
private static int plainHttpConnection(String url, List args, CLIConnectionFactory factory) throws IOException, InterruptedException {
@@ -784,47 +395,6 @@ public class CLI implements AutoCloseable {
return loadKey(pemString, null);
}
- /**
- * Authenticate ourselves against the server.
- *
- * @return
- * identity of the server represented as a public key.
- * @deprecated Specific to {@link Mode#REMOTING}.
- */
- @Deprecated
- public PublicKey authenticate(Iterable privateKeys) throws IOException, GeneralSecurityException {
- Pipe c2s = Pipe.createLocalToRemote();
- Pipe s2c = Pipe.createRemoteToLocal();
- entryPoint.authenticate("ssh",c2s, s2c);
- Connection c = new Connection(s2c.getIn(), c2s.getOut());
-
- try {
- byte[] sharedSecret = c.diffieHellman(false).generateSecret();
- PublicKey serverIdentity = c.verifyIdentity(sharedSecret);
-
- // try all the public keys
- for (KeyPair key : privateKeys) {
- c.proveIdentity(sharedSecret,key);
- if (c.readBoolean())
- return serverIdentity; // succeeded
- }
- if (privateKeys.iterator().hasNext())
- throw new GeneralSecurityException("Authentication failed. No private key accepted.");
- else
- throw new GeneralSecurityException("No private key is available for use in authentication");
- } finally {
- c.close();
- }
- }
-
- /**
- * @deprecated Specific to {@link Mode#REMOTING}.
- */
- @Deprecated
- public PublicKey authenticate(KeyPair key) throws IOException, GeneralSecurityException {
- return authenticate(Collections.singleton(key));
- }
-
/** For access from {@code HelpCommand}. */
static String usage() {
return Messages.CLI_Usage();
diff --git a/cli/src/main/java/hudson/cli/CLIConnectionFactory.java b/cli/src/main/java/hudson/cli/CLIConnectionFactory.java
index 894e4c0fdac60ff446e3a67ecf68e44192d93f97..288696b0da0828be52b2bd7c8cafd62e90719914 100644
--- a/cli/src/main/java/hudson/cli/CLIConnectionFactory.java
+++ b/cli/src/main/java/hudson/cli/CLIConnectionFactory.java
@@ -2,10 +2,6 @@ package hudson.cli;
import org.apache.commons.codec.binary.Base64;
-import java.io.IOException;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.util.concurrent.ExecutorService;
/**
* Fluent-API to instantiate {@link CLI}.
@@ -13,41 +9,8 @@ import java.util.concurrent.ExecutorService;
* @author Kohsuke Kawaguchi
*/
public class CLIConnectionFactory {
- URL jenkins;
- ExecutorService exec;
- String httpsProxyTunnel;
String authorization;
- /**
- * Top URL of the Jenkins to connect to.
- */
- public CLIConnectionFactory url(URL jenkins) {
- this.jenkins = jenkins;
- return this;
- }
-
- public CLIConnectionFactory url(String jenkins) throws MalformedURLException {
- return url(new URL(jenkins));
- }
-
- /**
- * This {@link ExecutorService} is used to execute closures received from the server.
- * Used only in Remoting mode.
- */
- public CLIConnectionFactory executorService(ExecutorService es) {
- this.exec = es;
- return this;
- }
-
- /**
- * Configures the HTTP proxy that we use for making a plain TCP/IP connection.
- * "host:port" that points to an HTTP proxy or null.
- */
- public CLIConnectionFactory httpsProxyTunnel(String value) {
- this.httpsProxyTunnel = value;
- return this;
- }
-
/**
* For CLI connection that goes through HTTP, sometimes you need
* to pass in the custom authentication header (before Jenkins even get to authenticate
@@ -74,11 +37,4 @@ public class CLIConnectionFactory {
return authorization("Basic " + new String(Base64.encodeBase64((userInfo).getBytes())));
}
- /**
- * @deprecated Specific to Remoting-based protocol.
- */
- @Deprecated
- public CLI connect() throws IOException, InterruptedException {
- return new CLI(this);
- }
}
diff --git a/cli/src/main/java/hudson/cli/CliEntryPoint.java b/cli/src/main/java/hudson/cli/CliEntryPoint.java
deleted file mode 100644
index fe1f6c835097888be71632babbe31f1b6530fab5..0000000000000000000000000000000000000000
--- a/cli/src/main/java/hudson/cli/CliEntryPoint.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * The MIT License
- *
- * Copyright (c) 2004-2009, Sun Microsystems, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-package hudson.cli;
-
-import hudson.remoting.Pipe;
-
-import java.io.OutputStream;
-import java.io.InputStream;
-import java.util.List;
-import java.util.Locale;
-
-/**
- * Remotable interface for CLI entry point on the server side.
- *
- * @author Kohsuke Kawaguchi
- * @deprecated Specific to Remoting-based protocol.
- */
-@Deprecated
-public interface CliEntryPoint {
- /**
- * Just like the static main method.
- *
- * @param locale
- * Locale of this client.
- */
- int main(List args, Locale locale, InputStream stdin, OutputStream stdout, OutputStream stderr);
-
- /**
- * Does the named command exist?
- */
- boolean hasCommand(String name);
-
- /**
- * Returns {@link #VERSION}, so that the client and the server can detect version incompatibility
- * gracefully.
- */
- int protocolVersion();
-
- /**
- * Initiates authentication out of band.
- *
- * This method starts two-way byte channel that allows the client and the server to perform authentication.
- * The current supported implementation is based on SSH public key authentication that mutually authenticates
- * clients and servers.
- *
- * @param protocol
- * Currently only "ssh" is supported.
- * @throws UnsupportedOperationException
- * If the specified protocol is not supported by the server.
- */
- void authenticate(String protocol, Pipe c2s, Pipe s2c);
-
- int VERSION = 1;
-}
diff --git a/cli/src/main/java/hudson/cli/CliPort.java b/cli/src/main/java/hudson/cli/CliPort.java
deleted file mode 100644
index 56165e766ba6186489d4e3017b0a7a35510358ab..0000000000000000000000000000000000000000
--- a/cli/src/main/java/hudson/cli/CliPort.java
+++ /dev/null
@@ -1,44 +0,0 @@
-package hudson.cli;
-
-import org.apache.commons.codec.binary.Base64;
-
-import java.net.InetSocketAddress;
-import java.security.GeneralSecurityException;
-import java.security.KeyFactory;
-import java.security.PublicKey;
-import java.security.spec.X509EncodedKeySpec;
-
- /**
- * @deprecated Specific to Remoting mode.
- */
-public final class CliPort {
- /**
- * The TCP endpoint to talk to.
- */
- final InetSocketAddress endpoint;
-
- /**
- * CLI protocol version. 1 and 2 are currently defined.
- */
- final int version;
-
- /**
- * Server instance identity. Can be null.
- */
- final String identity;
-
- public CliPort(InetSocketAddress endpoint, String identity, int version) {
- this.endpoint = endpoint;
- this.identity = identity;
- this.version = version;
- }
-
- /**
- * Gets the public part of the RSA key that represents the server identity.
- */
- public PublicKey getIdentity() throws GeneralSecurityException {
- if (identity==null) return null;
- byte[] image = Base64.decodeBase64(identity);
- return KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(image));
- }
-}
diff --git a/cli/src/main/java/hudson/cli/Connection.java b/cli/src/main/java/hudson/cli/Connection.java
index eacc567a7e5d822afc9e4d1b20afc5473cbb0b3b..1961447778d04ab829c9b550305ac016309bcd35 100644
--- a/cli/src/main/java/hudson/cli/Connection.java
+++ b/cli/src/main/java/hudson/cli/Connection.java
@@ -58,8 +58,9 @@ import java.security.spec.X509EncodedKeySpec;
import org.jenkinsci.remoting.util.AnonymousClassWarnings;
/**
- * Used by Jenkins core only in deprecated Remoting-based CLI.
+ * @deprecated No longer used.
*/
+@Deprecated
public class Connection {
public final InputStream in;
public final OutputStream out;
diff --git a/cli/src/main/java/hudson/cli/FullDuplexHttpStream.java b/cli/src/main/java/hudson/cli/FullDuplexHttpStream.java
index 9b18142b7824257af32e510e4eb99d5cc677cf69..723e97f16c26805a3550a0d9b8fcb17476396fee 100644
--- a/cli/src/main/java/hudson/cli/FullDuplexHttpStream.java
+++ b/cli/src/main/java/hudson/cli/FullDuplexHttpStream.java
@@ -9,8 +9,6 @@ import java.util.UUID;
import java.util.logging.Level;
import java.util.logging.Logger;
-import org.apache.commons.codec.binary.Base64;
-
/**
* Creates a capacity-unlimited bi-directional {@link InputStream}/{@link OutputStream} pair over
* HTTP, which is a request/response protocol.
@@ -19,10 +17,6 @@ import org.apache.commons.codec.binary.Base64;
*/
public class FullDuplexHttpStream {
private final URL base;
- /**
- * Authorization header value needed to get through the HTTP layer.
- */
- private final String authorization;
private final OutputStream output;
private final InputStream input;
@@ -43,28 +37,6 @@ public class FullDuplexHttpStream {
return output;
}
- @Deprecated
- public FullDuplexHttpStream(URL target) throws IOException {
- this(target,basicAuth(target.getUserInfo()));
- }
-
- private static String basicAuth(String userInfo) {
- if (userInfo != null)
- return "Basic "+new String(Base64.encodeBase64(userInfo.getBytes()));
- return null;
- }
-
- /**
- * @param target something like {@code http://jenkins/cli?remoting=true}
- * which we then need to split into {@code http://jenkins/} + {@code cli?remoting=true}
- * in order to construct a crumb issuer request
- * @deprecated use {@link #FullDuplexHttpStream(URL, String, String)} instead
- */
- @Deprecated
- public FullDuplexHttpStream(URL target, String authorization) throws IOException {
- this(new URL(target.toString().replaceFirst("/cli.*$", "/")), target.toString().replaceFirst("^.+/(cli.*)$", "$1"), authorization);
- }
-
/**
* @param base the base URL of Jenkins
* @param relativeTarget
@@ -81,7 +53,6 @@ public class FullDuplexHttpStream {
}
this.base = tryToResolveRedirects(base, authorization);
- this.authorization = authorization;
URL target = new URL(this.base, relativeTarget);
diff --git a/cli/src/main/java/hudson/cli/PrivateKeyProvider.java b/cli/src/main/java/hudson/cli/PrivateKeyProvider.java
index 9f87dd4a7b38a174229ccfc02b04779b51002951..bbf7873e2917f1b4edd456c8d53a23d48bf74459 100644
--- a/cli/src/main/java/hudson/cli/PrivateKeyProvider.java
+++ b/cli/src/main/java/hudson/cli/PrivateKeyProvider.java
@@ -24,26 +24,25 @@
package hudson.cli;
import static java.util.logging.Level.FINE;
+import static java.nio.charset.StandardCharsets.UTF_8;
import java.io.Console;
import java.io.DataInputStream;
+import java.io.ByteArrayInputStream;
import java.io.File;
-import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.InvalidPathException;
import java.security.GeneralSecurityException;
-import java.security.KeyFactory;
import java.security.KeyPair;
-import java.security.spec.DSAPrivateKeySpec;
-import java.security.spec.DSAPublicKeySpec;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.logging.Logger;
-import com.trilead.ssh2.crypto.PEMDecoder;
+import org.apache.sshd.common.config.keys.FilePasswordProvider;
+import org.apache.sshd.common.util.security.SecurityUtils;
/**
* Read DSA or RSA key from file(s) asking for password interactively.
@@ -141,22 +140,9 @@ public class PrivateKeyProvider {
}
public static KeyPair loadKey(String pemString, String passwd) throws IOException, GeneralSecurityException {
- Object key = PEMDecoder.decode(pemString.toCharArray(), passwd);
- if (key instanceof com.trilead.ssh2.signature.RSAPrivateKey) {
- com.trilead.ssh2.signature.RSAPrivateKey x = (com.trilead.ssh2.signature.RSAPrivateKey)key;
-
- return x.toJCEKeyPair();
- }
- if (key instanceof com.trilead.ssh2.signature.DSAPrivateKey) {
- com.trilead.ssh2.signature.DSAPrivateKey x = (com.trilead.ssh2.signature.DSAPrivateKey)key;
- KeyFactory kf = KeyFactory.getInstance("DSA");
-
- return new KeyPair(
- kf.generatePublic(new DSAPublicKeySpec(x.getY(), x.getP(), x.getQ(), x.getG())),
- kf.generatePrivate(new DSAPrivateKeySpec(x.getX(), x.getP(), x.getQ(), x.getG())));
- }
-
- throw new UnsupportedOperationException("Unrecognizable key format: " + key);
+ return SecurityUtils.loadKeyPairIdentity("key",
+ new ByteArrayInputStream(pemString.getBytes(UTF_8)),
+ FilePasswordProvider.of(passwd));
}
private static final Logger LOGGER = Logger.getLogger(PrivateKeyProvider.class.getName());
diff --git a/cli/src/main/resources/hudson/cli/client/Messages.properties b/cli/src/main/resources/hudson/cli/client/Messages.properties
index 2e7fde44cb075a87813b4cced7eb48f2952c85cd..c789036505014e64496809f9f56405146ea84be7 100644
--- a/cli/src/main/resources/hudson/cli/client/Messages.properties
+++ b/cli/src/main/resources/hudson/cli/client/Messages.properties
@@ -2,24 +2,21 @@ CLI.Usage=Jenkins CLI\n\
Usage: java -jar jenkins-cli.jar [-s URL] command [opts...] args...\n\
Options:\n\
\ -s URL : the server URL (defaults to the JENKINS_URL env var)\n\
- \ -http : use a plain CLI protocol over HTTP(S) (the default; mutually exclusive with -ssh and -remoting)\n\
+ \ -http : use a plain CLI protocol over HTTP(S) (the default; mutually exclusive with -ssh)\n\
\ -ssh : use SSH protocol (requires -user; SSH port must be open on server, and user must have registered a public key)\n\
- \ -remoting : use deprecated Remoting channel protocol (if enabled on server; for compatibility with legacy commands or command modes only)\n\
- \ -i KEY : SSH private key file used for authentication (for use with -ssh or -remoting)\n\
- \ -p HOST:PORT : HTTP proxy host and port for HTTPS proxy tunneling. See https://jenkins.io/redirect/cli-https-proxy-tunnel\n\
+ \ -i KEY : SSH private key file used for authentication (for use with -ssh)\n\
\ -noCertificateCheck : bypass HTTPS certificate check entirely. Use with caution\n\
- \ -noKeyAuth : don't try to load the SSH authentication private key. Conflicts with -i\n\
+ \ -noKeyAuth : don''t try to load the SSH authentication private key. Conflicts with -i\n\
\ -user : specify user (for use with -ssh)\n\
\ -strictHostKey : request strict host key checking (for use with -ssh)\n\
\ -logger FINE : enable detailed logging from the client\n\
\ -auth [ USER:SECRET | @FILE ] : specify username and either password or API token (or load from them both from a file);\n\
- \ for use with -http, or -remoting but only when the JNLP agent port is disabled.\n\
- \ Passing crendentials by a file is recommended.\n\
+ \ for use with -http.\n\
+ \ Passing credentials by file is recommended.\n\
\ See https://jenkins.io/redirect/cli-http-connection-mode for more info and options.\n\
\n\
- The available commands depend on the server. Run the 'help' command to \
+ The available commands depend on the server. Run the ''help'' command to \
see the list.
CLI.NoURL=Neither -s nor the JENKINS_URL env var is specified.
-CLI.VersionMismatch=Version mismatch. This CLI cannot work with this Jenkins server.
CLI.NoSuchFileExists=No such file exists: {0}
CLI.BadAuth=The JENKINS_USER_ID and JENKINS_API_TOKEN env vars should be both set or left empty.
diff --git a/cli/src/main/resources/hudson/cli/client/Messages_zh_CN.properties b/cli/src/main/resources/hudson/cli/client/Messages_zh_CN.properties
deleted file mode 100644
index 16fa41c48c9a4aad3d63e9f40e2d017b3bd9fb77..0000000000000000000000000000000000000000
--- a/cli/src/main/resources/hudson/cli/client/Messages_zh_CN.properties
+++ /dev/null
@@ -1,44 +0,0 @@
-# The MIT License
-#
-# Copyright (c) 2013, Sun Microsystems, Inc., Kohsuke Kawaguchi, Pei-Tang Huang,
-# Chunghwa Telecom Co., Ltd., and a number of other of contributers
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-
-CLI.Usage=Jenkins CLI\n\
- \u7528\u6cd5: java -jar jenkins-cli.jar [-s url] \u547d\u4ee4 [\u9009\u9879...] \u53c2\u6570...\n\
- \u9009\u9879:\n\
- -s URL : \u670d\u52a1\u5668url \uff08\u9ed8\u8ba4\u662fjenkins_url\u73af\u5883\u53d8\u91cf\uff09\n\
- -http : \u5728http%28s%29\u4e0a\u4f7f\u7528\u539f\u59cb\u7684cli\u534f\u8bae\uff08\u9ed8\u8ba4\u503c%3b \u4e0e -ssh \u548c -remoting \u4e92\u65a5\uff09\n\
- -ssh : \u4f7f\u7528ssh\u534f\u8bae\uff08\u9700\u8981 -user%3b \u670d\u52a1\u5668\u7684ssh\u7aef\u53e3\u5fc5\u987b\u6253\u5f00\uff0c\u4e14\u7528\u6237\u5fc5\u987b\u5df2\u6ce8\u518c\u516c\u94a5\u3002\uff09\n\
- -remoting : \u4f7f\u7528\u4e0d\u63a8\u8350\u7684\u8fdc\u7a0b\u4fe1\u9053\u534f\u8bae \uff08\u5982\u679c\u670d\u52a1\u5668\u4e0a\u662f\u6253\u5f00\u7684\uff1b\u4ec5\u7528\u4e8e\u517c\u5bb9\u9057\u7559\u547d\u4ee4\u6216\u547d\u4ee4\u6a21\u5f0f\uff09\n\
- -i KEY : \u7528\u4e8e\u8ba4\u8bc1\u7684ssh\u79c1\u94a5\u6587\u4ef6\uff08\u4e0e -ssh \u6216 -remoting \u4e00\u8d77\u4f7f\u7528\uff09\n\
- -p HOST:PORT : \u7528\u6237https\u4ee3\u7406\u96a7\u9053\u7684http\u4ee3\u7406\u4e3b\u673a\u548c\u7aef\u53e3\u3002\u53c2\u89c1 https://jenkins.io/redirect/cli-https-proxy-tunnel\n\
- -noCertificateCheck : \u5b8c\u5168\u5ffd\u7565https\u8bc1\u4e66\u8ba4\u8bc1\u3002\u8c28\u614e\u4f7f\u7528\n\
- -noKeyAuth : \u65e0\u9700\u5c1d\u8bd5\u52a0\u8f7dssh\u8ba4\u8bc1\u79c1\u94a5\u3002\u4e0e -i \u76f8\u53cd\n\
- -user : \u6307\u5b9a\u7528\u6237\uff08\u4e0e -ssh \u4e00\u8d77\u4f7f\u7528\uff09\n\
- -strictHostKey : \u8981\u6c42\u9a8c\u8bc1\u4e3b\u673akey\u68c0\u67e5\uff08\u4e0e -ssh \u4e00\u8d77\u4f7f\u7528\uff09\n\
- -logger FINE : \u5141\u8bb8\u5ba2\u6237\u7aef\u8be6\u7ec6\u65e5\u5fd7\u8bb0\u5f55\n\
- -auth [ USER:SECRET | @FILE ] : \u6307\u5b9a\u7528\u6237\u540d\u4e0e\u5bc6\u7801\u6216\u7528\u6237\u540d\u4e0eapi token\uff08\u6216\u8005\u4ece\u6587\u4ef6\u52a0\u8f7d\uff09\uff1b\n\
- \u4e0e -http \u4e00\u8d77\u4f7f\u7528\uff0c\u6216\u8005\u53ea\u5728jnlp\u4ee3\u7406\u7aef\u53e3\u7981\u7528\u65f6\u4e0e -remoting \u4e00\u8d77\u4f7f\u7528\n\
- \n\
- \u53ef\u7528\u7684\u547d\u4ee4\u53d6\u51b3\u4e8e\u670d\u52a1\u5668\u3002\u6267\u884c 'help' \u547d\u4ee4\u53ef\u4ee5\u67e5\u770b\u5b8c\u6574\u6e05\u5355\u3002
-CLI.NoURL=\u6c92\u6709\u6307\u5b9a -s \u53c2\u6570\u6216\u8005 jenkins_url \u73af\u5883\u53d8\u91cf\u3002
-CLI.VersionMismatch=\u7248\u672c\u4e0d\u5339\u914d\u3002cli \u65e0\u6cd5\u5728\u6b64 jenkins \u670d\u52a1\u5668\u4e0a\u8fd0\u884c\u3002
-CLI.NoSuchFileExists=\u6587\u4ef6\u4e0d\u5b58\u5728: {0}
diff --git a/cli/src/test/java/hudson/cli/ConnectionTest.java b/cli/src/test/java/hudson/cli/ConnectionTest.java
deleted file mode 100644
index f4cb0e8b1d595516130553bbe6568f8255324327..0000000000000000000000000000000000000000
--- a/cli/src/test/java/hudson/cli/ConnectionTest.java
+++ /dev/null
@@ -1,87 +0,0 @@
-package hudson.cli;
-
-import static org.junit.Assert.*;
-
-import hudson.remoting.FastPipedInputStream;
-import hudson.remoting.FastPipedOutputStream;
-import org.codehaus.groovy.runtime.Security218;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
-
-import javax.crypto.SecretKey;
-import javax.crypto.spec.SecretKeySpec;
-import java.io.IOException;
-
-/**
- * @author Kohsuke Kawaguchi
- */
-public class ConnectionTest {
-
- Throwable e;
- private Connection c1;
- private Connection c2;
-
- @Before
- public void setUp() throws IOException {
- FastPipedInputStream i = new FastPipedInputStream();
- FastPipedInputStream j = new FastPipedInputStream();
-
- c1 = new Connection(i,new FastPipedOutputStream(j));
- c2 = new Connection(j,new FastPipedOutputStream(i));
- }
-
- @Test
- public void testEncrypt() throws Throwable {
- final SecretKey sessionKey = new SecretKeySpec(new byte[16],"AES");
-
- Thread t1 = new Thread() {
- @Override
- public void run() {
- try {
- c1.encryptConnection(sessionKey,"AES/CFB8/NoPadding").writeUTF("Hello");
- } catch (Throwable x) {
- e = x;
- }
- }
- };
- t1.start();
-
- Thread t2 = new Thread() {
- @Override
- public void run() {
- try {
- String data = c2.encryptConnection(sessionKey,"AES/CFB8/NoPadding").readUTF();
- assertEquals("Hello", data);
- } catch (Throwable x) {
- e = x;
- }
- }
- };
- t2.start();
-
- t1.join(9999);
- t2.join(9999);
-
- if (e != null) {
- throw e;
- }
-
- if (t1.isAlive() || t2.isAlive()) {
- t1.interrupt();
- t2.interrupt();
- throw new Error("thread is still alive");
- }
- }
-
- @Test
- public void testSecurity218() throws Exception {
- c1.writeObject(new Security218());
- try {
- c2.readObject();
- fail();
- } catch (SecurityException e) {
- assertTrue(e.getMessage().contains(Security218.class.getName()));
- }
- }
-}
diff --git a/cli/src/test/java/hudson/cli/HexDumpTest.java b/cli/src/test/java/hudson/cli/HexDumpTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..9cd1c78995f5bc5405046faedb8a844e6870190c
--- /dev/null
+++ b/cli/src/test/java/hudson/cli/HexDumpTest.java
@@ -0,0 +1,37 @@
+package hudson.cli;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class HexDumpTest {
+
+ @Test
+ public void testToHex1() {
+ Assert.assertEquals("'fooBar'",
+ HexDump.toHex(new byte[] {'f', 'o', 'o', 'B', 'a', 'r'}));
+ Assert.assertEquals("0xc3",
+ HexDump.toHex(new byte[] {(byte)'Ã'}));
+ Assert.assertEquals("0xac '100'",
+ HexDump.toHex(new byte[] {(byte)'€', '1', '0', '0'}));
+ Assert.assertEquals("'1' 0xf7 '2'",
+ HexDump.toHex(new byte[] {'1', (byte)'÷', '2'}));
+ Assert.assertEquals("'foo' 0x0a\n'Bar'",
+ HexDump.toHex(new byte[] {'f', 'o', 'o', '\n', 'B', 'a', 'r'}));
+ }
+
+ @Test
+ public void testToHex2() {
+ Assert.assertEquals("'ooBa'",
+ HexDump.toHex(new byte[] {'f', 'o', 'o', 'B', 'a', 'r'}, 1, 4));
+ Assert.assertEquals("0xc3",
+ HexDump.toHex(new byte[] {(byte)'Ã'}, 0, 1));
+ Assert.assertEquals("0xac '10'",
+ HexDump.toHex(new byte[] {(byte)'€', '1', '0', '0'}, 0, 3));
+ Assert.assertEquals("0xf7 '2'",
+ HexDump.toHex(new byte[] {'1', (byte)'÷', '2'}, 1, 2));
+ Assert.assertEquals("'Bar'",
+ HexDump.toHex(new byte[] {'f', 'o', 'o', '\n', 'B', 'a', 'r'}, 4, 3));
+ Assert.assertEquals("",
+ HexDump.toHex(new byte[] {'f', 'o', 'o', 'B', 'a', 'r'}, 0, 0));
+ }
+}
diff --git a/cli/src/test/java/hudson/cli/PrivateKeyProviderTest.java b/cli/src/test/java/hudson/cli/PrivateKeyProviderTest.java
index a29af91e6eb818245140e987dda1c323786a3fd8..1bb49866ba6140ff1f8e27e905dfe4cd6e972862 100644
--- a/cli/src/test/java/hudson/cli/PrivateKeyProviderTest.java
+++ b/cli/src/test/java/hudson/cli/PrivateKeyProviderTest.java
@@ -1,134 +1,104 @@
-/*
- * The MIT License
- *
- * Copyright (c) 2014 Red Hat, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
package hudson.cli;
-import static org.mockito.Mockito.verify;
-import static org.powermock.api.mockito.PowerMockito.doReturn;
-import static org.powermock.api.mockito.PowerMockito.mock;
-import static org.powermock.api.mockito.PowerMockito.mockStatic;
-import static org.powermock.api.mockito.PowerMockito.whenNew;
+import org.junit.Test;
import java.io.File;
import java.io.IOException;
-import java.net.URISyntaxException;
-import java.net.URL;
+import java.lang.IllegalArgumentException;
import java.security.GeneralSecurityException;
-import java.security.Key;
import java.security.KeyPair;
-import java.util.Arrays;
+import java.security.NoSuchAlgorithmException;
-import org.hamcrest.Description;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentMatcher;
-import org.mockito.Mockito;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.powermock.modules.junit4.PowerMockRunner;
+import static org.junit.Assert.assertNotNull;
-@RunWith(PowerMockRunner.class)
-@PrepareForTest({CLI.class, CLIConnectionFactory.class}) // When mocking new operator caller has to be @PreparedForTest, not class itself
+/**
+keys were generated with ssh-keygen from OpenSSH_7.9p1, LibreSSL 2.7.3
+*/
public class PrivateKeyProviderTest {
+ /**
+ key command: ssh-keygen -f dsa -t dsa -b 1024 -m PEM
+ */
@Test
- public void specifyKeysExplicitly() throws Exception {
- final CLI cli = fakeCLI();
-
- final File dsaKey = keyFile(".ssh/id_dsa");
- final File rsaKey = keyFile(".ssh/id_rsa");
-
- run("-remoting", "-i", dsaKey.getAbsolutePath(), "-i", rsaKey.getAbsolutePath(), "-s", "http://example.com");
-
- verify(cli).authenticate(withKeyPairs(
- keyPair(dsaKey),
- keyPair(rsaKey)
- ));
+ public void loadKeyDSA() throws IOException, GeneralSecurityException {
+ File file = new File(this.getClass().getResource("dsa").getFile());
+ String password = null;
+ KeyPair keyPair = PrivateKeyProvider.loadKey(file, password);
+ assertNotNull(keyPair);
+ assertNotNull(keyPair.getPrivate());
+ assertNotNull(keyPair.getPublic());
}
+ /**
+ key command: ssh-keygen -f dsa-password -t dsa -b 1024 -m PEM -p password
+ */
@Test
- public void useDefaultKeyLocations() throws Exception {
- final CLI cli = fakeCLI();
-
- final File rsaKey = keyFile(".ssh/id_rsa");
- final File dsaKey = keyFile(".ssh/id_dsa");
-
- fakeHome();
- run("-remoting", "-s", "http://example.com");
-
- verify(cli).authenticate(withKeyPairs(
- keyPair(rsaKey),
- keyPair(dsaKey)
- ));
- }
-
- private CLI fakeCLI() throws Exception {
- final CLI cli = mock(CLI.class);
-
- final CLIConnectionFactory factory = mock(CLIConnectionFactory.class, Mockito.CALLS_REAL_METHODS);
- factory.jenkins = new URL("http://example.com");
- doReturn(cli).when(factory).connect();
-
- mockStatic(CLIConnectionFactory.class);
- whenNew(CLIConnectionFactory.class).withNoArguments().thenReturn(factory);
-
- return cli;
+ public void loadKeyDSAPassword() throws IOException, GeneralSecurityException {
+ File file = new File(this.getClass().getResource("dsa-password").getFile());
+ String password = "password";
+ KeyPair keyPair = PrivateKeyProvider.loadKey(file, password);
+ assertNotNull(keyPair);
+ assertNotNull(keyPair.getPrivate());
+ assertNotNull(keyPair.getPublic());
}
-
- private void fakeHome() throws URISyntaxException {
- final File home = new File(this.getClass().getResource(".ssh").toURI()).getParentFile();
- System.setProperty("user.home", home.getAbsolutePath());
+
+ /**
+ key command: ssh-keygen -f rsa -t rsa -b 1024 -m PEM
+ */
+ @Test
+ public void loadKeyRSA() throws IOException, GeneralSecurityException {
+ File file = new File(this.getClass().getResource("rsa").getFile());
+ String password = null;
+ KeyPair keyPair = PrivateKeyProvider.loadKey(file, password);
+ assertNotNull(keyPair);
+ assertNotNull(keyPair.getPrivate());
+ assertNotNull(keyPair.getPublic());
}
- private int run(String... args) throws Exception {
- return CLI._main(args);
+ /**
+ key command: ssh-keygen -f rsa-password -t rsa -b 1024 -m PEM -p password
+ */
+ @Test
+ public void loadKeyRSAPassword() throws IOException, GeneralSecurityException {
+ File file = new File(this.getClass().getResource("rsa-password").getFile());
+ String password = "password";
+ KeyPair keyPair = PrivateKeyProvider.loadKey(file, password);
+ assertNotNull(keyPair);
+ assertNotNull(keyPair.getPrivate());
+ assertNotNull(keyPair.getPublic());
}
-
- private File keyFile(String name) throws URISyntaxException {
- return new File(this.getClass().getResource(name).toURI());
+
+ /**
+ key command: ssh-keygen -f openssh -t rsa -b 1024
+ */
+ @Test
+ public void loadKeyOpenSSH() throws IOException, GeneralSecurityException {
+ File file = new File(this.getClass().getResource("openssh").getFile());
+ String password = null;
+ KeyPair keyPair = PrivateKeyProvider.loadKey(file, password);
+ assertNotNull(keyPair);
+ assertNotNull(keyPair.getPrivate());
+ assertNotNull(keyPair.getPublic());
}
-
- private KeyPair keyPair(File file) throws IOException, GeneralSecurityException {
- return PrivateKeyProvider.loadKey(file, null);
+
+ /**
+ key command: ssh-keygen -f openssh-unsupported -t rsa -b 1024 -p password
+ */
+ @Test(expected = NoSuchAlgorithmException.class)
+ public void loadKeyUnsupportedCipher() throws IOException, GeneralSecurityException {
+ File file = new File(this.getClass().getResource("openssh-unsuported").getFile());
+ String password = "password";
+ PrivateKeyProvider.loadKey(file, password);
}
- private Iterable withKeyPairs(final KeyPair... expected) {
- return Mockito.argThat(new ArgumentMatcher>() {
-
- @Override
- public boolean matches(Iterable actual) {
- int i = 0;
- for (KeyPair akp: actual) {
- if (!eq(expected[i].getPublic(), akp.getPublic())) return false;
- if (!eq(expected[i].getPrivate(), akp.getPrivate())) return false;
- i++;
- }
-
- return i == expected.length;
- }
-
- private boolean eq(final Key expected, final Key actual) {
- return Arrays.equals(expected.getEncoded(), actual.getEncoded());
- }
- });
+ /**
+ key command: ssh-keygen -f openssh -t rsa -b 1024
+ in this key we remove some lines to break the key.
+ */
+ @Test(expected = IllegalArgumentException.class)
+ public void loadKeyBroken() throws IOException, GeneralSecurityException {
+ File file = new File(this.getClass().getResource("openssh-broken").getFile());
+ String password = "password";
+ PrivateKeyProvider.loadKey(file, password);
}
}
diff --git a/cli/src/test/java/org/codehaus/groovy/runtime/Security218.java b/cli/src/test/java/org/codehaus/groovy/runtime/Security218.java
deleted file mode 100644
index cc3dfeef041c6ac07b91f80d3dc98a5f1530e4c7..0000000000000000000000000000000000000000
--- a/cli/src/test/java/org/codehaus/groovy/runtime/Security218.java
+++ /dev/null
@@ -1,11 +0,0 @@
-package org.codehaus.groovy.runtime;
-
-import java.io.Serializable;
-
-/**
- * Test payload in a prohibited package name.
- *
- * @author Kohsuke Kawaguchi
- */
-public class Security218 implements Serializable {
-}
diff --git a/cli/src/test/resources/hudson/cli/.ssh/id_dsa b/cli/src/test/resources/hudson/cli/.ssh/id_dsa
deleted file mode 100644
index be556daa6d02984101686a02939b6777c780db86..0000000000000000000000000000000000000000
--- a/cli/src/test/resources/hudson/cli/.ssh/id_dsa
+++ /dev/null
@@ -1,12 +0,0 @@
------BEGIN DSA PRIVATE KEY-----
-MIIBugIBAAKBgQCA9mMzB1O52hpObIyaJXgFJQUmc1HV0NEJXsFFGh8U2l0Tkgv4
-fp3MWadiAMmc5H1ot4KQLXl7SwU7dHCCFcGcfQiOjeD5rWeZuHoPAJSDMilcJGE3
-Xo2C+wlescTByEgRRA16vdSlNaDJXKVxq9Wr59G8P4JC6/5EvpeypgYdTQIVAMTf
-aC0O2EGLnJrNBsUdc1s+iUp9AoGAZA7pZYPMJHJWTanJb2DlWHn/QM63jfh38N6W
-ERzmQQks6QdS7UkFlg9cbVGUtn0Yz2SfX3VKiMXNMkAdGD8loBcJS5w6oMMU7rcj
-lldRQ63+fMgdVZYMF5bchC6RhQeGZQ8Imf2iFF28SsE4bi+K12HYgIO5bFxPFUTH
-WSWsMLcCgYBgHJ90ZLU400axB5P0qw/0s4arPD0g53Vzi/Y2h5TJr3KPF2sEIbAc
-2gpFEzUNY0hvH6REKJ+VPPUvlH6ieaXomW8pSGjv4SdxZhJRrDe+Ac/xQse1QdYx
-uWJzpVm3cIGfqLxmQnrklnutI/1F62VZQlq9vjiZL7ir/00vdUTYHwIUUkttGGgl
-a0rWLzPTPF4X4lZfFhk=
------END DSA PRIVATE KEY-----
diff --git a/cli/src/test/resources/hudson/cli/.ssh/id_dsa.pub b/cli/src/test/resources/hudson/cli/.ssh/id_dsa.pub
deleted file mode 100644
index 4a42a845727297abcfa1c1204d0a270392c5a9a6..0000000000000000000000000000000000000000
--- a/cli/src/test/resources/hudson/cli/.ssh/id_dsa.pub
+++ /dev/null
@@ -1 +0,0 @@
-ssh-dss AAAAB3NzaC1kc3MAAACBAID2YzMHU7naGk5sjJoleAUlBSZzUdXQ0QlewUUaHxTaXROSC/h+ncxZp2IAyZzkfWi3gpAteXtLBTt0cIIVwZx9CI6N4PmtZ5m4eg8AlIMyKVwkYTdejYL7CV6xxMHISBFEDXq91KU1oMlcpXGr1avn0bw/gkLr/kS+l7KmBh1NAAAAFQDE32gtDthBi5yazQbFHXNbPolKfQAAAIBkDullg8wkclZNqclvYOVYef9AzreN+Hfw3pYRHOZBCSzpB1LtSQWWD1xtUZS2fRjPZJ9fdUqIxc0yQB0YPyWgFwlLnDqgwxTutyOWV1FDrf58yB1VlgwXltyELpGFB4ZlDwiZ/aIUXbxKwThuL4rXYdiAg7lsXE8VRMdZJawwtwAAAIBgHJ90ZLU400axB5P0qw/0s4arPD0g53Vzi/Y2h5TJr3KPF2sEIbAc2gpFEzUNY0hvH6REKJ+VPPUvlH6ieaXomW8pSGjv4SdxZhJRrDe+Ac/xQse1QdYxuWJzpVm3cIGfqLxmQnrklnutI/1F62VZQlq9vjiZL7ir/00vdUTYHw== ogondza@localhost.localdomain
diff --git a/cli/src/test/resources/hudson/cli/.ssh/id_rsa b/cli/src/test/resources/hudson/cli/.ssh/id_rsa
deleted file mode 100644
index ee2ad6b569a3b5ebbea0d5d1bfcf6ed2bd0dbe27..0000000000000000000000000000000000000000
--- a/cli/src/test/resources/hudson/cli/.ssh/id_rsa
+++ /dev/null
@@ -1,27 +0,0 @@
------BEGIN RSA PRIVATE KEY-----
-MIIEpAIBAAKCAQEAyTqwFqp5Ww2Tr/52D7hhdOwgzYGBUqxrOFopa+kjNEL1Yqwb
-+mApUWZ+D3zN9PurhUcVUfeYVXiYWFJ0kG72HIJawL/0BR5oYxRJfumK8Z/sAzAL
-xdhc5O5twETrr9gU3cxtvF5oJNP0I9HickAOeC+ZNpiDIIblrhvxXl/QwqrR+/Gv
-Nb8TApj+rxXEfNp+N69iGnnxzWn1FeKeOAWpwoBAxZNoqBQAFacF7xfQnoygyekC
-xk+ts2O5Zzv8iJ10sVf+x2Q79rxAtsc0xOGhZbBAzbmFTz0PE4iWuo/Vo1c6mM7u
-/dam+FxB2NqPNw7W+4eiCnEVkiQZlrxmuGvK7wIDAQABAoIBACml1+QZDFzoBnUa
-eVzvkFwesvtVnmp5/QcAwinvarXaVedCL9g2JtcOG3EhJ49YtzsyZxs7329xMja1
-eiKalJ157UaPc/XLQVegT0XRGEzCCJrwSr979F39awGsQgt28XqmYN/nui5FH/Z5
-7iAvWc9OKqu+DQWiZc8PQXmC4zYmvhGQ8vKx44RSqlWCjd9IqBVhpE5gxpI/SmCx
-umUNNtoH0hBWr+MsVHzr6UUrC3a99+7bB4We8XMXXFLzbTUSgiYFmK+NxPs/Fux/
-IAyXAMbDw2HeqZ7g4kTaf4cvmVOwhh4zlvB4p7j301LdO1jmvs9z0fn/QJcTpVM7
-ISMKwAECgYEA/uKVdmOKTk3dKzKRFXtWJjqypOXakoX+25lUcVv2PXYRr8Sln9jC
-A13fbhvwq+FqbdnNlB23ag5niCVLfUpB1DYYP5jd4lU8D6HZQiHlmokB6nLT9NIW
-iTcG88E58Bta/l1Ue5Yn+LqluBC4i289wFbH1kZyxQ565s5dJEv9uAECgYEAyhwF
-ZOqTK2lZe5uuN4owVLQaYFj9fsdFHULzlK/UAtkG1gCJhjBmwSEpZFFMH6WgwHk5
-SHJEom0uB4qRv8gQcxl9OSiDsp56ymr0NBhlPVXWr6IzLotLy5XBC1muqvYYlj7E
-kHgSet/h8RUM/FeEiwOFHDU2DkMb8Qx1hfMdAu8CgYBSEsYL9CuB4WK5WTQMlcV8
-0+PYY0dJbSpOrgXZ5sHYsp8pWQn3+cUnbl/WxdpujkxGCR9AdX0tAmxmE5RGSNX/
-rleKiv/PtKB9bCFYQS/83ecnBkioCcpF7tknPm4YmcZoJ8dfcE94sSlRpti11WEu
-AQOiRNcKCwqaLZMib/HIAQKBgQCdiOffeERMYypfgcJzAiCX9WZV0SeOCS7jFwub
-ys17hsSgS/zl/pYpVXrY+dFXHZfGTvcKdB7xaB6nvCfND9lajfSgd+bndEYLvwAo
-Fxfajizv64LvdZ4XytuUyEuwcHBLtBMs9Jqa8iU/8AOWMXVbkdvQV92RkleWNPrp
-9MyZOwKBgQD9x8MnX5LVBfQKuL9qX6l9Da06EyMkzfz3obKn9AAJ3Xj9+45TNPJu
-HnZyvJWesl1vDjXQTm+PVkdyE0WQgoiVX+wxno0hsoly5Uqb5EYHtTUrZzRpkyLK
-1VmtDxT5D8gorUgn6crzk4PKaxRkPfAimZdlkQm6iOtuR3kqn5BtIQ==
------END RSA PRIVATE KEY-----
diff --git a/cli/src/test/resources/hudson/cli/.ssh/id_rsa.pub b/cli/src/test/resources/hudson/cli/.ssh/id_rsa.pub
deleted file mode 100644
index 91f8ff7180e5f05f989b9aec2104d102372e88a4..0000000000000000000000000000000000000000
--- a/cli/src/test/resources/hudson/cli/.ssh/id_rsa.pub
+++ /dev/null
@@ -1 +0,0 @@
-ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDJOrAWqnlbDZOv/nYPuGF07CDNgYFSrGs4Wilr6SM0QvVirBv6YClRZn4PfM30+6uFRxVR95hVeJhYUnSQbvYcglrAv/QFHmhjFEl+6Yrxn+wDMAvF2Fzk7m3AROuv2BTdzG28Xmgk0/Qj0eJyQA54L5k2mIMghuWuG/FeX9DCqtH78a81vxMCmP6vFcR82n43r2IaefHNafUV4p44BanCgEDFk2ioFAAVpwXvF9CejKDJ6QLGT62zY7lnO/yInXSxV/7HZDv2vEC2xzTE4aFlsEDNuYVPPQ8TiJa6j9WjVzqYzu791qb4XEHY2o83Dtb7h6IKcRWSJBmWvGa4a8rv your_email@example.com
diff --git a/cli/src/test/resources/hudson/cli/dsa b/cli/src/test/resources/hudson/cli/dsa
new file mode 100644
index 0000000000000000000000000000000000000000..4f3f64f95d0e0f1ce121fe33a5a00d25361991f5
--- /dev/null
+++ b/cli/src/test/resources/hudson/cli/dsa
@@ -0,0 +1,12 @@
+-----BEGIN DSA PRIVATE KEY-----
+MIIBvAIBAAKBgQCUlgM7pckNS/AU9w80QDlw304vdyK6u6cWXW7F1PFYMhCrsC7C
+ZcbSKo2mTPHk6P77z3zceSAHeYxkXx34N2HYWCth+79N3VIz/EZC/IaN0sea1teF
+XYLvdnDWazDcRdq+3d4iLAL+46QX6tIaEmUh9SFd4kz7P0rwPHz7SP7+MwIVAPnJ
+QmOwaMbyvb0Q0/OjtXF1orn5AoGBAIP6gOIhNErjgnyzHSfAaR/F2wNFW/TR5HFH
+GEnsVuxTXE00mjqZJaDznviDoVtWF/HlKnR6OcnVr7fm61PXKogeLeJ/zgNPWYCe
+7b45iO38Ztnmimmo9GbzTcDYOVDhNhgZEOUWes9Cdrku8yB3Ugf6nN6GY17LoQ9s
+EDk1Fa8TAoGAD3cFbpbnnw0sHaKMRopCPJKgmCtvzJFgf+xGUZRgEPbeB+1UnG2Z
+T8xPyPF4Zwyo0Mf/b0gxjynLpvzLrr3TMQjqjL4vGE1UIx638ff1Jw08tRRCfBIr
+GpIA5AIzZhxRE6aZREN5wqvnWnlEN+s6mOhcQ8gtNOObHaKuGdU+jAwCFQCvo83Q
+shI+la9gd69CWzJx5GJkJw==
+-----END DSA PRIVATE KEY-----
diff --git a/cli/src/test/resources/hudson/cli/dsa-password b/cli/src/test/resources/hudson/cli/dsa-password
new file mode 100644
index 0000000000000000000000000000000000000000..8a28798a8c0d1b8f37ee9d1b15d02c0c311efa44
--- /dev/null
+++ b/cli/src/test/resources/hudson/cli/dsa-password
@@ -0,0 +1,15 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-128-CBC,CC014AB7E7C376D246B02422C40ED26A
+
+VjIeNQw7EVgiMDJVglpma1CIvRlfzhBBR6r0i5QsVEPTNGLNNUvbqMxUATud8ql0
+Dc84nDj47qbp+jfsvtSfau32hONynT91mNZiCTPUMGFQqiBDMXUMYBv64NXNFi51
++QpI+bW85KLJyRZSmxmBHH31s+6buWwzpYQ2ImwA/Zzkn/1+Evts+VYWEAwXZNBR
+rlpouBiY7XIP3hifU6vBwkH1Dr5Qff0hq13b4T74X2cL2cmWwmPjWDm8nXgDW2Of
+B+5+w2vCp/QDBUpc8LsxNqUK2/B7KA22wqpmQhD7dY4orzaHQWGKwojSd4LwfX6r
+3NEeptKAAn4TusyREypO67g7xUDT0BfZmCNUg6J9dLPWGusx8IvpK/hABzo5Etn/
+CnBRMc1QaDUASHRgzCkadM1DpKmyVQFlMLXCRJaS+51CHGVVGFILcgPsCcrzFL0r
+HOzDbBymhU9Mfw1AygdKNMyZ8NdDsdZ1H3fkkZu7sMgt3PRaYZG+wNImpkdnQDoN
+V3VqTZ5orF4Lo4OqxOuEd7dakpdpyidRvQQc5GaOZuG+2X/NlKhzdGEjt0iubMnX
+S94J+KPJUeVfPphtA2Lb8w==
+-----END DSA PRIVATE KEY-----
diff --git a/cli/src/test/resources/hudson/cli/openssh b/cli/src/test/resources/hudson/cli/openssh
new file mode 100644
index 0000000000000000000000000000000000000000..6d5ce34bdaa8dc9f3e87e499171327ce96938486
--- /dev/null
+++ b/cli/src/test/resources/hudson/cli/openssh
@@ -0,0 +1,17 @@
+-----BEGIN OPENSSH PRIVATE KEY-----
+b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAlwAAAAdzc2gtcn
+NhAAAAAwEAAQAAAIEA6YOQ5he3DIIgu+O9HJLvcGlLNbKe04rN7KftKhaALsqJAtS435bk
+xjv/ycn2uMnTapx2Q+Eu/wqATITB+SZEfAkgRMZmTa2Ze3zt/b6rieRhgRgovu3VyXsRnM
+fgCEuJqU5VRW5WlayYRUsJnQTSaeUuJJvQWAeo9TI/DtYzvp8AAAIYX2d44V9neOEAAAAH
+c3NoLXJzYQAAAIEA6YOQ5he3DIIgu+O9HJLvcGlLNbKe04rN7KftKhaALsqJAtS435bkxj
+v/ycn2uMnTapx2Q+Eu/wqATITB+SZEfAkgRMZmTa2Ze3zt/b6rieRhgRgovu3VyXsRnMfg
+CEuJqU5VRW5WlayYRUsJnQTSaeUuJJvQWAeo9TI/DtYzvp8AAAADAQABAAAAgBRXdq7kj/
+iR+WIEs7uifSMwuPGDjtxksg2Uj09kSGRLFmZdu4EWtvUh0uV0J37vbfBSkubU3fAvrP99
+bRxUHhD5Z444BIyht8jlBetfoJOBSE/TQJ/69xguSmHB8XH8/WUqEaNZ2F+q0AAkRt5CTs
+lkML/YJI1mPzy+0ny6tS8hAAAAQQD6N3CByknj5WrDIJQCce+zbhbftnN4RM6OBuaHv4mm
+y0qIAH7i6ZHFqHlr1OnCPzqtzIt4McoyIDEf+9eH3ktKAAAAQQD8uQ/jcs27tMPwb2GYyU
+vSNZ9g225seV+Y1dU+GSk8zuqmkN1Cbc0dmJW8hqncYrbDuFbRH3kPiLTLO3Aifn2xAAAA
+QQDsirzo7Ox+f2SC0TCu6+wbar6f617IhWRlUyPDNa18+ju+BHdw1890sRSpany5RbJekq
+KoumXchRmzl8vZPoVPAAAAHWluaWZjQFRoZS10b3hpYy1hdmVuZ2VyLmxvY2FsAQIDBAU=
+
+-----END OPENSSH PRIVATE KEY-----
diff --git a/cli/src/test/resources/hudson/cli/openssh-broken b/cli/src/test/resources/hudson/cli/openssh-broken
new file mode 100644
index 0000000000000000000000000000000000000000..f4ebcef2d10778153ea17af9d2f1390189f17dc4
--- /dev/null
+++ b/cli/src/test/resources/hudson/cli/openssh-broken
@@ -0,0 +1,16 @@
+-----BEGIN OPENSSH PRIVATE KEY-----
+b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAlwAAAAdzc2gtcn
+NhAAAAAwEAAQAAAIEA6YOQ5he3DIIgu+O9HJLvcGlLNbKe04rN7KftKhaALsqJAtS435bk
+xjv/ycn2uMnTapx2Q+Eu/wqATITB+SZEfAkgRMZmTa2Ze3zt/b6rieRhgRgovu3VyXsRnM
+fgCEuJqU5VRW5WlayYRUsJnQTSaeUuJJvQWAeo9TI/DtYzvp8AAAIYX2d44V9neOEAAAAH
+c3NoLXJzYQAAAIEA6YOQ5he3DIIgu+O9HJLvcGlLNbKe04rN7KftKhaALsqJAtS435bkxj
+v/ycn2uMnTapx2Q+Eu/wqATITB+SZEfAkgRMZmTa2Ze3zt/b6rieRhgRgovu3VyXsRnMfg
+CEuJqU5VRW5WlayYRUsJnQTSaeUuJJvQWAeo9TI/DtYzvp8AAAADAQABAAAAgBRXdq7kj/
+iR+WIEs7uifSMwuPGDjtxksg2Uj09kSGRLFmZdu4EWtvUh0uV0J37vbfBSkubU3fAvrP99
+bRxUHhD5Z444BIyht8jlBetfoJOBSE/TQJ/69xguSmHB8XH8/WUqEaNZ2F+q0AAkRt5CTs
+y0qIAH7i6ZHFqHlr1OnCPzqtzIt4McoyIDEf+9eH3ktKAAAAQQD8uQ/jcs27tMPwb2GYyU
+vSNZ9g225seV+Y1dU+GSk8zuqmkN1Cbc0dmJW8hqncYrbDuFbRH3kPiLTLO3Aifn2xAAAA
+QQDsirzo7Ox+f2SC0TCu6+wbar6f617IhWRlUyPDNa18+ju+BHdw1890sRSpany5RbJekq
+KoumXchRmzl8vZPoVPAAAAHWluaWZjQFRoZS10b3hpYy1hdmVuZ2VyLmxvY2FsAQIDBAU=
+
+-----END OPENSSH PRIVATE KEY-----
diff --git a/cli/src/test/resources/hudson/cli/openssh-unsuported b/cli/src/test/resources/hudson/cli/openssh-unsuported
new file mode 100644
index 0000000000000000000000000000000000000000..4ed6878f12c88cf120eb680b5cca53e904ff54cb
--- /dev/null
+++ b/cli/src/test/resources/hudson/cli/openssh-unsuported
@@ -0,0 +1,17 @@
+-----BEGIN OPENSSH PRIVATE KEY-----
+b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jdHIAAAAGYmNyeXB0AAAAGAAAABDIzkiSdr
+mRRbRY1S2YtBacAAAAEAAAAAEAAACXAAAAB3NzaC1yc2EAAAADAQABAAAAgQCpXxUyU7MR
+b4GrSMnufZb6kaBb1lHBywI7+dBNnpHyq1rpZJRi36lpxxZoaiG+inOeSBh7QPnDVvm2aN
+DdT7V0PFzfZKWzxl2PRSd6EIXUsaaXuqaFcJM7rSqU1EB+9qM9JfGIqkdNKwzGdu3kdJJG
+3VQQUQVtYXAOLIrApslndQAAAiDAF+/lDARNPSMcOlH6uGqfSBszQBwOf22df5yGHLbnpi
+e5yslN+9Z3jFrl2XNDb8sD9e7gZtB/CbkJaDqFCqSOoW979xLLl89jJYle2L48SBbpV7i2
+0/51YYrxs4/75kJUd8uMaOBpNanyI8CBqA5IPmms1NLrSOpAbU20imQNoLUb1B8v2zNBxo
+R64UyU8AkKDMwPmAHwdrM73c7eirAsuVknhg0fFjy4iCxurqz5RO0Hpjf8GHfaCh37gim/
+8f/XqwS+MlAn9KaAGi4hZJFaSuyPPVLmRTS+gleoM0zSt5J+Fvdrs/JnL/XIpf64QZafKZ
+HyiZXnbJKxWhhhpslHz6QoiZ76LxwRS6bP//fsl7KWPY6IUGMD8h6JGi8o6xpsj16xIGUf
+7K+c9TNcjzaO8jtC8ggaixoKdC48LdenfdaagAtBgyWQqxfxTg9ZLiQ2lrZIaF4C0aZi3+
+byeT/mzPyh6aSAsBETjHCbdy/ixi0BNbDB10LlD44J8i9yBROk7WQtM3lJL78Va4KfxSCC
+dsJQPu1ABZEr1SGVqVprUaM43C/VKZk5PjXmkbAy5TCztztiWwa8HtKk4V7sH4G/ENjAtJ
+w2SEybRTx0WNhD9viTSu8z+BqH1mWP2ek/orE0OWU+H6r1zSoBo9scvpUrLC2NYvcUMw+I
+cDupua/5kKQgTzY+kEyRClwvziHEVe4TLZen3UMf2GM3fVC9AUC8
+-----END OPENSSH PRIVATE KEY-----
diff --git a/cli/src/test/resources/hudson/cli/rsa b/cli/src/test/resources/hudson/cli/rsa
new file mode 100644
index 0000000000000000000000000000000000000000..850ecb0e3d710f1477eb482677b041c8de4e5bd9
--- /dev/null
+++ b/cli/src/test/resources/hudson/cli/rsa
@@ -0,0 +1,15 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICXQIBAAKBgQDcPcvFMiF7OsfaV9MuHQytEOffnyyFraVyYJrgRsdMsFMJcUVJ
+JY2oo2OdMF42CzstSe1fasAZnxalkGBvSdfH6PphgIhBcVj1eCgPR/76q2OyuRk7
+GE5R8GDlQSCsFsV658zyoBXELVFL9HvhXOw/0u7h60h/ertIoYawz44e3wIDAQAB
+AoGBAKTP7bQ07o88DqCbRmJkxL6iPxK+F+A1cPDl0CBzduMxtAIF7LZvTtHa60mP
+D4Fb6D3c67CSvwytW5IsN64wUTNaB6pOXmVnscgsXzNXz4UGsxsEOFUcYkEGJZ8M
+EMKDSqaCI43EMR7nJi/UNrJyj37Axn4cU3bgnDP5DAxO+AK5AkEA7kWA7zw86AoR
+vuSSWEINNSglzTRLZjciDX2b93kh97voRV0q/CHIoSvB3sLU0R/oLpOjaUhPFWrM
+JfI9GQemNQJBAOyg3MHBQhAd1rhXzNkW62903ICjlNGLOTemi+E11iIfGyA0bhLH
+DJQfR+Tx/VLQEVbAMU1pkUg33GRck4SPA0MCQHbmuDCqHrqsS6624VCppW2hWzvL
+nNSlLpkM1YfpKso1OvNiStEHCtdivpwrHYg+I98aTbF8I/rMEJPfDh4vcwECQQCv
+LBbAyNSjIbPHHBhlzXXVOOnTwUV2Kl7dN8ntmvE+qVBncujZtck2DkIm1o32NFnh
+or3c1P3cPJ5HHdGHHGgJAkBdbOMa8VIFBliHr22akFD43gakZ/7ymRNTXA1uj6xt
+NO/1mklbaj4u41UQZU9JjsqebOMGnIc88KMFh6wdfaed
+-----END RSA PRIVATE KEY-----
diff --git a/cli/src/test/resources/hudson/cli/rsa-password b/cli/src/test/resources/hudson/cli/rsa-password
new file mode 100644
index 0000000000000000000000000000000000000000..55c3f7568176f238069be9abc1d01ef4eb9455d5
--- /dev/null
+++ b/cli/src/test/resources/hudson/cli/rsa-password
@@ -0,0 +1,18 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-128-CBC,B937F90AFDFDE86CD9023373F5079F8F
+
+N6ohIfZ+nmqodFzFlFCG6gBXEGIBOl/ojaV+GSHpCJRKJs6lgGSwVmSHESqiKpAI
+ZNQpWEURIVXRpScAuqB+BNQyNjnlFwoo47aBkfDFR2DTY6y+21Z1Fll9ZExABgRJ
+IsMoRVjVbd4eJ1njln73b290EUBNu4ej14pPFsHqSdHQ4atPXw3Alph0NuFYz1CI
+Jg/0vUFFX1u2UjLYAHRU7EKJUk027H1GjZdlV7kcogMRblINokGK0rpmuize6fE9
+WHzEkeGb7qwU4fJ1Sa396TwA5sU6K7xPqV+sArWevavVC4xi0yKoSMmzR2ps5rg+
+XDNBnscNo0dTxnR/Dku2fsqiTsvXZ/LQDWTyTkC0Sx/gYKmfmYfmOpFh6pW0PRUF
+h8Cxm/XkAZV90pK+SrwKA/Pj2vi5nJvAsQlHD+5f7GYLMiB2pWJdbTuXjg0MJjvP
+3TMZm7SqOMe7G4iyXKmlg7Hri2jMPkzvmoGMQZk8bFoX87579w4s0bCdP23lcI2H
+6F7OHTHnPbPc302vN2NWARuqP6XJGRlwJJaNkL8/cvMh42UeVZEZ5WwacUW5g0IN
+IE+K/L5EemBVI2whRsgBBxbyKymBMTolKDhLbGicxAb7E1jr3UXsRv17LaoaPMDN
+TbCjhRkXiYAWXzR/BVwG2vhCI9geCXbLXAVhp2U/z6+KDAVXUIf2Hwz1v1g+fabV
+DGQBzCobfJv9ML9/oO6+KP/dgAA/kBMsLNmQTAR9NslDqdbVujNJ0fSvqaEG1lbq
+7oc36BIyjJgPEehE0kCfzAeVRHq73N8lfbZaz5cnvdMjCXwMubcIL1kBfUpv5eSg
+-----END RSA PRIVATE KEY-----
diff --git a/core/move-l10n.groovy b/core/move-l10n.groovy
index c52e66ae53aecf6318efc70b079e6777df580bd6..8d002348827a6c76ec3b4832278384c74a91d692 100644
--- a/core/move-l10n.groovy
+++ b/core/move-l10n.groovy
@@ -1,30 +1,30 @@
// Usage: groovy move-l10n.groovy hudson/model/OldClass/old-view jenkins/model/NewClass/new-view 'Some\ Translatable\ Text'
// (The new view may be given as '-' to simply delete the key.)
-def oldview = args[0];
-def newview = args[1];
-def key = args[2];
+def oldview = args[0]
+def newview = args[1]
+def key = args[2]
-def scriptDir = new File(getClass().protectionDomain.codeSource.location.path).parent;
-def resDir = new File(scriptDir, 'src/main/resources');
+def scriptDir = new File(getClass().protectionDomain.codeSource.location.path).parent
+def resDir = new File(scriptDir, 'src/main/resources')
-def basename = new File(resDir, oldview).name;
+def basename = new File(resDir, oldview).name
for (p in new File(resDir, oldview).parentFile.listFiles()) {
- def n = p.name;
+ def n = p.name
if (n == "${basename}.properties" || n.startsWith("${basename}_") && n.endsWith(".properties")) {
- def lines = p.readLines('ISO-8859-1');
+ def lines = p.readLines('ISO-8859-1')
// TODO does not handle multiline values correctly
- def matches = lines.findAll({it.startsWith("${key}=")});
+ def matches = lines.findAll({it.startsWith("${key}=")})
if (!matches.isEmpty()) {
- lines.removeAll(matches);
+ lines.removeAll(matches)
p.withWriter('ISO-8859-1') {out ->
lines.each {line -> out.writeLine(line)}
}
if (newview == '-') {
- println("deleting ${matches.size()} matches from ${n}");
+ println("deleting ${matches.size()} matches from ${n}")
} else {
- def nue = new File(resDir, newview + n.substring(basename.length()));
- println("moving ${matches.size()} matches from ${n} to ${nue.name}");
+ def nue = new File(resDir, newview + n.substring(basename.length()))
+ println("moving ${matches.size()} matches from ${n} to ${nue.name}")
// TODO if the original lacked a trailing newline, this will corrupt previously final key
nue.withWriterAppend('ISO-8859-1') {out ->
matches.each {line -> out.writeLine(line)}
diff --git a/core/pom.xml b/core/pom.xml
index 4ba0498ae9a876d95afc42bad9b0b84eb47eda0a..41c58c486f36bd2da15944db611de066481285a8 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -39,7 +39,7 @@ THE SOFTWARE.
true
- 1.256
+ 1.257.22.5.6.SEC032.4.12
@@ -63,7 +63,7 @@ THE SOFTWARE.
org.jenkins-civersion-number
- 1.4
+ 1.6org.jenkins-ci
@@ -101,6 +101,11 @@ THE SOFTWARE.
+
+ org.connectbot.jbcrypt
+ jbcrypt
+ 1.0.0
+ org.jruby.ext.posixjna-posix
@@ -111,16 +116,6 @@ THE SOFTWARE.
jnr-posix3.0.45
-
- org.kohsuke
- trilead-putty-extension
- 1.2
-
-
- org.jenkins-ci
- trilead-ssh2
- build-217-jenkins-14
- org.kohsuke.staplerstapler-groovy
@@ -180,7 +175,7 @@ THE SOFTWARE.
io.jenkins.staplerjenkins-stapler-support
- 1.0
+ 1.1org.hamcrest
@@ -207,7 +202,7 @@ THE SOFTWARE.
args4jargs4j
- 2.0.31
+ 2.33org.jenkins-ci
@@ -226,7 +221,7 @@ THE SOFTWARE.
org.jvnet.localizerlocalizer
- 1.24
+ 1.26antlr
@@ -297,13 +292,9 @@ THE SOFTWARE.
-
commons-beanutilscommons-beanutils
- 1.8.3
+ 1.9.3org.apache.commons
@@ -518,7 +509,7 @@ THE SOFTWARE.
org.jvnet.winpwinp
- 1.27
+ 1.28org.jenkins-ci
@@ -531,14 +522,14 @@ THE SOFTWARE.
3.2.9
- org.jenkins-ci
+ org.jmdnsjmdns
- 3.4.0-jenkins-3
+ 3.5.5net.java.dev.jnajna
- 4.5.2
+ 5.3.1org.kohsuke
@@ -598,9 +589,9 @@ THE SOFTWARE.
- com.google.code.findbugs
- annotations
- provided
+ com.github.spotbugs
+ spotbugs-annotations
+ true
@@ -810,10 +801,6 @@ THE SOFTWARE.
-
- org.codehaus.mojo
- findbugs-maven-plugin
-
@@ -876,11 +863,11 @@ THE SOFTWARE.
-
-
- findbugs
+
+
+ spotbugs
-
+
true
diff --git a/core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message.properties b/core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message.properties
index fffef47e59cd5c72bb4ac44cd9f2d6bc2ca5cee4..a76332f6767c045688896db6808c5ca074b21cf6 100644
--- a/core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message.properties
+++ b/core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message.properties
@@ -20,8 +20,9 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
-NewVersionAvailable=New version of Jenkins ({0}) is available for download \
- (changelog).
+NewVersionAvailable=New version of Jenkins ({0}) is available for download \
+ (changelog).
+ChangelogUrl=${changelog.url}
UpgradeComplete=Upgrade to Jenkins {0} is complete, awaiting restart.
UpgradeCompleteRestartNotSupported=Upgrade to Jenkins {0} is complete, awaiting restart.
UpgradeProgress=Upgrade to Jenkins {0} is in progress.
diff --git a/core/src/main/java/hudson/AbstractMarkupText.java b/core/src/main/java/hudson/AbstractMarkupText.java
index 1e78b3e10cfadca15f5745415141a6d4d8edf4dc..2398f6f7446972a1f724a0ee85fc58d251f1b22e 100644
--- a/core/src/main/java/hudson/AbstractMarkupText.java
+++ b/core/src/main/java/hudson/AbstractMarkupText.java
@@ -141,7 +141,7 @@ public abstract class AbstractMarkupText {
public List findTokens(Pattern pattern) {
String text = getText();
Matcher m = pattern.matcher(text);
- List r = new ArrayList();
+ List r = new ArrayList<>();
while(m.find()) {
int idx = m.start();
diff --git a/core/src/main/java/hudson/BulkChange.java b/core/src/main/java/hudson/BulkChange.java
index 28b9fde4261074ca2e4828534139d16e18c8f464..e65fa4d3acb6d96705125c78274e129d53352235 100644
--- a/core/src/main/java/hudson/BulkChange.java
+++ b/core/src/main/java/hudson/BulkChange.java
@@ -132,7 +132,7 @@ public class BulkChange implements Closeable {
/**
* {@link BulkChange}s that are effective currently.
*/
- private static final ThreadLocal INSCOPE = new ThreadLocal();
+ private static final ThreadLocal INSCOPE = new ThreadLocal<>();
/**
* Gets the {@link BulkChange} instance currently in scope for the current thread.
diff --git a/core/src/main/java/hudson/ClassicPluginStrategy.java b/core/src/main/java/hudson/ClassicPluginStrategy.java
index 5d173c3839022d162265f7b2a2779c436e30791a..e46014f1a9208589b1d9aa645a7b49d5cac2cd57 100644
--- a/core/src/main/java/hudson/ClassicPluginStrategy.java
+++ b/core/src/main/java/hudson/ClassicPluginStrategy.java
@@ -23,29 +23,21 @@
*/
package hudson;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
-
-import java.io.FileNotFoundException;
-import java.io.InputStream;
-import java.nio.file.Files;
-import java.nio.file.InvalidPathException;
-
-import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
-import jenkins.util.AntWithFindResourceClassLoader;
-import jenkins.util.SystemProperties;
import com.google.common.collect.Lists;
+import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import hudson.Plugin.DummyImpl;
import hudson.PluginWrapper.Dependency;
import hudson.model.Hudson;
-import jenkins.util.AntClassLoader;
import hudson.util.CyclicGraphDetector;
import hudson.util.CyclicGraphDetector.CycleDetectedException;
import hudson.util.IOUtils;
import hudson.util.MaskingClassLoader;
-import hudson.util.VersionNumber;
import jenkins.ClassLoaderReflectionToolkit;
import jenkins.ExtensionFilter;
+import jenkins.plugins.DetachedPluginsUtil;
+import jenkins.util.AntClassLoader;
+import jenkins.util.AntWithFindResourceClassLoader;
+import jenkins.util.SystemProperties;
import org.apache.commons.io.output.NullOutputStream;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Project;
@@ -60,37 +52,36 @@ import org.apache.tools.ant.util.GlobPatternMapper;
import org.apache.tools.zip.ZipEntry;
import org.apache.tools.zip.ZipExtraField;
import org.apache.tools.zip.ZipOutputStream;
+import org.jenkinsci.bytecode.Transformer;
+import javax.annotation.Nonnull;
import java.io.Closeable;
import java.io.File;
+import java.io.FileNotFoundException;
import java.io.FilenameFilter;
import java.io.IOException;
+import java.io.InputStream;
import java.net.URL;
-import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.InvalidPathException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.List;
-import java.util.Set;
import java.util.jar.Attributes;
import java.util.jar.JarFile;
import java.util.jar.Manifest;
import java.util.logging.Level;
import java.util.logging.Logger;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-import org.jenkinsci.bytecode.Transformer;
-import org.kohsuke.accmod.Restricted;
-import org.kohsuke.accmod.restrictions.NoExternalUse;
-
-import javax.annotation.Nonnull;
import static org.apache.commons.io.FilenameUtils.getBaseName;
public class ClassicPluginStrategy implements PluginStrategy {
+ private static final Logger LOGGER = Logger.getLogger(ClassicPluginStrategy.class.getName());
+
/**
* Filter for jar files.
*/
@@ -146,6 +137,7 @@ public class ClassicPluginStrategy implements PluginStrategy {
} catch (InvalidPathException e) {
throw new IOException(e);
}
+ //noinspection StatementWithEmptyBody
if (firstLine.startsWith("Manifest-Version:")) {
// this is the manifest already
} else {
@@ -167,7 +159,7 @@ public class ClassicPluginStrategy implements PluginStrategy {
@Override public PluginWrapper createPluginWrapper(File archive) throws IOException {
final Manifest manifest;
- URL baseResourceURL = null;
+ URL baseResourceURL;
File expandDir = null;
// if .hpi, this is the directory where war is expanded
@@ -194,6 +186,10 @@ public class ClassicPluginStrategy implements PluginStrategy {
} catch (InvalidPathException e) {
throw new IOException(e);
}
+ String canonicalName = manifest.getMainAttributes().getValue("Short-Name") + ".jpi";
+ if (!archive.getName().equals(canonicalName)) {
+ LOGGER.warning(() -> "encountered " + archive + " under a nonstandard name; expected " + canonicalName);
+ }
}
final Attributes atts = manifest.getMainAttributes();
@@ -201,7 +197,7 @@ public class ClassicPluginStrategy implements PluginStrategy {
// TODO: define a mechanism to hide classes
// String export = manifest.getMainAttributes().getValue("Export");
- List paths = new ArrayList();
+ List paths = new ArrayList<>();
if (isLinked) {
parseClassPath(manifest, archive, paths, "Libraries", ",");
parseClassPath(manifest, archive, paths, "Class-Path", " +"); // backward compatibility
@@ -227,8 +223,8 @@ public class ClassicPluginStrategy implements PluginStrategy {
}
// compute dependencies
- List dependencies = new ArrayList();
- List optionalDependencies = new ArrayList();
+ List dependencies = new ArrayList<>();
+ List optionalDependencies = new ArrayList<>();
String v = atts.getValue("Plugin-Dependencies");
if (v != null) {
for (String s : v.split(",")) {
@@ -259,39 +255,27 @@ public class ClassicPluginStrategy implements PluginStrategy {
createClassLoader(paths, dependencyLoader, atts), disableFile, dependencies, optionalDependencies);
}
- private static void fix(Attributes atts, List optionalDependencies) {
+ private void fix(Attributes atts, List optionalDependencies) {
String pluginName = atts.getValue("Short-Name");
String jenkinsVersion = atts.getValue("Jenkins-Version");
if (jenkinsVersion==null)
jenkinsVersion = atts.getValue("Hudson-Version");
-
- optionalDependencies.addAll(getImpliedDependencies(pluginName, jenkinsVersion));
+
+ for (Dependency d : DetachedPluginsUtil.getImpliedDependencies(pluginName, jenkinsVersion)) {
+ LOGGER.fine(() -> "implied dep " + pluginName + " → " + d.shortName);
+ pluginManager.considerDetachedPlugin(d.shortName);
+ optionalDependencies.add(d);
+ }
}
-
+
/**
- * Returns all the plugin dependencies that are implicit based on a particular Jenkins version
- * @since 2.0
+ * @see DetachedPluginsUtil#getImpliedDependencies(String, String)
*/
+ @Deprecated // since TODO
@Nonnull
public static List getImpliedDependencies(String pluginName, String jenkinsVersion) {
- List out = new ArrayList<>();
- for (DetachedPlugin detached : DETACHED_LIST) {
- // don't fix the dependency for itself, or else we'll have a cycle
- if (detached.shortName.equals(pluginName)) {
- continue;
- }
- if (BREAK_CYCLES.contains(pluginName + ' ' + detached.shortName)) {
- LOGGER.log(Level.FINE, "skipping implicit dependency {0} → {1}", new Object[] {pluginName, detached.shortName});
- continue;
- }
- // some earlier versions of maven-hpi-plugin apparently puts "null" as a literal in Hudson-Version. watch out for them.
- if (jenkinsVersion == null || jenkinsVersion.equals("null") || new VersionNumber(jenkinsVersion).compareTo(detached.splitWhen) <= 0) {
- out.add(new PluginWrapper.Dependency(detached.shortName + ':' + detached.requiredVersion));
- LOGGER.log(Level.FINE, "adding implicit dependency {0} → {1} because of {2}", new Object[] {pluginName, detached.shortName, jenkinsVersion});
- }
- }
- return out;
+ return DetachedPluginsUtil.getImpliedDependencies(pluginName, jenkinsVersion);
}
@Deprecated
@@ -319,140 +303,6 @@ public class ClassicPluginStrategy implements PluginStrategy {
return classLoader;
}
- /**
- * Get the list of all plugins that have ever been {@link DetachedPlugin detached} from Jenkins core.
- * @return A {@link List} of {@link DetachedPlugin}s.
- */
- @Restricted(NoExternalUse.class)
- public static @Nonnull List getDetachedPlugins() {
- return DETACHED_LIST;
- }
-
- /**
- * Get the list of plugins that have been detached since a specific Jenkins release version.
- * @param since The Jenkins version.
- * @return A {@link List} of {@link DetachedPlugin}s.
- */
- @Restricted(NoExternalUse.class)
- public static @Nonnull List getDetachedPlugins(@Nonnull VersionNumber since) {
- List detachedPlugins = new ArrayList<>();
-
- for (DetachedPlugin detachedPlugin : DETACHED_LIST) {
- if (!detachedPlugin.getSplitWhen().isOlderThan(since)) {
- detachedPlugins.add(detachedPlugin);
- }
- }
-
- return detachedPlugins;
- }
-
- /**
- * Is the named plugin a plugin that was detached from Jenkins at some point in the past.
- * @param pluginId The plugin ID.
- * @return {@code true} if the plugin is a plugin that was detached from Jenkins at some
- * point in the past, otherwise {@code false}.
- */
- @Restricted(NoExternalUse.class)
- public static boolean isDetachedPlugin(@Nonnull String pluginId) {
- for (DetachedPlugin detachedPlugin : DETACHED_LIST) {
- if (detachedPlugin.getShortName().equals(pluginId)) {
- return true;
- }
- }
-
- return false;
- }
-
- /**
- * Information about plugins that were originally in the core.
- *
- * A detached plugin is one that has any of the following characteristics:
- *
- *
- * Was an existing plugin that at some time previously bundled with the Jenkins war file.
- *
- *
- * Was previous code in jenkins core that was split to a separate-plugin (but may not have
- * ever been bundled in a jenkins war file - i.e. it gets split after this 2.0 update).
- *
- *
- */
- @Restricted(NoExternalUse.class)
- public static final class DetachedPlugin {
- private final String shortName;
- /**
- * Plugins built for this Jenkins version (and earlier) will automatically be assumed to have
- * this plugin in its dependency.
- *
- * When core/pom.xml version is 1.123-SNAPSHOT when the code is removed, then this value should
- * be "1.123.*" (because 1.124 will be the first version that doesn't include the removed code.)
- */
- private final VersionNumber splitWhen;
- private final String requiredVersion;
-
- private DetachedPlugin(String shortName, String splitWhen, String requiredVersion) {
- this.shortName = shortName;
- this.splitWhen = new VersionNumber(splitWhen);
- this.requiredVersion = requiredVersion;
- }
-
- /**
- * Get the short name of the plugin.
- * @return The short name of the plugin.
- */
- public String getShortName() {
- return shortName;
- }
-
- /**
- * Get the Jenkins version from which the plugin was detached.
- * @return The Jenkins version from which the plugin was detached.
- */
- public VersionNumber getSplitWhen() {
- return splitWhen;
- }
-
- /**
- * Gets the minimum required version for the current version of Jenkins.
- *
- * @return the minimum required version for the current version of Jenkins.
- * @since 2.16
- */
- public VersionNumber getRequiredVersion() {
- return new VersionNumber(requiredVersion);
- }
-
- @Override
- public String toString() {
- return shortName + " " + splitWhen.toString().replace(".*", "") + " " + requiredVersion;
- }
- }
-
- /** Record of which plugins which removed from core and when. */
- private static final List DETACHED_LIST;
-
- /** Implicit dependencies that are known to be unnecessary and which must be cut out to prevent a dependency cycle among bundled plugins. */
- private static final Set BREAK_CYCLES;
-
- static {
- try (InputStream is = ClassicPluginStrategy.class.getResourceAsStream("/jenkins/split-plugins.txt")) {
- DETACHED_LIST = ImmutableList.copyOf(configLines(is).map(line -> {
- String[] pieces = line.split(" ");
- return new DetachedPlugin(pieces[0], pieces[1] + ".*", pieces[2]);
- }).collect(Collectors.toList()));
- } catch (IOException x) {
- throw new ExceptionInInitializerError(x);
- }
- try (InputStream is = ClassicPluginStrategy.class.getResourceAsStream("/jenkins/split-plugin-cycles.txt")) {
- BREAK_CYCLES = ImmutableSet.copyOf(configLines(is).collect(Collectors.toSet()));
- } catch (IOException x) {
- throw new ExceptionInInitializerError(x);
- }
- }
- private static Stream configLines(InputStream is) throws IOException {
- return org.apache.commons.io.IOUtils.readLines(is, StandardCharsets.UTF_8).stream().filter(line -> !line.matches("#.*|\\s*"));
- }
-
/**
* Computes the classloader that takes the class masking into account.
*
@@ -474,7 +324,7 @@ public class ClassicPluginStrategy implements PluginStrategy {
List finders;
if (type==ExtensionFinder.class) {
// Avoid infinite recursion of using ExtensionFinders to find ExtensionFinders
- finders = Collections.singletonList(new ExtensionFinder.Sezpoz());
+ finders = Collections.singletonList(new ExtensionFinder.Sezpoz());
} else {
finders = hudson.getExtensionList(ExtensionFinder.class);
}
@@ -483,7 +333,7 @@ public class ClassicPluginStrategy implements PluginStrategy {
* See {@link ExtensionFinder#scout(Class, Hudson)} for the dead lock issue and what this does.
*/
if (LOGGER.isLoggable(Level.FINER))
- LOGGER.log(Level.FINER,"Scout-loading ExtensionList: "+type, new Throwable());
+ LOGGER.log(Level.FINER, "Scout-loading ExtensionList: "+type, new Throwable());
for (ExtensionFinder finder : finders) {
finder.scout(type, hudson);
}
@@ -495,7 +345,7 @@ public class ClassicPluginStrategy implements PluginStrategy {
} catch (AbstractMethodError e) {
// backward compatibility
for (T t : finder.findExtensions(type, hudson))
- r.add(new ExtensionComponent(t));
+ r.add(new ExtensionComponent<>(t));
}
}
@@ -737,7 +587,7 @@ public class ClassicPluginStrategy implements PluginStrategy {
CyclicGraphDetector cgd = new CyclicGraphDetector() {
@Override
protected List getEdges(PluginWrapper pw) {
- List dep = new ArrayList();
+ List dep = new ArrayList<>();
for (Dependency d : pw.getDependencies()) {
PluginWrapper p = pluginManager.getPlugin(d.shortName);
if (p!=null && p.isActive())
@@ -803,7 +653,7 @@ public class ClassicPluginStrategy implements PluginStrategy {
@SuppressFBWarnings(value = "DMI_COLLECTION_OF_URLS",
justification = "Should not produce network overheads since the URL is local. JENKINS-53793 is a follow-up")
protected Enumeration findResources(String name) throws IOException {
- HashSet result = new HashSet();
+ HashSet result = new HashSet<>();
if (PluginManager.FAST_LOOKUP) {
for (PluginWrapper pw : getTransitiveDependencies()) {
@@ -864,6 +714,5 @@ public class ClassicPluginStrategy implements PluginStrategy {
}
public static boolean useAntClassLoader = SystemProperties.getBoolean(ClassicPluginStrategy.class.getName()+".useAntClassLoader");
- private static final Logger LOGGER = Logger.getLogger(ClassicPluginStrategy.class.getName());
public static boolean DISABLE_TRANSFORMER = SystemProperties.getBoolean(ClassicPluginStrategy.class.getName()+".noBytecodeTransformer");
}
diff --git a/core/src/main/java/hudson/DNSMultiCast.java b/core/src/main/java/hudson/DNSMultiCast.java
index aa71b2e23b2be38ba799c7d3f3742e9442a5c550..9352fd9decbed61f704cc53fcfc2f69d744d827f 100644
--- a/core/src/main/java/hudson/DNSMultiCast.java
+++ b/core/src/main/java/hudson/DNSMultiCast.java
@@ -4,14 +4,21 @@ import jenkins.util.SystemProperties;
import jenkins.model.Jenkins;
import jenkins.model.Jenkins.MasterComputer;
-import javax.jmdns.JmDNS;
+import javax.jmdns.ServiceEvent;
import javax.jmdns.ServiceInfo;
+import javax.jmdns.ServiceListener;
+import javax.jmdns.impl.JmDNSImpl;
import java.io.Closeable;
import java.io.IOException;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.net.InetAddress;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutorService;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -21,7 +28,7 @@ import java.util.logging.Logger;
* @author Kohsuke Kawaguchi
*/
public class DNSMultiCast implements Closeable {
- private JmDNS jmdns;
+ private JenkinsJmDNS jmdns;
public DNSMultiCast(final Jenkins jenkins) {
if (disabled) return; // escape hatch
@@ -30,9 +37,9 @@ public class DNSMultiCast implements Closeable {
MasterComputer.threadPoolForRemoting.submit(new Callable