Skip to content

Commit 453d748

Browse files
committed
Merge branch 'issues'
2 parents 7637701 + 142439d commit 453d748

File tree

18 files changed

+7247
-6597
lines changed

18 files changed

+7247
-6597
lines changed

.claude/skills/mendix/manage-security.md

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,8 @@ REVOKE VIEW ON PAGE MyModule.Customer_Overview FROM MyModule.User;
121121

122122
### Entity Access (CRUD)
123123

124+
GRANT is **additive** — it merges with existing access, never removes permissions.
125+
124126
```sql
125127
-- Full access (all CRUD + all members)
126128
GRANT MyModule.Admin ON MyModule.Customer (CREATE, DELETE, READ *, WRITE *);
@@ -131,11 +133,23 @@ GRANT MyModule.Viewer ON MyModule.Customer (READ *);
131133
-- Selective member access
132134
GRANT MyModule.User ON MyModule.Customer (READ (Name, Email), WRITE (Email));
133135

136+
-- Additive: adds Phone to existing read access (Name, Email preserved)
137+
GRANT MyModule.User ON MyModule.Customer (READ (Phone));
138+
134139
-- With XPath constraint
135140
GRANT MyModule.User ON MyModule.Order (READ *, WRITE *) WHERE '[Status = ''Open'']';
136141

137-
-- Revoke entity access for a role
142+
-- Revoke entity access entirely
138143
REVOKE MyModule.Viewer ON MyModule.Customer;
144+
145+
-- Partial revoke: remove read on specific attribute
146+
REVOKE MyModule.User ON MyModule.Customer (READ (Phone));
147+
148+
-- Partial revoke: downgrade write to read-only
149+
REVOKE MyModule.User ON MyModule.Customer (WRITE (Email));
150+
151+
-- Partial revoke: remove structural permission
152+
REVOKE MyModule.User ON MyModule.Customer (DELETE);
139153
```
140154

141155
### User Roles

cmd/mxcli/help_topics/security.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,13 @@ PAGE ACCESS:
2929
ENTITY ACCESS:
3030
GRANT <role> ON <module>.<entity> (<rights>) [WHERE '<xpath>'];
3131
REVOKE <role> ON <module>.<entity>;
32+
REVOKE <role> ON <module>.<entity> (<rights>);
3233

3334
Rights: CREATE, DELETE, READ *, READ (<attr>,...), WRITE *, WRITE (<attr>,...)
3435

36+
GRANT is additive — merges new rights into existing access rules.
37+
REVOKE without rights removes the entire rule; with rights, downgrades selectively.
38+
3539
USER ROLES:
3640
CREATE USER ROLE <name> (<role> [, ...]) [MANAGE ALL ROLES];
3741
ALTER USER ROLE <name> ADD MODULE ROLES (<role> [, ...]);

docs-site/src/examples/security.md

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,12 +73,28 @@ CREATE OR MODIFY DEMO USER 'manager' PASSWORD 'Password1!' (SalesManager);
7373
ALTER PROJECT SECURITY DEMO USERS ON;
7474
```
7575

76+
## Additive Grants
77+
78+
GRANT merges with existing access — it never removes permissions:
79+
80+
```sql
81+
-- Viewer already has READ (Name, Email)
82+
GRANT Sales.Viewer ON Sales.Customer (READ (Phone));
83+
-- Result: READ (Name, Email, Phone)
84+
```
85+
7686
## Revoking Access
7787

7888
```sql
79-
-- Remove a specific grant
89+
-- Remove all access for a role
8090
REVOKE Sales.Viewer ON Sales.Customer;
8191

