Commit Graph

8331 Commits

Author SHA1 Message Date
Lukasz Lenart cf22320e33 docs(security): treat a fix or PR as disclosure, require private report first (#1785)
The disclosure rules only forbade publishing exploit/PoC code, so a
contributor who opens a public PR that fixes or hints at a suspected
vulnerability reads them as satisfied — the fix itself telegraphs the
weakness before a fixed release exists.

Add a dedicated "Do not disclose through a pull request, commit, or issue"
section directing reporters to email security@struts.apache.org first, and
extend the PoC rule in Report Quality Rules to state that a fix, patch, or
hardening change is a public disclosure in the same way a PoC is. Aligns
SECURITY.md with the rule already stated in CLAUDE.md/AGENTS.md.

🤖 Generated by AI Assistant
2026-07-14 20:25:56 +02:00
Lukasz Lenart 40fcae3101 WW-4858 test(json): cover nested-leaf accepted-name and include patterns (#1783)
Add two tests to JSONInterceptorTest exercising the nested-object path for
the name/value filtering added in WW-4858:

- testAcceptedNamePatternRejectsNestedKey: accepted name patterns are raw
  full-match regexes with no hierarchy expansion, so the intermediate node
  ("bean") must itself match an accepted pattern or the whole subtree is
  dropped before the leaf is visited.
- testIncludePropertiesAppliedToNestedInputWhenEnabled: include patterns do
  expand across the hierarchy, so "bean.stringField" also matches the
  intermediate "bean" and the nested leaf populates while the excluded
  sibling "bean.intField" is dropped.

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-14 13:31:06 +02:00
Arun b70ecc8e15 WW-5645 Canonicalise static content paths and remove redundant URL decode (#1777)
* Add path segment validation utility to StaticContentLoader

* Remove redundant URL decode in buildPath and reject malformed path segments early

* Use shared path segment validation in WebJar URL provider

* Document encoding contract on RequestUtils.getServletPath

* Add tests for path segment validation in static content loader

* Add encoded traversal test for WebJar static content serving

* Add encoded traversal tests for WebJar URL provider

* Fix missing closing brace in StaticContentLoader causing compile failure

* Use per-segment matching in containsMalformedPathSegment to avoid false positives

* Remove redundant dot-segment check now handled by containsMalformedPathSegment

* Fix indentation on validateStaticContentPath closing brace

* Remove unused encoding field and setter from DefaultStaticContentLoader

* Replace denylist with path canonicalisation in Validator

* Wire canonicalisePath into static content serving

* Wire canonicalisePath into WebJar URL provider

* Update tests for canonicalise approach and remove unused setEncoding call

* Remove setEncoding calls from tests to match updated DefaultStaticContentLoader

* Remove setEncoding calls from tests to match updated DefaultStaticContentLoader

* Remove redundant encoded-traversal tests per maintainer review — end-to-end 404 already covered
2026-07-14 09:37:21 +00:00
ⳕⲛτⲉⲅⲥⲉⳏτⲟⲅ 🕵🏻 18955b98a4 WW-5644 fix(json): confine StrutsJSONWriter write state to the writing thread (#1776)
* fix(json): confine StrutsJSONWriter write state to the writing thread

JSONUtil obtains its JSONWriter once via @Inject and reuses that same
instance across every concurrent response handled by that JSONResult/
JSONInterceptor configuration. StrutsJSONWriter kept its output buffer,
cyclic-reference stack, root object, and expression-path state
(buf/stack/root/buildExpr/exprStack/excludeProperties/
includeProperties/excludeNullProperties) as plain instance fields, all
reset in place at the start of write().

Two concurrent write() calls on the same instance therefore race on
that reset: one call's in-progress buffer can be wiped and overwritten
by a second, unrelated concurrent call before the first call reads it
back via buf.toString(), so one request's serialized JSON can be
returned as a completely different, concurrently-served request's
response body.

Move buf/stack/root/buildExpr/exprStack/excludeProperties/
includeProperties/excludeNullProperties into a WriteState confined to
a ThreadLocal, scoped to a single write() call. Method signatures and
behavior are otherwise unchanged so existing StrutsJSONWriter
subclasses keep working; ignoreHierarchy/dateFormat/enumAsBean/
excludeProxyProperties stay as plain instance fields since they are
set to the same value on every call for a given writer configuration
and are safe to share.

* test(json): raise writer concurrency test to 16 threads for reliable repro

Verified independently that the 2-thread version can miss the race on
machines with more cores than contending threads (with no CPU
contention, the OS scheduler has no need to preempt either thread
mid-call, so the corruption window is rarely hit): 0 reproductions in
8 reruns against unpatched code on a 10-core machine. Sixteen threads
reproduced it reliably (44,646/320,000 corrupted responses against
unpatched StrutsJSONWriter), and confirmed zero corruption against the
fix under the same load.

---------

Co-authored-by: g0w6y <g0w6y@users.noreply.github.com>
2026-07-14 08:49:07 +02:00
ⳕⲛτⲉⲅⲥⲉⳏτⲟⲅ 🕵🏻 75a285a106 WW-5643 fix(json): confine StrutsJSONReader parse state to the parsing thread (#1775)
* fix(json): confine StrutsJSONReader parse state to the parsing thread

JSONInterceptor obtains its JSONReader once via @Inject and reuses that
same instance across every concurrent request handled by that
interceptor. StrutsJSONReader kept its parse cursor, token buffer and
nesting-depth counter (used to enforce maxDepth/maxElements/
maxStringLength/maxKeyLength) as plain instance fields, so two
concurrent read() calls on the same instance tore each other's state:
one request's depth counter could be decremented by an unrelated
concurrent request finishing its own parse, letting payloads deeper
than the configured maxDepth through, and the shared character cursor
and string/number buffer let fragments of one request's JSON body leak
into a different, concurrently-parsed request's result.

Move the cursor, current character, token, buffer and depth into a
ParseState confined to a ThreadLocal, scoped to a single read() call.
Method signatures and behavior are otherwise unchanged so existing
StrutsJSONReader subclasses keep working; the limit fields
(maxElements/maxDepth/maxStringLength/maxKeyLength) stay as plain
instance fields since they are set to the same value on every call for
a given interceptor configuration and are safe to share.

* test(json): raise reader concurrency test to 16 threads for reliable repro

Verified independently that the 2-thread version can miss the race on
machines with more cores than contending threads (with no CPU
contention, the OS scheduler has no need to preempt either thread
mid-call, so the corruption window is rarely hit): 0 reproductions in
8 reruns against unpatched code on a 10-core machine. Sixteen threads
reproduced both symptoms reliably against unpatched StrutsJSONReader
(81 cross-thread data leaks and 79 maxDepth bypasses out of 160,000
attempts), and confirmed zero of either against the fix under the
same load. Combined the two prior tests into one, since both symptoms
come from the same shared parse state and are naturally checked
together per thread.

---------

Co-authored-by: g0w6y <g0w6y@users.noreply.github.com>
2026-07-14 08:48:46 +02:00
dependabot[bot] 8fb8bcbcf0 build(deps): bump net.sf.jasperreports:jasperreports (#1779)
Bumps [net.sf.jasperreports:jasperreports](https://github.com/Jaspersoft/jasperreports) from 7.0.4 to 7.0.7.
- [Release notes](https://github.com/Jaspersoft/jasperreports/releases)
- [Changelog](https://github.com/Jaspersoft/jasperreports/blob/master/changes.txt)
- [Commits](https://github.com/Jaspersoft/jasperreports/compare/7.0.4...7.0.7)

---
updated-dependencies:
- dependency-name: net.sf.jasperreports:jasperreports
  dependency-version: 7.0.7
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-12 11:40:42 +02:00
dependabot[bot] f03198c6f8 build(deps-dev): bump commons-logging:commons-logging (#1760)
Bumps [commons-logging:commons-logging](https://github.com/apache/commons-logging) from 1.3.6 to 1.4.0.
- [Changelog](https://github.com/apache/commons-logging/blob/master/RELEASE-NOTES.txt)
- [Commits](https://github.com/apache/commons-logging/compare/rel/commons-logging-1.3.6...rel/commons-logging-1.4.0)

---
updated-dependencies:
- dependency-name: commons-logging:commons-logging
  dependency-version: 1.4.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-12 11:37:11 +02:00
Lukasz Lenart 525c7dae37 WW-4858 Honor parameter filtering during JSON population (#1773)
* WW-4858 docs(json): design for honoring parameter filtering during JSON population

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* WW-4858 docs(json): implementation plan for JSON parameter filtering

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* WW-4858 feat(json): enforce excluded/accepted name patterns on JSON population

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* WW-4858 feat(json): enforce param-name max length on JSON population

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* WW-4858 feat(json): honor ParameterNameAware and ParameterValueAware on JSON population

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* WW-4858 feat(json): add opt-in excluded/accepted value patterns on JSON population

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* WW-4858 feat(json): opt-in applying excludeProperties/includeProperties to JSON input

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* WW-4858 test(json): cover nested and list-element paths; clarify filter comments

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-12 11:32:12 +02:00
Lukasz Lenart 5c130f9411 WW-5641 Restore struts.json.writer / struts.json.reader override in JSON plugin (#1766)
* WW-5641 docs: design spec for JSON writer/reader override regression

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* WW-5641 docs: implementation plan for JSON writer/reader override fix

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* WW-5641 fix: run JSON bean-selection from struts-deferred.xml

The JSON plugin declared <bean-selection> in struts-plugin.xml, which runs
at plugin-parse time, before the application struts.xml is folded in. That
froze the JSONWriter/JSONReader default binding to StrutsJSONWriter/Reader,
so struts.json.writer / struts.json.reader overrides were ignored.

Move the element to struts-deferred.xml, which Dispatcher loads last (after
the app config and core's StrutsBeanSelectionProvider), so the alias honors
the override. Mirrors the velocity plugin. JSONUtil is unchanged from main.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-12 11:29:41 +02:00
dependabot[bot] 08fba59807 build(deps): bump org.apache.logging.log4j:log4j-bom (#1767)
Bumps [org.apache.logging.log4j:log4j-bom](https://github.com/apache/logging-log4j2) from 2.26.0 to 2.26.1.
- [Release notes](https://github.com/apache/logging-log4j2/releases)
- [Changelog](https://github.com/apache/logging-log4j2/blob/2.x/RELEASE-NOTES.adoc)
- [Commits](https://github.com/apache/logging-log4j2/compare/rel/2.26.0...rel/2.26.1)

---
updated-dependencies:
- dependency-name: org.apache.logging.log4j:log4j-bom
  dependency-version: 2.26.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-09 09:25:44 +02:00
dependabot[bot] 30cbd1c3c4 build(deps): bump github/codeql-action/upload-sarif (#1768)
Bumps [github/codeql-action/upload-sarif](https://github.com/github/codeql-action) from 628fc3f124e68b0151f0d2a5d81e864ee1e42335 to f58f0d11ebf5dedd870fab2f999275f7602cfa46.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/628fc3f124e68b0151f0d2a5d81e864ee1e42335...f58f0d11ebf5dedd870fab2f999275f7602cfa46)

---
updated-dependencies:
- dependency-name: github/codeql-action/upload-sarif
  dependency-version: f58f0d11ebf5dedd870fab2f999275f7602cfa46
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-09 09:25:31 +02:00
dependabot[bot] 16aa43137d build(deps): bump github/codeql-action from 4.36.2 to 4.36.3 (#1769)
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 4.36.2 to 4.36.3.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/v4.36.2...v4.36.3)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-version: 4.36.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-09 09:25:18 +02:00
dependabot[bot] 745c08c7ac build(deps-dev): bump byte-buddy.version from 1.18.10 to 1.18.11 (#1771)
Bumps `byte-buddy.version` from 1.18.10 to 1.18.11.

Updates `net.bytebuddy:byte-buddy` from 1.18.10 to 1.18.11
- [Release notes](https://github.com/raphw/byte-buddy/releases)
- [Changelog](https://github.com/raphw/byte-buddy/blob/master/release-notes.md)
- [Commits](https://github.com/raphw/byte-buddy/compare/byte-buddy-1.18.10...byte-buddy-1.18.11)

Updates `net.bytebuddy:byte-buddy-agent` from 1.18.10 to 1.18.11
- [Release notes](https://github.com/raphw/byte-buddy/releases)
- [Changelog](https://github.com/raphw/byte-buddy/blob/master/release-notes.md)
- [Commits](https://github.com/raphw/byte-buddy/compare/byte-buddy-1.18.10...byte-buddy-1.18.11)

---
updated-dependencies:
- dependency-name: net.bytebuddy:byte-buddy
  dependency-version: 1.18.11
  dependency-type: direct:development
  update-type: version-update:semver-patch
- dependency-name: net.bytebuddy:byte-buddy-agent
  dependency-version: 1.18.11
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-09 09:25:01 +02:00
Lukasz Lenart 789dbf3cd2 WW-5640 Add WebJars support to Struts core (#1765)
* WW-5640 docs: design for WebJars support in Struts core

Adds first-class WebJars support so client-side libraries can be
referenced by a version-less logical path and served through the
existing static-content pipeline. Grounded against 7.2.x source.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* WW-5640 docs: implementation plan for WebJars support

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* WW-5640 build: add webjars-locator-lite dependency

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* WW-5640 feat: add webjars config constants and defaults

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* WW-5640 docs: correct plan test framework to JUnit 4

core uses JUnit 4 + AssertJ + Mockito, not JUnit 5 Jupiter (no
Jupiter engine on the classpath). Test tasks translate accordingly.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* WW-5640 feat: add WebJarUrlProvider resolution seam

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* WW-5640 feat: register WebJarUrlProvider bean

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* WW-5640 feat: extend static content-type map for webjar assets

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* WW-5640 feat: serve webjar assets via static content loader

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* WW-5640 feat: add <s:webjar> tag and <@s.webjar> macro

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* WW-5640 docs: add generated tag reference for <s:webjar>

Annotation-processor-generated tag reference (attributes + description),
tracked like every other tag's docs under core/src/site/resources/tags/.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* WW-5640 fix: address final review (log level, resolveUrl traversal test, javadoc)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* WW-5640 refactor: address SonarCloud code smells

- getContentType: replace long if/else chain with a static extension->
  MIME map (S3776 cognitive complexity)
- DefaultWebJarUrlProvider.split: return Optional<String[]> instead of a
  null sentinel (S1168; Optional fits the reject semantics, empty-array
  would not)
- serving tests: rename local 'loader' -> 'webJarLoader' to stop hiding
  the ContentTypeProbe field (S1117)
- WebJarTest: use assertThat(writer).hasToString(...) (S5838)

S110 (WebJarTag inheritance depth) is inherent to the Struts tag base
class hierarchy shared by every tag; left as-is.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 15:03:05 +02:00
dependabot[bot] a09f2a93af build(deps): bump github/codeql-action/upload-sarif (#1758)
Bumps [github/codeql-action/upload-sarif](https://github.com/github/codeql-action) from eda5730a8bfb740e03a28087a958444c646e5842 to 628fc3f124e68b0151f0d2a5d81e864ee1e42335.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/eda5730a8bfb740e03a28087a958444c646e5842...628fc3f124e68b0151f0d2a5d81e864ee1e42335)

---
updated-dependencies:
- dependency-name: github/codeql-action/upload-sarif
  dependency-version: 628fc3f124e68b0151f0d2a5d81e864ee1e42335
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-01 12:57:29 +02:00
dependabot[bot] 29f75f2dc0 build(deps): bump org.htmlunit:htmlunit from 5.1.0 to 5.2.0 (#1762)
Bumps [org.htmlunit:htmlunit](https://github.com/HtmlUnit/htmlunit) from 5.1.0 to 5.2.0.
- [Release notes](https://github.com/HtmlUnit/htmlunit/releases)
- [Commits](https://github.com/HtmlUnit/htmlunit/compare/5.1.0...5.2.0)

---
updated-dependencies:
- dependency-name: org.htmlunit:htmlunit
  dependency-version: 5.2.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-01 12:57:04 +02:00
Jarek Potiuk dc90e48909 Add draft security threat model (THREAT_MODEL.md) + discoverability pointer (#1756)
* Add draft security threat model (THREAT_MODEL.md)

Generated-by: Claude Opus 4.8 (1M context)

* SECURITY.md: link to THREAT_MODEL.md for scanner/triager discoverability

Generated-by: Claude Opus 4.8 (1M context)

* Fix dangling §14 refs and tighten provenance in threat model

Address code-review findings on the THREAT_MODEL.md draft:

- Add the missing §14 Q-env and Q-egress open questions, so every
  *(inferred)* claim that cites them now resolves (restores the
  "each inferred claim has a matching §14 question" invariant).
- Tag the two previously bare *(inferred)* claims (examples/showcase,
  on-path attacker) with their matching question IDs.
- Soften the §1 header: drop the ASF Security team / PMC authorship
  attribution on an unratified draft; state it is drafted for PMC review.
- Correct the OGNL Java Security Manager wording: SecurityManager is
  deprecated for removal since JDK 17 and permanently disabled in JDK 24,
  not simply "does not work on JDK 21+".
- AGENTS.md: point the Assess step at THREAT_MODEL.md's disposition guide
  so the triage wrapper links the model directly.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: Lukasz Lenart <lukaszlenart@apache.org>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-29 21:10:42 +02:00
Lukasz Lenart 50c16e93b1 Release 7.2.1-RC1 (#1744)
* [maven-release-plugin] prepare release STRUTS_7_2_1

* [maven-release-plugin] prepare for next development iteration
2026-06-26 07:18:26 +02:00
dependabot[bot] 07afccbb2f build(deps): bump actions/checkout from 6 to 7 (#1755)
Bumps [actions/checkout](https://github.com/actions/checkout) from 6 to 7.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v6...v7)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-26 07:18:09 +02:00
dependabot[bot] 153e42bb9b build(deps): bump org.glassfish.jaxb:jaxb-bom from 4.0.8 to 4.0.9 (#1753)
Bumps org.glassfish.jaxb:jaxb-bom from 4.0.8 to 4.0.9.

---
updated-dependencies:
- dependency-name: org.glassfish.jaxb:jaxb-bom
  dependency-version: 4.0.9
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-26 07:17:43 +02:00
dependabot[bot] 46ba90f797 build(deps-dev): bump org.jacoco:jacoco-maven-plugin (#1751)
Bumps [org.jacoco:jacoco-maven-plugin](https://github.com/jacoco/jacoco) from 0.8.14 to 0.8.15.
- [Release notes](https://github.com/jacoco/jacoco/releases)
- [Commits](https://github.com/jacoco/jacoco/compare/v0.8.14...v0.8.15)

---
updated-dependencies:
- dependency-name: org.jacoco:jacoco-maven-plugin
  dependency-version: 0.8.15
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-26 07:17:30 +02:00
dependabot[bot] 22243e75f5 build(deps): bump org.sitemesh:sitemesh from 3.2.2 to 3.2.3 (#1749)
Bumps [org.sitemesh:sitemesh](https://github.com/sitemesh/sitemesh3) from 3.2.2 to 3.2.3.
- [Release notes](https://github.com/sitemesh/sitemesh3/releases)
- [Commits](https://github.com/sitemesh/sitemesh3/compare/3.2.2...3.2.3)

---
updated-dependencies:
- dependency-name: org.sitemesh:sitemesh
  dependency-version: 3.2.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-26 07:17:04 +02:00
dependabot[bot] 1e3fa9a2d7 build(deps-dev): bump byte-buddy.version from 1.18.8 to 1.18.10 (#1745)
Bumps `byte-buddy.version` from 1.18.8 to 1.18.10.

Updates `net.bytebuddy:byte-buddy` from 1.18.8 to 1.18.10
- [Release notes](https://github.com/raphw/byte-buddy/releases)
- [Changelog](https://github.com/raphw/byte-buddy/blob/master/release-notes.md)
- [Commits](https://github.com/raphw/byte-buddy/compare/byte-buddy-1.18.8...byte-buddy-1.18.10)

Updates `net.bytebuddy:byte-buddy-agent` from 1.18.8 to 1.18.10
- [Release notes](https://github.com/raphw/byte-buddy/releases)
- [Changelog](https://github.com/raphw/byte-buddy/blob/master/release-notes.md)
- [Commits](https://github.com/raphw/byte-buddy/compare/byte-buddy-1.18.8...byte-buddy-1.18.10)

---
updated-dependencies:
- dependency-name: net.bytebuddy:byte-buddy
  dependency-version: 1.18.10
  dependency-type: direct:development
  update-type: version-update:semver-patch
- dependency-name: net.bytebuddy:byte-buddy-agent
  dependency-version: 1.18.10
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-26 07:16:26 +02:00
Lukasz Lenart 01a561d9d8 Add CONTRIBUTING.md for new contributors (#1757) 2026-06-25 19:43:45 +00:00
Lukasz Lenart 59e342488d WW-5256 Decouple FreeMarker whitespace stripping from devMode (#1743)
* WW-5256 docs: design to decouple FreeMarker whitespace stripping from devMode

Fixes s:textarea rendering blank lines and HTML whitespace bloat in devMode
by honoring struts.freemarker.whitespaceStripping unconditionally.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* WW-5256 docs: implementation plan to decouple whitespace stripping from devMode

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* WW-5256 test: prove whitespace stripping wrongly disabled in devMode

* WW-5256 fix(freemarker): honor whitespaceStripping regardless of devMode

* WW-5256 docs: drop devMode note from whitespaceStripping constant

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 12:22:51 +02:00
Lukasz Lenart 489445c78d Release 7.2.0-RC1 (#1742)
* [maven-release-plugin] prepare release STRUTS_7_2_0

* [maven-release-plugin] prepare for next development iteration
2026-06-15 12:07:02 +02:00
Arun cc3ebc3c1f WW-5635 Avoid logging sensitive token values in TokenHelper (#1738)
* Avoid logging sensitive token values in TokenHelper

Redact form and session token values from WARN-level log output
in TokenHelper.validToken() and update corresponding i18n message
properties. Detailed diagnostics moved to DEBUG level with
sanitized input.

* Update struts-messages.properties

* Update invalid token error message for clarity

* Update struts-messages_da.properties

* Update struts-messages_de.properties

* Update Polish translation for invalid token message

* Update invalid token message in Portuguese properties

* Improve token mismatch warning logging

Updated warning message to include the form token in the log.

* Update struts-messages.properties

* Update invalid token message format in properties file

* Update invalid token message for clarity

* Update struts-messages_de.properties

* Update struts-messages_pl.properties

* Update invalid token message format in properties file

* Update TokenHelper.java

* Refactor token mismatch logging for development mode
2026-06-14 17:08:39 +00:00
Arun 8f9b4b8a90 WW-5636 Harden redirect URL escaping in non-302 response body (#1737)
* Implement test for status code 200 with HTML escaping

* Escape HTML in ServletRedirectResult response

Escape HTML in the final location before writing to the response.
2026-06-14 18:44:43 +02:00
Lukasz Lenart dd830dca80 WW-5630 test: streamline ConfigParseUtilTest and convert to JUnit 4 (#1740)
Collapse 12 overlapping cache tests to 5 focused ones, replace the
~80-entry JDK class-name literal with a synthetic-name loop bounded by
the inner-cache limit, and drop reflection from the behavioral tests
(load-count assertions only). Reflection is retained solely in the two
size-bound tests, where Caffeine exposes no public seam.

Production ConfigParseUtil caching logic is unchanged.

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-14 09:16:39 +00:00
dependabot[bot] 289bcaa922 build(deps): bump org.htmlunit:htmlunit from 4.21.0 to 5.1.0 (#1733)
Bumps [org.htmlunit:htmlunit](https://github.com/HtmlUnit/htmlunit) from 4.21.0 to 5.1.0.
- [Release notes](https://github.com/HtmlUnit/htmlunit/releases)
- [Commits](https://github.com/HtmlUnit/htmlunit/compare/4.21.0...5.1.0)

---
updated-dependencies:
- dependency-name: org.htmlunit:htmlunit
  dependency-version: 5.1.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-13 08:34:36 +02:00
dependabot[bot] b808dcb845 build(deps): bump com.fasterxml.jackson:jackson-bom (#1729)
Bumps [com.fasterxml.jackson:jackson-bom](https://github.com/FasterXML/jackson-bom) from 2.21.3 to 2.22.0.
- [Commits](https://github.com/FasterXML/jackson-bom/compare/jackson-bom-2.21.3...jackson-bom-2.22.0)

---
updated-dependencies:
- dependency-name: com.fasterxml.jackson:jackson-bom
  dependency-version: 2.22.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-13 08:33:28 +02:00
Lukasz Lenart 4f3fd69aa6 WW-5632 Harden commons-fileupload2 dependency against milestone binary-incompatibility (#1735)
* WW-5632 docs: add commons-fileupload2 milestone-hardening design spec

Design for hardening the commons-fileupload2 dependency against
milestone binary-incompatibility (manage -core, activate a scoped
enforcer rule, add a runtime API guard in AbstractMultiPartRequest).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* WW-5632 docs: add implementation plan for fileupload2 milestone hardening

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* WW-5632 build(deps): manage commons-fileupload2-core alongside jakarta-servlet6

Pin both commons-fileupload2 artifacts to a single
commons-fileupload2.version property so the volatile -core API can no
longer skew from -jakarta-servlet6 in the reactor.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* WW-5632 build: enforce a single commons-fileupload2 version

Activate maven-enforcer-plugin (previously dormant in pluginManagement)
with a fileupload-scoped bannedDependencies rule so any divergent
commons-fileupload2 version fails the build early.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* WW-5632 fix(fileupload): fail fast on incompatible commons-fileupload2 API

Verify once per JVM that the fileupload size-limit setters exist and
throw a clear StrutsException reporting the core/jakarta version skew,
replacing an opaque deep-stack NoSuchMethodError in downstream runtimes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* WW-5632 fix(fileupload): make API-verification guard static

Resolve Sonar java:S2696 (instance method writing a static field) by
making ensureFileUploadApiVerified() static; verification is JVM-global.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-13 08:28:47 +02:00
brianandle 210dc86b88 WW-5630 - Performance Issue SecurityMemberAccess (#1721)
* WW-5630 - Performance Issue SecurityMemberAccess
* Add size bound cache, 50, for Class lookup
* Add unit test

Code generated by Copilot

* WW-5630 - Add additional UT

* WW-5630 - Add UT for non-existent class

* WW-5630 - Review feedback changes
* Cache ClassLoader directly
* Use weakKeys and weakValues
* Comment on the ClassLookupException
* Additional Unit Tests

Assistance in coding using co-pilot

* WW-5630 - Additional review
* Limit outer, Classloader, to 25. Ensure memory bounding.
* Limit inner, Classes, to 50. Ensure memory bounding.
* Additional UTs

With co-pilot assitance
2026-06-12 17:12:26 +00:00
dependabot[bot] 7c6034c667 build(deps-dev): bump org.apache.maven.plugins:maven-failsafe-plugin (#1732)
Bumps [org.apache.maven.plugins:maven-failsafe-plugin](https://github.com/apache/maven-surefire) from 3.5.5 to 3.5.6.
- [Release notes](https://github.com/apache/maven-surefire/releases)
- [Commits](https://github.com/apache/maven-surefire/compare/surefire-3.5.5...surefire-3.5.6)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-failsafe-plugin
  dependency-version: 3.5.6
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-10 13:23:50 +02:00
dependabot[bot] 5e725a72cd build(deps): bump github/codeql-action from 4.36.0 to 4.36.2 (#1734)
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 4.36.0 to 4.36.2.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Commits](https://github.com/github/codeql-action/compare/v4.36.0...v4.36.2)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-version: 4.36.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-10 13:23:21 +02:00
dependabot[bot] 53ef1ad883 build(deps): bump org.apache.maven.plugins:maven-dependency-plugin (#1730)
Bumps [org.apache.maven.plugins:maven-dependency-plugin](https://github.com/apache/maven-dependency-plugin) from 3.10.0 to 3.11.0.
- [Release notes](https://github.com/apache/maven-dependency-plugin/releases)
- [Commits](https://github.com/apache/maven-dependency-plugin/compare/maven-dependency-plugin-3.10.0...maven-dependency-plugin-3.11.0)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-dependency-plugin
  dependency-version: 3.11.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-10 13:22:50 +02:00
dependabot[bot] 0972a608a3 build(deps): bump maven-surefire-plugin.version from 3.5.5 to 3.5.6 (#1731)
Bumps `maven-surefire-plugin.version` from 3.5.5 to 3.5.6.

Updates `org.apache.maven.surefire:surefire-junit47` from 3.5.5 to 3.5.6

Updates `org.apache.maven.plugins:maven-surefire-plugin` from 3.5.5 to 3.5.6
- [Release notes](https://github.com/apache/maven-surefire/releases)
- [Commits](https://github.com/apache/maven-surefire/compare/surefire-3.5.5...surefire-3.5.6)

---
updated-dependencies:
- dependency-name: org.apache.maven.surefire:surefire-junit47
  dependency-version: 3.5.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
- dependency-name: org.apache.maven.plugins:maven-surefire-plugin
  dependency-version: 3.5.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-10 13:22:32 +02:00
Lukasz Lenart 9011c32b38 WW-5631 Add opt-in @StrutsParameter enforcement to ChainingInterceptor (#1719)
* WW-5631 feat(chaining): add struts.chaining.requireAnnotations constant

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* WW-5631 feat(chaining): default struts.chaining.requireAnnotations=false

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* WW-5631 test(chaining): add annotated/unannotated chaining fixtures

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* WW-5631 test(chaining): add failing @StrutsParameter enforcement tests

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* WW-5631 feat(chaining): enforce @StrutsParameter on target when opted in

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* WW-5631 refactor(chaining): align requireAnnotations parsing with BooleanUtils

Use BooleanUtils.toBoolean for the chaining requireAnnotations flag so it
accepts the same values (yes/on/1) as the sibling
struts.parameters.requireAnnotations switch, and unify the enforcement WARN
message prefix.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* WW-5631 test(chaining): cover includes interaction and proxied target

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* WW-5631 docs(chaining): document struts.chaining.requireAnnotations

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* WW-5631 test(chaining): cover fail-closed introspection; clarify target==action

Add a test asserting nothing is copied when the target action cannot be
introspected (fail-closed), and document why isAuthorized is called with
target == action for chaining (no ModelDriven exemption).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* WW-5631 fix(chaining): address SonarCloud findings

- Mark injected parameterAuthorizer/ognlUtil fields transient (S1948);
  they are re-injected by the container, not serialized.
- Extract per-object copy into copyObjectToAction so the copyStack loop
  uses no break/continue (S135); fail-closed path now returns from the
  helper instead of continuing the loop.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-10 13:19:43 +02:00
Lukasz Lenart 69cb2964f0 docs(skills): add triaging-security-reports skill (#1722)
Add an agent skill for triaging privately-disclosed security reports:
research each claim from source without trusting the reporter, verify
effective runtime defaults (config overrides field initializers), avoid
introducing unverified facts into responses, and frame findings as
vulnerability vs. operator responsibility.

Developed test-first: a baseline run produced contradictory, unverified
claims about defaults; the skill closes that gap and was verified to also
avoid over-correcting into reflexive rejection of valid reports.

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-02 08:44:18 +02:00
dependabot[bot] e637bb16a3 build(deps): bump asm.version from 9.10 to 9.10.1 (#1713)
Bumps `asm.version` from 9.10 to 9.10.1.

Updates `org.ow2.asm:asm` from 9.10 to 9.10.1

Updates `org.ow2.asm:asm-commons` from 9.10 to 9.10.1

---
updated-dependencies:
- dependency-name: org.ow2.asm:asm
  dependency-version: 9.10.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
- dependency-name: org.ow2.asm:asm-commons
  dependency-version: 9.10.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-28 07:17:30 +02:00
dependabot[bot] 1555cabff1 build(deps): bump org.apache.maven.plugins:maven-site-plugin (#1711)
Bumps [org.apache.maven.plugins:maven-site-plugin](https://github.com/apache/maven-site-plugin) from 3.21.0 to 3.22.0.
- [Release notes](https://github.com/apache/maven-site-plugin/releases)
- [Commits](https://github.com/apache/maven-site-plugin/compare/maven-site-plugin-3.21.0...maven-site-plugin-3.22.0)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-site-plugin
  dependency-version: 3.22.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-28 07:17:16 +02:00
dependabot[bot] c7b1ca3f0a build(deps): bump github/codeql-action from 4.35.5 to 4.36.0 (#1710)
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 4.35.5 to 4.36.0.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Commits](https://github.com/github/codeql-action/compare/v4.35.5...v4.36.0)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-version: 4.36.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-28 07:16:52 +02:00
Lukasz Lenart 26756ce85c security(versions): updates list of supported versions (#1708) 2026-05-22 04:47:05 +00:00
dependabot[bot] d628d949a0 build(deps): bump org.apache.logging.log4j:log4j-bom (#1685)
Bumps [org.apache.logging.log4j:log4j-bom](https://github.com/apache/logging-log4j2) from 2.25.4 to 2.26.0.
- [Release notes](https://github.com/apache/logging-log4j2/releases)
- [Changelog](https://github.com/apache/logging-log4j2/blob/2.x/RELEASE-NOTES.adoc)
- [Commits](https://github.com/apache/logging-log4j2/compare/rel/2.25.4...rel/2.26.0)

---
updated-dependencies:
- dependency-name: org.apache.logging.log4j:log4j-bom
  dependency-version: 2.26.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-20 10:06:49 +02:00
dependabot[bot] cc6b4cfd6e build(deps): bump asm.version from 9.9.1 to 9.10 (#1695)
Bumps `asm.version` from 9.9.1 to 9.10.

Updates `org.ow2.asm:asm` from 9.9.1 to 9.10

Updates `org.ow2.asm:asm-commons` from 9.9.1 to 9.10

---
updated-dependencies:
- dependency-name: org.ow2.asm:asm
  dependency-version: '9.10'
  dependency-type: direct:production
  update-type: version-update:semver-minor
- dependency-name: org.ow2.asm:asm-commons
  dependency-version: '9.10'
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-20 09:18:23 +02:00
Lukasz Lenart f26325ff90 ci(dependabot): fix cooldown property name (#1702)
The `cooldown` block expects `default-days`, not `default`. Using the
wrong key fails schema validation, causing Dependabot to silently fall
back to the previously valid config — which still targets
`release/struts-6-8-x` instead of `support/struts-6-x-x`.

Also adds a 3-day cooldown to the `main` maven entry for consistency.

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-20 07:07:05 +00:00
dependabot[bot] 1bd2951f7e build(deps-dev): bump org.apache.maven.plugins:maven-enforcer-plugin (#1698)
Bumps [org.apache.maven.plugins:maven-enforcer-plugin](https://github.com/apache/maven-enforcer) from 3.6.2 to 3.6.3.
- [Release notes](https://github.com/apache/maven-enforcer/releases)
- [Commits](https://github.com/apache/maven-enforcer/compare/enforcer-3.6.2...enforcer-3.6.3)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-enforcer-plugin
  dependency-version: 3.6.3
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-20 08:59:25 +02:00
dependabot[bot] 16618e0236 build(deps): bump github/codeql-action from 4.35.4 to 4.35.5 (#1694)
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 4.35.4 to 4.35.5.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Commits](https://github.com/github/codeql-action/compare/v4.35.4...v4.35.5)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-version: 4.35.5
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-20 08:58:58 +02:00
Lukasz Lenart 419fb1f5c6 WW-5535 test(core): cover wildcard-resolved unannotated methods via real proxy (#1692)
Closes the test gap noted in the WW-5535 research: no integration test
exercised HttpMethodInterceptor against a real DefaultActionProxy resolving
a wildcard action with an unannotated method.

Uses xwork-test-allowed-methods.xml's existing <action name="Wild-*"
method="{1}"> on HttpMethodsTestAction. URL "Wild-execute" resolves to
ActionSupport.execute() (no method-level HTTP annotation); the class-level
@AllowedHttpMethod(POST) must still reject GET end-to-end.

Together with the prior MockActionProxy regression tests, this locks in
both halves of the fix:
- DefaultActionProxy.resolveMethod() sets isMethodSpecified()=true for
  wildcard-resolved methods (WW-5535 / #1592)
- HttpMethodInterceptor falls back to class-level annotations when the
  resolved method is unannotated (#1690)
2026-05-19 08:26:49 +00:00
ⳕⲛτⲉⲅⲥⲉⳏτⲟⲅ 🕵🏻 213b83f64f fix(core): enforce class-level HTTP method annotations for wildcard-resolved unannotated methods (#1690)
The WW-5535 fix (commit 4d2eb93) corrected isMethodSpecified() for wildcard-resolved
methods but introduced a structural gap in HttpMethodInterceptor.intercept().

The if/else-if structure made the class-level annotation check unreachable whenever
isMethodSpecified()=true and the resolved method carries no method-level annotation:

  if (isMethodSpecified()) {
      if (isAnnotatedBy(method)) { ... }
      // falls through silently
  } else if (isAnnotatedBy(class)) { ... }  // never reached
  return invocation.invoke();               // no enforcement

Fix: convert else-if to standalone if so the class-level check is always evaluated
as a fallback when the method itself has no annotation. Method-level annotations
still take precedence (checked first).

Add two regression tests covering the wildcard-resolved unannotated method scenario.

Co-authored-by: g0w6y <g0w6y@users.noreply.github.com>
2026-05-19 08:05:21 +02:00