|
23 | 23 | */ |
24 | 24 | package org.jenkinsci.plugins.docker.workflow; |
25 | 25 |
|
| 26 | +import com.cloudbees.jenkins.plugins.sshcredentials.impl.BasicSSHUserPrivateKey; |
26 | 27 | import com.cloudbees.plugins.credentials.CredentialsProvider; |
27 | 28 | import com.cloudbees.plugins.credentials.CredentialsScope; |
28 | 29 | import com.cloudbees.plugins.credentials.common.IdCredentials; |
|
37 | 38 | import hudson.model.Node; |
38 | 39 | import hudson.model.Result; |
39 | 40 | import hudson.model.User; |
| 41 | +import hudson.plugins.sshslaves.SSHLauncher; |
| 42 | +import hudson.slaves.DumbSlave; |
| 43 | +import java.io.ByteArrayOutputStream; |
40 | 44 | import jenkins.model.Jenkins; |
41 | 45 | import jenkins.security.QueueItemAuthenticatorConfiguration; |
42 | 46 | import org.jenkinsci.plugins.docker.commons.credentials.DockerRegistryEndpoint; |
|
70 | 74 | import java.util.Set; |
71 | 75 | import java.util.logging.Level; |
72 | 76 | import org.apache.commons.text.StringEscapeUtils; |
| 77 | +import org.apache.sshd.common.config.keys.KeyUtils; |
| 78 | +import org.apache.sshd.common.config.keys.writer.openssh.OpenSSHKeyPairResourceWriter; |
| 79 | +import org.apache.sshd.common.keyprovider.KeyPairProvider; |
73 | 80 | import static org.hamcrest.MatcherAssert.assertThat; |
74 | 81 | import static org.hamcrest.Matchers.containsString; |
75 | 82 | import static org.hamcrest.Matchers.not; |
| 83 | +import static org.jenkinsci.plugins.docker.workflow.DockerTestUtil.assumeDocker; |
76 | 84 | import org.jenkinsci.plugins.structs.describable.DescribableModel; |
77 | 85 | import org.jenkinsci.plugins.workflow.support.pickles.FilePathPickle; |
78 | 86 | import org.jenkinsci.plugins.workflow.test.steps.SemaphoreStep; |
79 | 87 | import org.junit.ClassRule; |
80 | 88 | import org.jvnet.hudson.test.BuildWatcher; |
81 | 89 | import org.jvnet.hudson.test.JenkinsSessionRule; |
82 | 90 | import org.jvnet.hudson.test.LoggerRule; |
| 91 | +import org.testcontainers.containers.GenericContainer; |
83 | 92 |
|
84 | 93 | public class RegistryEndpointStepTest { |
85 | 94 |
|
@@ -200,36 +209,68 @@ public void stepExecutionWithCredentialsAndQueueItemAuthenticator() throws Throw |
200 | 209 |
|
201 | 210 | @Issue("JENKINS-75679") |
202 | 211 | @Test public void noFilePathPickle() throws Throwable { |
203 | | - assumeNotWindows(); |
204 | | - rr.then(r -> { |
205 | | - var registryCredentials = new UsernamePasswordCredentialsImpl(CredentialsScope.GLOBAL, "registryCreds", null, "me", "s3cr3t"); |
206 | | - CredentialsProvider.lookupStores(r.jenkins).iterator().next().addCredentials(Domain.global(), registryCredentials); |
207 | | - var p = r.createProject(WorkflowJob.class, "p"); |
208 | | - p.setDefinition(new CpsFlowDefinition( |
| 212 | + assumeDocker(); |
| 213 | + try (var agent = new SSHAgentContainer()) { |
| 214 | + agent.start(); |
| 215 | + rr.then(r -> { |
| 216 | + agent.register("remote"); |
| 217 | + var registryCredentials = new UsernamePasswordCredentialsImpl(CredentialsScope.GLOBAL, "registryCreds", null, "me", "s3cr3t"); |
| 218 | + CredentialsProvider.lookupStores(r.jenkins).iterator().next().addCredentials(Domain.global(), registryCredentials); |
| 219 | + var p = r.createProject(WorkflowJob.class, "p"); |
| 220 | + p.setDefinition(new CpsFlowDefinition( |
209 | 221 | """ |
210 | | - node { |
| 222 | + node('remote') { |
211 | 223 | mockDockerLogin { |
212 | 224 | withDockerRegistry(url: 'https://my-reg:1234', credentialsId: 'registryCreds') { |
213 | 225 | semaphore 'wait' |
214 | 226 | } |
215 | 227 | } |
216 | 228 | } |
217 | 229 | """, true)); |
218 | | - var b = p.scheduleBuild2(0).waitForStart(); |
219 | | - SemaphoreStep.waitForStart("wait/1", b); |
220 | | - }); |
221 | | - @SuppressWarnings("deprecation") |
222 | | - var verboten = FilePathPickle.class.getName(); |
223 | | - assertThat(StringEscapeUtils.escapeJava(Files.readString(rr.getHome().toPath().resolve("jobs/p/builds/1/program.dat"), StandardCharsets.ISO_8859_1)), not(containsString(verboten))); |
224 | | - rr.then(r -> { |
225 | | - var b = r.jenkins.getItemByFullName("p", WorkflowJob.class).getBuildByNumber(1); |
226 | | - SemaphoreStep.success("wait/1", null); |
227 | | - r.assertBuildStatusSuccess(r.waitForCompletion(b)); |
228 | | - r.assertLogContains("docker login -u me -p ******** https://my-reg:1234", b); |
229 | | - r.assertLogNotContains("s3cr3t", b); |
230 | | - }); |
| 230 | + var b = p.scheduleBuild2(0).waitForStart(); |
| 231 | + SemaphoreStep.waitForStart("wait/1", b); |
| 232 | + }); |
| 233 | + @SuppressWarnings("deprecation") |
| 234 | + var verboten = FilePathPickle.class.getName(); |
| 235 | + assertThat(StringEscapeUtils.escapeJava(Files.readString(rr.getHome().toPath().resolve("jobs/p/builds/1/program.dat"), StandardCharsets.ISO_8859_1)), not(containsString(verboten))); |
| 236 | + rr.then(r -> { |
| 237 | + var b = r.jenkins.getItemByFullName("p", WorkflowJob.class).getBuildByNumber(1); |
| 238 | + SemaphoreStep.success("wait/1", null); |
| 239 | + r.assertBuildStatusSuccess(r.waitForCompletion(b)); |
| 240 | + r.assertLogContains("docker login -u me -p ******** https://my-reg:1234", b); |
| 241 | + r.assertLogNotContains("s3cr3t", b); |
| 242 | + }); |
| 243 | + } |
231 | 244 | } |
232 | 245 |
|
| 246 | + private static final class SSHAgentContainer extends GenericContainer<SSHAgentContainer> { |
| 247 | + private final String priv; |
| 248 | + SSHAgentContainer() { |
| 249 | + super("jenkins/ssh-agent:6.17.0"); |
| 250 | + try { |
| 251 | + var kp = KeyUtils.generateKeyPair(KeyPairProvider.SSH_RSA, 2048); |
| 252 | + var kprw = new OpenSSHKeyPairResourceWriter(); |
| 253 | + var baos = new ByteArrayOutputStream(); |
| 254 | + kprw.writePublicKey(kp, null, baos); |
| 255 | + var pub = baos.toString(StandardCharsets.US_ASCII); |
| 256 | + baos.reset(); |
| 257 | + kprw.writePrivateKey(kp, null, null, baos); |
| 258 | + priv = baos.toString(StandardCharsets.US_ASCII); |
| 259 | + withEnv("JENKINS_AGENT_SSH_PUBKEY", pub); |
| 260 | + withExposedPorts(22); |
| 261 | + } catch (Exception x) { |
| 262 | + throw new AssertionError(x); |
| 263 | + } |
| 264 | + } |
| 265 | + void register(String name) throws Exception{ |
| 266 | + var creds = new BasicSSHUserPrivateKey(CredentialsScope.GLOBAL, null, "jenkins", new BasicSSHUserPrivateKey.DirectEntryPrivateKeySource(priv), null, null); |
| 267 | + CredentialsProvider.lookupStores(Jenkins.get()).iterator().next().addCredentials(Domain.global(), creds); |
| 268 | + var port = getMappedPort(22); |
| 269 | + Jenkins.get().addNode(new DumbSlave(name, "/home/jenkins/agent", new SSHLauncher(getHost(), port, creds.getId()))); |
| 270 | + } |
| 271 | + } |
| 272 | + |
| 273 | + |
233 | 274 | public static class MockLauncherStep extends Step { |
234 | 275 |
|
235 | 276 | @DataBoundConstructor |
|
0 commit comments