From f87418ac75a81d94cff82a4836d7cece24f88502 Mon Sep 17 00:00:00 2001 From: Olivier Lamy Date: Mon, 5 Aug 2024 12:12:51 +1000 Subject: [PATCH] [JENKINS-73568] rewrite the tests using RealJenkinsRule so test doesn't need to be skipped depending on Jenkins core version" (#1625) * Use RealJenkinsRule Signed-off-by: Olivier Lamy * Rewrite tests using RealJenkinsRule Signed-off-by: Olivier Lamy * exclusion not needed Signed-off-by: Olivier Lamy * add comments about the exclusion Signed-off-by: Olivier Lamy --------- Signed-off-by: Olivier Lamy --- pom.xml | 8 + .../plugins/git/FIPSModeUrlCheckTest.java | 410 +++++++++--------- .../plugins/git/FIPSModeSCMSourceTest.java | 84 ++-- 3 files changed, 239 insertions(+), 263 deletions(-) diff --git a/pom.xml b/pom.xml index a5365cf294..2eddb9dc94 100644 --- a/pom.xml +++ b/pom.xml @@ -229,6 +229,14 @@ git-tag-message 1.7.1 test + + + + ${project.groupId} + ${project.artifactId} + + org.testcontainers diff --git a/src/test/java/hudson/plugins/git/FIPSModeUrlCheckTest.java b/src/test/java/hudson/plugins/git/FIPSModeUrlCheckTest.java index 9ef1eb01df..2f59c84c59 100644 --- a/src/test/java/hudson/plugins/git/FIPSModeUrlCheckTest.java +++ b/src/test/java/hudson/plugins/git/FIPSModeUrlCheckTest.java @@ -16,13 +16,11 @@ import hudson.model.FreeStyleProject; import hudson.model.Result; import hudson.util.FormValidation; -import hudson.util.VersionNumber; import java.io.File; import java.nio.file.Files; import java.util.List; import jenkins.branch.MultiBranchProject; import jenkins.plugins.git.GitSCMSource; -import jenkins.security.FIPS140; import org.apache.commons.lang.StringUtils; import org.eclipse.jgit.api.Git; import org.eclipse.jgit.lib.StoredConfig; @@ -32,170 +30,161 @@ import org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject; import org.jetbrains.annotations.NotNull; import org.junit.Assume; -import org.junit.BeforeClass; -import org.junit.ClassRule; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; -import org.jvnet.hudson.test.FlagRule; -import org.jvnet.hudson.test.JenkinsRule; +import org.jvnet.hudson.test.RealJenkinsRule; import org.testcontainers.DockerClientFactory; import org.testcontainers.containers.BindMode; public class FIPSModeUrlCheckTest { - @ClassRule - public static final FlagRule FIPS_FLAG = - FlagRule.systemProperty(FIPS140.class.getName() + ".COMPLIANCE", "true"); - - @Rule - public JenkinsRule r = new JenkinsRule(); + @Rule public RealJenkinsRule rule = new RealJenkinsRule().omitPlugins("eddsa-api", "trilead-api", "git-tag-message") + .javaOptions("-Djenkins.security.FIPS140.COMPLIANCE=true"); @Rule public TemporaryFolder directory = new TemporaryFolder(); - @BeforeClass - public static void checkJenkinsVersion() { - /* TODO: Remove when failing tests are fixed */ - /* JenkinsRule throws an exception before any test method is executed */ - /* Guess the version number from the Maven command line property */ - /* Default version number copied from pom.xml jenkins.version */ - VersionNumber jenkinsFailsTests = new VersionNumber("2.461"); - VersionNumber jenkinsVersion = new VersionNumber(System.getProperty("jenkins.version", "2.440.3")); - /** Skip tests to avoid delaying plugin BOM and Spring Security 6.x Upgrade */ - boolean skipTests = false; - if (jenkinsVersion.isNewerThanOrEqualTo(jenkinsFailsTests)) { - skipTests = true; - } - Assume.assumeFalse(skipTests); - } @Test - public void testFIPSLtsMethod() { - assertThat(GitSCMSource.isFIPSCompliantTLS(null, "http://github.com/cheese/wine"), is(true)); - assertThat(GitSCMSource.isFIPSCompliantTLS("beer", "http://github.com/cheese/wine"), is(false)); - assertThat(GitSCMSource.isFIPSCompliantTLS(null, "https://github.com/cheese/wine"), is(true)); - assertThat(GitSCMSource.isFIPSCompliantTLS("beer", "https://github.com/cheese/wine"), is(true)); - assertThat(GitSCMSource.isFIPSCompliantTLS(null, "git@github.com:cheese/wine.git"), is(true)); - assertThat(GitSCMSource.isFIPSCompliantTLS("beer", "git@github.com:cheese/wine.git"), is(true)); - assertThat(GitSCMSource.isFIPSCompliantTLS(null, "git://github.com/cheese/wine"), is(true)); - assertThat(GitSCMSource.isFIPSCompliantTLS("beer", "git://github.com/cheese/wine"), is(false)); + public void testFIPSLtsMethod() throws Throwable { + rule.then( r -> { + assertThat(GitSCMSource.isFIPSCompliantTLS(null, "http://github.com/cheese/wine"), is(true)); + assertThat(GitSCMSource.isFIPSCompliantTLS("beer", "http://github.com/cheese/wine"), is(false)); + assertThat(GitSCMSource.isFIPSCompliantTLS(null, "https://github.com/cheese/wine"), is(true)); + assertThat(GitSCMSource.isFIPSCompliantTLS("beer", "https://github.com/cheese/wine"), is(true)); + assertThat(GitSCMSource.isFIPSCompliantTLS(null, "git@github.com:cheese/wine.git"), is(true)); + assertThat(GitSCMSource.isFIPSCompliantTLS("beer", "git@github.com:cheese/wine.git"), is(true)); + assertThat(GitSCMSource.isFIPSCompliantTLS(null, "git://github.com/cheese/wine"), is(true)); + assertThat(GitSCMSource.isFIPSCompliantTLS("beer", "git://github.com/cheese/wine"), is(false)); + }); } @Test public void testGitSCMSourceCheck() throws Throwable { - SystemCredentialsProvider.getInstance() - .getCredentials() - .add(new UsernamePasswordCredentialsImpl( - CredentialsScope.GLOBAL, "mycreds", null, "jenkins", "s3cr3t")); - SystemCredentialsProvider.getInstance().save(); - MultiBranchProject mbp = r.createProject(WorkflowMultiBranchProject.class, "mbp"); - GitSCMSource.DescriptorImpl descriptor = ExtensionList.lookupSingleton(GitSCMSource.DescriptorImpl.class); + rule.then( r -> { + SystemCredentialsProvider.getInstance() + .getCredentials() + .add(new UsernamePasswordCredentialsImpl( + CredentialsScope.GLOBAL, "mycreds", null, "jenkins", "s3cr3t")); + SystemCredentialsProvider.getInstance().save(); + MultiBranchProject mbp = r.createProject(WorkflowMultiBranchProject.class, "mbp"); + GitSCMSource.DescriptorImpl descriptor = ExtensionList.lookupSingleton(GitSCMSource.DescriptorImpl.class); - { - // http with creds rejected - FormValidation validation = descriptor.doCheckRemote(mbp, "mycreds", "http://github.com/foo/beer"); - assertThat(validation.kind, is(FormValidation.Kind.ERROR)); - assertThat(validation.getMessage(), containsString(Messages.git_fips_url_notsecured())); - } + { + // http with creds rejected + FormValidation validation = descriptor.doCheckRemote(mbp, "mycreds", "http://github.com/foo/beer"); + assertThat(validation.kind, is(FormValidation.Kind.ERROR)); + assertThat(validation.getMessage(), containsString(Messages.git_fips_url_notsecured())); + } - { - // https with creds ok - FormValidation validation = descriptor.doCheckRemote(mbp, "mycreds", "https://github.com/foo/vegemite"); - assertThat(validation.kind, is(FormValidation.Kind.OK)); - } + { + // https with creds ok + FormValidation validation = descriptor.doCheckRemote(mbp, "mycreds", "https://github.com/foo/vegemite"); + assertThat(validation.kind, is(FormValidation.Kind.OK)); + } - { - // ssh with creds ok - FormValidation validation = descriptor.doCheckRemote(mbp, "mycreds", "git@github.com:foo/wine.git"); - assertThat(validation.kind, is(FormValidation.Kind.OK)); - } + { + // ssh with creds ok + FormValidation validation = descriptor.doCheckRemote(mbp, "mycreds", "git@github.com:foo/wine.git"); + assertThat(validation.kind, is(FormValidation.Kind.OK)); + } - { - // http without creds ok - FormValidation validation = descriptor.doCheckRemote(mbp, null, "http://github.com/foo/cheese"); - assertThat(validation.kind, is(FormValidation.Kind.OK)); - } + { + // http without creds ok + FormValidation validation = descriptor.doCheckRemote(mbp, null, "http://github.com/foo/cheese"); + assertThat(validation.kind, is(FormValidation.Kind.OK)); + } + }); } @Test public void testUserRemoteConfigCheck() throws Throwable { - SystemCredentialsProvider.getInstance() - .getCredentials() - .add(new UsernamePasswordCredentialsImpl( - CredentialsScope.GLOBAL, "mycreds", null, "jenkins", "s3cr3t")); - SystemCredentialsProvider.getInstance().save(); - FreeStyleProject p = r.createProject(FreeStyleProject.class, "mbp"); - UserRemoteConfig.DescriptorImpl descriptor = - ExtensionList.lookupSingleton(UserRemoteConfig.DescriptorImpl.class); + Assume.assumeTrue(DockerClientFactory.instance().isDockerAvailable()); + // ssh with credentials all good + try (GitServerContainer containerUnderTest = + new GitServerContainer(GitServerVersions.V2_45.getDockerImageName()).withGitRepo("someRepo")) { + containerUnderTest.withClasspathResourceMapping( + "ssh-keys/id_rsa.pub", "/home/git/.ssh/authorized_keys", BindMode.READ_ONLY); + containerUnderTest.withClasspathResourceMapping( + "sshd_config", "/etc/ssh/sshd_config", BindMode.READ_ONLY); - { - // http with credentials rejected - FormValidation validation = descriptor.doCheckUrl(p, "mycreds", "http://github.com/olamy/beer"); - assertThat(validation.kind, is(FormValidation.Kind.ERROR)); - assertThat(validation.getMessage(), containsString(Messages.git_fips_url_notsecured())); - } + containerUnderTest.start(); - { - // https without credentials all good - FormValidation validation = descriptor.doCheckUrl(p, null, "https://github.com/jenkinsci/git-plugin"); - assertThat(validation.kind, is(FormValidation.Kind.OK)); - } + SshIdentity sshClientIdentity = new SshIdentity( + this.getClass() + .getClassLoader() + .getResourceAsStream("ssh-keys/id_rsa") + .readAllBytes(), + this.getClass() + .getClassLoader() + .getResourceAsStream("ssh-keys/id_rsa.pub") + .readAllBytes(), + new byte[0]); + byte[] privateKey = sshClientIdentity.getPrivateKey(); + byte[] passphrase = sshClientIdentity.getPassphrase(); + // ssh://git@localhost:33011/srv/git/someRepo.git + // we don't want the user part of the uri or jgit will use this user + // and we want to be sure to test our implementation with dynamic user + final String repoUrl = StringUtils.remove(containerUnderTest.getGitRepoURIAsSSH().toString(), "git@"); + rule.then( r -> { + BasicSSHUserPrivateKey sshUserPrivateKey = getBasicSSHUserPrivateKey(privateKey, passphrase); + SystemCredentialsProvider.getInstance().getCredentials().add(sshUserPrivateKey); + SystemCredentialsProvider.getInstance() + .getCredentials() + .add(new UsernamePasswordCredentialsImpl( + CredentialsScope.GLOBAL, "mycreds", null, "jenkins", "s3cr3t")); + SystemCredentialsProvider.getInstance().save(); + FreeStyleProject p = r.createProject(FreeStyleProject.class, "mbp"); + UserRemoteConfig.DescriptorImpl descriptor = + ExtensionList.lookupSingleton(UserRemoteConfig.DescriptorImpl.class); - Assume.assumeTrue(DockerClientFactory.instance().isDockerAvailable()); + { + // http with credentials rejected + FormValidation validation = descriptor.doCheckUrl(p, "mycreds", "http://github.com/olamy/beer"); + assertThat(validation.kind, is(FormValidation.Kind.ERROR)); + assertThat(validation.getMessage(), containsString(Messages.git_fips_url_notsecured())); + } - { - // ssh with credentials all good - try (GitServerContainer containerUnderTest = - new GitServerContainer(GitServerVersions.V2_45.getDockerImageName()).withGitRepo("someRepo")) { - containerUnderTest.withClasspathResourceMapping( - "ssh-keys/id_rsa.pub", "/home/git/.ssh/authorized_keys", BindMode.READ_ONLY); - containerUnderTest.withClasspathResourceMapping( - "sshd_config", "/etc/ssh/sshd_config", BindMode.READ_ONLY); + { + // https without credentials all good + FormValidation validation = descriptor.doCheckUrl(p, null, "https://github.com/jenkinsci/git-plugin"); + assertThat(validation.kind, is(FormValidation.Kind.OK)); + } - containerUnderTest.start(); + Assume.assumeTrue(DockerClientFactory.instance().isDockerAvailable()); - SshIdentity sshClientIdentity = new SshIdentity( - this.getClass() - .getClassLoader() - .getResourceAsStream("ssh-keys/id_rsa") - .readAllBytes(), - this.getClass() - .getClassLoader() - .getResourceAsStream("ssh-keys/id_rsa.pub") - .readAllBytes(), - new byte[0]); - BasicSSHUserPrivateKey sshUserPrivateKey = getBasicSSHUserPrivateKey(sshClientIdentity); - SystemCredentialsProvider.getInstance().getCredentials().add(sshUserPrivateKey); - String repoUrl = containerUnderTest.getGitRepoURIAsSSH().toString(); - // ssh://git@localhost:33011/srv/git/someRepo.git - // we don't want the user part of the uri or jgit will use this user - // and we want to be sure to test our implementation with dynamic user - repoUrl = StringUtils.remove(repoUrl, "git@"); - FormValidation validation = descriptor.doCheckUrl(p, sshUserPrivateKey.getId(), repoUrl); - assertThat(validation.kind, is(FormValidation.Kind.OK)); - } + { + FormValidation validation = descriptor.doCheckUrl(p, sshUserPrivateKey.getId(), repoUrl); + assertThat(validation.kind, is(FormValidation.Kind.OK)); + } + }); } - { - // http without credentials all good - try (GitHttpServerContainer containerUnderTest = - new GitHttpServerContainer(GitServerVersions.V2_45.getDockerImageName())) { - containerUnderTest.start(); + // http without credentials all good + try (GitHttpServerContainer containerUnderTest = + new GitHttpServerContainer(GitServerVersions.V2_45.getDockerImageName())) { + containerUnderTest.start(); + String repoUri = containerUnderTest.getGitRepoURIAsHttp().toString(); + rule.then( r -> { + FreeStyleProject p = r.createProject(FreeStyleProject.class, "mbp2"); + UserRemoteConfig.DescriptorImpl descriptor = + ExtensionList.lookupSingleton(UserRemoteConfig.DescriptorImpl.class); // no TLS is fine without credentials FormValidation validation = descriptor.doCheckUrl( - p, null, containerUnderTest.getGitRepoURIAsHttp().toString()); + p, null, repoUri); assertThat(validation.kind, is(FormValidation.Kind.OK)); - } + }); } + } - private static BasicSSHUserPrivateKey getBasicSSHUserPrivateKey(SshIdentity sshIdentity) { + private static BasicSSHUserPrivateKey getBasicSSHUserPrivateKey(byte[] privateKey, byte[] passphrase) { BasicSSHUserPrivateKey.PrivateKeySource privateKeySource = new BasicSSHUserPrivateKey.PrivateKeySource() { @NotNull @Override public List getPrivateKeys() { - return List.of(new String(sshIdentity.getPrivateKey())); + return List.of(new String(privateKey)); } }; return new BasicSSHUserPrivateKey( @@ -203,108 +192,111 @@ public List getPrivateKeys() { "some-id", "git", privateKeySource, - new String(sshIdentity.getPassphrase()), + new String(passphrase), "description"); } @Test public void gitStepTLSCheck() throws Throwable { - WorkflowJob p = r.createProject(WorkflowJob.class, "some project"); - { - // http with creds rejected - p.setDefinition(new CpsFlowDefinition( - "node {\n" + - " dir('foo') {\n" + - " git url: 'http://foo.com/beer.git', credentialsId: 'yup'\n" + - " }\n" + - "}", true)); - WorkflowRun b = r.buildAndAssertStatus(Result.FAILURE, p); - r.assertLogContains(Messages.git_fips_url_notsecured(), b); - } - Assume.assumeTrue(DockerClientFactory.instance().isDockerAvailable()); + try (GitHttpServerContainer containerUnderTest = + new GitHttpServerContainer(GitServerVersions.V2_45.getDockerImageName())) { + containerUnderTest.start(); + // need to have at least on revision to avoid build failure + File tmp = directory.newFolder(); + Git git = Git.cloneRepository() + .setURI(containerUnderTest.getGitRepoURIAsHttp().toString()) + .setDirectory(tmp) + .call(); + StoredConfig storedConfig = git.getRepository().getConfig(); + storedConfig.setBoolean("commit", null, "gpgsign", false); + storedConfig.setBoolean("tag", null, "gpgSign", false); + storedConfig.save(); + Files.writeString(new File(tmp, "foo.txt").toPath(), "nothing too see here"); + git.add().addFilepattern("foo.txt").call(); + git.commit().setMessage("add foo").call(); + git.push().call(); + String repoUri = containerUnderTest.getGitRepoURIAsHttp().toString(); + rule.then(r -> { + WorkflowJob p = r.createProject(WorkflowJob.class, "some project"); + { + // http with creds rejected + p.setDefinition(new CpsFlowDefinition( + "node {\n" + + " dir('foo') {\n" + + " git url: 'http://foo.com/beer.git', credentialsId: 'yup'\n" + + " }\n" + + "}", true)); + WorkflowRun b = r.buildAndAssertStatus(Result.FAILURE, p); + r.assertLogContains(Messages.git_fips_url_notsecured(), b); + } - { - // http without creds not rejected - try (GitHttpServerContainer containerUnderTest = - new GitHttpServerContainer(GitServerVersions.V2_45.getDockerImageName())) { - containerUnderTest.start(); - // need to have at least on revision to avoid build failure - File tmp = directory.newFolder(); - Git git = Git.cloneRepository() - .setURI(containerUnderTest.getGitRepoURIAsHttp().toString()) - .setDirectory(tmp) - .call(); - StoredConfig storedConfig = git.getRepository().getConfig(); - storedConfig.setBoolean("commit", null, "gpgsign", false); - storedConfig.setBoolean("tag", null, "gpgSign", false); - storedConfig.save(); - Files.writeString(new File(tmp, "foo.txt").toPath(), "nothing too see here"); - git.add().addFilepattern("foo.txt").call(); - git.commit().setMessage("add foo").call(); - git.push().call(); - - p.setDefinition(new CpsFlowDefinition( - "node {\n" + - " dir('foo') {\n" + - " git url: '" + containerUnderTest.getGitRepoURIAsHttp() + "', changelog: false\n" + - " }\n" + - "}", true)); - WorkflowRun b = r.buildAndAssertStatus(Result.SUCCESS, p); - } + { + // http without creds not rejected + p.setDefinition(new CpsFlowDefinition( + "node {\n" + + " dir('foo') {\n" + + " git url: '" + repoUri + "', changelog: false\n" + + " }\n" + + "}", true)); + r.buildAndAssertStatus(Result.SUCCESS, p); + } + }); } } @Test public void checkoutStepTLSCheck() throws Throwable { - WorkflowJob p = r.createProject(WorkflowJob.class, "some project"); - { - // http with creds rejected - // Intentionally using modern syntax to check compatibility - p.setDefinition(new CpsFlowDefinition( - "node {\n" + - " dir('foo') {\n" + - " checkout scmGit(branches: [[name: 'master']],\n" + - " userRemoteConfigs: [[credentialsId: 'foocreds', url: 'http://github.com/foo/beer.git']])\n" + - " }\n" + - "}", true)); - WorkflowRun b = r.buildAndAssertStatus(Result.FAILURE, p); - r.assertLogContains(Messages.git_fips_url_notsecured(), b); - } - Assume.assumeTrue(DockerClientFactory.instance().isDockerAvailable()); + try (GitHttpServerContainer containerUnderTest = + new GitHttpServerContainer(GitServerVersions.V2_45.getDockerImageName())) { + containerUnderTest.start(); + // need to have at least on revision to avoid build failure + File tmp = directory.newFolder(); + Git git = Git.cloneRepository() + .setURI(containerUnderTest.getGitRepoURIAsHttp().toString()) + .setDirectory(tmp) + .call(); + StoredConfig storedConfig = git.getRepository().getConfig(); + storedConfig.setBoolean("commit", null, "gpgsign", false); + storedConfig.setBoolean("tag", null, "gpgSign", false); + storedConfig.save(); + Files.writeString(new File(tmp, "foo.txt").toPath(), "nothing too see here"); + git.add().addFilepattern("foo.txt").call(); + git.commit().setMessage("add foo").call(); + git.push().call(); + String repoUri = containerUnderTest.getGitRepoURIAsHttp().toString(); + rule.then(r -> { + WorkflowJob p = r.createProject(WorkflowJob.class, "some project"); + { + // http with creds rejected + // Intentionally using modern syntax to check compatibility + p.setDefinition(new CpsFlowDefinition( + "node {\n" + + " dir('foo') {\n" + + " checkout scmGit(branches: [[name: 'master']],\n" + + " userRemoteConfigs: [[credentialsId: 'foocreds', url: 'http://github.com/foo/beer.git']])\n" + + " }\n" + + "}", true)); + WorkflowRun b = r.buildAndAssertStatus(Result.FAILURE, p); + r.assertLogContains(Messages.git_fips_url_notsecured(), b); + } - { - // http without creds not rejected - try (GitHttpServerContainer containerUnderTest = - new GitHttpServerContainer(GitServerVersions.V2_45.getDockerImageName())) { - containerUnderTest.start(); - // need to have at least on revision to avoid build failure - File tmp = directory.newFolder(); - Git git = Git.cloneRepository() - .setURI(containerUnderTest.getGitRepoURIAsHttp().toString()) - .setDirectory(tmp) - .call(); - StoredConfig storedConfig = git.getRepository().getConfig(); - storedConfig.setBoolean("commit", null, "gpgsign", false); - storedConfig.setBoolean("tag", null, "gpgSign", false); - storedConfig.save(); - Files.writeString(new File(tmp, "foo.txt").toPath(), "nothing too see here"); - git.add().addFilepattern("foo.txt").call(); - git.commit().setMessage("add foo").call(); - git.push().call(); + { + // http without creds not rejected + // Intentionally using old syntax to check compatibility + p.setDefinition(new CpsFlowDefinition( + "node {\n" + + " dir('foo') {\n" + + " checkout([$class: 'GitSCM',\n" + + " branches: [[name: '*/master']],\n" + + " userRemoteConfigs: [[url: '" + repoUri + "']]])\n" + + " }\n" + + "}", true)); + r.buildAndAssertStatus(Result.SUCCESS, p); + } - // Intentionally using old syntax to check compatibility - p.setDefinition(new CpsFlowDefinition( - "node {\n" + - " dir('foo') {\n" + - " checkout([$class: 'GitSCM',\n" + - " branches: [[name: '*/master']],\n" + - " userRemoteConfigs: [[url: '" + containerUnderTest.getGitRepoURIAsHttp() + "']]])\n" + - " }\n" + - "}", true)); - WorkflowRun b = r.buildAndAssertStatus(Result.SUCCESS, p); - } + }); } } } diff --git a/src/test/java/jenkins/plugins/git/FIPSModeSCMSourceTest.java b/src/test/java/jenkins/plugins/git/FIPSModeSCMSourceTest.java index 641c6f06c2..2d8b38f348 100644 --- a/src/test/java/jenkins/plugins/git/FIPSModeSCMSourceTest.java +++ b/src/test/java/jenkins/plugins/git/FIPSModeSCMSourceTest.java @@ -1,20 +1,14 @@ package jenkins.plugins.git; +import hudson.logging.LogRecorder; import hudson.model.TaskListener; import hudson.plugins.git.GitException; import hudson.util.StreamTaskListener; -import hudson.util.VersionNumber; -import jenkins.security.FIPS140; -import org.junit.Assume; -import org.junit.BeforeClass; -import org.junit.ClassRule; import org.junit.Rule; import org.junit.Test; -import org.jvnet.hudson.test.FlagRule; -import org.jvnet.hudson.test.JenkinsRule; -import org.jvnet.hudson.test.LoggerRule; +import org.jvnet.hudson.test.RealJenkinsRule; -import java.io.IOException; +import java.util.List; import java.util.logging.Level; import static org.hamcrest.CoreMatchers.containsString; @@ -25,53 +19,35 @@ public class FIPSModeSCMSourceTest { - @ClassRule - public static final FlagRule FIPS_FLAG = - FlagRule.systemProperty(FIPS140.class.getName() + ".COMPLIANCE", "true"); - - @Rule - public JenkinsRule rule = new JenkinsRule(); - - @Rule - public LoggerRule logger = new LoggerRule(); - - @BeforeClass - public static void checkJenkinsVersion() { - /* TODO: Remove when failing tests are fixed */ - /* JenkinsRule throws an exception before any test method is executed */ - /* Guess the version number from the Maven command line property */ - /* Default version number copied from pom.xml jenkins.version */ - VersionNumber jenkinsFailsTests = new VersionNumber("2.461"); - VersionNumber jenkinsVersion = new VersionNumber(System.getProperty("jenkins.version", "2.440.3")); - /** Skip tests to avoid delaying plugin BOM and Spring Security 6.x Upgrade */ - boolean skipTests = false; - if (jenkinsVersion.isNewerThanOrEqualTo(jenkinsFailsTests)) { - skipTests = true; - } - Assume.assumeFalse(skipTests); - } + @Rule public RealJenkinsRule rule = new RealJenkinsRule().omitPlugins("eddsa-api", "trilead-api", "git-tag-message") + .javaOptions("-Djenkins.security.FIPS140.COMPLIANCE=true") + .withLogger(AbstractGitSCMSource.class, Level.SEVERE); @Test @SuppressWarnings("deprecation") - public void remotesAreNotFetchedTest() throws IOException, InterruptedException { - GitSCMSource source = new GitSCMSource("http://insecure-repo"); - // Credentials are null, so we should have no FIPS error - logger.record(AbstractGitSCMSource.class, Level.SEVERE); - logger.capture(10); - TaskListener listener = StreamTaskListener.fromStderr(); - assertThrows("expected exception as repo doesn't exist", GitException.class, () ->source.fetch(listener)); - assertThat("We should no see the error in the logs", logger.getMessages().size(), is(0)); - - // Using creds we should be getting an exception - Throwable exception = assertThrows("We're not saving creds", IllegalArgumentException.class, () -> source.setCredentialsId("cred-id")); - assertThat(exception.getMessage(), containsString("FIPS requires a secure channel")); - assertThat("credentials are not saved", source.getCredentialsId(), nullValue()); - - // Using old constructor (restricted since 3.4.0) to simulate credentials are being set with unsecure connection - // This would be equivalent to a user manually adding credentials to config.xml - GitSCMSource anotherSource = new GitSCMSource("fake", "http://insecure", "credentialsId", "", "", true); - exception = assertThrows("fetch was interrupted so no credential was leaked", IllegalArgumentException.class, () -> anotherSource.fetch(listener)); - assertThat("We should have a severe log indicating the error", logger.getMessages().size(), is(1)); - assertThat("Exception indicates problem", exception.getMessage(), containsString("FIPS requires a secure channel")); + public void remotesAreNotFetchedTest() throws Throwable { + rule.then( r -> { + GitSCMSource source = new GitSCMSource("http://insecure-repo"); + TaskListener listener = StreamTaskListener.fromStderr(); + assertThrows("expected exception as repo doesn't exist", GitException.class, () -> source.fetch(listener)); + + LogRecorder logRecorder = new LogRecorder(AbstractGitSCMSource.class.getName()); + LogRecorder.Target target = new LogRecorder.Target(AbstractGitSCMSource.class.getName(), Level.SEVERE); + logRecorder.setLoggers(List.of(target)); + r.jenkins.getLog().getRecorders().add(logRecorder); + assertThat("We should no see the error in the logs", logRecorder.getLogRecords().size(), is(0)); + + // Using creds we should be getting an exception + Throwable exception = assertThrows("We're not saving creds", IllegalArgumentException.class, () -> source.setCredentialsId("cred-id")); + assertThat(exception.getMessage(), containsString("FIPS requires a secure channel")); + assertThat("credentials are not saved", source.getCredentialsId(), nullValue()); + + // Using old constructor (restricted since 3.4.0) to simulate credentials are being set with unsecure connection + // This would be equivalent to a user manually adding credentials to config.xml + GitSCMSource anotherSource = new GitSCMSource("fake", "http://insecure", "credentialsId", "", "", true); + exception = assertThrows("fetch was interrupted so no credential was leaked", IllegalArgumentException.class, () -> anotherSource.fetch(listener)); + assertThat("We should have a severe log indicating the error", logRecorder.getLogRecords().size(), is(1)); + assertThat("Exception indicates problem", exception.getMessage(), containsString("FIPS requires a secure channel")); + }); } }