This is an automated email from the ASF dual-hosted git repository.

lukaszlenart pushed a commit to branch WW-5675-share-parsed-ognl-security-config
in repository https://gitbox.apache.org/repos/asf/struts.git

commit 9b1eb89be1bfa018e48cb95ec4f5be30ff97f1e1
Author: Lukasz Lenart <[email protected]>
AuthorDate: Fri Aug 14 14:45:23 2026 +0200

    WW-5675 docs(ognl): correct the wiring claim the full-suite run disproved
    
    Dispatcher installs its own provider list and never adds
    StrutsDefaultConfigurationProvider, so bootstrapFactories is not on the
    production path. The bean needs registering in struts-beans.xml too,
    matching ProviderAllowlist and ThreadAllowlist.
    
    Co-Authored-By: Claude Opus 5 <[email protected]>
---
 ...security-member-access-config-sharing-design.md | 37 ++++++++++++++++------
 1 file changed, 27 insertions(+), 10 deletions(-)

diff --git 
a/docs/superpowers/specs/2026-08-14-WW-5675-security-member-access-config-sharing-design.md
 
b/docs/superpowers/specs/2026-08-14-WW-5675-security-member-access-config-sharing-design.md
index 50ecb2962..319ce54ec 100644
--- 
a/docs/superpowers/specs/2026-08-14-WW-5675-security-member-access-config-sharing-design.md
+++ 
b/docs/superpowers/specs/2026-08-14-WW-5675-security-member-access-config-sharing-design.md
@@ -86,16 +86,33 @@ Concrete class, no interface, **not** aliased in 
`StrutsBeanSelectionProvider`.
 the shape of `ProviderAllowlist` and `ThreadAllowlist` 
(`DefaultConfiguration.java:418-419`), not a user extension
 point.
 
-`bootstrapFactories` is on the production path, not test-only: 
`ConfigurationManager.addDefaultContainerProviders`
-(`ConfigurationManager.java:94`) registers 
`StrutsDefaultConfigurationProvider`, which calls it at
-`StrutsDefaultConfigurationProvider.java:116`, and `Dispatcher` drives 
`ConfigurationManager`. It reads as
-test-oriented in a grep only because a dozen tests name the provider 
explicitly and `XWorkTestCaseHelper` — test
-scaffolding that lives in `core/src/main` — registers it too.
-
-The method serves both the bootstrap container 
(`DefaultConfiguration.java:360`) and the main container, so each
-gets its own configuration singleton. The bootstrap container carries only 
`BOOTSTRAP_CONSTANTS`, so most security
-constants are absent there, the `required = false` setters do not fire, and 
the bean falls back to defaults —
-exactly as a `SecurityMemberAccess` constructed in that container behaves 
today.
+**The bean must be registered in two places.** An earlier draft of this design 
claimed `bootstrapFactories` was on
+the production path because 
`ConfigurationManager.addDefaultContainerProviders` 
(`ConfigurationManager.java:94`)
+registers `StrutsDefaultConfigurationProvider`, which calls it at
+`StrutsDefaultConfigurationProvider.java:116`. **That claim is wrong**, and it 
was only caught when the full core
+suite failed with 1579 errors during implementation.
+
+`ConfigurationManager.addDefaultContainerProviders()` fires only when 
`containerProviders.isEmpty()`
+(`ConfigurationManager.java:78-80`). `Dispatcher.init()` 
(`Dispatcher.java:711-719`) installs its own provider
+list — including `StrutsBeanSelectionProvider` via `init_AliasStandardObjects` 
— so the list is never empty and
+`StrutsDefaultConfigurationProvider` is never added. The production container 
is built from
+`StrutsBeanSelectionProvider` plus `struts-beans.xml`, and 
`bootstrapFactories` is not on that path at all.
+
+The registration therefore goes in both places, which is precisely what 
`ProviderAllowlist` and `ThreadAllowlist`
+already do — `DefaultConfiguration.java:418-419` and 
`struts-beans.xml:175-176`:
+
+```xml
+    <bean class="org.apache.struts2.ognl.SecurityMemberAccessConfig"/>
+```
+
+The `DefaultConfiguration` registration serves the bootstrap container 
(`DefaultConfiguration.java:360`) and the
+`XWorkTestCase` harness; the `struts-beans.xml` entry serves the real 
Dispatcher container. The bootstrap
+container carries only `BOOTSTRAP_CONSTANTS`, so most security constants are 
absent there, the
+`required = false` setters do not fire, and the bean falls back to defaults — 
exactly as a `SecurityMemberAccess`
+constructed in that container behaves today.
+
+This failure mode is loud, not silent: `useConfig` is a mandatory `@Inject`, 
so a container missing the binding
+throws at build time rather than running with empty exclusions.
 
 The `TODO: SpringObjectFactoryTest fails when these are SINGLETON` comment at 
the top of `bootstrapFactories`
 applies to the `*Factory` beans in the first block, not to this region, where 
singletons are already the norm.

Reply via email to