Skip to content

ls1intum/Ares2

Repository files navigation

Ares2

The Artemis Java Test Sandbox

Java CI Maven Central Sonatype Nexus (Snapshots)

Ares 2 is a framework for easy and secure remote execution of student submissions on the interactive learning platform. It is the second Java-based implementation of the Secure COder Remote Execution (SCORE) framework and the first one supporting Java 17 and later versions.

Its main features are:

  • policy-based sandboxing (static analysis + runtime instrumentation) to prevent unsafe operations and reduce cheating

  • more robust tests and builds due to limits on time, threads and io

  • support for public and hidden Artemis tests, where hidden ones obey a custom deadline

  • utilities for improved feedback in Artemis like processing multiline error messages or pointing to a possible location that caused an Exception

  • utilities to test exercises using System.out and System.in comfortably

Project Status

Quality Gate Status Maintainability Rating Security Rating Reliability Rating

Lines of Code Coverage Technical Debt Vulnerabilities Bugs Duplicated Lines (%)

1. Installation

Note: Ares2 requires at least Java 17.

Ares2 is provided as Maven/Gradle dependency. To use Ares2 in the test environment of a Maven project, include

<dependency>
    <groupId>de.tum.cit.ase</groupId>
    <artifactId>ares</artifactId>
    <version>2.0.1-Beta6</version>
</dependency>

in the dependencies section.

For Gradle projects, include

implementation("de.tum.cit.ase:ares:2.0.1-Beta6")

in the dependencies section.

You can remove explicit JUnit 5 dependencies because Ares2 already includes them. Keep or add AssertJ and Hamcrest if your tests use them. If you want to use jqwik (>= 1.2.4) or JUnit 4 (via the JUnit 5 vintage engine), include them in the dependencies section.

2. Basic Usage

Ares2 provides a high level of security, which comes at the cost of usability. Several steps need to be taken in order to make tests work properly, and it might require some time to understand what Ares2 does. Please study at least this complete basic usage guide before using Ares2 in production.

2.1. Setup

Assume you have a Java 17 Maven project, and the inside of pom.xml looks like this:

<properties>
    <maven.compiler.source>17</maven.compiler.source>
    <maven.compiler.target>17</maven.compiler.target>
</properties>

<dependencies>
    <dependency>
        <groupId>de.tum.cit.ase</groupId>
        <artifactId>ares</artifactId>
        <version>2.0.1-Beta6</version>
    </dependency>
</dependencies>

Consider the following student class that needs to be tested:

import java.util.Objects;

public final class Penguin {

    private final String name;

    public Penguin(String name) {
        this.name = Objects.requireNonNull(name, "name must not be null");
    }

    public String getName() {
        return name;
    }
}

And you have already written the following simple JUnit 5 test class:

import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.Test;

public class PenguinTest {

    @Test
    void testPenguinPublic() {
        Penguin pingu = new Penguin("Julian");
        assertEquals("Julian", pingu.getName(), "getName() does not return the name supplied to the contructor");
    }

    @Test
    void testPenguinHidden() {
        assertThrows(NullPointerException.class, () -> new Penguin(null));
    }
}

In this example,

  • testPenguinPublic() is supposed to be executed after each push and directly give the students their feedback, while

  • testPenguinHidden() should be executed only after the exercise deadline, and the results should not be visible before the deadline.

While Artemis has a feature to mark test cases as hidden, this will not prevent the contents of the test case leaking through static variables, files and similar, be it accidentally or on purpose. To prevent that, the hidden test case must not be executed before the deadline at all.

The public test case does not need to be hidden, as its purpose is to give direct feedback. However, there are still multiple possible problems like crashing the Maven build by System.exit(0) or containing an endless loop. Both can have a negative impact on the interactive learning experience because the students get confronted with an incomprehensible log of a failed build. Such errors can be explained, but that takes a lot of time, especially if it happens a lot (and it will, if the number of students is sufficiently large).

It is also a security concern again, students could try to read the .java files containing the test classes.

2.2. Integrating Ares2

Therefore, we will use Ares2 to secure the tests and avoid unintelligible feedback. The most basic way to do this is by using the @Public and @Hidden annotations:

import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.Test;

// IMPORTANT: make sure to use the "jupiter" ones (if you are not using jqwik)
import de.tum.cit.ase.ares.api.jupiter.Hidden;
import de.tum.cit.ase.ares.api.jupiter.Public;

// This example won't work just like that, see below why
public class PenguinTest {

    @Public
    @Test
    void testPenguinPublic() {
        Penguin pingu = new Penguin("Julian");
        assertEquals("Julian", pingu.getName(), "getName() does not return the name supplied to the contructor");
    }

    @Hidden
    @Test
    void testPenguinHidden() {
        assertThrows(NullPointerException.class, () -> new Penguin(null));
    }
}

2.3. Additional Ares2 Test Annotations

Besides using @Public and @Hidden together with JUnit’s @Test, Ares2 also provides two combined annotations: @PublicTest and @HiddenTest. These include the JUnit @Test annotation internally and therefore offer a shorter method-level notation. In other words, @PublicTest corresponds to using @Public and @Test together, and the same applies to @HiddenTest.

import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.Test;

// IMPORTANT: make sure to use the "jupiter" ones (if you are not using jqwik)
import de.tum.cit.ase.ares.api.jupiter.Hidden;
import de.tum.cit.ase.ares.api.jupiter.Public;

// This example won't work just like that, see below why
public class PenguinTest {

    @PublicTest
    void testPenguinPublic() {
        Penguin pingu = new Penguin("Julian");
        assertEquals("Julian", pingu.getName(), "getName() does not return the name supplied to the contructor");
    }

    @HiddenTest
    void testPenguinHidden() {
        assertThrows(NullPointerException.class, () -> new Penguin(null));
    }
}

These combined annotations are functionally equivalent and can be used when a more concise syntax is preferred.

However, note that hidden tests require a deadline to be specified. If a test method is marked as @Hidden (or @HiddenTest) and no deadline is provided on the class or the method itself, JUnit will report an error such as: java.lang.annotation.AnnotationFormatError: cannot find a deadline for hidden test testPenguinHidden()

Ares2 needs to know what the deadline is. We tell Ares2 with another annotation:

// Format must be ISO_LOCAL_DATE(T| )ISO_LOCAL_TIME( ZONE_ID)?
@Deadline("2020-06-09 03:14 Europe/Berlin")
public class PenguinTest {
    // ...
}

That annotation (like most of the Ares2 annotations) can also be placed on the test method (and nested classes), if multiple are present, the one that is closest to the test case is used.

