[Coldbox 7] Possible Bug With `moduleSettings` When ForgeBox Module is Private

I ran into something that feels a bit unintuitive (and possibly a bug) when referencing module settings for a private ForgeBox module.

The exception

When a private module is installed as a dependency and the module code tries to inject its own settings like this:

property name="settings" inject="coldbox:moduleSettings:my-private-module";

ColdBox throws the following exception at runtime:

The DSL provided was not valid:
{
  ref={null},
  delegateExcludes={[]},
  delegatePrefix={},
  delegateSuffix={},
  required={true},
  argName={},
  delegateIncludes={[]},
  javaCast={null},
  dsl={coldbox:moduleSettings:my-private-module},
  name={settings},
  type={any},
  delegate={false},
  scope={variables},
  value={null}
}

What I’ve observed

If the module is private on ForgeBox, accessing its settings appears to require the ForgeBox username to be appended to the module name.

For example, instead of:

getModuleSettings( "my-private-module" );

you must do:

getModuleSettings( "my-private-module@forgeboxUser" );

This works fine from the parent application that installs the module as a dependency.

However, it becomes problematic when building the module itself.

Why this feels odd

Inside the module’s own codebase:

  • The module’s test harness works with:
property name="settings" inject="coldbox:moduleSettings:my-private-module";
  • But once the module is installed as a dependency, the same code fails, unless the module name includes the ForgeBox username.

That means the module itself must ā€œknowā€ the ForgeBox username it was published under, which feels like a leaky abstraction. From a module author’s perspective, I’d expect the module to be able to reference its own settings by its canonical module name, regardless of whether it’s public or private.

Is this expected behavior for private ForgeBox modules, or is this a known limitation/bug in how moduleSettings are resolved?

If expected, is there a recommended pattern for modules to safely reference their own settings without hard-coding the ForgeBox username?

This is basically correct. The moduleName@user IS the canonical name. It’s more/less incorrect that the module’s test harness is inside of a folder that isn’t the module’s canonical name. This has less to do with private modules and is more broadly related to the fact that the folder the module lives in is the default name, therefore tying the module name to how/where it’s installed.

Again, that’s not working because the injection is ā€œinsideā€ the module code. It’s just working on accident because of how your directory structure is configured and how the module testing harness is loading the module name in a way that doesn’t reflect how ForgeBox/CommandBox will behave.

@lmajano can prolly confirm if setting the module name in the ModuleConfig will override this or not. Otherwise, we should prolly update our default module test harness to register the module with the expected name in the module service. Private modules are rare enough (and don’t overlap with our Open Source stuff) so we don’t come across this too often.

Thanks @bdw429s. Sorry I didn’t see your reply earlier as I was ā€œall hands on deckā€ working on a way to address the issue.

I feel pretty strongly that a module shouldn’t care or know whether it’s canonical name has the Forgebox username in it or not. The username doesn’t exist in the ModuleConfig.cfc and only lives in the box.json file. In my opinion, the module config’s modelNamespace should match the DSL.

Anyway, I pieced together a possible fix for the issue (with the help of Claude Sonnet, so I can’t take all the credit).

Here’s the issue link:
https://ortussolutions.atlassian.net/browse/COLDBOX-1374

Here’s my PR:

I do need some help with the Unit Tests I think to ensure everything is accounted for.

I don’t see the concern with a module knowing its name. Again, stop calling the partial name without the suffix the canonical name. The canonical name for private packages is the FULL name with the suffix, which helps avoid name collisions. There’s no difference between a module ā€œknowingā€ it’s called my-module vs my-module@user. The name is the name, and packages living in forgebox are subject to forgebox’s conventions. Just because you never considered the suffix to be part of the canonical name doesn’t mean it isn’t. Your module test suite loaded the module improperly, leading you to use the incorrect injection while testing. As far as whether the module mapping uses the suffix is up to you, but given the existing semantic meaning of @ in wirebox mappings, that would likely cause confusion in wirebox, which already uses module name based namespacing.

After sleeping on it, you are correct. I was overthinking this issue and instead of changing how Coldbox handles canonical mappings, I need to change how I think about it in my own head. I’ll go ahead and withdraw the issue and PR. As always, I appreciate your guidance.

No worries-- at let us know how we can improve our module templates to better handle these scenarios. Ideally this would have worked initially with the correct mapping name in the first place!

1 Like

In case anyone else who builds private Forgebox Coldbox modules stumbles upon this, here’s the solution that worked for me.

In my ModuleConfig.cfc, I created an alias:

// Module Properties
this.title       = "my-private-module";

// Model Namespace
this.modelNamespace = "my-private-module";

// This allows consistent moduleSettings DSL injection in both production (@forgeboxUser suffix) and test harness (no suffix)
this.aliases = [ "my-private-module" ];

Then you can inject module properties just like you would normally:

property name="settings"    inject="coldbox:moduleSettings:my-private-module";

Also, as Brad pointed out, make sure you aren’t installing and an aliasing a bunch of ambiguous module names with the same alias like util. Your best bet is to give your modules descriptive slugs.