@7365admin1/core 3.52.8 → 3.52.9

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.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@7365admin1/core",
3
3
  "license": "MIT",
4
- "version": "3.52.8",
4
+ "version": "3.52.9",
5
5
  "author": "7365admin1",
6
6
  "main": "dist/index.js",
7
7
  "module": "dist/index.mjs",
@@ -132,6 +132,7 @@ const SITE = "6923d6664150ca6a69b9f2b2";
132
132
  const OWNER_ORG = "6923d6664150ca6a69b9f000";
133
133
  const AGENCY_ORG = "6923d6664150ca6a69b9f111";
134
134
  const OTHER_ORG = "6923d6664150ca6a69b9f222";
135
+ const OTHER_SITE = "6923d6664150ca6a69b9f333";
135
136
 
136
137
  test("an org-level member of an engaged organisation reaches the engaged site", () => {
137
138
  assert.equal(
@@ -1102,3 +1103,134 @@ test("orgSiteScope: an unresolved role fails closed — it does not widen", () =
1102
1103
  [SCOPE_SITE_A],
1103
1104
  );
1104
1105
  });
1106
+
1107
+ /**
1108
+ * The camera side of the site-scope rule, reconciled with the LIST side.
1109
+ *
1110
+ * `orgSiteScope` (below) was changed on 2026-09-02 to the owner's rule: an
1111
+ * ORGANISATION-LEVEL role sees every site of its organisation even when its
1112
+ * membership row also names a `siteId`. `cameraGrant` kept the older, stricter
1113
+ * reading — `!siteId` only — so the switcher offered those people sites the
1114
+ * camera view then refused. Both halves must say the same thing or the menu is
1115
+ * lying.
1116
+ *
1117
+ * Site-level roles are NOT widened: a membership pinned to a site whose role
1118
+ * belongs to that site reaches that site and no other. Widening those would be
1119
+ * a cross-tenant leak, not a reconciliation.
1120
+ */
1121
+ const ORG_LEVEL = { orgLevelRole: true };
1122
+
1123
+ test("an org-level ROLE reaches the org's other sites even when its row names a site", () => {
1124
+ // The ~8 users this change is for: `Org Owner`-shaped roles whose membership
1125
+ // row carries a stray siteId. The list offers them every site; the camera
1126
+ // path refused every site but one.
1127
+ assert.equal(
1128
+ cameraGrant({
1129
+ cameraSite: SITE,
1130
+ cameraOrg: OWNER_ORG,
1131
+ memberships: [{ org: OWNER_ORG, siteId: OTHER_SITE, role: "org-role", ...ORG_LEVEL }],
1132
+ })?.role,
1133
+ "org-role",
1134
+ );
1135
+
1136
+ // Shape 2 — the same role with NO siteId still passes, unchanged.
1137
+ assert.equal(
1138
+ cameraGrant({
1139
+ cameraSite: SITE,
1140
+ cameraOrg: OWNER_ORG,
1141
+ memberships: [{ org: OWNER_ORG, role: "org-role", ...ORG_LEVEL }],
1142
+ })?.role,
1143
+ "org-role",
1144
+ );
1145
+ });
1146
+
1147
+ test("a SITE-level role pinned to another site is still refused — no cross-tenant widening", () => {
1148
+ assert.equal(
1149
+ cameraGrant({
1150
+ cameraSite: SITE,
1151
+ cameraOrg: OWNER_ORG,
1152
+ memberships: [{ org: OWNER_ORG, siteId: OTHER_SITE, role: "site-role" }],
1153
+ }),
1154
+ null,
1155
+ );
1156
+
1157
+ // Absent/unresolvable is read as site-level — the narrowing side.
1158
+ assert.equal(
1159
+ cameraGrant({
1160
+ cameraSite: SITE,
1161
+ cameraOrg: OWNER_ORG,
1162
+ memberships: [
1163
+ { org: OWNER_ORG, siteId: OTHER_SITE, role: "site-role", orgLevelRole: false },
1164
+ { org: OWNER_ORG, siteId: OTHER_SITE, role: "unknown-role", orgLevelRole: undefined },
1165
+ ],
1166
+ }),
1167
+ null,
1168
+ );
1169
+
1170
+ // ...and it still reaches its OWN site.
1171
+ assert.equal(
1172
+ cameraGrant({
1173
+ cameraSite: OTHER_SITE,
1174
+ cameraOrg: OWNER_ORG,
1175
+ memberships: [{ org: OWNER_ORG, siteId: OTHER_SITE, role: "site-role" }],
1176
+ })?.role,
1177
+ "site-role",
1178
+ );
1179
+ });
1180
+
1181
+ test("an org-level role in ANOTHER organisation reaches nothing", () => {
1182
+ assert.equal(
1183
+ cameraGrant({
1184
+ cameraSite: SITE,
1185
+ cameraOrg: OWNER_ORG,
1186
+ memberships: [{ org: OTHER_ORG, siteId: OTHER_SITE, role: "org-role", ...ORG_LEVEL }],
1187
+ }),
1188
+ null,
1189
+ );
1190
+
1191
+ // The engagement branch is NOT widened by this change: the owner's decision
1192
+ // of 2026-08-10 stands — an agency's site-pinned staff reach their own site
1193
+ // only, whatever their role's level. The list half does not widen here
1194
+ // either, so the two still agree.
1195
+ assert.equal(
1196
+ cameraGrant({
1197
+ cameraSite: SITE,
1198
+ cameraOrg: OWNER_ORG,
1199
+ memberships: [{ org: AGENCY_ORG, siteId: OTHER_SITE, role: "org-role", ...ORG_LEVEL }],
1200
+ engagedOrgs: new Set([AGENCY_ORG]),
1201
+ }),
1202
+ null,
1203
+ );
1204
+ });
1205
+
1206
+ test("a site-less membership still wins, so nobody's permissions change", () => {
1207
+ // Widening must not re-point the GRANTING membership: whoever passed before
1208
+ // must pass on the same row, or their role — and so their permissions —
1209
+ // silently change.
1210
+ const memberships = [
1211
+ { org: OWNER_ORG, siteId: OTHER_SITE, role: "pinned-org-role", ...ORG_LEVEL },
1212
+ { org: OWNER_ORG, role: "site-less-role" },
1213
+ ];
1214
+ assert.equal(
1215
+ cameraGrant({ cameraSite: SITE, cameraOrg: OWNER_ORG, memberships })?.role,
1216
+ "site-less-role",
1217
+ );
1218
+ assert.equal(
1219
+ cameraGrant({ cameraSite: SITE, cameraOrg: OWNER_ORG, memberships: [...memberships].reverse() })?.role,
1220
+ "site-less-role",
1221
+ "document order must not decide which membership grants",
1222
+ );
1223
+
1224
+ // And a membership AT the site still beats the widened branch.
1225
+ assert.equal(
1226
+ cameraGrant({
1227
+ cameraSite: SITE,
1228
+ cameraOrg: OWNER_ORG,
1229
+ memberships: [
1230
+ { org: OWNER_ORG, siteId: OTHER_SITE, role: "pinned-org-role", ...ORG_LEVEL },
1231
+ { org: OTHER_ORG, siteId: SITE, role: "at-the-site" },
1232
+ ],
1233
+ })?.role,
1234
+ "at-the-site",
1235
+ );
1236
+ });