Skip to content

Fix inheritance handling in security, mappings, XPath rendering and the Java version dialect - #820

Merged
ako merged 11 commits into
mendixlabs:mainfrom
ako:main
Aug 2, 2026
Merged

Fix inheritance handling in security, mappings, XPath rendering and the Java version dialect#820
ako merged 11 commits into
mendixlabs:mainfrom
ako:main

Conversation

@ako

@ako ako commented Aug 2, 2026

Copy link
Copy Markdown
Collaborator

Five fixes from issue triage on this fork, each verified against a real Mendix project with mx check and covered by a regression test plus an MDL repro fixture in mdl-examples/bug-tests/.

Take this one for the red nightly. The last sync's #759 fix regressed alter settings model JavaVersion on Mendix 11.12 — first bullet below. Until it lands, 14-project-settings-examples.mdl fails on every Mendix version and both engines.

The nightly regression

  • Java version: the rename changed the value format, not just the key. Mendix renamed JavaVersion to JavaMajorVersion between 11.6 and 11.12 and moved the value with it — 11.6 stores the enum member "Java21", 11.12 the bare major "21". The Runtime Configuration ( Create or Update ) are not fully supported #759 fix followed only the key and wrote the caller's value through verbatim, so alter settings model JavaVersion = 'Java21' put "Java21" into JavaMajorVersion and mxbuild refuses to load the project: ArgumentOutOfRangeException ... (Parameter 'majorVersion is an unsupported value: Java21') at JavaVersionExtensions.fromString.

    Note the failure mode is sharper than the original Runtime Configuration ( Create or Update ) are not fully supported #759 shape. That one wrote an unknown property, which mxbuild tolerates — only Studio Pro broke, so it took a user report to surface. A wrong value for a known enum fails the whole project load, taking every check downstream of the settings unit with it.

    settingsoverlay.JavaVersionValue now renders the value in the dialect the stored key expects, so either spelling is accepted on input and one MDL statement is portable across versions. Verified with mx check on real projects: 11.12.2 given 'Java21' stores '21' and checks clean on both engines (a pre-fix binary reproduces the nightly error exactly); 11.6.6 given '21' stores 'Java21', 0 errors.

Inheritance: a member reference belongs to the entity that declares it

Three of these turned out to be the same rule applied in different places — the umbrella issue is #765.

Other fixes

claude and others added 11 commits August 2, 2026 00:13
…ixlabs#772)

Mendix stores sibling predicate groups concatenated in one XPathConstraint field:

  [Reminders.Task_TaskGroup/Reminders.TaskGroup[EndDate = $EndDateLimit]]
  [Status != 'Completed']
  [CompletionDate = empty]

The grammar's xpathConstraint rule matches ONE bracket group. ParseXPathConstraint
removes the error listeners, so ANTLR parsed the first group, left the rest on the
token stream, and still returned ok=true. enrichXPathConstraintForDescribe read
that as a full parse and re-rendered only what came back — its
`if !ok { return original }` fallback never fired — so describe emitted:

  where Reminders.Task_TaskGroup/Reminders.TaskGroup[EndDate = $EndDateLimit];

That is worse than a crash. The output looks complete while describing a
materially less restrictive query than the project contains, which makes correct
defensive code read as buggy — and `describe` is what an agent reads to decide
whether code is right.

Fixed in two layers:

1. ParseXPathConstraint reports a partial parse as a failure (require the token
   stream to be at EOF). That alone stops the data loss: the caller falls back to
   the stored string, which the render path then splits correctly.
2. visitor.SplitXPathPredicateGroups splits a constraint into its top-level
   groups, and each is enriched and rendered separately — so enum enrichment
   reaches groups after the first, not just the first. The splitter tracks nesting
   depth and quoting, because the previous "][" split mangled both a nested
   [A/B[x = 1]] and a literal containing ']'. The render path now uses it too.

Verified end-to-end on a real 11.12.2 project carrying the reported constraint
shape: all three groups render, Status is enriched to its qualified enum value in
the second group, the output re-parses and re-executes to an identical flow, and
`mx check` reports 0 errors. A/B against a pre-fix binary on the same project
reproduces the two dropped groups exactly as reported.