92+
-- Partial revoke: remove read on a specific attribute
93+
REVOKE Sales.User ON Sales.Customer (READ (Phone));
94+
95+
-- Partial revoke: downgrade write to read-only
96+
REVOKE Sales.User ON Sales.Customer (WRITE (Email));
97+
8298
-- Remove microflow access
8399
REVOKE EXECUTE ON MICROFLOW Sales.ACT_Order_Delete FROM Sales.User;
84100
```

docs-site/src/language/entity-access.md

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,23 @@ GRANT Shop.User ON Shop.Order (READ *, WRITE *)
5959

6060
Note that single quotes inside XPath expressions must be doubled (`''`), since the entire expression is wrapped in single quotes.
6161

62+
### Additive Behavior
63+
64+
GRANT is **additive**. If a role already has an access rule on the entity, the new rights are merged in without removing existing permissions:
65+
66+
```sql
67+
-- Initial grant
68+
GRANT Shop.User ON Shop.Customer (READ (Name, Email));
69+
70+
-- Add Notes access — Name and Email are preserved
71+
GRANT Shop.User ON Shop.Customer (READ (Notes));
72+
-- Result: READ (Name, Email, Notes)
73+
74+
-- Upgrade Email to writable — existing reads preserved
75+
GRANT Shop.User ON Shop.Customer (WRITE (Email));
76+
-- Result: READ (Name, Notes), WRITE (Email)
77+
```
78+
6279
### Multiple Roles on the Same Entity
6380

6481
Each GRANT creates a separate access rule. An entity can have rules for multiple roles:
@@ -71,19 +88,30 @@ GRANT Shop.Viewer ON Shop.Order (READ *);
7188

7289
## REVOKE on Entities
7390

74-
Remove an entity access rule for a role:
91+
Remove an entity access rule entirely or revoke specific rights:
7592

7693
```sql
94+
-- Full revoke (removes entire rule)
7795
REVOKE <Module>.<Role> ON <Module>.<Entity>;
96+
97+
-- Partial revoke (downgrades specific rights)
98+
REVOKE <Module>.<Role> ON <Module>.<Entity> (<rights>);
7899
```
79100

80-
Example:
101+
Examples:
81102

82103
```sql
104+
-- Remove all access for Viewer
83105
REVOKE Shop.Viewer ON Shop.Customer;
106+
107+
-- Remove read access on a specific attribute
108+
REVOKE Shop.User ON Shop.Customer (READ (Notes));
109+
110+
-- Downgrade write to read-only on Email
111+
REVOKE Shop.User ON Shop.Customer (WRITE (Email));
84112
```
85113

86-
This removes the entire access rule for that role on that entity.
114+
A full `REVOKE` (without rights list) removes the entire access rule. A partial `REVOKE` downgrades specific rights: `REVOKE READ (x)` sets member x to no access, `REVOKE WRITE (x)` downgrades from ReadWrite to ReadOnly.
87115

88116
## Viewing Entity Access
89117

docs-site/src/language/grant-revoke.md

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ Where `<rights>` is a comma-separated list of:
2121
| `WRITE *` | Write all members |
2222
| `WRITE (<attr>, ...)` | Write specific members only |
2323

24+
GRANT is **additive**: if the role already has an access rule on the entity, new rights are merged in. Existing permissions are never removed by a GRANT — only upgraded.
25+
2426
Examples:
2527

2628
```sql
@@ -36,20 +38,39 @@ GRANT Shop.User ON Shop.Customer (READ (Name, Email), WRITE (Email));
3638
-- With XPath constraint (doubled single quotes for string literals)
3739
GRANT Shop.User ON Shop.Order (READ *, WRITE *)
3840
WHERE '[Status = ''Open'']';
41+
42+
-- Additive: adds Notes to existing read access without removing Name, Email
43+
GRANT Shop.User ON Shop.Customer (READ (Notes));
3944
```
4045

4146
### REVOKE
4247

43-
Remove an entity access rule entirely:
48+
Remove an entity access rule entirely, or revoke specific rights:
4449

4550
```sql
51+
-- Full revoke (removes entire rule)
4652
REVOKE <Module>.<Role> ON <Module>.<Entity>;
53+
54+
-- Partial revoke (downgrades specific rights)
55+
REVOKE <Module>.<Role> ON <Module>.<Entity> (<rights>);
4756
```
4857

49-
Example:
58+
For partial revoke, `REVOKE READ (x)` sets member x access to None. `REVOKE WRITE (x)` downgrades member x from ReadWrite to ReadOnly. `REVOKE CREATE` / `REVOKE DELETE` removes the structural permission.
59+
60+
Examples:
5061

5162
```sql
63+
-- Remove all access
5264
REVOKE Shop.Viewer ON Shop.Customer;
65+
66+
-- Remove read access on a specific member
67+
REVOKE Shop.User ON Shop.Customer (READ (Notes));
68+
69+
-- Downgrade write to read-only
70+
REVOKE Shop.User ON Shop.Customer (WRITE (Email));
71+
72+
-- Remove delete permission only
73+
REVOKE Shop.User ON Shop.Customer (DELETE);
5374
```
5475

5576
## Microflow Access

docs-site/src/reference/security/grant.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ Grants access rights to module roles. There are four forms of the GRANT statemen
2222

2323
### Entity Access
2424

25-
The entity access form creates an access rule on an entity for a given module role. The rule specifies which CRUD operations are permitted and optionally restricts visibility with an XPath constraint.
25+
The entity access form creates or updates an access rule on an entity for a given module role. **GRANT is additive**: if the role already has an access rule on the entity, the new rights are merged with existing ones. Existing permissions are never downgraded by a GRANT.
2626

2727
Entity access rules control:
2828
- **CREATE** -- whether the role can create new instances
@@ -117,6 +117,14 @@ Grant nanoflow execution:
117117
GRANT EXECUTE ON NANOFLOW Shop.NAV_ValidateInput TO Shop.User;
118118
```
119119

120+
Additive grant -- add new attribute access without removing existing:
121+
122+
```sql
123+
-- Viewer already has READ (Name, Email)
124+
GRANT Shop.Viewer ON Shop.Customer (READ (Phone));
125+
-- Result: READ (Name, Email, Phone)
126+
```
127+
120128
## See Also
121129

122130
[REVOKE](revoke.md), [CREATE MODULE ROLE](create-module-role.md), [CREATE USER ROLE](create-user-role.md)

docs-site/src/reference/security/revoke.md

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,12 @@
33
## Synopsis
44

55
```sql
6-
-- Entity access
6+
-- Entity access (full -- removes entire rule)
77
REVOKE module.Role ON module.Entity
88

9+
-- Entity access (partial -- downgrades specific rights)
10+
REVOKE module.Role ON module.Entity ( rights )
11+
912
-- Microflow access
1013
REVOKE EXECUTE ON MICROFLOW module.Name FROM module.Role [, ...]
1114

@@ -22,7 +25,9 @@ Removes previously granted access rights from module roles. Each form is the cou
2225

2326
### Entity Access
2427

25-
Removes the entire entity access rule for the specified module role on the entity. Unlike GRANT, there is no way to partially revoke (e.g., remove only WRITE while keeping READ). The entire rule is removed.
28+
Without a rights list, removes the entire entity access rule for the specified module role on the entity.
29+
30+
With a rights list, performs a **partial revoke**: `REVOKE READ (x)` sets member x to no access. `REVOKE WRITE (x)` downgrades member x from ReadWrite to ReadOnly. `REVOKE CREATE` and `REVOKE DELETE` remove the structural permission. The access rule itself is preserved.
2631

2732
### Microflow Access
2833

@@ -42,7 +47,16 @@ Removes execute permission on a nanoflow from one or more module roles.
4247
: The module role losing access. Must be a qualified name (`Module.RoleName`).
4348

4449
`module.Entity`
45-
: The entity whose access rule is removed.
50+
: The entity whose access rule is removed or modified.
51+
52+
`rights`
53+
: Optional. A comma-separated list of rights to revoke (partial revoke). Same syntax as GRANT rights:
54+
- `CREATE` -- revoke create permission
55+
- `DELETE` -- revoke delete permission
56+
- `READ *` -- revoke all read access
57+
- `READ (Attr1, ...)` -- revoke read on specific attributes
58+
- `WRITE *` -- downgrade all members from ReadWrite to ReadOnly
59+
- `WRITE (Attr1, ...)` -- downgrade specific attributes from ReadWrite to ReadOnly
4660

4761
`module.Name`
4862
: The target microflow, nanoflow, or page.
@@ -52,12 +66,30 @@ Removes execute permission on a nanoflow from one or more module roles.
5266

5367
## Examples
5468

55-
Remove entity access for a role:
69+
Remove all entity access for a role:
5670

5771
```sql
5872
REVOKE Shop.Viewer ON Shop.Customer;
5973
```
6074

75+
Partial revoke -- remove read access on a specific attribute:
76+
77+
```sql
78+
REVOKE Shop.User ON Shop.Customer (READ (Notes));
79+
```
80+
81+
Partial revoke -- downgrade write to read-only:
82+
83+
```sql
84+
REVOKE Shop.User ON Shop.Customer (WRITE (Email));
85+
```
86+
87+
Partial revoke -- remove structural permission:
88+
89+
```sql
90+
REVOKE Shop.User ON Shop.Customer (DELETE);
91+
```
92+
6193
Remove microflow execution from multiple roles:
6294

6395
```sql

docs/01-project/MDL_QUICK_REFERENCE.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -220,8 +220,9 @@ Nested folders use `/` separator: `'Parent/Child/Grandchild'`. Missing folders a
220220
| Revoke microflow access | `REVOKE EXECUTE ON MICROFLOW Mod.MF FROM Mod.Role, ...;` | |
221221
| Grant page access | `GRANT VIEW ON PAGE Mod.Page TO Mod.Role, ...;` | |
222222
| Revoke page access | `REVOKE VIEW ON PAGE Mod.Page FROM Mod.Role, ...;` | |
223-
| Grant entity access | `GRANT Mod.Role ON Mod.Entity (CREATE, DELETE, READ *, WRITE *);` | Supports member lists and WHERE |
224-
| Revoke entity access | `REVOKE Mod.Role ON Mod.Entity;` | |
223+
| Grant entity access | `GRANT Mod.Role ON Mod.Entity (CREATE, DELETE, READ *, WRITE *);` | Additive — merges with existing |
224+
| Revoke entity access | `REVOKE Mod.Role ON Mod.Entity;` | Full revoke — removes entire rule |
225+
| Revoke entity access (partial) | `REVOKE Mod.Role ON Mod.Entity (READ (Attr));` | Partial — downgrades specific rights |
225226
| Set security level | `ALTER PROJECT SECURITY LEVEL OFF\|PROTOTYPE\|PRODUCTION;` | |
226227
| Toggle demo users | `ALTER PROJECT SECURITY DEMO USERS ON\|OFF;` | |
227228
| Create demo user | `CREATE DEMO USER 'name' PASSWORD 'pass' [ENTITY Module.Entity] (UserRole, ...);` | |

docs/05-mdl-specification/01-language-reference.md

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1004,7 +1004,7 @@ REVOKE VIEW ON PAGE <module>.<name> FROM <module>.<role> [, ...]
10041004

10051005
### GRANT (Entity Access)
10061006

1007-
Creates an access rule on an entity for one or more module roles with CRUD permissions.
1007+
Creates or updates an access rule on an entity for one or more module roles with CRUD permissions. **GRANT is additive** — if the role already has an access rule, new rights are merged without removing existing permissions.
10081008

10091009
**Syntax:**
10101010
```sql
@@ -1030,15 +1030,36 @@ GRANT Shop.User ON Shop.Customer (READ (Name, Email), WRITE (Email));
10301030

10311031
-- With XPath constraint
10321032
GRANT Shop.User ON Shop.Order (READ *, WRITE *) WHERE '[Status = ''Open'']';
1033+
1034+
-- Additive: adds Phone to existing read access (Name, Email preserved)
1035+
GRANT Shop.User ON Shop.Customer (READ (Phone));
10331036
```
10341037

10351038
### REVOKE (Entity Access)
10361039

1037-
Removes an entity access rule for specified roles.
1040+
Removes an entity access rule entirely, or revokes specific rights.
10381041

10391042
**Syntax:**
10401043
```sql
1044+
-- Full revoke (removes entire rule)
10411045
REVOKE <module>.<role> ON <module>.<entity>
1046+
1047+
-- Partial revoke (downgrades specific rights)
1048+
REVOKE <module>.<role> ON <module>.<entity> (<rights>)
1049+
```
1050+
1051+
Partial revoke semantics: `REVOKE READ (x)` sets member x to no access. `REVOKE WRITE (x)` downgrades from ReadWrite to ReadOnly. `REVOKE CREATE` / `REVOKE DELETE` removes the structural permission.
1052+
1053+
**Examples:**
1054+
```sql
1055+
-- Remove all access
1056+
REVOKE Shop.Viewer ON Shop.Customer;
1057+
1058+
-- Remove read on specific attribute
1059+
REVOKE Shop.User ON Shop.Customer (READ (Phone));
1060+
1061+
-- Downgrade write to read-only
1062+
REVOKE Shop.User ON Shop.Customer (WRITE (Email));
10421063
```
10431064

10441065
### CREATE USER ROLE

mdl-examples/doctype-tests/08-security-examples.mdl

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -392,11 +392,38 @@ SHOW ACCESS ON SecTest.Customer;
392392
/
393393

394394
-- ============================================================================
395-
-- Level 5.5: Revoke Entity Access
395+
-- Level 5.5: Additive GRANT
396396
-- ============================================================================
397397

398398
/**
399-
* Remove the Viewer role's access rule from Customer.
399+
* GRANT is additive: adding Notes access preserves existing Name and Email.
400+
*/
401+
GRANT SecTest.User ON SecTest.Customer (READ (Notes));
402+
/
403+
404+
-- ============================================================================
405+
-- Level 5.6: Partial REVOKE
406+
-- ============================================================================
407+
408+
/**
409+
* Remove read access on a specific attribute (Notes).
410+
* Other permissions are preserved.
411+
*/
412+
REVOKE SecTest.User ON SecTest.Customer (READ (Notes));
413+
/
414+
415+
/**
416+
* Downgrade write to read-only on Email.
417+
*/
418+
REVOKE SecTest.User ON SecTest.Customer (WRITE (Email));
419+
/
420+
421+
-- ============================================================================
422+
-- Level 5.7: Full Revoke Entity Access
423+
-- ============================================================================
424+
425+
/**
426+
* Remove the Viewer role's access rule from Customer entirely.
400427
*/
401428
REVOKE SecTest.Viewer ON SecTest.Customer;
402429
/

0 commit comments

Comments
 (0)