@Override protected boolean matchesSafely(LoggerRule item) { synchronized (item) { for (LogRecord record : item.getRecords()) { if (level == null || record.getLevel() == level) { if (message.matches(record.getMessage())) { if (thrown != null) { if (thrown.matches(record.getThrown())) { return true; } } else { return true; } } } } } return false; }
/** * Same as {@link #record(Logger, Level)} but calls {@link Logger#getLogger(String)} for you first. */ public LoggerRule record(String name, Level level) { return record(Logger.getLogger(name), level); }
/** * Creates a {@link Matcher} that matches if the {@link LoggerRule} has a {@link LogRecord} * with a message matching the specified matcher. * You must have first called {@link #capture}. * * @param message the matcher to match against {@link LogRecord#getMessage} */ public static Matcher<LoggerRule> recorded(@Nonnull Matcher<String> message) { return recorded(null, message); }
@Test public void stop() throws Exception { WorkflowJob p = r.createProject(WorkflowJob.class, "p"); p.setDefinition(new CpsFlowDefinition("slowBlock {semaphore 'wait'}", true)); logging.record(CpsStepContext.class, Level.WARNING).capture(100); endExit.release(); assertThat(logging.getRecords(), empty());
@Test public void listener() throws Exception { logging.record( CpsFlowExecution.class, Level.WARNING).capture(200); String script = "node { \n" // + " echo \"hello\"\n" // + " " + "}"; WorkflowJob j = r.createProject( WorkflowJob.class, "listener" ); j.setDefinition( new CpsFlowDefinition( script, true ) ); Run run = r.buildAndAssertSuccess( j ); List<String> logs = logging.getMessages(); long found = logs.stream().filter( s -> s.contains( LOG_MESSAGE ) ).count(); Assert.assertTrue( "cannot find listener exception message", found > 0 ); }
@Override public void evaluate() throws Throwable { logger.record(CpsFlowExecution.TIMING_LOGGER, Level.FINE).capture(100); WorkflowJob p = story.j.jenkins.createProject(WorkflowJob.class, "p"); p.setDefinition(new CpsFlowDefinition("semaphore 'wait'", true)); WorkflowRun b = p.scheduleBuild2(0).waitForStart(); SemaphoreStep.waitForStart("wait/1", b); } });
@Test public void docker() throws Exception { StandardUsernamePasswordCredentials credentials = new UsernamePasswordCredentialsImpl(CredentialsScope.GLOBAL, "ContainerExecDecoratorPipelineTest-docker", "bob", "username", "secret_password"); SystemCredentialsProvider.getInstance().getCredentials().add(credentials); WorkflowJob p = r.jenkins.createProject(WorkflowJob.class, "docker"); p.setDefinition(new CpsFlowDefinition(loadPipelineScript("docker.groovy"), true)); containerExecLogs.capture(1000); WorkflowRun b = p.scheduleBuild2(0).waitForStart(); assertNotNull(b); r.waitForCompletion(b); r.assertLogContains("Wrote authentication to /home/jenkins/.dockercfg", b); // check that we don't accidentally start exporting sensitive info to the build log r.assertLogNotContains("secret_password", b); // check that we don't accidentally start exporting sensitive info to the Jenkins log assertFalse("credential leaked to log", containerExecLogs.getMessages().stream().anyMatch(msg -> msg.contains("secret_password"))); } }
/** * Same as {@link #record(String, Level)} but calls {@link Class#getName()} for you first. */ public LoggerRule record(Class<?> clazz, Level level) { return record(clazz.getName(), level); }
@Override public void evaluate() throws Throwable { WorkflowJob p = story.j.jenkins.getItemByFullName("p", WorkflowJob.class); WorkflowRun b = p.getLastBuild(); SemaphoreStep.success("wait/1", null); story.j.assertBuildStatusSuccess(story.j.waitForCompletion(b)); assertThat(logger.getRecords(), Matchers.hasSize(Matchers.equalTo(1))); assertEquals(CpsFlowExecution.TimingKind.values().length, ((CpsFlowExecution) b.getExecution()).timings.keySet().size()); } });
/** * Creates a {@link Matcher} that matches if the {@link LoggerRule} has a {@link LogRecord} at * the specified {@link Level} and with a message matching the specified matcher. * You must have first called {@link #capture}. * * @param level The {@link Level} of the {@link LoggerRule} to match. Pass {@code null} to match any {@link Level}. * @param message The matcher to match against {@link LogRecord#getMessage}. */ public static Matcher<LoggerRule> recorded(@CheckForNull Level level, @Nonnull Matcher<String> message) { return recorded(level, message, null); }
/** * Same as {@link #record(String, Level)} but calls {@link Class#getPackage()} and getName() for you first. */ public LoggerRule recordPackage(Class<?> clazz, Level level) { return record(clazz.getPackage().getName(), level); }
@Override public void evaluate() throws Throwable { WorkflowJob p = (WorkflowJob) story.j.jenkins.getItem("demo"); assertNotNull(p); WorkflowRun b = p.getLastBuild(); SemaphoreStep.success("wait/1", null); story.j.assertBuildStatusSuccess(story.j.waitForCompletion(b)); story.j.assertLogContains("before=demo", b); story.j.assertLogContains("ONAGENT=true", b); story.j.assertLogContains("reallyAfterFoo", b); story.j.assertLogNotContains("neverShouldReach", b); FlowExecution execution = b.getExecution(); assertNotNull(execution); FlowGraphWalker walker = new FlowGraphWalker(execution); List<WorkspaceAction> actions = new ArrayList<>(); for (FlowNode n : walker) { WorkspaceAction a = n.getAction(WorkspaceAction.class); if (a != null) { actions.add(a); } } assertEquals(1, actions.size()); assertEquals(new HashSet<>(Arrays.asList(LabelAtom.get("remote"), LabelAtom.get("quick"))), actions.get(0).getLabels()); assertThat(logger.getRecords(), Matchers.hasSize(Matchers.equalTo(0))); } });
/** * Creates a {@link Matcher} that matches if the {@link LoggerRule} has a {@link LogRecord} * with a message matching the specified matcher and with a {@link Throwable} matching the specified * matcher. * You must have first called {@link #capture}. * * @param message the matcher to match against {@link LogRecord#getMessage} * @param thrown the matcher to match against {@link LogRecord#getThrown()}. Passing {@code null} is equivalent to * passing {@link org.hamcrest.CoreMatchers#anything} */ public static Matcher<LoggerRule> recorded(@Nonnull Matcher<String> message, @CheckForNull Matcher<Throwable> thrown) { return recorded(null, message, thrown); }
@Issue("JENKINS-46088") @Test public void matcherTypeAssignment() throws Exception { logging.record(CpsTransformer.class, Level.FINEST); WorkflowJob p = jenkins.jenkins.createProject(WorkflowJob.class, "p"); p.setDefinition(new CpsFlowDefinition("@NonCPS\n" + "def nonCPSMatcherMethod(String x) {\n" + " java.util.regex.Matcher m = x =~ /bla/\n" + " return m.matches()\n" + "}\n" + "def cpsMatcherMethod(String x) {\n" + " java.util.regex.Matcher m = x =~ /bla/\n" + " return m.matches()\n" + "}\n" + "assert !nonCPSMatcherMethod('foo')\n" + "assert !cpsMatcherMethod('foo')\n", true)); jenkins.buildAndAssertSuccess(p); }
@Issue("SECURITY-567") @Test public void methodPointers() throws Exception { logging.record(CpsTransformer.class, Level.FINEST); WorkflowJob job = jenkins.jenkins.createProject(WorkflowJob.class, "p"); job.setDefinition(new CpsFlowDefinition("println((Jenkins.&getInstance)())", true)); WorkflowRun b = job.scheduleBuild2(0).get(); jenkins.assertBuildStatus(Result.FAILURE, b); jenkins.assertLogContains("org.jenkinsci.plugins.scriptsecurity.sandbox.RejectedAccessException: Scripts not permitted to use staticMethod jenkins.model.Jenkins getInstance", b); }
@Issue("JENKINS-46088") @Test public void rhsOfDeclarationSandboxedInCPS() throws Exception { logging.record(CpsTransformer.class, Level.FINEST); WorkflowJob job = jenkins.jenkins.createProject(WorkflowJob.class, "p"); job.setDefinition(new CpsFlowDefinition("jenkins.model.Jenkins x = jenkins.model.Jenkins.getInstance()\n", true)); WorkflowRun b = job.scheduleBuild2(0).get(); jenkins.assertBuildStatus(Result.FAILURE, b); jenkins.assertLogContains("org.jenkinsci.plugins.scriptsecurity.sandbox.RejectedAccessException: Scripts not permitted to use staticMethod jenkins.model.Jenkins getInstance", b); }
@Issue("JENKINS-46088") @Test public void rhsOfDeclarationTransformedInNonCPS() throws Exception { logging.record(CpsTransformer.class, Level.FINEST); WorkflowJob job = jenkins.jenkins.createProject(WorkflowJob.class, "p"); job.setDefinition(new CpsFlowDefinition("@NonCPS\n" + "def willFail() {\n" + " jenkins.model.Jenkins x = jenkins.model.Jenkins.getInstance()\n" + "}\n" + "willFail()\n", true)); WorkflowRun b = job.scheduleBuild2(0).get(); jenkins.assertBuildStatus(Result.FAILURE, b); jenkins.assertLogContains("org.jenkinsci.plugins.scriptsecurity.sandbox.RejectedAccessException: Scripts not permitted to use staticMethod jenkins.model.Jenkins getInstance", b); }
@Test public void staticInitializerSandbox() throws Exception { logging.record(CpsTransformer.class, Level.FINEST); WorkflowJob job = jenkins.jenkins.createProject(WorkflowJob.class, "p"); job.setDefinition(new CpsFlowDefinition("class X {static {Jenkins.instance.systemMessage = 'pwned'}}; new X()", true)); WorkflowRun b = job.scheduleBuild2(0).get(); assertNull(jenkins.jenkins.getSystemMessage()); jenkins.assertBuildStatus(Result.FAILURE, b); jenkins.assertLogContains("org.jenkinsci.plugins.scriptsecurity.sandbox.RejectedAccessException: Scripts not permitted to use staticMethod jenkins.model.Jenkins getInstance", b); }
@Issue("SECURITY-551") @Test public void constructorSandbox() throws Exception { logging.record(CpsTransformer.class, Level.FINEST); WorkflowJob job = jenkins.jenkins.createProject(WorkflowJob.class, "p"); job.setDefinition(new CpsFlowDefinition("class X {X() {Jenkins.instance.systemMessage = 'pwned'}}; new X()", true)); WorkflowRun b = job.scheduleBuild2(0).get(); assertNull(jenkins.jenkins.getSystemMessage()); jenkins.assertBuildStatus(Result.FAILURE, b); jenkins.assertLogContains("org.jenkinsci.plugins.scriptsecurity.sandbox.RejectedAccessException: Scripts not permitted to use staticMethod jenkins.model.Jenkins getInstance", b); }