Now, it already works! Try to play around with the deadline in the annotation. If the given LocalDateTime lies in the past, the test case is executed and - together with the student code presented earlier - passes. If the deadline hasn’t passed, the test case won’t pass either. It fails with org.opentest4j.AssertionFailedError: hidden tests will be executed after the deadline. and the test was not executed, as the deadline is always checked before any hidden test case is executed.

You might have noticed that we specify the time zone as well. Although the annotation parser permits leaving it unspecified, this bears the risk of (not) executing the tests at the correct time if the build agent’s time zone is different from the one on your machine or what you would expect it to be. If you run tests where the time zone is/was not set, Ares2 will warn you about that in the logs.

2.4. What about Security?

2.4.1. Advanced Blocking and Security Policies with AOP, AspectJ, Instrumentation, and Architecture Testing

In addition to its standard security features, Ares2 now supports advanced blocking mechanisms using AspectJ, AOP (Aspect-Oriented Programming), Instrumentation, and Architecture Tests. These tools provide fine-grained control over student submissions, allowing testers to block specific actions like filesystem access, networking, and thread management through customizable policies defined in YAML files. Moreover, architecture-based tests enforce structural constraints on student code.

Our goal is to prevent unauthorized access to key system resources, such as:

  • Filesystem operations (read, create, overwrite, execute, delete)

  • Networking

  • Thread creation and management

  • Command Execution

  • Usage of unsupported or dangerous methods

To make this possible, Ares2 provides two complementary “compile modes” that determine when these transformations are applied: precompile and postcompile.

2.4.2. Precompile

Precompile mode generates security test cases and infrastructure files before the student code is compiled or executed. Based on your security configuration file, Ares2 automatically creates:

  • Architecture test cases using ArchUnit or WALA

  • AOP configuration files for AspectJ or Instrumentation

  • Build system modifications (Maven/Gradle plugins and dependencies)

  • Test infrastructure for enforcing security policies

This mode is executed once during exercise setup and produces test files that are committed to the repository. When students submit their code, these pre-generated tests run automatically to enforce the security policy.

Key advantages:

  • Tests are versioned and can be reviewed before deployment

  • No runtime configuration parsing overhead

  • Clear separation between policy definition and enforcement

  • Exercise creators can validate generated tests before release

2.4.3. Postcompile

Postcompile mode enforces security policies at runtime by instrumenting the compiled bytecode during test execution. When a test is annotated with @Policy, Ares2:

  • Loads the security configuration file

  • Instruments student code using Java agents (Byte Buddy)

  • Intercepts method calls to protected resources (files, network, threads, commands)

  • Validates each operation against the policy and blocks unauthorized access

This mode activates dynamically when tests run and provides immediate, fine-grained control over student code execution without requiring pre-generated test files.

Key advantages:

  • Dynamic enforcement at runtime

  • No repository modifications needed

  • Easy policy updates without regenerating tests

  • Fine-grained control over individual test cases

  • Detailed security violation messages

Both modes work together:
Ares2 provides both steps to achieve strong isolation and predictable, student-friendly feedback.

Before discussing these modes, we first introduce the configuration file that defines the sandboxing policy used by both phases.

2.4.4. Configuration Overview (security-policy.yaml)

Ares2 security enforcement is driven by a central configuration file. This file defines how the supervised program is built, analyzed, and instrumented, as well as which resources and operations are permitted at runtime.

Both precompile and postcompile mode rely on this configuration.

You can create this configuration file either manually or by using Ares2UI (Link: https://github.com/ls1intum/Ares2UI).

1. Example configuration (security-policy.yaml)

Below is an illustrative configuration example:

This configuration file contains two main sections:
(1) metadata describing the supervised code, and
(2) resource access rules that define the sandbox policy.

regardingTheSupervisedCode:
  theFollowingProgrammingLanguageConfigurationIsUsed: JAVA_USING_MAVEN_WALA_AND_ASPECTJ
  theSupervisedCodeUsesTheFollowingPackage: "de.tum.cit.ase.aresUI"
  theMainClassInsideThisPackageIs: "Main"

  theFollowingClassesAreTestClasses:
    - "de.tum.cit.ase.example.ExampleTest"

  theFollowingResourceAccessesArePermitted:

    regardingFileSystemInteractions:
      - onThisPathAndAllPathsBelow: "pom.xml"
        readAllFiles: true
        overwriteAllFiles: true
        createAllFiles: true
        executeAllFiles: true
        deleteAllFiles: false

    regardingNetworkConnections:
      - onTheHost: "www.example.com"
        onThePort: 80
        openConnections: true
        sendData: true
        receiveData: true

    regardingCommandExecutions:
      - executeTheCommand: "ls"
        withTheseArguments:
          - "-l"

    regardingThreadCreations:
      - createTheFollowingNumberOfThreads: 10
        ofThisClass: "instrumentation.lang.Thread"

    regardingPackageImports:
      - importTheFollowingPackage: "instrumentation.util"

    regardingTimeouts:
      - timeout: 120

The most relevant fields in this configuration file are:

  • theFollowingProgrammingLanguageConfigurationIsUsed Selects the processing pipeline (build system, static analysis tool, and instrumentation backend). The available configurations are described in detail in the next section.

  • theSupervisedCodeUsesTheFollowingPackage The root package containing all student code to be supervised.

  • theMainClassInsideThisPackageIs The entrypoint class used to construct the call graph of the student program.

  • theFollowingClassesAreTestClasses Test classes that execute student code. These classes are trusted and not sandboxed.

  • regardingFileSystemInteractions Declares which paths the student code may interact with and what operations (read, create, overwrite, execute, delete) are allowed.

  • regardingNetworkConnections Allows the student program to open connections to specific hosts and ports.

  • regardingCommandExecutions Whitelists system commands that the supervised program may execute.

  • regardingThreadCreations Specifies thread creation limits and allowed thread classes.

  • regardingPackageImports Whitelists external packages that the supervised code is permitted to import.

  • regardingTimeouts Defines time limits for supervised code execution.

2. Supported programming language configurations

Ares2 currently supports eight Java-based configurations, formed by combining three orthogonal dimensions:

  1. Build system

    • Maven

    • Gradle

  2. Static analysis and structural validation

    • ArchUnit: Validates the architectural structure of the supervised codebase and ensures that forbidden packages, imports, and dependencies cannot be referenced.

    • WALA: Performs static call-graph and data-flow analysis to detect disallowed code paths before execution.

  3. Runtime instrumentation backend

    • AspectJ: Use aspect-oriented programming to intercept method calls at runtime and block access to specified operations.

    • Instrumentation API: Use a Java agent (Byte Buddy) to instrument bytecode at runtime and block access to specified operations.

The resulting configuration matrix contains the following eight modes:

  • JAVA_USING_MAVEN_ARCHUNIT_AND_ASPECTJ

  • JAVA_USING_MAVEN_ARCHUNIT_AND_INSTRUMENTATION

  • JAVA_USING_MAVEN_WALA_AND_ASPECTJ

  • JAVA_USING_MAVEN_WALA_AND_INSTRUMENTATION

  • JAVA_USING_GRADLE_ARCHUNIT_AND_ASPECTJ

  • JAVA_USING_GRADLE_ARCHUNIT_AND_INSTRUMENTATION

  • JAVA_USING_GRADLE_WALA_AND_ASPECTJ

  • JAVA_USING_GRADLE_WALA_AND_INSTRUMENTATION

Each mode determines:

  • how the submission is statically analyzed (ArchUnit vs. WALA),

  • how the project is built (Maven vs. Gradle), and

  • how the bytecode is instrumented at runtime (AspectJ vs. Java agent).

This field must be set correctly, as it controls the entire supervision pipeline and is required for both precompile and postcompile mode.

2.4.5. How to integrate Precompile mode

To make use of these protections in practice, we now show how precompile mode is integrated using a concrete example.

Consider the following student implementation. The method attempts to write to a file secret.txt inside getName():

public String getName() {
    try {
        BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter("secret.txt"));
        bufferedWriter.write("First Line");
        bufferedWriter.close();
    } catch (IOException e) {
        throw new RuntimeException(e);
    }
    return name;
}

