fix(appengine): removing obsolete symlink from java 8 on java 11 bundle services#10272
fix(appengine): removing obsolete symlink from java 8 on java 11 bundle services#10272Kef131 wants to merge 1 commit into
Conversation
There was a problem hiding this comment.
Code Review
This pull request migrates the Datastore sample code to the App Engine Java 11 runtime. The review identified several critical security vulnerabilities, specifically Cross-Site Scripting (XSS) risks in the ListPeopleServlet and guestbook.jsp, which require input escaping. Additionally, a potential runtime exception in MetadataNamespacesTest was flagged regarding empty filter lists. The feedback also suggests several refactoring opportunities to improve code conciseness using Java Streams and recommends addressing test flakiness in GuestbookTest by ensuring proper isolation of static state.
I am having trouble creating individual review comments. Click here to see my feedback.
appengine-java11-bundled-services/datastore/src/main/java/com/example/appengine/ListPeopleServlet.java (81)
The entity property name is written directly to the HTML output without escaping. This is a potential Cross-Site Scripting (XSS) vulnerability if the names can contain HTML characters. You should escape the property before writing it to the response. You can use a library like Guava's HtmlEscapers for this, since Guava is already a dependency.
w.println("<li>" + com.google.common.html.HtmlEscapers.htmlEscaper().escape((String) entity.getProperty("name")) + "</li>");
appengine-java11-bundled-services/datastore/src/main/webapp/guestbook.jsp (28)
The greeting.content is rendered directly to the page without escaping. This can lead to a Cross-Site Scripting (XSS) vulnerability if the content contains malicious HTML or JavaScript. You should use JSTL's <c:out> tag to escape the content.
<c:out value="${greeting.content}"/>
appengine-java11-bundled-services/datastore/src/test/java/com/example/appengine/MetadataNamespacesTest.java (124)
Calling CompositeFilterOperator.and() with an empty list of filters will throw an IllegalArgumentException. You should only set the filter if the subFilters list is not empty. Also, if there's only one filter, you don't need to wrap it in a CompositeFilter.
if (!subFilters.isEmpty()) {
if (subFilters.size() == 1) {
q.setFilter(subFilters.get(0));
} else {
q.setFilter(CompositeFilterOperator.and(subFilters));
}
}appengine-java11-bundled-services/datastore/src/main/java/com/example/appengine/AbstractGuestbook.java (65-69)
This loop can be simplified using Java Streams and Guava's ImmutableList.toImmutableList() collector for a more concise and functional approach.
return listGreetingEntities(datastore).stream()
.map(Greeting::create)
.collect(com.google.common.collect.ImmutableList.toImmutableList());appengine-java11-bundled-services/datastore/src/main/java/com/example/appengine/StartupServlet.java (109-115)
This entity creation and population logic can be simplified using Java Streams for a more modern and functional style.
java.util.List<Entity> people = US_PRESIDENTS.stream()
.map(name -> {
Entity person = new Entity(PERSON_ENTITY);
person.setProperty(NAME_PROPERTY, name);
return person;
})
.collect(java.util.stream.Collectors.toList());
datastore.put(people);
appengine-java11-bundled-services/datastore/src/test/java/com/example/appengine/GuestbookTest.java (43-44)
The static fields newJobCounter and existingJobCounter can lead to flaky tests, as their state is shared across test executions within the same JVM run. This can cause tests to interfere with each other.
To ensure test isolation, you should reset these counters before each test, for example in the setUp() method:
@Before
public void setUp() throws Exception {
helper.setUp();
CustomHighRepJobPolicy.newJobCounter = 0;
CustomHighRepJobPolicy.existingJobCounter = 0;
clock = new FakeClock();
guestbookUnderTest = new Guestbook(clock);
}appengine-java11-bundled-services/datastore/src/test/java/com/example/appengine/MetadataNamespacesTest.java (127-135)
This logic for collecting query results can be simplified using Java Streams for a more concise and functional approach.
// Build list of query results
return ds.prepare(q).asQueryResultIterable().stream()
.map(e -> Entities.getNamespaceFromNamespaceKey(e.getKey()))
.collect(java.util.stream.Collectors.toList());
Description
Fixes #10242
Internal: b/496677589
Same case as previous #10270
This PR dereferences the symbolic links in the Java 11 App Engine bundled services module (
appengine-java11-bundled-services) that previously pointed to the deleted/legacyappengine-java8directory. By making these files self-contained, this module can run independently without relying on Java 8 code.Additionally, this PR adds the missing JSTL dependency to the Java 11
pom.xmlto resolve JSP runtime compilation errors (JasperException / ClassNotFoundException for guestbook_jsp) when running the development server locally withmvn appengine:run.This PR dereferenced 32 Symbolic links on
appengine-java11-bundled-services/datastoreChecklist
pom.xmlparent set to latestshared-configurationmvn clean verifyrequiredmvn -P lint checkstyle:checkrequiredmvn -P lint clean compile pmd:cpd-check spotbugs:checkadvisory only