@7365admin1/core 3.52.9 → 3.52.10

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.9",
4
+ "version": "3.52.10",
5
5
  "author": "7365admin1",
6
6
  "main": "dist/index.js",
7
7
  "module": "dist/index.mjs",
@@ -0,0 +1,128 @@
1
+ import assert from "node:assert/strict";
2
+ import test from "node:test";
3
+ import { readFileSync } from "node:fs";
4
+ import { fileURLToPath } from "node:url";
5
+
6
+ import { entitledSiteScope } from "./.build/utils/camera-view.util.mjs";
7
+
8
+ /**
9
+ * `GET /api/vehicles` and `GET /api/vehicles/blocklisted` take an OPTIONAL
10
+ * `site`, and a request that omitted it applied no site predicate at all:
11
+ * `if (site) await requireSiteReach(...)` in the controller and
12
+ * `...(site && { site })` in the repository. Measured read-only on staging,
13
+ * 2026-09-03: one such call from the MA app's vehicle screen came back with 148
14
+ * vehicles belonging to four unrelated clients.
15
+ *
16
+ * The DECISION is `entitledSiteScope` and is covered here directly. The WIRING
17
+ * — that the controller asks for the scope and the repository applies it — needs
18
+ * a live Atlas connection to run, so it is asserted on the source, exactly as
19
+ * `camera-entitlement-wiring.test.mjs` does for the camera paths.
20
+ */
21
+
22
+ const ORG_A = "aaaaaaaaaaaaaaaaaaaaaaaa";
23
+ const ORG_B = "bbbbbbbbbbbbbbbbbbbbbbbb";
24
+ const SITE_A1 = "a1a1a1a1a1a1a1a1a1a1a1a1";
25
+ const SITE_A2 = "a2a2a2a2a2a2a2a2a2a2a2a2";
26
+ const SITE_B1 = "b1b1b1b1b1b1b1b1b1b1b1b1";
27
+
28
+ const sitesByOrg = { [ORG_A]: [SITE_A1, SITE_A2], [ORG_B]: [SITE_B1] };
29
+
30
+ test("a site-level role reaches only its own site", () => {
31
+ const scope = entitledSiteScope({
32
+ memberships: [{ org: ORG_A, siteId: SITE_A1, orgLevelRole: false }],
33
+ sitesByOrg,
34
+ engagedSitesByOrg: {},
35
+ });
36
+
37
+ assert.deepEqual(scope, [SITE_A1]);
38
+ assert.ok(!scope.includes(SITE_A2), "must not reach a sibling site");
39
+ assert.ok(!scope.includes(SITE_B1), "must never reach another organisation");
40
+ });
41
+
42
+ test("an org-level role reaches its whole organisation and no other", () => {
43
+ // The row also NAMES a site — the case that was the defect in the first cut of
44
+ // the camera change (owner decision, 2026-09-02: org-level roles see all
45
+ // sites).
46
+ const scope = entitledSiteScope({
47
+ memberships: [{ org: ORG_A, siteId: SITE_A1, orgLevelRole: true }],
48
+ sitesByOrg,
49
+ engagedSitesByOrg: {},
50
+ });
51
+
52
+ assert.deepEqual([...scope].sort(), [SITE_A1, SITE_A2].sort());
53
+ assert.ok(!scope.includes(SITE_B1), "must never reach another organisation");
54
+ });
55
+
56
+ test("a membership carrying no site is org-wide", () => {
57
+ const scope = entitledSiteScope({
58
+ memberships: [{ org: ORG_A, siteId: "", orgLevelRole: false }],
59
+ sitesByOrg,
60
+ engagedSitesByOrg: {},
61
+ });
62
+
63
+ assert.deepEqual([...scope].sort(), [SITE_A1, SITE_A2].sort());
64
+ });
65
+
66
+ test("an engagement grants only through a membership with no site", () => {
67
+ const engagedSitesByOrg = { [ORG_A]: [SITE_B1] };
68
+
69
+ const orgWide = entitledSiteScope({
70
+ memberships: [{ org: ORG_A, siteId: "", orgLevelRole: false }],
71
+ sitesByOrg,
72
+ engagedSitesByOrg,
73
+ });
74
+ assert.ok(orgWide.includes(SITE_B1), "an agency's org-level staff reach it");
75
+
76
+ // A membership PINNED to a site never grants a different site — the same rule
77
+ // `cameraGrant` applies (owner decision, 2026-08-10).
78
+ const pinned = entitledSiteScope({
79
+ memberships: [{ org: ORG_A, siteId: SITE_A1, orgLevelRole: false }],
80
+ sitesByOrg,
81
+ engagedSitesByOrg,
82
+ });
83
+ assert.deepEqual(pinned, [SITE_A1]);
84
+ });
85
+
86
+ test("no membership is an empty scope, not an unrestricted one", () => {
87
+ assert.deepEqual(
88
+ entitledSiteScope({ memberships: [], sitesByOrg, engagedSitesByOrg: {} }),
89
+ [],
90
+ );
91
+ });
92
+
93
+ const controller = readFileSync(
94
+ fileURLToPath(new URL("../src/controllers/vehicle.controller.ts", import.meta.url)),
95
+ "utf8",
96
+ );
97
+ const repo = readFileSync(
98
+ fileURLToPath(new URL("../src/repositories/vehicle.repo.ts", import.meta.url)),
99
+ "utf8",
100
+ );
101
+
102
+ test("both vehicle lists resolve a scope when no site is named", () => {
103
+ const asked = controller.match(/const siteScope = site \? null : await entitledSites\(req\);/g);
104
+ assert.equal(asked?.length, 2, "the list and the blocklist both ask");
105
+
106
+ // An explicitly supplied site is still authorised, and never trusted.
107
+ assert.equal(
108
+ controller.match(/if \(site\) await requireSiteReach\(req, site\);/g)?.length,
109
+ 2,
110
+ );
111
+
112
+ assert.ok(
113
+ controller.includes(" siteScope,\n"),
114
+ "the scope must reach the repository, not be resolved and dropped",
115
+ );
116
+ });
117
+
118
+ test("the repository applies an empty scope rather than dropping it", () => {
119
+ const applied = repo.match(/\.\.\.\(siteScope\n/g);
120
+ assert.equal(applied?.length, 2, "both queries carry the predicate");
121
+
122
+ // `siteScope && siteScope.length` here would turn "reaches no site" back into
123
+ // "sees everything", which is the whole defect.
124
+ assert.ok(
125
+ !/siteScope\?\.length|siteScope && siteScope\.length/.test(repo),
126
+ "an empty array must not collapse into the no-restriction branch",
127
+ );
128
+ });