In a secure testing environment, this behaviour must be blocked by Ares2. To activate this protection for a specific test, the integration consists of three simple steps:

1. Define a security-policy.yaml

A security policy must be provided for the precompile phase. The policy file does not have to be stored inside the student project and is typically maintained separately by instructors or test authors.

For illustration purposes only, the following example assumes that the security-policy.yaml file is placed in the project root:

The security policy can either be authored manually as a YAML file or created using Ares2UI(Link: https://github.com/ls1intum/Ares2UI), which provides a graphical editor with guided configuration and validation.

Both approaches result in the same security-policy.yaml file, which is used as input for the precompile phase.

example_project/
├── src/
│   ├── main/
│   │   └── java/
│   │       └── org/example/
│   │           ├── Main.java
│   │           └── Penguin.java
│   ├── test/
│   │   └── java/
│   │       └── org/example/
│   │           └── PenguinTest.java
├── build.gradle
├── pom.xml
├── secret.txt
├── something.txt
└── security-policy.yaml   ← example location

With the following minimal configuration file, virtually all actions are denied by default, providing a strict precompile sandbox for the sample test:

regardingTheSupervisedCode:
  theFollowingProgrammingLanguageConfigurationIsUsed: JAVA_USING_GRADLE_ARCHUNIT_AND_INSTRUMENTATION
  theSupervisedCodeUsesTheFollowingPackage: "org.example"
  theMainClassInsideThisPackageIs: "Main"
  theFollowingClassesAreTestClasses:
    - "org.example.PenguinTest"
  theFollowingResourceAccessesArePermitted:
    regardingFileSystemInteractions:
      - onThisPathAndAllPathsBelow: "something.txt"
        readAllFiles: true
        overwriteAllFiles: true
        createAllFiles: true
        executeAllFiles: true
        deleteAllFiles: true
    regardingNetworkConnections: [ ]
    regardingCommandExecutions: [ ]
    regardingThreadCreations: [ ]
    regardingPackageImports: [ ]
    regardingTimeouts: [ ]

This configuration explicitly permits file-system operations only on something.txt. All other paths—including secret.txt—are not listed here and are therefore fully denied by the sandbox. Any attempt by student code to read, create, overwrite, or delete secret.txt will be intercepted and blocked during postcompile execution.

If you are interested, you may try modifying the sample code to perform file operations on something.txt instead; these operations will succeed, whereas accesses to secret.txt will correctly trigger a security exception.

Once the security policy has been defined, the precompile phase can be executed using one of the following approaches:

  • Ares2UI (Link: https://github.com/ls1intum/Ares2UI), which provides an interactive environment to load a student project, create or import a security policy, and execute the precompile phase in a guided manner.

  • The Ares2 command-line runner, which enables manual execution of the precompile phase by invoking the entrypoint located at src/main/java/de/tum/cit/ase/ares/api/Main.java.

In the following sections, we explain both approaches in detail.

2. Running Precompile Mode via the Ares UI

Ares2UI provides an interactive way to execute the precompile phase without manually invoking the command-line runner.

The precompile workflow in Ares2UI consists of the following steps:

Select Project Directory

Choose the root directory of the student project that should be processed in precompile mode. For the example project shown above, this corresponds to selecting the example_project/ directory.

Select or Create a Security Policy

If a security-policy.yaml file already exists, it can be selected and loaded. Alternatively, a new security policy can be created using the built-in policy editor by clicking the Create Policy button.

Execute Precompile Phase

By clicking the Create Files button, Ares2UI executes the precompile phase and generates the required enforcement artifacts inside the selected project.

3. Running Precompile Mode via the Main Class

Before running the precompile phase manually, open the Main class in the Ares2 repository: src/main/java/de/tum/cit/ase/ares/api/Main.java.

Fill in the three required paths:

  • the path to your SecurityConfiguration.yaml

  • the path to the project that should be precompiled

  • the src/test/java directory inside that project

public class Main {
    public static void main(String[] args) {
        SecurityPolicyReaderAndDirector securityPolicyReaderAndDirector =
            new SecurityPolicyReaderAndDirector(
                // Path to your SecurityConfiguration.yaml
                Path.of("<path-to-your-SecurityConfiguration.yaml>"),

                // Path to the project you want to test (the student's project)
                // (e.g., the example_project/ directory shown above)
                Path.of("<path-to-student-project>")
            ).createTestCases();

        // Path to the test/java directory inside the same project
        securityPolicyReaderAndDirector.writeTestCases(
            Path.of("<path-to-student-project>/src/test/java")
        );
    }
}

Once these paths are set, simply run the Main class. Ares2 will interpret your SecurityConfiguration.yaml, generate the corresponding enforcement rules, and write them into the target project, completing the precompile integration.

4. Resulting Project Structure After Precompile

After the precompile phase has been executed—regardless of whether it was initiated via Ares2UI or the command-line runner—the project directory contains additional generated files required for enforcement during postcompile execution.

example_project/
├── src/
│   ├── main/
│   │   └── java/
│   │       └── org/example/
│   │           ├── Main.java
│   │           └── Penguin.java
│   ├── resources/
│   ├── test/
│   │   └── java/
│   │       └── org/example/
│   │           ├── PenguinTest.java
│   │           ├── ares/api/
│   │           └── META-INF/
├── build.gradle
├── pom.xml
├── secret.txt
├── something.txt
└── security-policy.yaml   ← example location

The generated de/tum/cit/aet/ directory contains Ares2-specific helper code, instrumentation logic, and metadata required during test execution. These files are generated automatically during the precompile phase and must not be modified manually.

5. Configure Gradle and Verify Enforcement

After the precompile phase, the generated enforcement artifacts are placed into the project’s test scope (e.g., under src/test/java/). To activate the instrumentation during test execution, the project must be configured to build the required agent JARs and to run tests with the corresponding JVM arguments.

5.1 Update build.gradle

Add or update the following Gradle configuration in your project’s build.gradle. It configures the required dependencies, builds the instrumentation JARs, and ensures that test runs with the Java agent and bootstrap append path:

The following Gradle configuration assumes that the student project uses the Java package org.example as shown in the example project structure above. If a different base package is used, all occurrences of org/example in the configuration must be adapted accordingly.

plugins {
    id 'java'
    id 'application'
}

group = 'de.tum.cit.aet'
version = '1.0-SNAPSHOT'

java {
    toolchain {
        languageVersion = JavaLanguageVersion.of(25)
    }
}

ext {
    ver = [
            junit                : '6.0.0',
            junitPlatformLauncher: '6.0.0',
            bytebuddy            : '1.17.7',
            aspectj              : '1.9.24',
            archunit             : '1.4.1',
            wala                 : '1.6.12',
            jacksonYaml          : '2.20.0',
            guava                : '31.1-jre',
            jsr305               : '3.0.2',
            opencsv              : '5.12.0'
    ]
}

repositories {
    mavenLocal()
    mavenCentral()
}

dependencies {
    testImplementation "net.bytebuddy:byte-buddy:${ver.bytebuddy}"
    testImplementation "org.junit.jupiter:junit-jupiter:${ver.junit}"
    testImplementation "org.junit.platform:junit-platform-launcher:${ver.junitPlatformLauncher}"
    testImplementation "com.google.code.findbugs:jsr305:${ver.jsr305}"
    testImplementation "com.google.guava:guava:${ver.guava}"
    testImplementation "com.opencsv:opencsv:${ver.opencsv}"
    testImplementation "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:${ver.jacksonYaml}"
    testImplementation "com.tngtech.archunit:archunit-junit5:${ver.archunit}"
    testImplementation "com.ibm.wala:com.ibm.wala.core:${ver.wala}"
    testImplementation "org.aspectj:aspectjrt:${ver.aspectj}"
    testImplementation 'io.vavr:vavr:0.10.4'
}

application {
    mainClass = 'org/example.Main'
}

test {
    //maxParallelForks = 1
    useJUnitPlatform()
    dependsOn 'javaagentJar', 'xbootclasspathJar'
    doFirst {
        def agentFile = tasks.named('javaagentJar').get().archiveFile.get().asFile
        def bootFile = tasks.named('xbootclasspathJar').get().archiveFile.get().asFile

        // Collect full Byte Buddy (and agent) jars to put on bootstrap append path
        def byteBuddyJars = configurations.testRuntimeClasspath.files.findAll { it.name.startsWith('byte-buddy') }*.absolutePath
        // Collect opentest4j jars to place on bootstrap append path as requested
        def opentest4jJars = configurations.testRuntimeClasspath.files.findAll { it.name.contains('opentest4j') }*.absolutePath
        // Collect ArchUnit jars to also place on bootstrap append path
        def archUnitJars = configurations.testRuntimeClasspath.files.findAll { it.name.startsWith('archunit') }*.absolutePath
        // Collect JUnit (org.junit.*) jars to place on bootstrap append path
        def junitJars = configurations.testRuntimeClasspath.files.findAll { it.name.startsWith('junit-') || it.name.startsWith('junit-platform-') }*.absolutePath
        // Collect SLF4J (org.slf4j.*) jars to place on bootstrap append path
        def slf4jJars = configurations.testRuntimeClasspath.files.findAll { it.name.contains('slf4j') }*.absolutePath
        // Collect OpenCSV (com.opencsv.*) jars to place on bootstrap append path
        def openCsvJars = configurations.testRuntimeClasspath.files.findAll { it.name.startsWith('opencsv-') || it.name.contains('opencsv') }*.absolutePath
        // Avoid duplicates if already present
        def bootAppendEntries = ([bootFile.absolutePath] + byteBuddyJars + opentest4jJars + archUnitJars + junitJars + slf4jJars + openCsvJars).unique()
        def bootAppend = bootAppendEntries.join(File.pathSeparator)

        // Clear any previous -Xbootclasspath/a we might have added on incremental runs
        def filtered = (jvmArgs ?: []).findAll { !it.startsWith('-Xbootclasspath/a:') && !it.startsWith('-javaagent:') }
        jvmArgs = filtered

        jvmArgs "-javaagent:${agentFile.absolutePath}"
        jvmArgs "-Xbootclasspath/a:${bootAppend}"
        jvmArgs "-Dinstrboot.jar.path=${bootFile.absolutePath}"
        jvmArgs '-Xshare:off'

        // Required opens for deep reflection/instrumentation
        jvmArgs '--add-opens', 'java.base/java.io=ALL-UNNAMED'
        jvmArgs '--add-opens', 'java.base/java.nio.file=ALL-UNNAMED'
        jvmArgs '--add-opens', 'java.base/java.lang=ALL-UNNAMED'
    }
}

tasks.register('copyTestTxtIntoClasses', Copy) {
    from('src/test/java') {
        include '**/*.txt'
    }
    into layout.buildDirectory.dir('classes/java/test')
}

tasks.register('javaagentJar', Jar) {
    archiveClassifier = 'agent'
    dependsOn 'testClasses'
    from(sourceSets.test.output) {
        include 'org/example/ares/api/aop/java/instrumentation/**'
        include '**/*$*.class'
    }
    manifest {
        from(file('src/test/java/org/example/META-INF/MANIFEST.MF'))
    }
}

tasks.register('xbootclasspathJar', Jar) {
    archiveClassifier = 'instrboot'
    dependsOn 'testClasses'
    from(sourceSets.test.output) {
        // Include all instrumentation advice classes
        include 'org/example/ares/api/aop/java/instrumentation/advice/**'
        // Include all instrumentation pointcut classes
        include 'org/example/ares/api/aop/java/instrumentation/pointcut/**'
        // Include the main AOP settings class
        include 'org/example/ares/api/aop/java/JavaAOPTestCaseSettings.class'
        // Include the Messages localization class
        include 'org/example/ares/api/localization/Messages.class'
        // Include utility classes that might be referenced
        include 'org/example/ares/api/util/FileTools.class'
        include 'org/example/ares/api/util/FileTools$*.class'
        include 'org/example/ares/api/util/LruCache.class'
        include 'org/example/ares/api/util/LruCache$*.class'
        include "org/example/ares/api/architecture/java/archunit/**"
        include "org/example/ares/api/policy/policySubComponents/**"
        include "org/example/ares/api/architecture/java/**"
        include "org/example/ares/api/architecture/**"
        // Include synthetic inner classes for any of the above
        include '**/*$*.class'
    }
}

tasks.named('build') { dependsOn 'javaagentJar', 'xbootclasspathJar' }
tasks.named('testClasses') { dependsOn 'copyTestTxtIntoClasses' }
5.2 Run the Tests

Run the test task as usual (e.g., ./gradlew test). During test execution, any policy violations are intercepted and result in a SecurityException.

For the example shown earlier (attempting to write secret.txt), the test run will fail with an exception similar to the following:

!security.advice.illegal.file.execution!
java.lang.SecurityException: !security.advice.illegal.file.execution!
    at org.example.ares.api.aop.java.instrumentation.advice.JavaInstrumentationAdviceFileSystemToolbox.checkFileSystemInteractionForAction(JavaInstrumentationAdviceFileSystemToolbox.java:538)
    at org.example.ares.api.aop.java.instrumentation.advice.JavaInstrumentationAdviceFileSystemToolbox.checkFileSystemInteraction(JavaInstrumentationAdviceFileSystemToolbox.java:597)
    ...

2.4.6. How to integrate Postcompile mode

To make use of these protections in practice, we now show how postcompile mode is integrated using a concrete example.

Consider the following student implementation. The method attempts to write to a file secret.txt inside getName():

public String getName() {
    try {
        BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter("secret.txt"));
        bufferedWriter.write("First Line");
        bufferedWriter.close();
    } catch (IOException e) {
        throw new RuntimeException(e);
    }
    return name;
}

In a secure testing environment, this behaviour must be blocked by Ares2’s runtime sandbox. Postcompile mode ensures this by instrumenting the compiled bytecode and intercepting all file-system operations performed by untrusted student code.

To activate this protection for a specific test, the integration consists of three simple steps:

1. Provide a SecurityConfiguration.yaml

You must include a security configuration file in your project. A common choice is to place it in the project’s main directory:

project/
├── src/
├── build.gradle
├── pom.xml
├── secret.txt
├── something.txt
└── SecurityConfiguration.yaml   ← placed here

With the following minimal configuration file, virtually all actions are denied by default, providing a strict postcompile sandbox for the sample test:

regardingTheSupervisedCode:
  theFollowingProgrammingLanguageConfigurationIsUsed: JAVA_USING_GRADLE_ARCHUNIT_AND_INSTRUMENTATION
  theSupervisedCodeUsesTheFollowingPackage: "org.example"
  theMainClassInsideThisPackageIs: "Main"
  theFollowingClassesAreTestClasses:
    - "org.example.PenguinTest"
  theFollowingResourceAccessesArePermitted:
    regardingFileSystemInteractions:
      - onThisPathAndAllPathsBelow: "something.txt"
        readAllFiles: true
        overwriteAllFiles: true
        createAllFiles: true
        executeAllFiles: true
        deleteAllFiles: true
    regardingNetworkConnections: [ ]
    regardingCommandExecutions: [ ]
    regardingThreadCreations: [ ]
    regardingPackageImports: [ ]
    regardingTimeouts: [ ]

This configuration explicitly permits file-system operations only on something.txt. All other paths—including secret.txt—are not listed here and are therefore fully denied by the sandbox. Any attempt by student code to read, create, overwrite, or delete secret.txt will be intercepted and blocked during postcompile execution.

If you are interested, you may try modifying the sample code to perform file operations on something.txt instead; these operations will succeed, whereas accesses to secret.txt will correctly trigger a security exception.

2. Annotate the test with @Policy

Ares2 activates the sandbox for a given test only when the test method is annotated with @Policy. The annotation links the test to the configuration file and defines the part of the student project that should be supervised.

Example:

@Policy(
    value = "SecurityConfiguration.yaml",       // path to the configuration file
    withinPath = ""
)
@PublicTest
void testPenguinPublic() {
    Penguin pingu = new Penguin("Julian");
    assertEquals("Julian", pingu.getName(),
        "getName() does not return the name supplied to the constructor");
}

You will now with Ares2 get the following error message:

Ares Security Error (Reason: Student-Code; Stage: Execution): org.example.Penguin.getName tried to illegally overwrite File
/// target file location: secret.txt via java.io.FileOutputStream.write([B,int,int) but was blocked by Ares. ///
3. What you need to do outside Ares2

Sadly, due to the way classes are loaded and the class path works when testing student code with maven, there are still vulnerabilities if students manage to load classes that would be in trusted packages. This is especially problematic if they shadow library classes, such as JUnit’s Assertions.

To prevent that, you have to use the Maven Enforcer Plugin to make sure no student content lands in trusted packages:

Maven:

<properties>
        <studentOutputDir>${project.basedir}/build/classes/java/main</studentOutputDir>
        <ares.version>2.0.1-Beta6</ares.version>
        <agent.dir>${project.build.directory}/agents</agent.dir>
    </properties>

    <dependencies>
        <dependency>
            <groupId>de.tum.cit.ase</groupId>
            <artifactId>ares</artifactId>
            <version>${ares.version}</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

<build>
    <plugins>

        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-enforcer-plugin</artifactId>
            <version>3.1.0</version>
            <executions>
                <execution>
                    <id>enforce-no-student-code-in-trusted-packages</id>
                    <phase>process-classes</phase>
                    <goals><goal>enforce</goal></goals>
                    <configuration>
                        <rules>
                            <requireFilesDontExist>
                                <files>
                                <!--(1)-->

                                    <file>${studentOutputDir}/ch/qos/logback/</file>
                                    <file>${studentOutputDir}/com/github/javaparser/</file>
                                    <file>${studentOutputDir}/com/intellij/</file>
                                    <file>${studentOutputDir}/com/sun/</file>
                                    <file>${studentOutputDir}/de/tum/cit/ase/ares/api/</file>
                                    <file>${studentOutputDir}/java/</file>
                                    <file>${studentOutputDir}/javax/</file>
                                    <file>${studentOutputDir}/jdk/</file>
                                    <file>${studentOutputDir}/net/jqwik/</file>
                                    <file>${studentOutputDir}/org/assertj/</file>
                                    <file>${studentOutputDir}/org/apache/</file>
                                    <file>${studentOutputDir}/org/eclipse/</file>
                                    <file>${studentOutputDir}/org/gradle/</file>
                                    <file>${studentOutputDir}/org/jacoco/</file>
                                    <file>${studentOutputDir}/org/json/</file>
                                    <file>${studentOutputDir}/org/junit/</file>
                                    <file>${studentOutputDir}/org/opentest4j/</file>
                                    <file>${studentOutputDir}/sun/</file>
                                    <file>${studentOutputDir}/worker/org/gradle/</file>
                                </files>
                            </requireFilesDontExist>
                        </rules>
                    </configuration>
                </execution>
            </executions>
        </plugin>

        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-dependency-plugin</artifactId>
            <version>3.6.1</version>
            <executions>
                <execution>
                    <id>unpack-ares</id>
                    <phase>generate-resources</phase>
                    <goals><goal>unpack</goal></goals>
                    <configuration>
                        <artifactItems>
                            <artifactItem>
                                <groupId>de.tum.cit.ase</groupId>
                                <artifactId>ares</artifactId>
                                <version>${ares.version}</version>
                                <outputDirectory>${agent.dir}/unpacked</outputDirectory>
                            </artifactItem>
                        </artifactItems>
                    </configuration>
                </execution>
            </executions>
        </plugin>

        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-jar-plugin</artifactId>
            <version>3.4.2</version>
            <executions>
                <execution>
                    <id>build-ares-agent-jar</id>
                    <phase>test-compile</phase>
                    <goals><goal>jar</goal></goals>
                    <configuration>
                        <classesDirectory>${agent.dir}/unpacked</classesDirectory>
                        <finalName>ares-agent</finalName>
                        <outputDirectory>${agent.dir}</outputDirectory>
                        <archive>
                            <manifestEntries>
                                <Premain-Class>de.tum.cit.ase.ares.api.aop.java.instrumentation.JavaInstrumentationAgent</Premain-Class>
                                <Can-Redefine-Classes>true</Can-Redefine-Classes>
                                <Can-Retransform-Classes>true</Can-Retransform-Classes>
                                <Can-Set-Native-Method-Prefix>true</Can-Set-Native-Method-Prefix>
                            </manifestEntries>
                        </archive>
                    </configuration>
                </execution>
            </executions>
        </plugin>

        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-surefire-plugin</artifactId>
            <version>3.2.5</version>
            <configuration>
                <useSystemClassLoader>false</useSystemClassLoader>
                <argLine>
                    -javaagent:${agent.dir}/ares-agent.jar
                    --add-opens java.base/jdk.internal.misc=ALL-UNNAMED
                    --add-opens java.base/java.lang=ALL-UNNAMED
                </argLine>
                <systemPropertyVariables>
                    <file.encoding>UTF-8</file.encoding>
                </systemPropertyVariables>
            </configuration>
        </plugin>

    </plugins>
</build>

Gradle:

configurations {
    aresAgent
}

dependencies {
    aresAgent 'de.tum.cit.ase:ares:2.0.1-Beta6'
    testImplementation("de.tum.cit.ase:ares:2.0.1-Beta6")
}

def forbiddenPackageFolders = [
    // (1)
    "$studentOutputDir/ch/qos/logback/",
    "$studentOutputDir/com/github/javaparser/",
    "$studentOutputDir/com/intellij/",
    "$studentOutputDir/com/sun/",
    "$studentOutputDir/de/tum/cit/ase/ares/api/",
    "$studentOutputDir/java/",
    "$studentOutputDir/javax/",
    "$studentOutputDir/jdk/",
    "$studentOutputDir/net/jqwik/",
    "$studentOutputDir/org/assertj/",
    "$studentOutputDir/org/apache/",
    "$studentOutputDir/org/eclipse/",
    "$studentOutputDir/org/gradle/",
    "$studentOutputDir/org/jacoco/",
    "$studentOutputDir/org/json/",
    "$studentOutputDir/org/junit/",
    "$studentOutputDir/org/opentest4j/",
    "$studentOutputDir/sun/",
    "$studentOutputDir/worker/org/gradle/"
]
tasks.register('prepareInstrumentationAgentFiles', Copy) {
    dependsOn configurations.aresAgent
    description 'Extracts Ares agent from JAR for JVM injection'
    from configurations.aresAgent.filter { it.name.startsWith('ares-') }
    into layout.buildDirectory.dir("agents")
}

tasks.register('buildInstrumentationAgent', Jar) {
    dependsOn prepareInstrumentationAgentFiles
    description 'Builds a proper Java agent from the Ares JAR with correct manifest'
    archiveFileName = 'ares-agent.jar'
    destinationDirectory = layout.buildDirectory.dir("agents")
    from zipTree(layout.buildDirectory.file("agents/ares-2.0.1-Beta6.jar").get().asFile)
    manifest {
        attributes(
                'Manifest-Version': '1.0',
                'Premain-Class': 'de.tum.cit.ase.ares.api.aop.java.instrumentation.JavaInstrumentationAgent',
                'Can-Redefine-Classes': 'true',
                'Can-Retransform-Classes': 'true',
                'Can-Set-Native-Method-Prefix': 'true',
                'Boot-Class-Path': '',
                'Main-Class': 'de.tum.cit.ase.ares.api.aop.java.instrumentation.JavaInstrumentationAgent'
        )
    }
}

test {
    doFirst {
        for (String packageFolder in forbiddenPackageFolders) {
            assert !file(packageFolder).exists(): "$packageFolder must not exist within the submission."
        }
    }
    defaultCharacterEncoding = 'UTF-8'
    testLogging.showStandardStreams = true
    useJUnitPlatform()

    //<editor-fold desc="Instrumentation (1)">
    jvmArgs += [
            "-javaagent:${new File(buildDir, 'agents/ares-agent.jar').absolutePath}",
            "--add-opens", "java.base/jdk.internal.misc=ALL-UNNAMED",
            "--add-exports", "java.base/jdk.internal.misc=ALL-UNNAMED",
            "--add-opens", "java.base/java.lang=ALL-UNNAMED",
            "--add-exports", "java.base/java.lang=ALL-UNNAMED"
    ]

    dependsOn buildInstrumentationAgent
    //</editor-fold>
}
  1. This is where all folders/packages go that we don’t want to exist in student code. You will always find the most recent recommendation for Ares2 here. If you use additional third-party libraries that need to be configured using @AddTrustedPackage, you should add those packages here as well. Ares2 will check that all entries are present.
    If you don’t want Ares2 to do so, set the ares.maven.ignore or ares.gradle.ignore system property to true. In case you want Ares2 to look into a different file, you can set the ares.maven.pom or ares.gradle.build to a path other than the default pom.xml or build.gradle.

2.5. But what is whitelisted?

By default, Ares2 trusts certain core packages and classes that are necessary for the testing framework itself to function. The following packages are automatically whitelisted and excluded from security restrictions:

Core Java and JDK packages:

  • java.* - Core Java API classes

  • javax.* - Java extension APIs

  • jdk.* - JDK internal classes

  • sun.* - Sun/Oracle internal implementation classes

Testing frameworks:

  • org.junit.* - JUnit 5 and JUnit 4 (Vintage)

  • org.opentest4j.* - Open Test Alliance

  • net.jqwik.* - jqwik property-based testing

  • org.assertj.* - AssertJ assertion library

  • org.hamcrest.* - Hamcrest matchers

  • org.mockito.* - Mockito mocking framework

Ares2 framework:

  • de.tum.cit.ase.ares.api.* - All Ares2 classes

Build and analysis tools:

  • org.apache.* - Apache Commons and Maven

  • org.gradle.* - Gradle build system

  • org.eclipse.* - Eclipse compiler and tooling

  • com.intellij.* - IntelliJ IDEA integration

  • org.jacoco.* - JaCoCo code coverage

Static analysis and AOP:

  • com.tngtech.archunit.* - ArchUnit

  • com.ibm.wala.* - WALA call graph analysis

  • org.aspectj.* - AspectJ

  • net.bytebuddy.* - Byte Buddy instrumentation

Additional libraries:

  • ch.qos.logback.* - Logback logging

  • com.github.javaparser.* - JavaParser AST analysis

  • org.json.* - JSON parsing

You can extend the whitelist for your specific needs using annotations:

  • @AddTrustedPackage("com.example.library") - Trust an additional package

  • @WhitelistPackage("com.student.helpers") - Allow student code in specific package

  • @WhitelistClass("com.example.UtilityClass") - Allow specific class

Important: Student code should never be placed in trusted packages, as this would bypass all security restrictions. The enforcer plugin in your pom.xml or build.gradle prevents this.

2.6. Further Important Options

Are we done now? With the most fundamental parts yes, but there is a bit more you need to know about testing with Ares2, as this was just a very basic example with a single class and not much testing. Without further knowledge, you might not get Ares2 to work and consequently get rather annoyed or even enraged. To prevent that, please read on.

2.6.1. Path Access and Class Loading

Ares2 carefully controls which files and directories student code can access. Understanding path access rules is crucial for writing secure tests.

Default behavior:

  • Student code runs in a restricted sandbox

  • Access to most filesystem paths is blocked by default

  • Only explicitly whitelisted paths are accessible

  • Test classes run with elevated privileges (trusted)

Configuring path access:

Use the security configuration file to specify allowed paths:

regardingFileSystemInteractions:
  - onThisPathAndAllPathsBelow: "data/input.txt"
    readAllFiles: true
    overwriteAllFiles: false
    createAllFiles: false
    executeAllFiles: false
    deleteAllFiles: false

Or use annotations directly in test code:

@WhitelistPath(value = "data", type = PathType.DIRECTORY)
@WhitelistPath(value = "**/*.txt", type = PathType.GLOB)
@PublicTest
void testFileAccess() {
    // Student code can now read from data/ directory
}

Path types:

  • PathType.EXACT - Exact file/directory path

  • PathType.GLOB - Glob pattern (e.g., */.txt)

  • PathType.DIRECTORY - Directory and all contents

Blacklisting paths:

@BlacklistPath(value = "secret.txt")
@PublicTest
void testRestrictedAccess() {
    // Access to secret.txt will throw SecurityException
}

Class loading considerations:

  • Ares2 uses a custom class loader hierarchy to isolate student code

  • Test classes are loaded by the system class loader (trusted)

  • Student classes are loaded by a restricted class loader

  • This prevents students from shadowing trusted classes

  • The enforcer plugin validates that no student code exists in trusted packages

Best practices:

  • Keep whitelist as restrictive as possible

  • Use relative paths, not absolute paths

  • Whitelist only directories needed for the exercise

  • Test your path restrictions before releasing the exercise

  • Document which files students should create/modify

2.6.2. Testing the Exercise before Release

Hidden tests will be executed by Ares2 only after the deadline. This poses the problem, how the exercise creators should work on the tasks, tests and the sample solution. One possible solution would be to use an alternative deadline annotation or change the deadline temporarily. The problem is that it is quite likely one might forget to change it back again, and protecting the hidden tests would fail.

Use @ActivateHiddenBefore just like @Deadline to state the LocalDateTime before which hidden tests should be executed. This date should, of course, be before the release of the exercise on Artemis.

2.6.3. Extending a Deadline and Disability Compensation

You can use @ExtendedDeadline together with a duration like 1d or 2d 12h 30m to extend the deadline by the given amount. @ExtendedDeadline("1d"), for example, extends the deadline by one day. If you use the annotation on different levels (e.g. class and method) without stating a new deadline (e.g. deadline only on class level), the extensions will be added together.

2.6.4. Threads and Concurrency

Ares2 provides comprehensive control over thread creation and management to prevent students from:

  • Creating excessive threads that could impact system performance

  • Using threads to bypass time limits

  • Exploiting concurrency to circumvent security restrictions

  • Causing deadlocks or race conditions in the test environment

Controlling thread creation:

In your security configuration:

regardingThreadCreations:
  - createTheFollowingNumberOfThreads: 5
    ofThisClass: "java.lang.Thread"

Or using annotations:

@AllowThreads(maxActiveCount = 5)
@PublicTest
void testConcurrentCode() {
    // Student code can create up to 5 threads
}

Thread trust scopes:

Ares2 distinguishes between trusted and untrusted threads:

@TrustedThreads(TrustScope.MINIMAL)  // Only test threads trusted
@TrustedThreads(TrustScope.EXTENDED) // Test + whitelisted student threads

Handling concurrent tests:

@PublicTest
@AllowThreads(maxActiveCount = 10)
void testThreadPoolExecution() {
    ExecutorService executor = Executors.newFixedThreadPool(5);
    List<Future<String>> futures = new ArrayList<>();

    for (int i = 0; i < 10; i++) {
        futures.add(executor.submit(() -> studentCode.processTask()));
    }

    // All threads are monitored by Ares2
    executor.shutdown();
    executor.awaitTermination(10, TimeUnit.SECONDS);
}

Security considerations:

  • Threads created by student code inherit security restrictions

  • Each thread is monitored for resource access violations

  • Thread count limits prevent resource exhaustion

  • Uncaught exceptions in student threads are properly captured

  • Daemon threads are automatically stopped after test completion

Common issues:

  • Exceeded thread limit: Increase maxActiveCount or refactor student code

  • Threads not terminating: Use timeouts with @StrictTimeout

  • Race conditions: Consider using @RepeatedTest to detect flaky tests

2.6.5. Testing Console Interaction

One example showing some possibilities here:

void testSquareCorrect(IOTester tester) { //(1)
    tester.provideInputLines("5"); //(2)

    InputOutputPenguin.calculateSquare(); //(3)

    tester.err().assertThat().isEmpty(); //(4)
    tester.out().assertThat().isEqualTo("""
                Enter Number:
                Answer:
                25"""); //(5)
}
  1. Declare IOTester as parameter.

  2. Provide input lines before calling the student code. This content will be used for reading lines from System.in.

  3. Call the student code to process the input and produce output.

  4. Assert that nothing was printed to System.err.

  5. Assert that the standard output (in this case excluding the final line break) is equal to the given text block (if you use text blocks, be aware of their newline handling).

Note that Ares2 normalizes the line breaks to \n, and OutputTester offers many different approaches to checking output (e.g. single string, list of strings, …​).

If students read more lines than provided, they get the following feedback: …​ java.lang.IllegalStateException: no further console input request after the last(number 1: "5") expected. …​

See also IOTester and for more examples, the InputOutputUser test.

[showing-standard-output] covers how the student output is managed and shown in the test logs.

Tip

In case the default IOTester from Ares2 does not meet your requirements, you can provide a custom implementation by applying @WithIOManager(MyCustomOne.class) to e.g. the test class or individual methods. This also allows you to register a custom parameter to control IO testing with ease inside the test method. Have a look into the test class linked above to learn more or read the documentation of IOManager.

2.6.6. Networking

Ares2 controls all network operations to prevent students from:

  • Accessing external resources not required for the exercise

  • Exfiltrating data or test solutions

  • Performing denial-of-service attacks

  • Bypassing security through network-based exploits

Allowing network access:

In your security configuration:

regardingNetworkConnections:
  - onTheHost: "api.example.com"
    onThePort: 443
    openConnections: true
    sendData: true
    receiveData: true
  - onTheHost: "localhost"
    onThePort: 8080
    openConnections: true
    sendData: true
    receiveData: true

Or using annotations:

@AllowLocalPort(8080)
@PublicTest
void testHttpServer() {
    // Student code can connect to localhost:8080
}

Port ranges:

@AllowLocalPort(above = 8000, mode = PortMode.ABOVE)
@PublicTest
void testDynamicPorts() {
    // Allows all ports above 8000
}

Testing REST APIs:

@Policy("network-config.yaml")
@PublicTest
void testRestClient() {
    // Configuration allows api.example.com:443
    String response = studentCode.fetchData("https://api.example.com/data");
    assertThat(response).isNotEmpty();
}

Common patterns:

Testing a local HTTP server:

@AllowLocalPort(8080)
@PublicTest
void testWebServer() {
    studentCode.startServer(8080);
    HttpClient client = HttpClient.newHttpClient();
    HttpRequest request = HttpRequest.newBuilder()
        .uri(URI.create("http://localhost:8080/"))
        .build();
    HttpResponse<String> response = client.send(request,
        HttpResponse.BodyHandlers.ofString());
    assertEquals(200, response.statusCode());
}

Mocking external services:

@PublicTest
void testWithMockedService() {
    // Use WireMock or similar instead of real network access
    WireMockServer mockServer = new WireMockServer(8089);
    mockServer.start();
    // No @AllowLocalPort needed for test infrastructure
    mockServer.stop();
}

Security notes:

  • By default, all network access is blocked

  • DNS lookups are also controlled

  • Socket connections require explicit permission

  • Multicast and broadcast are blocked

  • Consider using mocks instead of real network access when possible

2.6.7. Locale

You can set a locale for Ares2 (and the rest of Java) by adding the @UseLocale JUnit extension to classes/methods, which will set the Java default locale via Locale.setDefault(Locale) that is also used by Ares2. The locale is changed only for the scope where the annotation is applied.

Ares2 is currently localized in German (de_DE) and English (en_US), where en_US is the fallback for any other locale.

See also the LocaleUser test for more examples.

2.7. GitHub Packages

GitHub Packages does currently not allow unregistered, public access to the packages. Therefore, you will need to authenticate to GitHub if you use GitHub Packages as a repository source.

Maven configuration:

Add the following to your pom.xml:

<repositories>
    <repository>
        <id>github</id>
        <name>GitHub ls1intum Apache Maven Packages</name>
        <url>https://maven.pkg.github.com/ls1intum/Ares2</url>
    </repository>
</repositories>

Then add authentication to your ~/.m2/settings.xml:

<settings>
    <servers>
        <server>
            <id>github</id>
            <username>YOUR_GITHUB_USERNAME</username>
            <password>YOUR_GITHUB_TOKEN</password>
        </server>
    </servers>
</settings>

Gradle configuration:

Add the following to your build.gradle:

repositories {
    maven {
        url = uri("https://maven.pkg.github.com/ls1intum/Ares2")
        credentials {
            username = project.findProperty("gpr.user") ?: System.getenv("GITHUB_USERNAME")
            password = project.findProperty("gpr.token") ?: System.getenv("GITHUB_TOKEN")
        }
    }
}

Generating a GitHub token:

  1. Go to GitHub Settings → Developer settings → Personal access tokens

  2. Generate a new token with read:packages scope

  3. Store the token securely in your settings

Note: Using Maven Central is recommended for most users as it does not require authentication:

<dependency>
    <groupId>de.tum.cit.ase</groupId>
    <artifactId>ares</artifactId>
    <version>2.0.1-Beta6</version>
</dependency>

3. License

Ares2 is licensed under the MIT License.

See LICENSE for details.

About

No description, website, or topics provided.

Resources

License

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Contributors