From 5dc7ebd86204104a543c321b47a8c79af7a507c8 Mon Sep 17 00:00:00 2001 From: Josh Eckels Date: Wed, 4 Feb 2026 10:55:57 -0800 Subject: [PATCH 1/3] Support non-user-visible rendering of HTML comments in Markdown (#7373) Co-authored-by: Adam Rauch --- .../labkey/core/wiki/MarkdownServiceImpl.java | 60 +++++++++++++++++++ .../labkey/core/wiki/MarkdownTestCase.java | 27 +++++++-- 2 files changed, 81 insertions(+), 6 deletions(-) diff --git a/core/src/org/labkey/core/wiki/MarkdownServiceImpl.java b/core/src/org/labkey/core/wiki/MarkdownServiceImpl.java index 064d35930ce..c8ec46de4b4 100644 --- a/core/src/org/labkey/core/wiki/MarkdownServiceImpl.java +++ b/core/src/org/labkey/core/wiki/MarkdownServiceImpl.java @@ -23,10 +23,15 @@ import org.commonmark.ext.image.attributes.ImageAttributesExtension; import org.commonmark.node.Node; import org.commonmark.parser.Parser; +import org.commonmark.renderer.html.HtmlNodeRendererContext; import org.commonmark.renderer.html.HtmlRenderer; +import org.commonmark.renderer.html.CoreHtmlNodeRenderer; +import org.commonmark.node.HtmlInline; +import org.commonmark.node.HtmlBlock; import org.labkey.api.markdown.MarkdownService; import java.util.List; +import java.util.Set; public class MarkdownServiceImpl implements MarkdownService { @@ -55,10 +60,65 @@ public MarkdownServiceImpl() .softbreak("
\n") // See Issue #34169 .sanitizeUrls(true) .escapeHtml(true) + .nodeRendererFactory(CommentNodeRenderer::new) .extensions(extensions) .build(); } + private static class CommentNodeRenderer extends CoreHtmlNodeRenderer + { + private final HtmlNodeRendererContext _context; + + public CommentNodeRenderer(HtmlNodeRendererContext context) + { + super(context); + _context = context; + } + + @Override + public Set> getNodeTypes() + { + return Set.of(HtmlInline.class, HtmlBlock.class); + } + + @Override + public void render(Node node) + { + if (node instanceof HtmlInline inline) + { + String literal = inline.getLiteral(); + if (isComment(literal)) + { + _context.getWriter().raw(literal); + } + else + { + _context.getWriter().text(literal); + } + } + else if (node instanceof HtmlBlock block) + { + String literal = block.getLiteral(); + if (isComment(literal)) + { + _context.getWriter().raw(literal); + } + else + { + _context.getWriter().tag("p"); + _context.getWriter().text(literal); + _context.getWriter().tag("/p"); + _context.getWriter().line(); + } + } + } + + private boolean isComment(String literal) + { + return literal != null && literal.trim().startsWith(""); + } + } + @Override public String toHtml(String mdText) { diff --git a/core/src/org/labkey/core/wiki/MarkdownTestCase.java b/core/src/org/labkey/core/wiki/MarkdownTestCase.java index f1c6402f787..a54fcea07c4 100644 --- a/core/src/org/labkey/core/wiki/MarkdownTestCase.java +++ b/core/src/org/labkey/core/wiki/MarkdownTestCase.java @@ -15,7 +15,7 @@ class MarkdownTestCase extends Assert @Test public void testMdHeadingToHtml() { - MarkdownService markdownService = MarkdownService.get(); + MarkdownService markdownService = new MarkdownServiceImpl(); String testMdText = "# This is a H1 header"; String expectedHtmlText = "

This is a H1 header

\n
"; String htmlText = markdownService.toHtml(testMdText); @@ -28,7 +28,7 @@ public void testMdHeadingToHtml() @Test public void testMdBoldToHtml() { - MarkdownService markdownService = MarkdownService.get(); + MarkdownService markdownService = new MarkdownServiceImpl(); String testMdText = "**This is bold text**"; String expectedHtmlText = "

This is bold text

\n
"; String htmlText = markdownService.toHtml(testMdText); @@ -41,11 +41,10 @@ public void testMdBoldToHtml() @Test public void testMdHtmlTags() { - MarkdownService markdownService = MarkdownService.get(); - + MarkdownService markdownService = new MarkdownServiceImpl(); String testMdText = "

header

"; - String expectedHtmlText = "

<h2>header</h2>

\n
"; String htmlText = markdownService.toHtml(testMdText); + String expectedHtmlText = "

<h2>header</h2>

\n
"; assertEquals("The MarkdownService failed to correctly escape html tags.", expectedHtmlText, htmlText); testMdText = ""; @@ -60,7 +59,7 @@ public void testMdHtmlTags() @Test public void testMdComplexToHtml() { - MarkdownService markdownService = MarkdownService.get(); + MarkdownService markdownService = new MarkdownServiceImpl(); // this sample of markdown and translation taken from part of: https://markdown-it.github.io/ String testMdText = """ --- @@ -341,4 +340,20 @@ public void testMdComplexToHtml() String htmlText = markdownService.toHtml(testMdText); assertEquals("The MarkdownService failed to correctly translate complex markdown text to html.", expectedHtmlText, htmlText); } + @Test + public void testHtmlComments() + { + MarkdownService markdownService = new MarkdownServiceImpl(); + + String testMdText = "Text before text after"; + String htmlText = markdownService.toHtml(testMdText); + + assertTrue("Comment was encoded: " + htmlText, htmlText.contains("")); + assertFalse("Comment should not be encoded: " + htmlText, htmlText.contains("<!--")); + + // Verification for "; + String scriptHtml = markdownService.toHtml(scriptMd); + assertTrue("Script tags should still be encoded: " + scriptHtml, scriptHtml.contains("<script>")); + } } From 214773a03b4dd47a467afe51ddd153a796d548ec Mon Sep 17 00:00:00 2001 From: Trey Chadick Date: Wed, 4 Feb 2026 14:27:21 -0800 Subject: [PATCH 2/3] Use all-caps label for metadata PK name (#7388) --- api/src/org/labkey/api/data/dialect/PkMetaDataReader.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/src/org/labkey/api/data/dialect/PkMetaDataReader.java b/api/src/org/labkey/api/data/dialect/PkMetaDataReader.java index 89e3c831f7d..e8efaf2c5a7 100644 --- a/api/src/org/labkey/api/data/dialect/PkMetaDataReader.java +++ b/api/src/org/labkey/api/data/dialect/PkMetaDataReader.java @@ -44,6 +44,6 @@ public int getKeySeq() throws SQLException public String getKeyName() throws SQLException { - return _rsCols.getString("pk_name"); + return _rsCols.getString("PK_NAME"); } } From d319bea619906cc3daad777552a72953690e223e Mon Sep 17 00:00:00 2001 From: Marty Pradere Date: Fri, 6 Feb 2026 06:54:02 -0800 Subject: [PATCH 3/3] Private issue tracker search results (#7384) * don't throw * Suppress restricted issue exception on search --------- Co-authored-by: Lum --- issues/src/org/labkey/issue/model/IssueManager.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/issues/src/org/labkey/issue/model/IssueManager.java b/issues/src/org/labkey/issue/model/IssueManager.java index 617024a7ac3..447fcc8901a 100644 --- a/issues/src/org/labkey/issue/model/IssueManager.java +++ b/issues/src/org/labkey/issue/model/IssueManager.java @@ -1038,7 +1038,7 @@ public HttpView getCustomSearchResult(User user, @NotNull String resourceIdentif return null; } - final IssueObject issue = getIssue(null, user, issueId); + final IssueObject issue = getIssue(null, user, issueId, false); if (null == issue) return null; Container c = issue.lookupContainer(); @@ -1319,7 +1319,7 @@ public static WebdavResource resolve(String id) return null; } - final IssueObject issue = getIssue(null, User.getSearchUser(), issueId); + final IssueObject issue = getIssue(null, User.getSearchUser(), issueId, false); if (null == issue) return null;