@memberjunction/core-entities-server 6.1.0-edge.6 → 6.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. package/dist/custom/MJAIBridgeProviderEntityServer.server.d.ts +1 -5
  2. package/dist/custom/MJAIBridgeProviderEntityServer.server.d.ts.map +1 -1
  3. package/dist/custom/MJAIBridgeProviderEntityServer.server.js +13 -12
  4. package/dist/custom/MJAIBridgeProviderEntityServer.server.js.map +1 -1
  5. package/dist/custom/MJAIRemoteBrowserProviderEntityServer.server.d.ts +2 -6
  6. package/dist/custom/MJAIRemoteBrowserProviderEntityServer.server.d.ts.map +1 -1
  7. package/dist/custom/MJAIRemoteBrowserProviderEntityServer.server.js +16 -14
  8. package/dist/custom/MJAIRemoteBrowserProviderEntityServer.server.js.map +1 -1
  9. package/dist/custom/MJEntityEntityServer.server.d.ts +36 -0
  10. package/dist/custom/MJEntityEntityServer.server.d.ts.map +1 -0
  11. package/dist/custom/MJEntityEntityServer.server.js +77 -0
  12. package/dist/custom/MJEntityEntityServer.server.js.map +1 -0
  13. package/dist/custom/MJEntityFieldPermissionEntityServer.server.d.ts +167 -0
  14. package/dist/custom/MJEntityFieldPermissionEntityServer.server.d.ts.map +1 -0
  15. package/dist/custom/MJEntityFieldPermissionEntityServer.server.js +347 -0
  16. package/dist/custom/MJEntityFieldPermissionEntityServer.server.js.map +1 -0
  17. package/dist/custom/MJUserRoleEntityServer.server.d.ts +105 -8
  18. package/dist/custom/MJUserRoleEntityServer.server.d.ts.map +1 -1
  19. package/dist/custom/MJUserRoleEntityServer.server.js +170 -10
  20. package/dist/custom/MJUserRoleEntityServer.server.js.map +1 -1
  21. package/dist/custom/fieldPermissionDelta.d.ts +57 -0
  22. package/dist/custom/fieldPermissionDelta.d.ts.map +1 -0
  23. package/dist/custom/fieldPermissionDelta.js +196 -0
  24. package/dist/custom/fieldPermissionDelta.js.map +1 -0
  25. package/dist/custom/fieldPermissionReconciler.d.ts +34 -0
  26. package/dist/custom/fieldPermissionReconciler.d.ts.map +1 -0
  27. package/dist/custom/fieldPermissionReconciler.js +96 -0
  28. package/dist/custom/fieldPermissionReconciler.js.map +1 -0
  29. package/dist/index.d.ts +4 -0
  30. package/dist/index.d.ts.map +1 -1
  31. package/dist/index.js +4 -0
  32. package/dist/index.js.map +1 -1
  33. package/package.json +28 -28
@@ -0,0 +1,347 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ var MJEntityFieldPermissionEntityServer_1;
8
+ import { BaseEntity, BaseEntityResult, FieldPermissionAccess, IsRestrictingFieldRule, LogError, RunView, ValidationErrorInfo, ValidationErrorType, } from '@memberjunction/core';
9
+ import { RegisterClass, UUIDsEqual } from '@memberjunction/global';
10
+ import { MJEntityFieldPermissionEntity } from '@memberjunction/core-entities';
11
+ import { SystemUserFieldAccessLossReason, SystemUserHoldsRole, UserCache } from '@memberjunction/generic-database-provider';
12
+ /**
13
+ * Server-side `MJ: Entity Field Permissions` entity — the save-time half of the
14
+ * unrestrictable-target guard for field-level security.
15
+ *
16
+ * The runtime aggregation (`EntityFieldInfo.GetUserFieldPermissions`) already forces access
17
+ * open for these targets, so this subclass is not what makes the system safe. It is what makes
18
+ * the system *diagnosable*: without it an administrator can save a row that silently does
19
+ * nothing, then reasonably conclude the feature is broken. Rejecting at save says why.
20
+ *
21
+ * Two categories are refused, matching the two runtime guards exactly:
22
+ *
23
+ * 1. **Primary keys and system columns.** Stripping a primary key from a result breaks entity
24
+ * load, `CompositeKey` construction, relationship resolution, and cache fingerprinting —
25
+ * failures that surface nowhere near the permission record that caused them.
26
+ * 2. **The security-configuration and identity surface** (see
27
+ * {@link EntityFieldInfo.IsOnUnrestrictableEntity}). Restricting a column on the very
28
+ * entities field security is administered through produces a configuration that cannot be
29
+ * reversed through the product — recovery would mean direct SQL against the database.
30
+ *
31
+ * A third category is refused for a different reason: a **`Deny`** aimed at a role the MJ system
32
+ * user holds (see {@link SystemUserRoleRejectionReason}). That one is not about diagnosability —
33
+ * it is what lets the runtime aggregation have no exempt user at all. The server's own account
34
+ * gets its access from ordinary `Allow` rows like everyone else, and this guard is what stops
35
+ * those being revoked.
36
+ *
37
+ * Note what is deliberately NOT here: any notion of a user who is exempt from a Deny at
38
+ * RUNTIME. The guards are on which *targets* are restrictable and on what may be *configured*,
39
+ * never on whose access is evaluated. A feature whose purpose is compensation and donor-giving
40
+ * confidentiality cannot ship with a role that quietly reads everything.
41
+ */
42
+ let MJEntityFieldPermissionEntityServer = MJEntityFieldPermissionEntityServer_1 = class MJEntityFieldPermissionEntityServer extends MJEntityFieldPermissionEntity {
43
+ Validate() {
44
+ const result = super.Validate();
45
+ const target = this.resolveTarget();
46
+ if (target) {
47
+ const entityPermissionRejection = MJEntityFieldPermissionEntityServer_1.EntityPermissionRequiredRejectionReason(target.Entity, this.RoleID);
48
+ if (entityPermissionRejection) {
49
+ result.Errors.push(new ValidationErrorInfo('RoleID', entityPermissionRejection, this.RoleID, ValidationErrorType.Failure));
50
+ }
51
+ }
52
+ const targetField = target?.Field;
53
+ if (targetField) {
54
+ const rejection = MJEntityFieldPermissionEntityServer_1.RejectionReason(targetField);
55
+ if (rejection) {
56
+ result.Errors.push(new ValidationErrorInfo('EntityFieldID', rejection, this.EntityFieldID, ValidationErrorType.Failure));
57
+ }
58
+ const writeVerbRejection = MJEntityFieldPermissionEntityServer_1.WriteVerbRejectionReason(targetField, this);
59
+ if (writeVerbRejection) {
60
+ result.Errors.push(new ValidationErrorInfo('EntityFieldID', writeVerbRejection, this.EntityFieldID, ValidationErrorType.Failure));
61
+ }
62
+ }
63
+ const roleRejection = MJEntityFieldPermissionEntityServer_1.SystemUserRoleRejectionReason(this.RoleID, this);
64
+ if (roleRejection) {
65
+ result.Errors.push(new ValidationErrorInfo('RoleID', roleRejection, this.RoleID, ValidationErrorType.Failure));
66
+ }
67
+ result.Success = result.Success && result.Errors.length === 0;
68
+ return result;
69
+ }
70
+ /**
71
+ * Refuses an EDIT that would strip the MJ system user's last `Allow` on a field.
72
+ *
73
+ * Not in `Validate()` for two reasons. It needs the field's rules as they stand in the
74
+ * DATABASE — loaded metadata lags recent writes, and reading a stale sibling row as `Allow` is
75
+ * exactly how three individually-innocent `No Access` edits get through one at a time. And
76
+ * loading them is asynchronous, which `Validate()` is not.
77
+ *
78
+ * Inserts are deliberately not checked: adding a rule can only add access, never remove an
79
+ * existing `Allow`, so the `Deny` check in `Validate()` covers them completely. It has to —
80
+ * snapshot initialization writes its rows one at a time, and an aggregate check would refuse
81
+ * the half-built state.
82
+ */
83
+ async Save(options) {
84
+ if (this.IsSaved) {
85
+ const rejection = await this.systemUserAccessLossReason(false);
86
+ if (rejection) {
87
+ return this.refuse(rejection, 'save');
88
+ }
89
+ }
90
+ return super.Save(options);
91
+ }
92
+ /**
93
+ * Refuses a DELETE that would strip the MJ system user's last `Allow` on a field — the other
94
+ * way, besides editing one to `No Access`, to remove access without writing a `Deny`.
95
+ *
96
+ * Reconciliation's own orphan deletes are unaffected: it only removes rows whose role has lost
97
+ * entity-level read (so the system user is already denied one level up and the guard stands
98
+ * down) or whose field became unrestrictable (forced open regardless).
99
+ */
100
+ async Delete(options) {
101
+ const rejection = await this.systemUserAccessLossReason(true);
102
+ if (rejection) {
103
+ return this.refuse(rejection, 'delete');
104
+ }
105
+ return super.Delete(options);
106
+ }
107
+ /**
108
+ * Records a refusal on the result history so `LatestResult.CompleteMessage` explains it, and
109
+ * returns false — the contract `Save()` and `Delete()` already have for a logical failure.
110
+ */
111
+ refuse(message, type) {
112
+ const result = new BaseEntityResult();
113
+ result.Success = false;
114
+ result.Type = type === 'delete' ? 'delete' : this.IsSaved ? 'update' : 'create';
115
+ result.Message = message;
116
+ result.StartedAt = new Date();
117
+ result.EndedAt = new Date();
118
+ this.ResultHistory.push(result);
119
+ return false;
120
+ }
121
+ /**
122
+ * Why the pending change would leave the system user short of its entity-level access, or null.
123
+ *
124
+ * @param removing true when this row is being deleted rather than edited
125
+ */
126
+ async systemUserAccessLossReason(removing) {
127
+ // Cheap exit first: the aggregation only ever consults rules bound to a role the user
128
+ // holds, so a change to any other role's rule cannot move the system user's access at all.
129
+ // This is what keeps the query below off the path of ordinary permission administration —
130
+ // it runs only for edits to the handful of roles the server's own account holds.
131
+ if (!SystemUserHoldsRole(this.RoleID)) {
132
+ return null;
133
+ }
134
+ const target = this.resolveTarget();
135
+ if (!target) {
136
+ return null;
137
+ }
138
+ const current = await this.loadCurrentRules(target.Field.ID);
139
+ const others = current.filter(r => !UUIDsEqual(r.ID, this.ID));
140
+ const projected = removing
141
+ ? others
142
+ : [
143
+ ...others,
144
+ {
145
+ RoleID: this.RoleID,
146
+ ReadAccess: this.ReadAccess,
147
+ UpdateAccess: this.UpdateAccess,
148
+ CreateAccess: this.CreateAccess,
149
+ },
150
+ ];
151
+ return SystemUserFieldAccessLossReason(target.Entity, target.Field, projected);
152
+ }
153
+ /**
154
+ * Every rule currently stored against this field, straight from the database.
155
+ *
156
+ * `BypassCache` because this decides an access-control question: a cached result that predates
157
+ * a sibling row's edit would answer it with data the guard is specifically trying to catch up
158
+ * with. Inside a transaction this reads the scope's own uncommitted writes, which is what
159
+ * reconciliation needs.
160
+ */
161
+ async loadCurrentRules(entityFieldID) {
162
+ const rv = new RunView(this.RunViewProviderToUse);
163
+ const result = await rv.RunView({
164
+ EntityName: 'MJ: Entity Field Permissions',
165
+ ExtraFilter: `EntityFieldID = '${entityFieldID}'`,
166
+ Fields: ['ID', 'RoleID', 'ReadAccess', 'UpdateAccess', 'CreateAccess'],
167
+ ResultType: 'simple',
168
+ BypassCache: true,
169
+ }, this.ContextCurrentUser);
170
+ if (!result.Success) {
171
+ // Cannot evaluate the guard — say so rather than silently permitting. The caller sees
172
+ // an empty rule set, which never produces a refusal, so this is a fail-open that is at
173
+ // least visible in the log; the startup sweep is the backstop.
174
+ LogError(`[FieldSecurity] Could not load sibling rules for field ${entityFieldID}; ` +
175
+ `the system-user access guard did not run: ${result.ErrorMessage}`);
176
+ return [];
177
+ }
178
+ return result.Results ?? [];
179
+ }
180
+ /**
181
+ * Why this rule may not target this role, or null when it may.
182
+ *
183
+ * Refuses a **restricting** rule aimed at a role the MJ **system user** holds. The system
184
+ * user is what the server runs background work as: it pre-warms the shared engine caches at
185
+ * startup, and in task mode (job and agent runners) whichever caller touches an engine first
186
+ * configures it for the whole process. Restricting that account does not just restrict it —
187
+ * engines cache their data process-wide, so a partially loaded engine would then serve
188
+ * incomplete records to every user afterward. The damage is silent and nowhere near the rule
189
+ * that caused it.
190
+ *
191
+ * **Only a `Deny` is refused.** Field security has no runtime exemption for any user, so the
192
+ * system user's own access comes from ordinary rows: snapshot initialization writes it
193
+ * `Allow` on every field its roles can read, and this guard is what stops that access being
194
+ * taken away again. `Allow` and `No Access` both save — `Allow` is the grant the server
195
+ * depends on, and `No Access` is neutral, unable to reduce access another role has granted.
196
+ * Refusing those would make it impossible to enable field security on any entity at all,
197
+ * since the standard roles (UI, Developer, Integration) carry entity permissions almost
198
+ * everywhere.
199
+ *
200
+ * This is a guard on CONFIGURATION, not a runtime exemption. What is refused is the
201
+ * arrangement that would make the server unable to do its own work. Take the role off the
202
+ * system user and the rule saves.
203
+ *
204
+ * The database tier already refuses the equivalent arrangement: CodeGen skips a column DENY
205
+ * for any role a service login belongs to, and warns. This is the same rule for the
206
+ * application tier.
207
+ *
208
+ * @param roleID the role the rule targets
209
+ * @param rule the rule's three verbs; omitted only by callers that are pre-checking a role
210
+ * rather than a specific rule, which are answered as though the rule denied
211
+ */
212
+ static SystemUserRoleRejectionReason(roleID, rule) {
213
+ if (!roleID) {
214
+ return null;
215
+ }
216
+ if (rule && !IsRestrictingFieldRule(rule)) {
217
+ return null; // grants and neutrals are exactly what keep the system user working
218
+ }
219
+ // UserCache is populated on the server; a client-side save (or a cold cache) simply
220
+ // skips the check rather than blocking an administrator on missing state.
221
+ const systemUser = UserCache.Instance?.GetSystemUser?.();
222
+ if (!systemUser?.UserRoles?.length) {
223
+ return null;
224
+ }
225
+ const holdsRole = systemUser.UserRoles.some(ur => UUIDsEqual(ur.RoleID, roleID));
226
+ if (!holdsRole) {
227
+ return null;
228
+ }
229
+ const roleName = systemUser.UserRoles.find(ur => UUIDsEqual(ur.RoleID, roleID))?.Role ?? roleID;
230
+ return (`Role '${roleName}' is held by the MJ system user, so it cannot carry a Deny on any field. ` +
231
+ `The server runs background work as that account and shares one engine cache across all users — ` +
232
+ `restricting it would let partially loaded records reach everyone. ` +
233
+ `Remove the role from the system user first, or apply this rule to a different role.`);
234
+ }
235
+ /**
236
+ * Why this rule's Update/Create verbs may not target this field, or null when they may.
237
+ *
238
+ * A **read-only** field cannot be written through the API by anyone: it is excluded from the
239
+ * generated create input type and from the update SET list, and `BaseEntity` never marks it
240
+ * dirty. So an Update or Create verb on it is inert in both directions — a `Deny` prevents
241
+ * nothing that was possible, and an `Allow` grants nothing that was not. Left to save, it
242
+ * reads on screen as a working permission and silently is not one.
243
+ *
244
+ * **Read is untouched, deliberately.** Restricting READ on a read-only field is legitimate
245
+ * and is one of the main things administrators want: foreign-key display columns are
246
+ * read-only, and "hide which client this contract belongs to" is exactly a read restriction
247
+ * on one. Only the two write verbs are refused.
248
+ *
249
+ * Note `EntityFieldInfo.ReadOnly` is the right predicate here, not `IsVirtual`: IS-A parent
250
+ * fields are virtual but ARE writable through the child's save chain, and `ReadOnly` is
251
+ * defined off `AllowUpdateAPI` precisely to tell those apart from joined display columns.
252
+ */
253
+ static WriteVerbRejectionReason(field, rule) {
254
+ if (!field.ReadOnly) {
255
+ return null;
256
+ }
257
+ const offending = [];
258
+ if (rule.UpdateAccess !== FieldPermissionAccess.NoAccess)
259
+ offending.push('Update');
260
+ if (rule.CreateAccess !== FieldPermissionAccess.NoAccess)
261
+ offending.push('Create');
262
+ if (offending.length === 0) {
263
+ return null;
264
+ }
265
+ return (`Field '${field.Entity}.${field.Name}' is read-only, so its ${offending.join(' and ')} ` +
266
+ `${offending.length > 1 ? 'permissions have' : 'permission has'} no effect — the field cannot be written ` +
267
+ `through the API by any user. Set ${offending.length > 1 ? 'them' : 'it'} to 'No Access'. ` +
268
+ `Read permission on this field still applies normally.`);
269
+ }
270
+ /**
271
+ * Why this field may not be secured, or null when it may be.
272
+ * Static + field-driven so the same wording can back a future admin-UI pre-check.
273
+ */
274
+ static RejectionReason(field) {
275
+ if (field.IsUnrestrictableField) {
276
+ const reason = field.IsPrimaryKey || field.IsSoftPrimaryKey ? 'a primary key' : 'a system column';
277
+ return (`Field '${field.Entity}.${field.Name}' is ${reason} and cannot be secured by field-level permissions. ` +
278
+ `Primary keys and system columns must stay readable — removing one from a result breaks entity loading, ` +
279
+ `composite keys, relationship resolution, and cache fingerprinting. Secure the sensitive field itself instead.`);
280
+ }
281
+ if (field.IsOnUnrestrictableEntity) {
282
+ return (`Entity '${field.Entity}' is part of the security configuration and identity surface, so its fields ` +
283
+ `cannot be secured by field-level permissions. Restricting a column here can produce a configuration ` +
284
+ `that cannot be reversed through the application — undoing it would require direct database access.`);
285
+ }
286
+ return null;
287
+ }
288
+ /**
289
+ * Resolves `EntityFieldID` to its {@link EntityFieldInfo} from loaded metadata.
290
+ *
291
+ * Returns null when metadata cannot resolve it — for instance immediately after a schema
292
+ * change, before the metadata cache has refreshed. That case passes validation rather than
293
+ * blocking the administrator: the foreign key already guarantees the row points at a real
294
+ * field, and the runtime aggregation guards hold regardless of what is stored here. Failing
295
+ * closed would trade a real, recurring workflow block for no additional protection.
296
+ */
297
+ /**
298
+ * Why this role may not carry a field rule on this entity, or null when it may.
299
+ *
300
+ * A field permission REFINES an entity permission — the entity gate decides whether you reach
301
+ * the record at all, and field rules then decide which columns of it you see. A rule bound to a
302
+ * role that has no relationship to the entity is not a refinement of anything, and it is the
303
+ * configuration that made the reconciler's orphan test ambiguous: such a row is fully live at
304
+ * runtime (aggregation matches on role membership alone) while looking inert to any check that
305
+ * asks what the role can do on its own.
306
+ *
307
+ * Requires only that an entity-permission row EXISTS, not that it grants read. A role whose
308
+ * entity permission grants nothing is the ordinary way to express a deny-only carve-out —
309
+ * "these users are normal, minus this column" — and demanding a grant would force an
310
+ * administrator to hand out entity access in order to take a column away. Deleting the entity
311
+ * permission removes the relationship, and reconciliation then cleans up the field rules with
312
+ * it; see `computeOrphanRowIDs`, which tests exactly this condition.
313
+ *
314
+ * Attributed to `RoleID` because that is the value the administrator must change — either pick
315
+ * a role that has entity access, or grant this one an entity permission first.
316
+ */
317
+ static EntityPermissionRequiredRejectionReason(entity, roleID) {
318
+ if (!roleID) {
319
+ return null; // the NOT NULL column is the base class's problem to report, not ours
320
+ }
321
+ if (entity.Permissions.some((p) => UUIDsEqual(p.RoleID, roleID))) {
322
+ return null;
323
+ }
324
+ return (`This role has no entity permission on '${entity.Name}', so a field rule for it would refine nothing. ` +
325
+ `Field permissions narrow the access an entity permission already grants — give the role an entity ` +
326
+ `permission on '${entity.Name}' first (one that grants nothing is fine, and is how a deny-only ` +
327
+ `carve-out is expressed), then set the field rule.`);
328
+ }
329
+ resolveTarget() {
330
+ if (!this.EntityFieldID) {
331
+ return null; // the NOT NULL column is the base class's problem to report, not ours
332
+ }
333
+ const md = this.ProviderToUse;
334
+ for (const entity of md?.Entities ?? []) {
335
+ const match = entity.Fields.find((f) => UUIDsEqual(f.ID, this.EntityFieldID));
336
+ if (match) {
337
+ return { Entity: entity, Field: match };
338
+ }
339
+ }
340
+ return null;
341
+ }
342
+ };
343
+ MJEntityFieldPermissionEntityServer = MJEntityFieldPermissionEntityServer_1 = __decorate([
344
+ RegisterClass(BaseEntity, 'MJ: Entity Field Permissions')
345
+ ], MJEntityFieldPermissionEntityServer);
346
+ export { MJEntityFieldPermissionEntityServer };
347
+ //# sourceMappingURL=MJEntityFieldPermissionEntityServer.server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MJEntityFieldPermissionEntityServer.server.js","sourceRoot":"","sources":["../../src/custom/MJEntityFieldPermissionEntityServer.server.ts"],"names":[],"mappings":"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"}
@@ -1,7 +1,21 @@
1
- import { EntityDeleteOptions, EntitySaveOptions, ValidationResult } from '@memberjunction/core';
1
+ import { EntityDeleteOptions, EntitySaveOptions, IMetadataProvider, ValidationResult } from '@memberjunction/core';
2
2
  import { MJUserRoleEntity } from '@memberjunction/core-entities';
3
3
  /**
4
- * Server-side `MJ: User Roles` entity enforcing MJ's role-elevation invariant (issue #4282).
4
+ * Server-side `MJ: User Roles` entity. It carries TWO independent guards that happen to protect the
5
+ * same table from opposite directions. They share no state and no helpers, and every write path
6
+ * must satisfy both:
7
+ *
8
+ * A. **Role elevation** (issue #4282) — bounds what the CALLER may do, by their own roles.
9
+ * B. **System-user field access** — bounds what may be done TO the system user's role set.
10
+ *
11
+ * Guard A and guard B are orthogonal: A asks "is this caller entitled to make this change", B asks
12
+ * "does this change leave the system user field-restricted". A change must clear both, so the
13
+ * checks compose as a conjunction and are evaluated A-then-B (A is an in-memory role-list test; B
14
+ * walks cached metadata and only ever runs when the system user is the target).
15
+ *
16
+ * ---------------------------------------------------------------------------------------------
17
+ * GUARD A — ROLE ELEVATION (issue #4282)
18
+ * ---------------------------------------------------------------------------------------------
5
19
  *
6
20
  * WHY THIS EXISTS AT ALL. Issue #4260 (`MJUserEntityServer`) closed the `User.Type` route to
7
21
  * elevated capability. Role assignment is the platform's OTHER authority mechanism and was
@@ -74,9 +88,43 @@ import { MJUserRoleEntity } from '@memberjunction/core-entities';
74
88
  * deployment whose system user is NOT an Owner will see those sync paths fail closed — loudly,
75
89
  * at the save — exactly as #4260 documented for `MJ: Users`.
76
90
  *
77
- * Pure: reads only this record's own field state and the caller's cached roles. No `RunView`, no
78
- * provider, no engine, no I/O — so it costs nothing per save/delete and is unit-testable without a
79
- * database.
91
+ * Guard A is pure: it reads only this record's own field state and the caller's cached roles. No
92
+ * `RunView`, no provider, no engine, no I/O — so it costs nothing per save/delete and is
93
+ * unit-testable without a database. (Guard B is NOT pure in that sense; see below.)
94
+ *
95
+ * ---------------------------------------------------------------------------------------------
96
+ * GUARD B — SYSTEM-USER FIELD ACCESS
97
+ * ---------------------------------------------------------------------------------------------
98
+ *
99
+ * This is the other half of the system-user guard for field-level security.
100
+ * `MJEntityFieldPermissionEntityServer` guards the RULES; this guards the account's ROLE SET, from
101
+ * both directions. Without both halves an administrator reaches the forbidden state simply by
102
+ * doing the steps in a different order.
103
+ *
104
+ * - **Assignment** ({@link SystemUserRejectionReason}) — refuses giving the system user a role that
105
+ * already denies a field. Only DENYING rules count here, because adding a role can only add rules
106
+ * to the aggregate: its `Allow` rows grant, its `No Access` rows are inert, and only a `Deny`
107
+ * can take something away. A guard that counted every rule would refuse to reassemble the
108
+ * account's own role set the moment field security was enabled anywhere.
109
+ * - **Removal** ({@link Delete}) — refuses taking a role away when that would leave the account
110
+ * short of its entity-level access. Removal is the opposite shape: it drops rules OUT of the
111
+ * aggregate, so what matters is not what the departing role said but whether an `Allow` survives
112
+ * without it.
113
+ *
114
+ * Why the system user must stay unrestricted: the server runs background work as that account.
115
+ * It pre-warms the shared engine caches at startup, and in task mode — which job and agent
116
+ * runners use — engines instead load on first touch, so whichever caller gets there first
117
+ * configures the engine for the entire process. Engine caches are process-wide and shared
118
+ * across users. A restricted system user could therefore leave partially loaded records in a
119
+ * cache that everyone reads afterward, with nothing at the point of failure pointing back at
120
+ * the role assignment that caused it.
121
+ *
122
+ * Unlike guard A, guard B reads cached metadata (`Metadata.Entities`, the provider, `UserCache`).
123
+ * It still performs no database I/O, but it is not state-free, and it needs those caches populated
124
+ * to have an opinion — a cold `UserCache` skips the check rather than blocking an administrator.
125
+ *
126
+ * This restricts CONFIGURATION only. There is no user who is exempt from a Deny at runtime —
127
+ * not even the system user, whose access comes from the same rows as everyone else's.
80
128
  */
81
129
  export declare class MJUserRoleEntityServer extends MJUserRoleEntity {
82
130
  Validate(): ValidationResult;
@@ -89,14 +137,26 @@ export declare class MJUserRoleEntityServer extends MJUserRoleEntity {
89
137
  */
90
138
  Save(options?: EntitySaveOptions): Promise<boolean>;
91
139
  /**
92
- * Invariant 3 — a non-Owner may only revoke a role they hold themselves.
140
+ * Enforces both guards on the delete path.
141
+ *
142
+ * Guard A, invariant 3 — a non-Owner may only revoke a role they hold themselves.
143
+ *
144
+ * Guard B — refuses REMOVING a role from the system user when that would cost the account its
145
+ * field access. The mirror of the assignment guard, and needed for the same reason the
146
+ * field-permission subclass guards its own delete path: the system user's access is ordinary
147
+ * `Allow` rows, and taking a role away drops that role's rows out of the aggregate. If the
148
+ * remaining roles have `No Access` on a field, the last removal denies it — with no `Deny`
149
+ * written anywhere and no field-permission row touched. It permits the removal when it also
150
+ * costs the account its entity-level read, since it is then denied one level up and field rules
151
+ * decide nothing — which is why the projection re-evaluates the entity ceiling too, rather than
152
+ * only the field rules.
93
153
  *
94
- * Reports the refusal the way `MJUserEntityServer.Delete` does — a `BaseEntityResult` on the
154
+ * Reports refusals the way `MJUserEntityServer.Delete` does — a `BaseEntityResult` on the
95
155
  * result history, so `LatestResult.CompleteMessage` carries the reason, `Delete()` returning
96
156
  * `false` on a logical rejection rather than throwing (the CLAUDE.md Save/Delete error-handling
97
157
  * contract). Note that `SyncRolesUsersResolver.SyncUserRoles` treats a `false` from this method
98
158
  * as a hard error and throws, rolling its transaction back; that mutation runs as the system
99
- * Owner, so it is exempt and never sees this refusal on a default install.
159
+ * Owner, so it is exempt from guard A and never sees that refusal on a default install.
100
160
  */
101
161
  Delete(options?: EntityDeleteOptions): Promise<boolean>;
102
162
  /**
@@ -140,7 +200,44 @@ export declare class MJUserRoleEntityServer extends MJUserRoleEntity {
140
200
  *
141
201
  * Reads `ActiveUser` rather than `ContextCurrentUser` directly so a per-request provider's
142
202
  * `CurrentUser` is honored on multi-provider servers.
203
+ *
204
+ * Applies to guard A only. Guard B has no Owner exemption — see `Validate()`.
143
205
  */
144
206
  private callerIsOwner;
207
+ /**
208
+ * Why this role may not be taken off this user, or null when it may.
209
+ * Only ever rejects for the system user; every other user is unaffected.
210
+ */
211
+ private systemUserRoleRemovalReason;
212
+ /**
213
+ * Why this role may not be given to this user, or null when it may.
214
+ * Only ever rejects for the system user; every other user is unaffected.
215
+ */
216
+ static SystemUserRejectionReason(userID: string | null, roleID: string | null, provider?: IMetadataProvider): string | null;
217
+ /**
218
+ * Names of entities where this role carries at least one RESTRICTING field rule — a `Deny`
219
+ * on any verb. Walks cached metadata only — no database access. Runs only when the system
220
+ * user is the save target, which is rare.
221
+ *
222
+ * Grants and neutrals are ignored, and must be: the system user holds the standard roles
223
+ * (UI, Developer, Integration), snapshot initialization writes those roles `Allow` rows on
224
+ * every entity they can read, and field security has no runtime exemption to fall back on.
225
+ * A guard that counted any rule at all would refuse to reassemble the system user's own role
226
+ * set the moment field security was enabled anywhere.
227
+ *
228
+ * Deliberately does NOT gate on {@link EntityInfo.EnableFieldLevelSecurity}, even though
229
+ * rules on a disabled entity are inactive and gating would be the cheaper walk. Gating
230
+ * would leave the two halves of this guard unable to compose, and the gap is reachable in
231
+ * three ordinary steps: disable field security on an entity, assign the role (now carrying
232
+ * no active rules) to the system user, re-enable. Each step is permitted and the end state
233
+ * is the one both guards exist to prevent. Disabling preserves rules so re-enabling does
234
+ * not lose them, so a rule on a disabled entity is dormant rather than gone.
235
+ */
236
+ private static EntitiesWithRestrictingFieldRulesForRole;
145
237
  }
238
+ /**
239
+ * Loader stub — prevents the class from being tree-shaken out of the bundle. Mirrors the
240
+ * pattern used by the other server-side entity subclasses in this package.
241
+ */
242
+ export declare function LoadMJUserRoleEntityServer(): void;
146
243
  //# sourceMappingURL=MJUserRoleEntityServer.server.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"MJUserRoleEntityServer.server.d.ts","sourceRoot":"","sources":["../../src/custom/MJUserRoleEntityServer.server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgC,mBAAmB,EAAE,iBAAiB,EAAsD,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAElL,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAEjE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6EG;AACH,qBACa,sBAAuB,SAAQ,gBAAgB;IACxC,QAAQ,IAAI,gBAAgB;IAiB5C;;;;;;OAMG;IACmB,IAAI,CAAC,OAAO,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,OAAO,CAAC;IAWzE;;;;;;;;;OASG;IACmB,MAAM,CAAC,OAAO,CAAC,EAAE,mBAAmB,GAAG,OAAO,CAAC,OAAO,CAAC;IAW7E;;;;OAIG;IACH,OAAO,CAAC,gBAAgB;IAOxB;;;;;;;;;OASG;IACH,OAAO,CAAC,qBAAqB;IAqB7B,4GAA4G;IAC5G,OAAO,CAAC,MAAM;IAWd;;;;;;;OAOG;IACH,OAAO,CAAC,eAAe;IAQvB;;;;;;;;;;;;;OAaG;IACH,OAAO,CAAC,aAAa;CAOxB"}
1
+ {"version":3,"file":"MJUserRoleEntityServer.server.d.ts","sourceRoot":"","sources":["../../src/custom/MJUserRoleEntityServer.server.ts"],"names":[],"mappings":"AAAA,OAAO,EAGH,mBAAmB,EAEnB,iBAAiB,EACjB,iBAAiB,EAMjB,gBAAgB,EACnB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAGjE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6HG;AACH,qBACa,sBAAuB,SAAQ,gBAAgB;IACxC,QAAQ,IAAI,gBAAgB;IAgC5C;;;;;;OAMG;IACmB,IAAI,CAAC,OAAO,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,OAAO,CAAC;IAWzE;;;;;;;;;;;;;;;;;;;;;OAqBG;IACmB,MAAM,CAAC,OAAO,CAAC,EAAE,mBAAmB,GAAG,OAAO,CAAC,OAAO,CAAC;IAiB7E;;;;OAIG;IACH,OAAO,CAAC,gBAAgB;IAOxB;;;;;;;;;OASG;IACH,OAAO,CAAC,qBAAqB;IAqB7B,4GAA4G;IAC5G,OAAO,CAAC,MAAM;IAWd;;;;;;;OAOG;IACH,OAAO,CAAC,eAAe;IAQvB;;;;;;;;;;;;;;;OAeG;IACH,OAAO,CAAC,aAAa;IAQrB;;;OAGG;IACH,OAAO,CAAC,2BAA2B;IAqBnC;;;OAGG;WACW,yBAAyB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,EAAE,QAAQ,CAAC,EAAE,iBAAiB,GAAG,MAAM,GAAG,IAAI;IAyBlI;;;;;;;;;;;;;;;;;;OAkBG;IACH,OAAO,CAAC,MAAM,CAAC,wCAAwC;CAe1D;AAED;;;GAGG;AACH,wBAAgB,0BAA0B,IAAI,IAAI,CAEjD"}