All three guards mutation-checked.

Refs mendixlabs#772
…ndixlabs#758, mendixlabs#765)

Mendix models inheritance across multiple tables: a child adds attributes to the
parent's, and all of the parent's are members of the child. An access rule must
therefore carry a MemberAccess entry for every member — own AND inherited — or
Mendix reports CE0066 "Entity access is out of date".

Both the GRANT builder and ReconcileMemberAccesses enumerated only
entity.Attributes. Two consequences, and the second explains why the first could
not be worked around:

  * GRANT naming an inherited member produced no entry at all, while reporting
    success.
  * Reconciliation runs immediately after every GRANT, and on any write touching
    the module. An inherited reference is qualified against the entity that
    DECLARES it, so it never matched the child's own attribute list and was
    deleted as stale — removing, in the same command, what the grant had just
    written. That is why REVOKE + GRANT never repaired a damaged rule.

The damage was masked: mx check reports CE0066 and stops, hiding the CE2729
"No read access to attribute" cascade until Studio Pro's Update security is
clicked, so CLI-only workflows shipped it undetected.

Two facts were established against mx check rather than inferred:

  1. An inherited member's reference must be qualified against its declaring
     entity. Sec758.Base.SharedField validates clean; the child-qualified
     Sec758.Item.SharedField is CE1613 "The selected attribute no longer exists".
     mxcli wrote the child form. This is the same rule the change-object writer
     needs (mendixlabs#451).
  2. System.User's members are the exception. Entities specialising it are user
     entities whose platform members Mendix manages: listing them turns a clean
     rule into CE0066 — confirmed on Mendix's own Administration.Account and on a
     fresh specialisation — while omitting System.FileDocument's six members is
     CE0066 until all are present.

Fixed:

  * EntityMembers walks the generalization chain, qualifying each member against
    its declaring entity and excluding System.User's platform members. The GRANT
    builder uses it, and now rejects a named member that matched nothing instead
    of dropping it in silence.
  * Reconciliation strips only a reference qualified to the entity itself. An
    ancestor may live in another module or in System, neither of which is loaded
    at that layer, so an inherited reference cannot be validated there — it is
    preserved rather than deleted. Applied to both engines.

Verified end-to-end on a real 11.12.2 project carrying all three specialisation
shapes at once — same-module ancestor, System.FileDocument, and System.User —
mx check reports 0 errors, and describe round-trips both members of the mixed
entity. All three guards mutation-checked.

Refs mendixlabs#758, mendixlabs#765
Nothing about entity inheritance appeared in any security doc, even though a
specialized entity's access rule must cover its inherited members and getting it
wrong is CE0066. Added to each surface the story touches:

- mxcli syntax security.entity-access — an "Inherited members" block plus
  examples for a same-module ancestor and System.FileDocument
- skills/mendix/manage-security.md — worked example, the None-rights detail, the
  new unknown-member error, and the System.User exception
- skills/mendix/generate-domain-model.md — a pointer from EXTENDS, where a reader
  meets inheritance first
- docs-site security/grant.md — the same as reference prose
- MDL_QUICK_REFERENCE.md — the grant-entity-access row

Covers what mendixlabs#758/mendixlabs#765 made work: inherited members are named exactly like the
entity's own, READ */WRITE * include them, unmatched names are an error rather
than a silent skip, and entities extending System.User must not grant their
inherited platform members.
…ixlabs#703)

Mendix inheritance is multi-table: a child adds attributes to its parent's, and
all the parent's are members of the child. A mapping element bound to one must
reference the entity that DECLARES it. The builder prefixed the entity being
mapped, unconditionally:

    attr := def.Attribute
    if parentEntity != "" && !strings.Contains(attr, ".") {
        attr = parentEntity + "." + attr      // always the CHILD
    }

so every inherited field produced a reference to an attribute that entity does
not have. Studio Pro shows the field unmapped — the reported symptom — and
mx check reports CE1613 "The selected attribute ... no longer exists".

A second, quieter defect sat next to it: resolveAttributeType scanned only the
entity's own attributes and fell through to a "String" default, so an inherited
Boolean or DateTime element carried the wrong DataType even once the reference
was correct. That function also matched entities by name across every domain
model, ignoring the module, so a same-named entity elsewhere could win; it now
resolves the module by name.

Both the import and export builders carried the same two lines, and both are
fixed. They route through the generalization walk added for mendixlabs#758, generalised
here into ResolveMemberRef (declaring-entity reference) and ResolveMemberType
(type from up the chain), each falling back to the previous behaviour when the
member cannot be resolved. EntityMembersFor takes the backend directly so the
mapping builders, which hold no ExecContext, can use it.

This closes the mapping half of the mendixlabs#765 umbrella; the same declaring-entity rule
governs entity access rules (mendixlabs#758) and the change-object writer (mendixlabs#451).

Verified end-to-end on a real 11.12.2 project with an entity extending another,
mapping one own and two inherited attributes in both directions:

    before:  Map703.Contract.DocName        StringType   -> CE1613
             Map703.Contract.Confidential   StringType   -> CE1613
    after:   Map703.DocumentBase.DocName        StringType
             Map703.DocumentBase.Confidential   BooleanType
             mx check -> 0 errors

Both halves mutation-checked, including a test at the resolveAttributeType call
site rather than only on the resolver — reverting the call site alone left the
resolver's own test green.

Docs: inheritance was unmentioned in every mapping doc, so the syntax topic, the
json-structures-and-mappings skill and docs-site create-import-mapping now cover
it.

Refs mendixlabs#703, mendixlabs#765
The doctype example granted read on SecTest.Customer (Notes), but the entity
only declares Name, Email and IsActive. Before mendixlabs#758 an unmatched member name was
dropped in silence, so the grant did nothing and the script still passed; with
that silence replaced by an error the example fails, and the integration tier
caught it.

The example is what is wrong: its own comment says "adding Notes access
preserves existing Name and Email", so it always meant to demonstrate an
additive grant on a third attribute. Declaring Notes makes it do that.

Fixes the build-and-test failure on main introduced by #81.
The mendixlabs#759 fix followed the JavaVersion -> JavaMajorVersion key rename but
wrote the caller's value through verbatim. The rename changed the value
format too: 11.6 stores the enum member "Java21", 11.12 the bare major
"21". So `alter settings model JavaVersion = 'Java21'` on an 11.12 project
put "Java21" into JavaMajorVersion, and mxbuild refuses to load it:

  System.ArgumentOutOfRangeException: Specified argument was out of the
  range of valid values. (Parameter 'majorVersion is an unsupported value:
  Java21') at Mendix.Modeler.Settings.JavaVersionExtensions.fromString

This is a harder failure than the original mendixlabs#759 shape. That one wrote an
unknown property, which mxbuild tolerates, so only Studio Pro broke; a
wrong value for a known enum fails the whole project load, taking every
check downstream of the settings unit with it. It is why the nightly went
red on 14-project-settings-examples.mdl at 11.12 rather than surfacing as
a user report.

settingsoverlay.JavaVersionValue renders the value per stored key, so
either spelling is accepted on input and stored in the project's own
dialect. A value with no recognisable major version passes through
untouched, so a typo surfaces as a Mendix error rather than as a silently
mangled setting.

Verified on real projects with mx check: 11.12.2 given 'Java21' stores
'21' and checks clean on both engines (pre-fix binary reproduces the
nightly error exactly); 11.6.6 given '21' stores 'Java21', 0 errors.

Also routes the unused third copy in modelsdk/mpr/serialize_services.go
through the same helper, so wiring it up later cannot reintroduce this.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012XR649rKk68z6gBpngu6MA
fix: write the Java version in the dialect the stored key expects
@ako
ako merged commit c376ccc into mendixlabs:main Aug 2, 2026
4 checks passed
@github-actions github-actions Bot mentioned this pull request Aug 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants