Skip to content

Fix dynamic-reflection and structural-discovery correctness issues found in the 2026-07-15 audit - #153

Open
LukaPetrovicTUM wants to merge 3 commits into
mainfrom
fix/ast/i-052-i-094-i099-structural-discovery-assertion-fixes
Open

Fix dynamic-reflection and structural-discovery correctness issues found in the 2026-07-15 audit#153
LukaPetrovicTUM wants to merge 3 commits into
mainfrom
fix/ast/i-052-i-094-i099-structural-discovery-assertion-fixes

Conversation

@LukaPetrovicTUM

@LukaPetrovicTUM LukaPetrovicTUM commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes four correctness issues from the 2026-07-15 audit (I-052, I-094, I-099, TD-043): two
reflection-validation bugs in the dynamic test-authoring API, a misconfigured Surefire test-container
class, and structural type-discovery/parameter-matching gaps that could fail correct submissions.

Linked issues

None. (Findings I-052, I-094, I-099 and TD-043 come from an internal 2026-07-15 audit report, not
GitHub issues.)

1. Problem

Four independent findings on one branch, each with its own cause. The original wording is kept in a comment below.

I-094, the dynamic reflection API. checkForPublicOrProtectedMethods matched the main
signature with endsWith rather than equals, so a public method whose signature was a suffix
of it was wrongly exempt. DynamicField.fieldsOf walked superclasses only, so it threw on an
interface and never saw superinterface fields.

I-099, structural discovery. ClassNameScanner took a file's one type from its filename,
so member and extra top-level types were undiscoverable, and checkParameters compared
parameters by simple name, so java.lang.String could never match. A structurally correct
submission failed: a false positive.

I-052 and TD-043, hygiene. A test set was neither static nor @Nested, so Surefire
warned about a stray class, and an assertThat with no predicate made a fixture line a no-op.

None of the four sits in the runtime sandbox.

2. Improvement from the user's perspective

Students: a submission using a member/nested class, or declaring a parameter with its fully-qualified
type name, is no longer incorrectly failed by a structural exercise's test.json oracle checks
(I-099). Instructors: dynamic-reflection-based structural assertions against interface-based fixtures
no longer crash with NullPointerException (I-094); Maven/Gradle build output for structural test
modules no longer carries a spurious Surefire stray-test-class warning (I-052).

3. Improvement from the maintainer's perspective

New unit test coverage for api/dynamic (previously zero unit tests, only indirect coverage via the
DynamicsTest integration suite). checkParameters's matching is now a correct bipartite algorithm
instead of a simple-name-only multiset comparison — every structural test provider
(ClassTestProvider, MethodTestProvider, ConstructorTestProvider) that compares parameters
benefits from the same fix. TD-043's non-asserting test now genuinely protects the behaviour it
claims to. A related latent fragility (ast/model/JavaFile.java's implicit dependence on
StaticJavaParser's shared global configuration rather than an explicitly-configured instance) was
found while debugging this PR's own ClassNameScanner change and has been raised with the maintainer
separately — it is not touched here.

4. Testing manual

Prerequisites

  1. Local Maven ≥ 3.9 (pom.xml's RequireMavenVersion enforcer rule) and JDK 17+ (CI builds/tests
    on JDK 21). No external exercise repository or policy file is needed: every fixture this PR
    touches lives inside this repo's own simulated exercise at
    src/test/resources/de/tum/cit/ase/ares/integration/testuser/ (a pom.xml + build.gradle pair,
    a test.json structural oracle, and fixture "student" classes under
    testuser/subject/structural/), which the StructuralTest/DynamicsTest integration suites
    already drive end-to-end exactly as an instructor's real exercise repository would.

Steps

  1. mvn test -Punit-core-tests -f pom.xml -Dtest=DynamicClassTest,DynamicFieldTest,ClassNameScannerTest,StructuralTestProviderTest
  2. mvn test -Pintegration-core-tests -f pom.xml -Dtest=de.tum.cit.ase.ares.integration.DynamicsTest
  3. mvn test -Pintegration-core-tests -f pom.xml -Dtest=de.tum.cit.ase.ares.integration.StructuralTest

Expected result

  • Step 1: 24/24 unit tests pass.
  • Step 2: 34/34 DynamicsTest cases pass, including test_class_searchPublicOrProtectedMethods and
    every test_field_* case.
  • Step 3: 32/32 StructuralTest cases pass, including the new test_testAttributesSomeClassNested,
    test_testConstructorsSomeClassNested, test_testConstructorsAdditionalTopLevelType,
    test_testMethodsSomeClassNested and test_testMethodsAdditionalTopLevelType assertions proving
    the previously-undiscoverable SomeClass.Nested member class and the canonical-parameter
    AdditionalTopLevelType fixture are now found and checked correctly.

Negative case (what must still be rejected)

  • test_testClassMisspelledClas/test_testClassMisspelledclass must still fail with the same
    typo/case-mismatch messages as before — the discovery rewrite must not become lenient about
    genuinely wrong class names.
  • test_class_searchPublicOrProtectedMethods must still fail (reject) a real public-API violation
    (doSomething(String) wrongly declared public) — confirms the main-suffix fix didn't
    over-correct into exempting unrelated public methods.
  • test_testConstructorsSomeFailingClass/test_testMethodsSomeFailingClass must still fail on
    genuinely mismatched parameter lists — confirms the new bipartite parameter matching didn't become
    permissive about real mismatches.

Modes exercised

No mode-specific behaviour changed — this PR touches only api/dynamic and api/structural
(reflection/structural-oracle utilities behind Ares' own test-authoring API), not aop/ or
architecture/ enforcement code.

  • ArchUnit + AspectJ
  • ArchUnit + instrumentation
  • WALA + AspectJ
  • WALA + instrumentation

5. Test case coverage regarding this PR

Every counter JaCoCo produces per class, read from site/jacoco/jacoco.csv in the coverage-report artefact of the Coverage Report job on this branch (workflow run 30800342411, the most recent green run). Each cell is COVERED out of MISSED plus COVERED, so a reviewer can recompute it. Nested classes are listed as their own rows. n/a (0/0) means the counter has no members at all for that class.

Class Instruction coverage Branch coverage Line coverage Complexity coverage Method coverage Confirmation (meaningful assertions)
DynamicClass 85.6% (469/548) 76.3% (58/76) 86.8% (99/114) 70.3% (45/64) 88.5% (23/26) yes
DynamicField 83.4% (372/446) 84.4% (27/32) 88.9% (64/72) 83.3% (25/30) 100.0% (14/14) yes
StructuralTestProvider 83.0% (504/607) 79.8% (67/84) 82.7% (105/127) 72.9% (43/59) 94.1% (16/17) yes
StructuralTestProvider.ExpectedClassStructure 96.6% (57/59) 50.0% (1/2) 93.3% (14/15) 88.9% (8/9) 100.0% (8/8) yes
StructuralTestProvider.ModifierSpecification 100.0% (57/57) 100.0% (6/6) 100.0% (12/12) 100.0% (7/7) 100.0% (4/4) yes
ClassNameScanner 77.3% (572/740) 77.9% (60/77) 84.3% (113/134) 72.5% (50/69) 92.3% (24/26) yes
ClassNameScanner.CachedFileTypes 100.0% (9/9) n/a (0/0) 100.0% (1/1) 100.0% (1/1) 100.0% (1/1) yes
Total (changed classes) 82.7% (2040/2466) 79.1% (219/277) 85.9% (408/475) 74.9% (179/239) 93.8% (90/96)

Confirmation basis: DynamicClassTest, DynamicFieldTest, StructuralTestProviderTest and ClassNameScannerTest (all changed by this pull request) assert the resolved members and the rejection messages themselves, so the reflection and structural-oracle defects fixed here fail an assertion rather than merely changing a covered line.

Breaking changes and migration

None. None of these four fixes change the shape of the public API under
de.tum.cit.ase.ares.api.dynamic/de.tum.cit.ase.ares.api.structural (no signatures added or
removed), the security policy file format/schema, or the generated security test code.
checkParameters accepting canonical type names is strictly more permissive than before (nothing
that previously matched now fails to match); the DynamicField/DynamicClass fixes correct a crash
and a false exemption without altering any existing method signature. Minimum JDK/Maven/Gradle
versions are unchanged.

Checklist

  • Tests were added or updated for the behaviour changed here.
  • Documentation (docs/, README.adoc, Javadoc) was updated where the change is user-facing — no docs/ file describes the specific matching/discovery behaviour that changed (docs/Overview.md's existing high-level description of api/dynamic/api/structural remains accurate), so nothing needed updating.
  • CI is green, or every remaining failure is explained above. The "Java CI with Maven" run on the current head is green, and its aggregated "Coverage Report" job confirms the §5 per-class figures.
  • No secrets, tokens or absolute local paths are contained in the diff (checked via grep against the actual diff, not assumed).

Review progress

  • Code review
  • Manual test

@LukaPetrovicTUM
LukaPetrovicTUM requested a review from a team July 26, 2026 20:09
@LukaPetrovicTUM
LukaPetrovicTUM requested review from a team and krusche as code owners July 26, 2026 20:09
@github-actions github-actions Bot added the tests Automated area label: tests label Jul 26, 2026
@coderabbitai

coderabbitai Bot commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Summary by CodeRabbit

  • Bug Fixes

    • Structural tests now recognise nested and additional top-level classes.
    • Parameter checks handle canonical type names, strict ordering, duplicate types, and unordered matching more reliably.
    • Dynamic field discovery now includes fields inherited through interfaces and superinterfaces.
    • Method validation only exempts the exact main(String[]) signature.
  • Test Improvements

    • Expanded coverage for nested classes, interface fields, parameter matching, class discovery, and integration scenarios.
    • Improved assertions and corrected structural test setup issues.

Walkthrough

The changes tighten dynamic method filtering, extend dynamic field traversal to interfaces, add JavaParser-based discovery for nested and additional top-level classes, improve structural parameter matching, and expand unit and integration coverage.

Changes

Dynamic API behaviour

Layer / File(s) Summary
Dynamic method and field lookup
src/main/java/de/tum/cit/ase/ares/api/dynamic/*, src/test/java/de/tum/cit/ase/ares/api/dynamic/*, src/test/java/de/tum/cit/ase/ares/integration/testuser/DynamicsUser.java
The main(java.lang.String[]) exemption now requires an exact static void signature. Field lookup traverses superclasses, interfaces, and superinterfaces. Regression tests cover both behaviours.

Structural test discovery and matching

Layer / File(s) Summary
Java type discovery and nested-class resolution
src/main/java/de/tum/cit/ase/ares/api/structural/*, src/main/java/de/tum/cit/ase/ares/api/structural/testutils/*, src/test/java/de/tum/cit/ase/ares/api/structural/testutils/*
Java source scanning discovers nested and additional top-level types through JavaParser. Results use caching and parse-failure fallback. Nested names resolve to JVM binary names.
Structural parameter matching
src/main/java/de/tum/cit/ase/ares/api/structural/StructuralTestProvider.java, src/test/java/de/tum/cit/ase/ares/api/structural/StructuralTestProviderTest.java
Parameter checks support canonical names, strict ordering, unordered one-to-one matching, duplicate types, count mismatches, and empty lists.
Structural integration coverage
src/test/java/de/tum/cit/ase/ares/integration/*, src/test/resources/de/tum/cit/ase/ares/integration/testuser/test.json
Integration fixtures and expected metadata cover nested and additional top-level classes, constructors, methods, and attributes. Nested test containers use the corrected abstract superclass.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant ClassNameScanner
  participant JavaParser
  participant StructuralTestProvider
  ClassNameScanner->>JavaParser: parse Java source
  JavaParser-->>ClassNameScanner: return discovered type names
  ClassNameScanner->>StructuralTestProvider: register discovered classes
  StructuralTestProvider->>StructuralTestProvider: convert nested names for Class.forName
Loading

Possibly related PRs

  • ls1intum/Ares2#103: Changes StructuralTestProvider, but addresses JSON parsing rather than nested-class discovery and parameter matching.

Suggested reviewers: markuspaulsen, krusche

🚥 Pre-merge checks | ✅ 4 | ❌ 4

❌ Failed checks (1 warning, 3 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 15.63% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Sandbox Fail-Closed Behaviour ❓ Inconclusive Repository clone failed, so this custom check could not run with code access. Retry the review run. If this persists, inspect pre-merge custom-check logs for infrastructure or agent runtime failures.
Trusted Boundary Preservation ❓ Inconclusive Repository clone failed, so this custom check could not run with code access. Retry the review run. If this persists, inspect pre-merge custom-check logs for infrastructure or agent runtime failures.
Github Workflow Least Privilege ❓ Inconclusive Repository clone failed, so this custom check could not run with code access. Retry the review run. If this persists, inspect pre-merge custom-check logs for infrastructure or agent runtime failures.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly summarises the dynamic-reflection and structural-discovery correctness fixes identified by the audit.
Description check ✅ Passed The description directly explains the four audit findings, their impact, implemented fixes, and test coverage.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/ast/i-052-i-094-i099-structural-discovery-assertion-fixes

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@LukaPetrovicTUM LukaPetrovicTUM changed the title Fix dynamic-reflection and structural-discovery correctness issues fo… Fix dynamic-reflection and structural-discovery correctness issues found in the 2026-07-15 audit Jul 26, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@src/main/java/de/tum/cit/ase/ares/api/structural/testutils/ClassNameScanner.java`:
- Around line 60-91: Update the shared parser used by
ClassNameScanner.qualifiedTypeNamesOf(...) so concurrent scans cannot invoke
JAVA_PARSER.parse(...) on the same mutable JavaParser instance; use a per-thread
JavaParser with the existing Java 17 ParserConfiguration or synchronize every
parse call, while preserving the current parsing behavior and cache flow.
- Around line 329-344: Update parseQualifiedTypeNames to also catch
StackOverflowError from JavaParser and use the existing fallback path: log the
parse failure and return fileNameDerivedTypeName(node.getName()). Preserve the
current handling for IOException and ParseProblemException.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 2232cd45-c348-432b-8d02-b530ee95a57a

📥 Commits

Reviewing files that changed from the base of the PR and between 11e1321 and 10d1e8f.

📒 Files selected for processing (13)
  • src/main/java/de/tum/cit/ase/ares/api/dynamic/DynamicClass.java
  • src/main/java/de/tum/cit/ase/ares/api/dynamic/DynamicField.java
  • src/main/java/de/tum/cit/ase/ares/api/structural/StructuralTestProvider.java
  • src/main/java/de/tum/cit/ase/ares/api/structural/testutils/ClassNameScanner.java
  • src/test/java/de/tum/cit/ase/ares/api/dynamic/DynamicClassTest.java
  • src/test/java/de/tum/cit/ase/ares/api/dynamic/DynamicFieldTest.java
  • src/test/java/de/tum/cit/ase/ares/api/structural/StructuralTestProviderTest.java
  • src/test/java/de/tum/cit/ase/ares/api/structural/testutils/ClassNameScannerTest.java
  • src/test/java/de/tum/cit/ase/ares/integration/StructuralTest.java
  • src/test/java/de/tum/cit/ase/ares/integration/testuser/DynamicsUser.java
  • src/test/java/de/tum/cit/ase/ares/integration/testuser/StructuralUser.java
  • src/test/java/de/tum/cit/ase/ares/integration/testuser/subject/structural/MisspelledClass.java
  • src/test/resources/de/tum/cit/ase/ares/integration/testuser/test.json
📜 Review details
⏰ Context from checks skipped due to timeout. (2)
  • GitHub Check: Build
  • GitHub Check: Analyse Java
🧰 Additional context used
📓 Path-based instructions (4)
**/*

⚙️ CodeRabbit configuration file

Dogmatically check all reviewed files for current British English in prose, comments, JavaDoc, documentation, workflow names, step names, issue/PR text, labels, user-facing messages, and review suggestions. Flag American spellings and grammar such as behavior, color, initialize, authorization, canceled, and program when they are natural-language text. Do not flag programming-language syntax, dependency coordinates, API names, class names, method names, package names, paths, URLs, quoted external identifiers, or other literals where American English is required by the technology.

Files:

  • src/main/java/de/tum/cit/ase/ares/api/dynamic/DynamicClass.java
  • src/test/java/de/tum/cit/ase/ares/api/structural/StructuralTestProviderTest.java
  • src/test/java/de/tum/cit/ase/ares/api/dynamic/DynamicClassTest.java
  • src/test/java/de/tum/cit/ase/ares/integration/testuser/DynamicsUser.java
  • src/main/java/de/tum/cit/ase/ares/api/dynamic/DynamicField.java
  • src/test/java/de/tum/cit/ase/ares/integration/testuser/subject/structural/MisspelledClass.java
  • src/test/java/de/tum/cit/ase/ares/api/dynamic/DynamicFieldTest.java
  • src/test/java/de/tum/cit/ase/ares/integration/testuser/StructuralUser.java
  • src/test/java/de/tum/cit/ase/ares/integration/StructuralTest.java
  • src/test/java/de/tum/cit/ase/ares/api/structural/testutils/ClassNameScannerTest.java
  • src/test/resources/de/tum/cit/ase/ares/integration/testuser/test.json
  • src/main/java/de/tum/cit/ase/ares/api/structural/StructuralTestProvider.java
  • src/main/java/de/tum/cit/ase/ares/api/structural/testutils/ClassNameScanner.java
src/main/java/**/*.java

⚙️ CodeRabbit configuration file

Review as a Java 17 Maven security framework used to test untrusted student code in Artemis programming exercises. Prioritise sandbox escapes, fail-open behaviour, unsafe reflection, classloader/bootstrap boundary mistakes, global mutable state, concurrency races, insufficient canonicalisation, and changes that weaken file, command, thread, network, package, or class access restrictions. Treat unrecognised security-sensitive inputs as a potential fail-closed requirement. Prefer simple Java code and one field or method declaration per line.

Files:

  • src/main/java/de/tum/cit/ase/ares/api/dynamic/DynamicClass.java
  • src/main/java/de/tum/cit/ase/ares/api/dynamic/DynamicField.java
  • src/main/java/de/tum/cit/ase/ares/api/structural/StructuralTestProvider.java
  • src/main/java/de/tum/cit/ase/ares/api/structural/testutils/ClassNameScanner.java
**/*Test.java

📄 CodeRabbit inference engine (AGENTS.md)

**/*Test.java: A sandboxed test JVM must never spin up its own server (echo server, socket listener, etc.) to test incoming or outgoing connections
Outgoing-connection tests must connect to an external echo server at a configurable endpoint running as a separate process or CI service on the loopback at port 25565, exercising only the student's client behaviour
If the external echo server is not reachable, the test must skip (using JUnit Assumptions.abort) rather than fail
An Ares SecurityException on an explicitly allowed connection is always a real failure and must propagate (never skipped)
Do not hard-code a self-hosted listener as the connection counterpart; use an external echo service to avoid in-JVM BindException/thread/lifecycle flakiness

Files:

  • src/test/java/de/tum/cit/ase/ares/api/structural/StructuralTestProviderTest.java
  • src/test/java/de/tum/cit/ase/ares/api/dynamic/DynamicClassTest.java
  • src/test/java/de/tum/cit/ase/ares/api/dynamic/DynamicFieldTest.java
  • src/test/java/de/tum/cit/ase/ares/integration/StructuralTest.java
  • src/test/java/de/tum/cit/ase/ares/api/structural/testutils/ClassNameScannerTest.java
src/test/java/**/*.java

⚙️ CodeRabbit configuration file

Require tests to distinguish fixture failures from sandbox failures. Network tests must not start in-process listeners inside the sandbox; external fixtures may be skipped when absent, but explicit Ares SecurityException failures must propagate.

Files:

  • src/test/java/de/tum/cit/ase/ares/api/structural/StructuralTestProviderTest.java
  • src/test/java/de/tum/cit/ase/ares/api/dynamic/DynamicClassTest.java
  • src/test/java/de/tum/cit/ase/ares/integration/testuser/DynamicsUser.java
  • src/test/java/de/tum/cit/ase/ares/integration/testuser/subject/structural/MisspelledClass.java
  • src/test/java/de/tum/cit/ase/ares/api/dynamic/DynamicFieldTest.java
  • src/test/java/de/tum/cit/ase/ares/integration/testuser/StructuralUser.java
  • src/test/java/de/tum/cit/ase/ares/integration/StructuralTest.java
  • src/test/java/de/tum/cit/ase/ares/api/structural/testutils/ClassNameScannerTest.java
🔇 Additional comments (17)
src/main/java/de/tum/cit/ase/ares/api/dynamic/DynamicClass.java (1)

208-208: LGTM!

src/main/java/de/tum/cit/ase/ares/api/dynamic/DynamicField.java (1)

111-130: LGTM!

src/test/java/de/tum/cit/ase/ares/api/dynamic/DynamicClassTest.java (1)

1-48: LGTM!

src/test/java/de/tum/cit/ase/ares/api/dynamic/DynamicFieldTest.java (1)

1-58: LGTM!

src/test/java/de/tum/cit/ase/ares/integration/testuser/DynamicsUser.java (1)

200-200: LGTM!

src/main/java/de/tum/cit/ase/ares/api/structural/StructuralTestProvider.java (3)

125-146: LGTM!


298-354: LGTM!

The switch from simple-name arrays/hash-map occurrence counting to checkExpectedType-based comparison plus Kuhn's algorithm for the unordered case is correct and well covered by StructuralTestProviderTest (duplicate-type rejection, canonical-name acceptance regardless of position, etc.).

Also applies to: 356-401


527-538: LGTM!

src/main/java/de/tum/cit/ase/ares/api/structural/testutils/ClassNameScanner.java (3)

87-91: 🩺 Stability & Availability

Verify deployment model for the static path+mtime cache.

JAVA_FILE_TYPE_CACHE is a JVM-static map keyed only by absolute path and last-modified time. If this harness JVM is ever reused across separate student submissions that occupy the same workspace path, a coincidental mtime match (e.g., a checkout/extraction tool stamping a fixed reference time) could serve a stale discovery result from a different submission's file, silently corrupting grading output — a correctness concern squarely in "global mutable state" territory for a framework that tests untrusted code.

Could you confirm whether each structural-test run executes in its own fresh JVM (in which case this is safe, as the accompanying comment implies for "a single structural test run"), or whether the harness JVM/process can be reused across submissions?

Also applies to: 317-327


266-286: LGTM!


287-328: LGTM!

qualifiedNameWithinFile's handling of local/anonymous classes and the dot-separated qualified naming is correct and matches the accompanying ClassNameScannerTest coverage.

Also applies to: 359-416

src/test/java/de/tum/cit/ase/ares/api/structural/testutils/ClassNameScannerTest.java (1)

28-66: LGTM!

Good targeted coverage of top-level, additional top-level, nested, doubly-nested, and local-class cases.

src/test/java/de/tum/cit/ase/ares/api/structural/StructuralTestProviderTest.java (1)

1-79: LGTM!

Solid regression coverage for both strict-order canonical-name acceptance and unordered bipartite matching, including the duplicate-type rejection edge case that a naive greedy pairing would get wrong.

src/test/java/de/tum/cit/ase/ares/integration/StructuralTest.java (1)

22-26: LGTM!

Also applies to: 36-72, 114-117, 200-208, 238-246

src/test/java/de/tum/cit/ase/ares/integration/testuser/StructuralUser.java (1)

36-36: LGTM!

Also applies to: 46-46, 116-123

src/test/java/de/tum/cit/ase/ares/integration/testuser/subject/structural/MisspelledClass.java (1)

6-27: LGTM!

src/test/resources/de/tum/cit/ase/ares/integration/testuser/test.json (1)

165-197: LGTM!

@LukaPetrovicTUM
LukaPetrovicTUM force-pushed the fix/ast/i-052-i-094-i099-structural-discovery-assertion-fixes branch from 10d1e8f to 5e14b76 Compare August 2, 2026 23:44

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/main/java/de/tum/cit/ase/ares/api/structural/StructuralTestProvider.java (1)

458-469: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Remove the unreachable createParametersHashMap helper.

createParametersHashMap has no Java callers, so drop it unless it is needed for another supported purpose.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/de/tum/cit/ase/ares/api/structural/StructuralTestProvider.java`
around lines 458 - 469, Remove the unused createParametersHashMap method from
StructuralTestProvider, including its parameter-counting implementation, since
it has no Java callers or other supported purpose.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/main/java/de/tum/cit/ase/ares/api/dynamic/DynamicClass.java`:
- Around line 208-209: Update the exemption condition in DynamicClass to
recognize main(java.lang.String[]) only when the declared method is public
static void, preserving normal validation for instance or non-void main methods.
Add regression cases covering public instance and non-void variants to verify
they are not exempted.

In `@src/test/java/de/tum/cit/ase/ares/api/dynamic/DynamicClassTest.java`:
- Around line 19-47: Add separate test fixtures for a public instance void
main(String[]) and a public static int main(String[]) alongside
MainSuffixFixture, then add tests using
DynamicClass.toDynamic(...).checkForPublicOrProtectedMethods() that assert each
throws AssertionFailedError and identifies main(java.lang.String[]).

In `@src/test/java/de/tum/cit/ase/ares/api/dynamic/DynamicFieldTest.java`:
- Around line 52-56: Update
lookupStartingFromAnInterfaceDoesNotThrowOnNullSuperclass to capture the boolean
result of the missing-field lookup, assert that it is false, and retain the
no-exception assertion so the test verifies both safe traversal and absence
semantics.

---

Outside diff comments:
In
`@src/main/java/de/tum/cit/ase/ares/api/structural/StructuralTestProvider.java`:
- Around line 458-469: Remove the unused createParametersHashMap method from
StructuralTestProvider, including its parameter-counting implementation, since
it has no Java callers or other supported purpose.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: af4a35c7-ba37-47e8-9287-03cd711b388b

📥 Commits

Reviewing files that changed from the base of the PR and between 10d1e8f and 5e14b76.

📒 Files selected for processing (13)
  • src/main/java/de/tum/cit/ase/ares/api/dynamic/DynamicClass.java
  • src/main/java/de/tum/cit/ase/ares/api/dynamic/DynamicField.java
  • src/main/java/de/tum/cit/ase/ares/api/structural/StructuralTestProvider.java
  • src/main/java/de/tum/cit/ase/ares/api/structural/testutils/ClassNameScanner.java
  • src/test/java/de/tum/cit/ase/ares/api/dynamic/DynamicClassTest.java
  • src/test/java/de/tum/cit/ase/ares/api/dynamic/DynamicFieldTest.java
  • src/test/java/de/tum/cit/ase/ares/api/structural/StructuralTestProviderTest.java
  • src/test/java/de/tum/cit/ase/ares/api/structural/testutils/ClassNameScannerTest.java
  • src/test/java/de/tum/cit/ase/ares/integration/StructuralTest.java
  • src/test/java/de/tum/cit/ase/ares/integration/testuser/DynamicsUser.java
  • src/test/java/de/tum/cit/ase/ares/integration/testuser/StructuralUser.java
  • src/test/java/de/tum/cit/ase/ares/integration/testuser/subject/structural/MisspelledClass.java
  • src/test/resources/de/tum/cit/ase/ares/integration/testuser/test.json
📜 Review details
⏰ Context from checks skipped due to timeout. (2)
  • GitHub Check: Build
  • GitHub Check: Analyse Java
🧰 Additional context used
📓 Path-based instructions (4)
**/*

⚙️ CodeRabbit configuration file

Dogmatically check all reviewed files for current British English in prose, comments, JavaDoc, documentation, workflow names, step names, issue/PR text, labels, user-facing messages, and review suggestions. Flag American spellings and grammar such as behavior, color, initialize, authorization, canceled, and program when they are natural-language text. Do not flag programming-language syntax, dependency coordinates, API names, class names, method names, package names, paths, URLs, quoted external identifiers, or other literals where American English is required by the technology.

Files:

  • src/test/java/de/tum/cit/ase/ares/integration/testuser/StructuralUser.java
  • src/test/java/de/tum/cit/ase/ares/api/structural/StructuralTestProviderTest.java
  • src/main/java/de/tum/cit/ase/ares/api/dynamic/DynamicClass.java
  • src/main/java/de/tum/cit/ase/ares/api/dynamic/DynamicField.java
  • src/test/java/de/tum/cit/ase/ares/api/dynamic/DynamicClassTest.java
  • src/test/java/de/tum/cit/ase/ares/integration/testuser/DynamicsUser.java
  • src/test/java/de/tum/cit/ase/ares/integration/testuser/subject/structural/MisspelledClass.java
  • src/test/resources/de/tum/cit/ase/ares/integration/testuser/test.json
  • src/main/java/de/tum/cit/ase/ares/api/structural/StructuralTestProvider.java
  • src/test/java/de/tum/cit/ase/ares/api/dynamic/DynamicFieldTest.java
  • src/test/java/de/tum/cit/ase/ares/api/structural/testutils/ClassNameScannerTest.java
  • src/main/java/de/tum/cit/ase/ares/api/structural/testutils/ClassNameScanner.java
  • src/test/java/de/tum/cit/ase/ares/integration/StructuralTest.java
src/test/java/**/*.java

⚙️ CodeRabbit configuration file

Require tests to distinguish fixture failures from sandbox failures. Network tests must not start in-process listeners inside the sandbox; external fixtures may be skipped when absent, but explicit Ares SecurityException failures must propagate.

Files:

  • src/test/java/de/tum/cit/ase/ares/integration/testuser/StructuralUser.java
  • src/test/java/de/tum/cit/ase/ares/api/structural/StructuralTestProviderTest.java
  • src/test/java/de/tum/cit/ase/ares/api/dynamic/DynamicClassTest.java
  • src/test/java/de/tum/cit/ase/ares/integration/testuser/DynamicsUser.java
  • src/test/java/de/tum/cit/ase/ares/integration/testuser/subject/structural/MisspelledClass.java
  • src/test/java/de/tum/cit/ase/ares/api/dynamic/DynamicFieldTest.java
  • src/test/java/de/tum/cit/ase/ares/api/structural/testutils/ClassNameScannerTest.java
  • src/test/java/de/tum/cit/ase/ares/integration/StructuralTest.java
**/*Test.java

📄 CodeRabbit inference engine (AGENTS.md)

**/*Test.java: A sandboxed test JVM must never spin up its own server (echo server, socket listener, etc.) to test incoming or outgoing connections
Outgoing-connection tests must connect to an external echo server at a configurable endpoint running as a separate process or CI service on the loopback at port 25565, exercising only the student's client behaviour
If the external echo server is not reachable, the test must skip (using JUnit Assumptions.abort) rather than fail
An Ares SecurityException on an explicitly allowed connection is always a real failure and must propagate (never skipped)
Do not hard-code a self-hosted listener as the connection counterpart; use an external echo service to avoid in-JVM BindException/thread/lifecycle flakiness

Files:

  • src/test/java/de/tum/cit/ase/ares/api/structural/StructuralTestProviderTest.java
  • src/test/java/de/tum/cit/ase/ares/api/dynamic/DynamicClassTest.java
  • src/test/java/de/tum/cit/ase/ares/api/dynamic/DynamicFieldTest.java
  • src/test/java/de/tum/cit/ase/ares/api/structural/testutils/ClassNameScannerTest.java
  • src/test/java/de/tum/cit/ase/ares/integration/StructuralTest.java
src/main/java/**/*.java

⚙️ CodeRabbit configuration file

Review as a Java 17 Maven security framework used to test untrusted student code in Artemis programming exercises. Prioritise sandbox escapes, fail-open behaviour, unsafe reflection, classloader/bootstrap boundary mistakes, global mutable state, concurrency races, insufficient canonicalisation, and changes that weaken file, command, thread, network, package, or class access restrictions. Treat unrecognised security-sensitive inputs as a potential fail-closed requirement. Prefer simple Java code and one field or method declaration per line.

Files:

  • src/main/java/de/tum/cit/ase/ares/api/dynamic/DynamicClass.java
  • src/main/java/de/tum/cit/ase/ares/api/dynamic/DynamicField.java
  • src/main/java/de/tum/cit/ase/ares/api/structural/StructuralTestProvider.java
  • src/main/java/de/tum/cit/ase/ares/api/structural/testutils/ClassNameScanner.java
🔇 Additional comments (16)
src/main/java/de/tum/cit/ase/ares/api/dynamic/DynamicField.java (1)

111-130: LGTM!

src/test/java/de/tum/cit/ase/ares/api/dynamic/DynamicFieldTest.java (1)

18-50: LGTM!

src/test/java/de/tum/cit/ase/ares/integration/testuser/DynamicsUser.java (1)

200-200: LGTM!

src/test/java/de/tum/cit/ase/ares/integration/StructuralTest.java (2)

36-51: Substring-matching fragility is transparently documented; no action needed now.

The comment correctly identifies that EventConditions#test(String) matches dynamic-test IDs by substring, so "dynamic-test:#1" would also match "dynamic-test:#10" once a container has 10 or more entries. None of the current containers cross that boundary, so this is not a live defect, but it is a latent fragility worth keeping in mind for future fixture additions to testConstructors() or testMethods().


114-118: New dynamic-test assertions are consistent with the fixture and oracle.

I cross-checked the new testAttributesSomeClassNested, testConstructorsSomeClassNested, testConstructorsAdditionalTopLevelType, testMethodsSomeClassNested, and testMethodsAdditionalTopLevelType IDs against test.json's new entries and MisspelledClass.java's AdditionalTopLevelType. The numbering, class filtering rationale (no testClasses() entry for either fixture, since neither declares class-level properties), and expected outcomes all align.

Also applies to: 200-209, 238-247

src/main/java/de/tum/cit/ase/ares/api/structural/StructuralTestProvider.java (2)

336-401: Bipartite matching implementation verified correct.

I traced hasMatchingPairingForEachExpectedParameter/tryPairExpectedParameter through several scenarios, including the augmenting-path case exercised by unorderedMatchAcceptsRepeatedType in StructuralTestProviderTest.java. The algorithm correctly implements Kuhn's augmenting-path search and produces the expected results for duplicate and ambiguous parameter types.


130-133: Nested-class name translation is consistent end-to-end.

The dot-to-$ translation in getQualifiedClassName() uses String.replace (literal), not replaceAll (regex), which correctly avoids mangling every character. I cross-checked this against ClassNameScanner.qualifiedNameWithinFile() (dot-separated Outer.Inner registration) and test.json's "SomeClass.Nested" entry: the naming convention is consistent across discovery, storage, and class loading.

Also applies to: 302-308, 528-537

src/main/java/de/tum/cit/ase/ares/api/structural/testutils/ClassNameScanner.java (4)

60-91: Thread-safety fix confirmed correct.

The ThreadLocal<JavaParser> correctly addresses the previously flagged concurrency concern. A web search confirms a JavaParser instance "is not thread safe", so per-thread instantiation is the right fix, and the accompanying comment correctly documents the rationale.


330-345: StackOverflowError handling fix confirmed correct.

The catch (IOException | ParseProblemException | StackOverflowError e) clause correctly addresses the previously flagged gap and falls back to the filename-derived type name, consistent with the fallback behaviour used elsewhere in this method.


318-328: Cache correctness verified for the common case.

qualifiedTypeNamesOf keys the cache by normalised absolute path and invalidates on lastModified() change. A concurrent get-then-put is not atomic, so two threads could redundantly re-parse the same unchanged file, but this cannot corrupt the cached result since both threads compute the same value from the same file content. This is a minor, self-recovering inefficiency, not a correctness defect.


360-374: qualifiedNameWithinFile logic verified against test coverage.

The parent-chain walk correctly distinguishes top-level, member, and doubly nested types from local classes by checking whether the chain terminates at a CompilationUnit. This matches all five new test cases in ClassNameScannerTest.java.

src/test/java/de/tum/cit/ase/ares/api/structural/testutils/ClassNameScannerTest.java (1)

28-65: LGTM!

src/test/java/de/tum/cit/ase/ares/api/structural/StructuralTestProviderTest.java (1)

1-79: Good regression coverage for the new matching behaviour.

The tests cover strict-order and unordered matching, canonical vs. simple names, duplicate types, mismatched counts, and the empty-parameters case. I traced the bipartite-matching implementation against unorderedMatchAcceptsRepeatedType and unorderedMatchStillRejectsAWrongDuplicateType and confirmed the algorithm behaves as asserted.

src/test/java/de/tum/cit/ase/ares/integration/testuser/StructuralUser.java (1)

36-36: StrucuralTestSetStructuralTestSet rename and abstract modifier are correct.

Marking the shared nested test base abstract is the right fix for Surefire's stray-test-class heuristic, since the class declares @Nested/@TestFactory members but is itself neither static, @Nested, nor abstract before this change.

Also applies to: 46-46, 116-123

src/test/java/de/tum/cit/ase/ares/integration/testuser/subject/structural/MisspelledClass.java (1)

6-27: AdditionalTopLevelType fixture matches its oracle entry.

The constructor and acceptCanonicalParameter method signatures match the java.lang.String canonical parameter types declared in test.json, and the package-private visibility is valid Java syntax alongside the public MisspelledClass in the same file.

src/test/resources/de/tum/cit/ase/ares/integration/testuser/test.json (1)

165-197: New oracle entries are consistent with the fixture classes.

The SomeClass.Nested and AdditionalTopLevelType entries match their corresponding Java fixtures and the dot-separated nested-class naming convention used elsewhere in this file.

Comment thread src/main/java/de/tum/cit/ase/ares/api/dynamic/DynamicClass.java Outdated
Comment thread src/test/java/de/tum/cit/ase/ares/api/dynamic/DynamicClassTest.java
Comment thread src/test/java/de/tum/cit/ase/ares/api/dynamic/DynamicFieldTest.java Outdated

@SedaOran SedaOran left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approving, code LGTM.

Cleanly fixes four real correctness bugs from the audit (the main endsWith check, the DynamicField interface NPE, canonical/bipartite parameter matching, and nested-type discovery), each with solid regression tests. All 13 CI checks green, including Core Integration Tests.

@Claudia-Anthropica Claudia-Anthropica left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@LukaPetrovicTUM The fixes correctly tighten dynamic reflection validation, traverse interface fields safely, discover nested and additional top-level types, and match canonical parameter names without weakening mismatch detection. The regression coverage is meaningful, all captured CI checks pass, and the previously raised review concerns are resolved on this head.

@MarkusPaulsen

Copy link
Copy Markdown
Collaborator

The pull request template now bounds each section: 500 characters for Summary, 1000 for
Linked issues, sections 1 to 3 and Breaking changes and migration, 5000 for the testing
manual. The count is what a reader sees, so the template's own instruction comments do not
count towards it.

This description was written before those limits and exceeds 1 of them, so I have
shortened it. Nothing is lost: the original text of every section I touched is kept below,
so you can restore, reword or move any of it yourself.

1. Problem, as it read before (3981 characters, limit 1000)

This PR bundles four independent findings on one branch (explicit exception to one-branch-per-issue,
per the audit's own scope) — each has its own root cause, listed separately.

I-094 — DynamicClass/DynamicField reflection validation. Observed:
DynamicClass.checkForPublicOrProtectedMethods used "main(java.lang.String[])".endsWith(sig)
instead of .equals(sig), so a public method whose signature happened to be a textual suffix of the
literal main signature (e.g. a public ain(String[])) was wrongly exempted from the public-method
check. Separately, DynamicField.fieldsOf walked only Class.getSuperclass() until Object.class;
since getSuperclass() returns null for an interface, it threw NullPointerException once the
walk reached one, and never visited implemented/extended superinterfaces at all. Expected: only the
literal main(String[]) method is exempt; field lookup resolves uniformly across classes and
interfaces, including inherited superinterface fields, without throwing. Root cause layer: none of
policy/generated-security-test/enforcement/build-integration — api/dynamic is Ares' own
instructor-facing dynamic-reflection test-authoring API, used to write structural assertions against
student code shape, not the runtime sandbox boundary. Framing: the main-suffix bug is the
structural-test analogue of a false negative (a public-API violation that should have failed a
structural check was silently accepted); the field-lookup bug was a crash, not a false result.

I-052 — StructuralUser's shared nested-test base class. Observed: StrucuralTestSet
(misspelt) was neither static nor @Nested, tripping Surefire's stray-test-class heuristic in the
build output, even though it functioned correctly (its members are inherited into the Maven/
Gradle @Nested subclasses via JUnit 5's nested-class inheritance). Expected: no spurious warning,
same test behaviour. Root cause layer: none — pure build/test-tooling hygiene, no runtime behaviour
involved. Framing: neither false positive nor false negative applies — this never affected any
test's pass/fail outcome, confirmed by StructuralTest's pre-existing COUNT = 2 assertions passing
identically before and after.

I-099 — structural discovery and parameter matching. Observed:
ClassNameScanner.walkProjectFileStructure derived a source file's one-and-only declared type from
its filename, so member/nested classes and additional top-level types declared in the same file were
undiscoverable (the pre-existing code even carried a // TODO: we should also support inner classes here comment marking the gap); separately, StructuralTestProvider.checkParameters compared every
observed parameter via Class.getSimpleName() only, so a canonical oracle entry (java.lang.String)
could never match, unlike checkExpectedType (return/field/annotation types), which already accepted
either form. Expected: a structurally correct submission using a member class or canonical parameter
type name passes its exercise's structural checks. Root cause layer: none — api/structural
implements Ares' structural-conformance oracle (comparing submitted code shape against an
instructor-authored test.json), used by instructor-authored exercise structural tests, not the
runtime sandbox enforcement path. Framing: false positive — a structurally correct student
submission would incorrectly fail the exercise's structural test.

TD-043 — non-asserting assertThat in a test fixture. Observed:
DynamicsUser.field_setStaticSuccess called assertThat(field.exists()); with no terminal predicate,
making the line a no-op regardless of outcome. Expected: the assertion genuinely fails if
field.exists() were ever false. Root cause layer: none — Ares' own regression-test fixture quality,
not an exercise-facing behaviour. Framing: neither applies — this reduced the trustworthiness of
Ares' own regression suite, it never affected a real exercise outcome.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

tests Automated area label: tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants