diff --git a/.gitignore b/.gitignore
index 602de1073..2d4b00f00 100644
--- a/.gitignore
+++ b/.gitignore
@@ -332,6 +332,9 @@ scripts/dockerize/dockerfiles
/jdk_21_maven/cs/rest/redis-sample/target/
/jdk_21_maven/em/external/rest/redis-sample/target/
/jdk_21_maven/em/embedded/rest/redis-sample/target/
+/jdk_21_maven/cs/rest/arimaa/target/
+/jdk_21_maven/em/external/rest/arimaa/target/
+/jdk_21_maven/em/embedded/rest/arimaa/target/
/jdk_21_maven/cs/rest/joinus/target/
/jdk_21_maven/em/external/rest/joinus/target/
/jdk_21_maven/em/embedded/rest/joinus/target/
diff --git a/README.md b/README.md
index 40f1018bc..a058785f0 100644
--- a/README.md
+++ b/README.md
@@ -85,7 +85,9 @@ How to setup authentication information, based on the current content of the ini
Auth configuration files can found in the [auth](auth) folder.
-### REST: Java/Kotlin (40)
+### REST: Java/Kotlin (41)
+
+* **Arimaa** (not-known license), [jdk_21_maven/cs/rest/arimaa](jdk_21_maven/cs/rest/arimaa), from [https://github.com/KEAArimaaProject/arimaa-backend](https://github.com/KEAArimaaProject/arimaa-backend)
* **Bibliothek** (MIT), [jdk_17_gradle/cs/rest/bibliothek](jdk_17_gradle/cs/rest/bibliothek), from [https://github.com/PaperMC/bibliothek](https://github.com/PaperMC/bibliothek)
diff --git a/auth/arimaa-auth.yaml b/auth/arimaa-auth.yaml
new file mode 100644
index 000000000..229fdcda1
--- /dev/null
+++ b/auth/arimaa-auth.yaml
@@ -0,0 +1,9 @@
+auth:
+ - name: wfd_admin1
+ fixedHeaders:
+ - name: Authorization
+ value: Basic d2ZkX2FkbWluMTpXZmQtQWRtaW4tUGFzczE=
+ - name: wfd_admin2
+ fixedHeaders:
+ - name: Authorization
+ value: Basic d2ZkX2FkbWluMjpXZmQtQWRtaW4tUGFzczI=
diff --git a/dockerfiles/arimaa.dockerfile b/dockerfiles/arimaa.dockerfile
new file mode 100644
index 000000000..e16ab6daa
--- /dev/null
+++ b/dockerfiles/arimaa.dockerfile
@@ -0,0 +1,13 @@
+FROM amazoncorretto:21-alpine-jdk
+
+COPY ./dist/arimaa-sut.jar .
+COPY ./dist/jacocoagent.jar .
+
+
+
+
+ENTRYPOINT \
+ java \
+ -javaagent:jacocoagent.jar=output=tcpserver,address=*,port=6300,append=false,dumponexit=false \
+ -jar arimaa-sut.jar \
+ --server.port=8080 --spring.datasource.url=jdbc:mysql://db:3306/arimaadockermysqldb --spring.datasource.username=admin --spring.datasource.password=AdminPassword123! --spring.mongodb.uri=mongodb://mongodb:27017/arimaadb --spring.neo4j.uri=bolt://neo4j:7687 --spring.neo4j.authentication.username=neo4j --spring.neo4j.authentication.password=wfdNeo4jPass123
\ No newline at end of file
diff --git a/dockerfiles/arimaa.yaml b/dockerfiles/arimaa.yaml
new file mode 100644
index 000000000..46f42f634
--- /dev/null
+++ b/dockerfiles/arimaa.yaml
@@ -0,0 +1,70 @@
+services:
+ mitmproxy:
+ image: mitmproxy/mitmproxy:10.2.4
+ user: "0:0"
+ environment:
+ MITM_LOG_DIR: /custom-logs
+ MITM_LOG_FILE: ${MITM_LOG_FILE:-minlog.csv}
+ command: >
+ mitmdump
+ --mode reverse:http://sut-arimaa:8080
+ --listen-host 0.0.0.0
+ --listen-port 8080
+ --set keep_host_header=true
+ -s /addons/minlog.py
+ volumes:
+ - ${HOST_LOG_DIR:-./mitm-logs}:/custom-logs
+ - ./addons:/addons:ro
+ ports:
+ - "${HOST_PORT:-8080}:8080"
+ depends_on:
+ - sut-arimaa
+ sut-arimaa:
+ image: webfuzzing/wfd-arimaa:FINAL
+# build:
+# dockerfile: ./dockerfiles/arimaa.dockerfile
+# context: ..
+ environment:
+ AUTH_PORT: ${AUTH_PORT:-8081}
+ ports:
+ - "${JACOCO_PORT:-6300}:6300"
+ depends_on:
+ db:
+ condition: service_healthy
+ mongodb:
+ condition: service_healthy
+ neo4j:
+ condition: service_healthy
+ db:
+ image: mysql:9.5.0
+ environment:
+ MYSQL_DATABASE: arimaadockermysqldb
+ MYSQL_ROOT_PASSWORD: wfdRootPass123!
+ volumes:
+ - ../jdk_21_maven/cs/rest/arimaa/Database/mysql:/docker-entrypoint-initdb.d
+ healthcheck:
+ test: mysqladmin ping -h localhost -u root -pwfdRootPass123! --silent
+ interval: 30s
+ timeout: 30s
+ retries: 3
+ mongodb:
+ image: mongo:7
+ volumes:
+ - ../scripts/dockerize/data/additional_files/arimaa/arimaa-mongo-seed.js:/docker-entrypoint-initdb.d/arimaa-mongo-seed.js
+ healthcheck:
+ test: mongosh --quiet --eval "db.adminCommand('ping')"
+ interval: 30s
+ timeout: 30s
+ retries: 3
+ neo4j:
+ image: neo4j:5.26
+ environment:
+ NEO4J_AUTH: neo4j/wfdNeo4jPass123
+ volumes:
+ - ../scripts/dockerize/data/additional_files/arimaa/arimaa-neo4j-seed.cypher:/seed.cypher
+ healthcheck:
+ test: cypher-shell -u neo4j -p wfdNeo4jPass123 "MATCH (:WfdSeedComplete) RETURN 1"
+ interval: 30s
+ timeout: 30s
+ retries: 3
+ command: ["bash", "-c", '/startup/docker-entrypoint.sh neo4j & pid=$!; until cypher-shell -u neo4j -p wfdNeo4jPass123 "RETURN 1" >/dev/null 2>&1; do sleep 2; done; cypher-shell -u neo4j -p wfdNeo4jPass123 -f /seed.cypher; cypher-shell -u neo4j -p wfdNeo4jPass123 "CREATE (:WfdSeedComplete)"; wait $pid']
\ No newline at end of file
diff --git a/experiments/bb-exp.py b/experiments/bb-exp.py
index cad954c41..c6aedd369 100644
--- a/experiments/bb-exp.py
+++ b/experiments/bb-exp.py
@@ -77,6 +77,7 @@ def __init__(self, name, auth, sleep, schemaformat, classfiles):
# To ge the SUTs, you need in EMB to run the script "scripts/dist.py"
SUTS = [
+ Sut("arimaa",True,SLEEP,JSON,["jdk_21_maven/cs/rest/arimaa/target/classes"]),
Sut("bibliothek",False,SLEEP,JSON,["jdk_17_gradle/cs/rest/bibliothek/build/classes"]),
Sut("blogapi",True, SLEEP,JSON,["jdk_8_maven/cs/rest/original/blogapi/target/classes"]),
Sut("catwatch",False,SLEEP,JSON,["jdk_8_maven/cs/rest/original/catwatch/catwatch-backend/target/classes"]),
diff --git a/experiments/wb-exp.py b/experiments/wb-exp.py
index d275faf23..2040e3fda 100644
--- a/experiments/wb-exp.py
+++ b/experiments/wb-exp.py
@@ -182,6 +182,7 @@ def __init__(self, name, platform):
SUTS = [
# REST
+ Sut("arimaa", JDK_21),
Sut("bibliothek", JDK_17),
Sut("blogapi",JDK_8),
Sut("catwatch", JDK_8),
diff --git a/jacoco.dockerfile b/jacoco.dockerfile
index 61b283121..6518882eb 100644
--- a/jacoco.dockerfile
+++ b/jacoco.dockerfile
@@ -13,6 +13,7 @@ ENV CLASS_FILES=/classfiles
### IMPORTANT!!!: must be kept in sync with what declared in run-tools.py, which will need to be updated
### any time in this file we add a new entry to WFD
+COPY jdk_21_maven/cs/rest/arimaa/target/classes ${CLASS_FILES}/jdk_21_maven/cs/rest/arimaa/target/classes
COPY jdk_17_gradle/cs/rest/bibliothek/build/classes ${CLASS_FILES}/jdk_17_gradle/cs/rest/bibliothek/build/classes
COPY jdk_8_maven/cs/rest/original/blogapi/target/classes ${CLASS_FILES}/jdk_8_maven/cs/rest/original/blogapi/target/classes
COPY jdk_8_maven/cs/rest/original/catwatch/catwatch-backend/target/classes ${CLASS_FILES}/jdk_8_maven/cs/rest/original/catwatch/catwatch-backend/target/classes
diff --git a/jdk_21_maven/cs/rest/arimaa/Database/mysql/Sql_arimaa_62b_default_user.sql b/jdk_21_maven/cs/rest/arimaa/Database/mysql/Sql_arimaa_62b_default_user.sql
index 8f229bc7a..c68e73396 100644
--- a/jdk_21_maven/cs/rest/arimaa/Database/mysql/Sql_arimaa_62b_default_user.sql
+++ b/jdk_21_maven/cs/rest/arimaa/Database/mysql/Sql_arimaa_62b_default_user.sql
@@ -1,10 +1,15 @@
USE `arimaadockermysqldb`;
-INSERT IGNORE INTO `Users` (`username`, `email`, `password`, `role`, `created_at`, `updated_at`)
+INSERT IGNORE INTO `Users` (`username`, `email`, `password`, `role`, `created_at`, `updated_at`)
VALUES
('admin1', 'admin1@example.com', '$2a$10$a7Dii8pcWQMclYxLt9Kb1eWpbRNbAPTsMRlJkm7ZT.wYIemq4oiBi', 'ADMIN', NOW(), NOW()),
- ('user1', 'user1@example.com', '$2a$10$DK1T8LJLPBcPLWhm7i/L1esnux0b7mV0HjMbB02CL794blj0M0lYG', 'USER', NOW(), NOW())
-ON DUPLICATE KEY UPDATE
- `password` = VALUES(`password`),
- `role` = VALUES(`role`),
+ ('user1', 'user1@example.com', '$2a$10$DK1T8LJLPBcPLWhm7i/L1esnux0b7mV0HjMbB02CL794blj0M0lYG', 'USER', NOW(), NOW()),
+ -- MODIFIED: admin1's password is unknown, and self-registration can never grant ADMIN, so a
+ -- second known-credential ADMIN account is needed to test broken access control between admins.
+ ('wfd_admin1', 'wfd_admin1@example.com', '$2a$10$3mawxiylgOPZOvvJO24bxeuUcQyQf.n53SzzAX9fBNiT7bfzZn4WO', 'ADMIN', NOW(), NOW()),
+ ('wfd_admin2', 'wfd_admin2@example.com', '$2a$10$8h.Zwu6RHMf0VZsEIZ2rcewbF4CU/nLpzoSSPjE1M1D.nof/9ZQVy', 'ADMIN', NOW(), NOW())
+ -- MODIFIED
+ON DUPLICATE KEY UPDATE
+ `password` = VALUES(`password`),
+ `role` = VALUES(`role`),
`updated_at` = NOW();
\ No newline at end of file
diff --git a/jdk_21_maven/cs/rest/arimaa/pom.xml b/jdk_21_maven/cs/rest/arimaa/pom.xml
index 2a5bde4bb..f7ffc4554 100644
--- a/jdk_21_maven/cs/rest/arimaa/pom.xml
+++ b/jdk_21_maven/cs/rest/arimaa/pom.xml
@@ -146,11 +146,18 @@
3.2.0
test
+
com.fasterxml.jackson.core
jackson-databind
- test
+
+
+ org.springdoc
+ springdoc-openapi-starter-webmvc-ui
+ 3.1.0
+
+
@@ -161,6 +168,12 @@
spring-boot-maven-plugin
com.example.arimaabackend.ArimaaBackendApplication
+
+
+ arimaa
+ sut
+
diff --git a/jdk_21_maven/cs/rest/pom.xml b/jdk_21_maven/cs/rest/pom.xml
index 615c1360b..aa6c99cfd 100644
--- a/jdk_21_maven/cs/rest/pom.xml
+++ b/jdk_21_maven/cs/rest/pom.xml
@@ -16,6 +16,7 @@
joinus
person-controller
redis-sample
+ arimaa
diff --git a/jdk_21_maven/em/embedded/rest/arimaa/pom.xml b/jdk_21_maven/em/embedded/rest/arimaa/pom.xml
new file mode 100644
index 000000000..669a479bd
--- /dev/null
+++ b/jdk_21_maven/em/embedded/rest/arimaa/pom.xml
@@ -0,0 +1,59 @@
+
+
+
+ 4.0.0
+
+ evomaster-benchmark-jdk21-em-embedded-rest-arimaa
+ jar
+
+
+ org.evomaster
+ evomaster-benchmark-jdk21-em-embedded-rest
+ 4.3.1-SNAPSHOT
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-dependencies
+ 4.0.5
+ pom
+ import
+
+
+
+
+
+
+
+ com.example
+ arimaa-backend
+ 0.0.1-SNAPSHOT
+
+
+
+ org.testcontainers
+ testcontainers
+ compile
+
+
+
+ com.mysql
+ mysql-connector-j
+
+
+
+ org.mongodb
+ mongodb-driver-sync
+ 5.6.4
+
+
+ org.neo4j.driver
+ neo4j-java-driver
+ 6.0.3
+
+
+
+
diff --git a/jdk_21_maven/em/embedded/rest/arimaa/src/main/java/em/embedded/com/example/arimaabackend/EmbeddedEvoMasterController.java b/jdk_21_maven/em/embedded/rest/arimaa/src/main/java/em/embedded/com/example/arimaabackend/EmbeddedEvoMasterController.java
new file mode 100644
index 000000000..c37b4da1e
--- /dev/null
+++ b/jdk_21_maven/em/embedded/rest/arimaa/src/main/java/em/embedded/com/example/arimaabackend/EmbeddedEvoMasterController.java
@@ -0,0 +1,371 @@
+package em.embedded.com.example.arimaabackend;
+
+import com.example.arimaabackend.ArimaaBackendApplication;
+import org.evomaster.client.java.controller.EmbeddedSutController;
+import org.evomaster.client.java.controller.InstrumentedSutStarter;
+import org.evomaster.client.java.controller.api.dto.auth.AuthenticationDto;
+import org.evomaster.client.java.controller.api.dto.SutInfoDto;
+import org.evomaster.client.java.controller.api.dto.database.schema.DatabaseType;
+import org.evomaster.client.java.sql.DbSpecification;
+import org.evomaster.client.java.controller.problem.ProblemInfo;
+import org.evomaster.client.java.controller.problem.RestProblem;
+import com.webfuzzing.commons.auth.Header;
+import com.mongodb.client.MongoClient;
+import com.mongodb.client.MongoClients;
+import com.mongodb.client.MongoDatabase;
+import org.bson.Document;
+import org.neo4j.driver.Driver;
+import org.neo4j.driver.GraphDatabase;
+import org.neo4j.driver.Session;
+import org.neo4j.driver.AuthTokens;
+import org.springframework.boot.SpringApplication;
+import org.springframework.context.ConfigurableApplicationContext;
+import org.testcontainers.containers.GenericContainer;
+import org.testcontainers.containers.wait.strategy.Wait;
+import org.testcontainers.utility.MountableFile;
+
+import java.io.File;
+import java.nio.charset.StandardCharsets;
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.time.Duration;
+import java.util.ArrayList;
+import java.util.Base64;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Class used to start/stop the SUT.
+ */
+public class EmbeddedEvoMasterController extends EmbeddedSutController {
+
+ private static final String MYSQL_IMAGE = "mysql:9.5.0";
+
+ private static final int MYSQL_PORT = 3306;
+
+ private static final String MYSQL_DATABASE = "arimaadockermysqldb";
+
+ private static final String MYSQL_APP_USER = "admin";
+
+ private static final String MYSQL_APP_PASSWORD = "AdminPassword123!";
+
+ private static final String MYSQL_ROOT_PASSWORD = "wfdRootPass123!";
+
+ private static final String MONGODB_IMAGE = "mongo:7";
+
+ private static final int MONGODB_PORT = 27017;
+
+ private static final String MONGODB_DATABASE = "arimaadb";
+
+ private static final String NEO4J_IMAGE = "neo4j:5.26";
+
+ private static final int NEO4J_BOLT_PORT = 7687;
+
+ private static final String NEO4J_USERNAME = "neo4j";
+
+ private static final String NEO4J_PASSWORD = "wfdNeo4jPass123";
+
+ // Two known-credential ADMIN accounts (see Database/mysql/Sql_arimaa_62b_default_user.sql)
+ private static final String INIT_SQL =
+ "INSERT IGNORE INTO Users (username, email, password, role, created_at, updated_at) VALUES "
+ + "('admin1', 'admin1@example.com', '$2a$10$a7Dii8pcWQMclYxLt9Kb1eWpbRNbAPTsMRlJkm7ZT.wYIemq4oiBi', 'ADMIN', NOW(), NOW()), "
+ + "('user1', 'user1@example.com', '$2a$10$DK1T8LJLPBcPLWhm7i/L1esnux0b7mV0HjMbB02CL794blj0M0lYG', 'USER', NOW(), NOW()), "
+ + "('wfd_admin1', 'wfd_admin1@example.com', '$2a$10$3mawxiylgOPZOvvJO24bxeuUcQyQf.n53SzzAX9fBNiT7bfzZn4WO', 'ADMIN', NOW(), NOW()), "
+ + "('wfd_admin2', 'wfd_admin2@example.com', '$2a$10$8h.Zwu6RHMf0VZsEIZ2rcewbF4CU/nLpzoSSPjE1M1D.nof/9ZQVy', 'ADMIN', NOW(), NOW());";
+
+ private static final GenericContainer mysql = new GenericContainer(MYSQL_IMAGE)
+ .withEnv("MYSQL_DATABASE", MYSQL_DATABASE)
+ .withEnv("MYSQL_ROOT_PASSWORD", MYSQL_ROOT_PASSWORD)
+ .withCopyFileToContainer(MountableFile.forHostPath("cs/rest/arimaa/Database/mysql"), "/docker-entrypoint-initdb.d")
+ .withExposedPorts(MYSQL_PORT)
+ // First "ready for connections" is the temporary bootstrap server that runs the
+ // initdb.d scripts; the second is the real server, only up once they have finished.
+ .waitingFor(Wait.forLogMessage(".*ready for connections.*", 2))
+ .withStartupTimeout(Duration.ofMinutes(3));
+
+ private static final GenericContainer mongodb = new GenericContainer(MONGODB_IMAGE)
+ .withExposedPorts(MONGODB_PORT);
+
+ private static final GenericContainer neo4j = new GenericContainer(NEO4J_IMAGE)
+ .withEnv("NEO4J_AUTH", NEO4J_USERNAME + "/" + NEO4J_PASSWORD)
+ .withExposedPorts(NEO4J_BOLT_PORT)
+ .waitingFor(Wait.forLogMessage(".*Started.*", 1))
+ .withStartupTimeout(Duration.ofMinutes(2));
+
+ public static void main(String[] args) {
+
+ int port = 40100;
+ if (args.length > 0) {
+ port = Integer.parseInt(args[0]);
+ }
+
+ EmbeddedEvoMasterController controller = new EmbeddedEvoMasterController(port);
+ InstrumentedSutStarter starter = new InstrumentedSutStarter(controller);
+
+ starter.start();
+ }
+
+
+ private ConfigurableApplicationContext ctx;
+
+ private Connection sqlConnection;
+
+ private MongoClient mongoClient;
+
+ private Driver neo4jDriver;
+
+ // Snapshot taken right after migration; resetStateOfSUT() wipes and replays it
+ private Map> mongoSnapshot;
+
+ // Of the Neo4j data, only :User nodes (and the (:Player)-[:HAS_USER]->(:User) edges to them)
+ // are ever mutated through the API - Match/Player/Move/... are read-only, so only User needs
+ // resetting; that also keeps the reset itself fast (the full graph has ~11k nodes).
+ private List