diff --git a/.github/workflows/http-tests.yml b/.github/workflows/http-tests.yml index 22e9740bd8..adac057374 100644 --- a/.github/workflows/http-tests.yml +++ b/.github/workflows/http-tests.yml @@ -8,11 +8,16 @@ jobs: runs-on: ubuntu-latest env: ASF_ARCHIVE: https://archive.apache.org/dist/ - JENA_VERSION: 4.7.0 + JENA_VERSION: 6.1.0 BASE_URI: https://localhost:4443/ steps: - name: Install Linux packages run: sudo apt-get update && sudo apt-get install -qq raptor2-utils && sudo apt-get install curl + - name: Set up Java 21 + uses: actions/setup-java@v4 + with: + distribution: 'temurin' + java-version: '21' - name: Download Jena run: curl -sS --fail "${{ env.ASF_ARCHIVE }}jena/binaries/apache-jena-${{ env.JENA_VERSION }}.tar.gz" -o "${{ runner.temp }}/jena.tar.gz" - name: Unpack Jena @@ -49,6 +54,12 @@ jobs: run: ./run.sh "$PWD/ssl/owner/cert.pem" "${{ secrets.HTTP_TEST_OWNER_CERT_PASSWORD }}" "$PWD/ssl/secretary/cert.pem" "${{ secrets.HTTP_TEST_SECRETARY_CERT_PASSWORD }}" shell: bash working-directory: http-tests + - name: Dump container logs on failure + if: failure() + run: docker compose --env-file ./http-tests/.env logs --no-color + - name: Dump Tomcat logs from linkeddatahub container on failure + if: failure() + run: docker compose --env-file ./http-tests/.env exec -T linkeddatahub sh -c 'for f in /usr/local/tomcat/logs/*; do echo "=== $f ==="; cat "$f"; done' || true - name: Stop Docker containers and remove volumes run: docker compose --env-file ./http-tests/.env down -v - name: Remove Docker containers diff --git a/Dockerfile b/Dockerfile index 3d8066e6e8..a5fdd51e49 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,8 +1,8 @@ -FROM maven:3.8.4-openjdk-17 AS maven +FROM maven:3.9-eclipse-temurin-21 AS maven # download and extract Jena -ARG JENA_VERSION=4.7.0 +ARG JENA_VERSION=6.1.0 ARG JENA_TAR_URL="https://archive.apache.org/dist/jena/binaries/apache-jena-${JENA_VERSION}.tar.gz" @@ -22,7 +22,7 @@ RUN mvn -Pstandalone clean install # ============================== -FROM atomgraph/letsencrypt-tomcat:10.1.46 +FROM atomgraph/letsencrypt-tomcat:10.1.52 LABEL maintainer="martynas@atomgraph.com" diff --git a/docker-compose.yml b/docker-compose.yml index c95560dbd4..02b5f52033 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -20,7 +20,7 @@ volumes: varnish_end_user_cache: services: nginx: - image: nginx:1.23.3 + image: nginx:1.31.1 mem_limit: 128m configs: - source: nginx_conf @@ -105,7 +105,7 @@ services: - ./config/dataspaces.trig:/var/linkeddatahub/datasets/dataspaces.trig - ./config/system.trig:/var/linkeddatahub/datasets/system.trig fuseki-admin: - image: atomgraph/fuseki:4.7.0 + image: atomgraph/fuseki:6.1.0 user: root # otherwise fuseki user does not have permissions to the mounted folder which is owner by root expose: - 3030 @@ -114,7 +114,7 @@ services: - ./fuseki/admin:/fuseki/databases command: [ "--config", "/fuseki/config.ttl" ] fuseki-end-user: - image: atomgraph/fuseki:4.7.0 + image: atomgraph/fuseki:6.1.0 user: root # otherwise the fuseki user does not have permissions to the mounted folder which is owner by root expose: - 3030 @@ -123,7 +123,7 @@ services: - ./fuseki/end-user:/fuseki/databases command: [ "--config", "/fuseki/config.ttl" ] varnish-frontend: - image: varnish:7.3.0 + image: varnish:7.7.3 user: root # otherwise varnish user does not have permissions to the mounted folder which is owner by root configs: - source: varnish-frontend_vcl @@ -136,7 +136,7 @@ services: entrypoint: varnishd command: [ "-F", "-f", "/etc/varnish/default.vcl", "-a", "http=:6060,HTTP", "-a", "proxy=:8443,PROXY", "-p", "feature=+http2", "-s", "file,/var/lib/varnish/storage.bin,3G", "-t", "86400" ] # -F: foreground, -f: config, -a: listeners, -p: http2, -s: storage, -t: TTL varnish-admin: - image: varnish:7.3.0 + image: varnish:7.7.3 user: root # otherwise the varnish user does not have permissions to the mounted folder which is owner by root configs: - source: varnish-admin_vcl @@ -147,7 +147,7 @@ services: entrypoint: varnishd command: [ "-F", "-f", "/etc/varnish/default.vcl", "-a", "http=:80,HTTP", "-a", "proxy=:8443,PROXY", "-p", "feature=+http2", "-s", "malloc,1G", "-t", "86400", "-p", "timeout_idle=60s" ] # -F: foreground, -f: config, -a: listeners, -p: http2 + idle timeout, -s: storage, -t: TTL varnish-end-user: - image: varnish:7.3.0 + image: varnish:7.7.3 user: root # otherwise varnish user does not have permissions to the mounted folder which is owner by root configs: - source: varnish-end-user_vcl diff --git a/platform/entrypoint.sh b/platform/entrypoint.sh index a737c3a6b2..a67ef53832 100755 --- a/platform/entrypoint.sh +++ b/platform/entrypoint.sh @@ -1,5 +1,7 @@ #!/usr/bin/env bash set -e +set -x # DEBUG: trace every command (revert before merge) +exec 2>&1 # DEBUG: merge stderr into stdout so the trace lands in docker logs # set timezone diff --git a/pom.xml b/pom.xml index abcad6aaab..3294574f1c 100644 --- a/pom.xml +++ b/pom.xml @@ -86,28 +86,28 @@ jakarta.servlet jakarta.servlet-api - 5.0.0 + 6.0.0 provided org.glassfish.jersey.connectors jersey-apache-connector - 3.1.0 + 3.1.11 org.glassfish.jersey.media jersey-media-multipart - 3.1.0 + 3.1.11 org.glassfish.jersey.media jersey-media-json-processing - 3.1.0 + 3.1.11 com.sun.mail jakarta.mail - 2.0.1 + 2.0.2 com.google.guava @@ -117,7 +117,7 @@ com.atomgraph.etl.csv csv2rdf - 2.1.11 + 2.2.0 @@ -129,57 +129,67 @@ org.apache.jena jena-shacl - 4.7.0 + 6.1.0 + + + org.apache.jena + jena-arq + 6.1.0 + + + com.github.jsonld-java + jsonld-java + 0.13.4 ${project.groupId} twirl - 1.0.33 + 1.1.0 ${project.groupId} client - 4.2.11 + 4.3.0 classes ${project.groupId} client - 4.2.11 + 4.3.0 war org.apache.httpcomponents httpclient-cache - 4.5.13 + 4.5.14 com.auth0 java-jwt - 3.19.3 + 3.19.4 net.jodah expiringmap - 0.5.10 + 0.5.11 org.jsoup jsoup - 1.15.3 + 1.22.1 org.apache.tomcat tomcat-coyote - 10.1.2 + 10.1.52 jar - junit - junit - 4.13.2 + org.junit.jupiter + junit-jupiter + 5.11.4 test @@ -188,6 +198,12 @@ 5.12.0 test + + org.mockito + mockito-junit-jupiter + 5.12.0 + test + @@ -216,10 +232,15 @@ + + org.apache.maven.plugins + maven-surefire-plugin + 3.5.2 + org.apache.maven.plugins maven-release-plugin - 2.5.3 + 3.3.1 release @@ -227,10 +248,10 @@ org.apache.maven.plugins maven-compiler-plugin - 3.10.1 + 3.14.1 - 17 - 17 + 21 + 21 -XDignore.symbol.file @@ -243,7 +264,7 @@ org.sonatype.central central-publishing-maven-plugin - 0.9.0 + 0.10.0 true central-portal-snapshots @@ -254,7 +275,7 @@ org.codehaus.mojo exec-maven-plugin - 3.0.0 + 3.6.3 find-xsl-files @@ -287,7 +308,7 @@ org.honton.chas readfiles-maven-plugin - 0.0.1 + 0.1.0 read-comma-separated-xsl-file-list @@ -338,7 +359,7 @@ com.github.eirslett frontend-maven-plugin - 1.15.1 + 1.15.4 v22.16.0 11.4.2 @@ -366,7 +387,7 @@ org.apache.maven.plugins maven-war-plugin - 3.3.2 + 3.5.1 ${build.warName} ${project.build.directory}/${build.warName} @@ -432,7 +453,7 @@ org.apache.maven.plugins maven-source-plugin - 3.2.1 + 3.4.0 attach-sources @@ -445,7 +466,7 @@ org.apache.maven.plugins maven-javadoc-plugin - 3.2.0 + 3.12.0 attach-javadocs diff --git a/src/main/java/com/atomgraph/linkeddatahub/client/SesameProtocolClient.java b/src/main/java/com/atomgraph/linkeddatahub/client/SesameProtocolClient.java index 0cb29e2c2a..1adae78188 100644 --- a/src/main/java/com/atomgraph/linkeddatahub/client/SesameProtocolClient.java +++ b/src/main/java/com/atomgraph/linkeddatahub/client/SesameProtocolClient.java @@ -123,7 +123,7 @@ public static MultivaluedMap solutionMapToMultivaluedMap(QuerySo { String varName = it.next(); RDFNode node = qsm.get(varName); - params.add("$" + varName, NodeFmtLib.str(node.asNode())); + params.add("$" + varName, NodeFmtLib.strNT(node.asNode())); } return params; diff --git a/src/main/java/com/atomgraph/linkeddatahub/resource/Namespace.java b/src/main/java/com/atomgraph/linkeddatahub/resource/Namespace.java index 095219cf30..4ccefa319f 100644 --- a/src/main/java/com/atomgraph/linkeddatahub/resource/Namespace.java +++ b/src/main/java/com/atomgraph/linkeddatahub/resource/Namespace.java @@ -46,15 +46,13 @@ import jakarta.ws.rs.core.Response.Status; import jakarta.ws.rs.core.SecurityContext; import jakarta.ws.rs.core.UriInfo; -import org.apache.jena.iri.IRI; -import org.apache.jena.iri.IRIFactory; +import org.apache.jena.irix.IRIx; import org.apache.jena.ontology.Ontology; import org.apache.jena.query.DatasetFactory; import org.apache.jena.query.Query; import org.apache.jena.query.QueryFactory; import org.apache.jena.rdf.model.Model; import org.apache.jena.rdf.model.ModelFactory; -import org.apache.jena.riot.system.Checker; import org.apache.jena.update.UpdateRequest; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -182,15 +180,12 @@ public Response post(UpdateRequest update, @QueryParam(USING_GRAPH_URI) List """; - @Test(expected = RiotException.class) + @Test public void testBillionLaughs() { - Model m = ModelFactory.createDefaultModel(); - - ByteArrayInputStream bais = new ByteArrayInputStream(MALICIOUS.getBytes(StandardCharsets.UTF_8)); - - RDFParser parser = RDFParser.create() - .lang(Lang.RDFXML) - .errorHandler(ErrorHandlerFactory.errorHandlerStrict) - .checking(true) - .base("http://example.org/") - .source(bais) - .build(); - - System.out.println("Starting parse..."); - parser.parse(StreamRDFLib.graph(m.getGraph())); - System.out.println("Model size: " + m.size()); + assertThrows(RiotException.class, () -> { + Model m = ModelFactory.createDefaultModel(); + + ByteArrayInputStream bais = new ByteArrayInputStream(MALICIOUS.getBytes(StandardCharsets.UTF_8)); + + RDFParser parser = RDFParser.create() + .lang(Lang.RDFXML) + .errorHandler(ErrorHandlerFactory.errorHandlerStrict) + .checking(true) + .base("http://example.org/") + .source(bais) + .build(); + + System.out.println("Starting parse..."); + parser.parse(StreamRDFLib.graph(m.getGraph())); + System.out.println("Model size: " + m.size()); + }); } } diff --git a/src/test/java/com/atomgraph/linkeddatahub/client/filter/ClientUriRewriteFilterTest.java b/src/test/java/com/atomgraph/linkeddatahub/client/filter/ClientUriRewriteFilterTest.java index 1c874c19b8..ce3d6e89fa 100644 --- a/src/test/java/com/atomgraph/linkeddatahub/client/filter/ClientUriRewriteFilterTest.java +++ b/src/test/java/com/atomgraph/linkeddatahub/client/filter/ClientUriRewriteFilterTest.java @@ -34,8 +34,8 @@ import java.util.List; import java.util.Locale; import java.util.Map; -import org.junit.Test; -import static org.junit.Assert.*; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; /** * Unit tests for {@link ClientUriRewriteFilter}. diff --git a/src/test/java/com/atomgraph/linkeddatahub/server/filter/request/ProxyRequestFilterTest.java b/src/test/java/com/atomgraph/linkeddatahub/server/filter/request/ProxyRequestFilterTest.java index 745ecd94dd..2321ecf817 100644 --- a/src/test/java/com/atomgraph/linkeddatahub/server/filter/request/ProxyRequestFilterTest.java +++ b/src/test/java/com/atomgraph/linkeddatahub/server/filter/request/ProxyRequestFilterTest.java @@ -24,11 +24,11 @@ import java.io.IOException; import java.net.URI; import java.util.List; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; import static org.mockito.ArgumentMatchers.anyList; import static org.mockito.Mockito.*; @@ -37,7 +37,7 @@ * * @author Martynas Jusevičius {@literal } */ -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class ProxyRequestFilterTest { @@ -47,7 +47,7 @@ public class ProxyRequestFilterTest private ProxyRequestFilter filter; - @Before + @BeforeEach public void setUp() { filter = new ProxyRequestFilter(); diff --git a/src/test/java/com/atomgraph/linkeddatahub/server/util/URLValidatorTest.java b/src/test/java/com/atomgraph/linkeddatahub/server/util/URLValidatorTest.java index fd22dae189..b72bc4b653 100644 --- a/src/test/java/com/atomgraph/linkeddatahub/server/util/URLValidatorTest.java +++ b/src/test/java/com/atomgraph/linkeddatahub/server/util/URLValidatorTest.java @@ -16,9 +16,10 @@ package com.atomgraph.linkeddatahub.server.util; import com.atomgraph.linkeddatahub.server.exception.InternalURLException; -import org.junit.Test; +import org.junit.jupiter.api.Test; import java.net.URI; +import static org.junit.jupiter.api.Assertions.assertThrows; /** * Unit tests for URLValidator SSRF protection. @@ -32,34 +33,34 @@ public class URLValidatorTest { - @Test(expected = IllegalArgumentException.class) + @Test public void testNullURI() { - new URLValidator(false).validate(null); + assertThrows(IllegalArgumentException.class, () -> new URLValidator(false).validate(null)); } - @Test(expected = InternalURLException.class) + @Test public void testLinkLocalIPv4Blocked() { - new URLValidator(false).validate(URI.create("http://169.254.1.1:8080/test")); + assertThrows(InternalURLException.class, () -> new URLValidator(false).validate(URI.create("http://169.254.1.1:8080/test"))); } - @Test(expected = InternalURLException.class) + @Test public void testPrivateClass10Blocked() { - new URLValidator(false).validate(URI.create("http://10.0.0.1:8080/test")); + assertThrows(InternalURLException.class, () -> new URLValidator(false).validate(URI.create("http://10.0.0.1:8080/test"))); } - @Test(expected = InternalURLException.class) + @Test public void testPrivateClass172Blocked() { - new URLValidator(false).validate(URI.create("http://172.16.0.0:8080/test")); + assertThrows(InternalURLException.class, () -> new URLValidator(false).validate(URI.create("http://172.16.0.0:8080/test"))); } - @Test(expected = InternalURLException.class) + @Test public void testPrivateClass192Blocked() { - new URLValidator(false).validate(URI.create("http://192.168.1.1:8080/test")); + assertThrows(InternalURLException.class, () -> new URLValidator(false).validate(URI.create("http://192.168.1.1:8080/test"))); } @Test