@stratum-hq/control-plane 0.3.0 → 0.4.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 (65) hide show
  1. package/dist/__tests__/admin-scope-query-string.test.d.ts +2 -0
  2. package/dist/__tests__/admin-scope-query-string.test.d.ts.map +1 -0
  3. package/dist/__tests__/admin-scope-query-string.test.js +69 -0
  4. package/dist/__tests__/admin-scope-query-string.test.js.map +1 -0
  5. package/dist/__tests__/configdiff-roles-scope.test.d.ts +2 -0
  6. package/dist/__tests__/configdiff-roles-scope.test.d.ts.map +1 -0
  7. package/dist/__tests__/configdiff-roles-scope.test.js +246 -0
  8. package/dist/__tests__/configdiff-roles-scope.test.js.map +1 -0
  9. package/dist/__tests__/default-deny.test.d.ts +2 -0
  10. package/dist/__tests__/default-deny.test.d.ts.map +1 -0
  11. package/dist/__tests__/default-deny.test.js +92 -0
  12. package/dist/__tests__/default-deny.test.js.map +1 -0
  13. package/dist/__tests__/tenant-create-scope.test.d.ts +2 -0
  14. package/dist/__tests__/tenant-create-scope.test.d.ts.map +1 -0
  15. package/dist/__tests__/tenant-create-scope.test.js +129 -0
  16. package/dist/__tests__/tenant-create-scope.test.js.map +1 -0
  17. package/dist/__tests__/tenant-move-scope.test.d.ts +2 -0
  18. package/dist/__tests__/tenant-move-scope.test.d.ts.map +1 -0
  19. package/dist/__tests__/tenant-move-scope.test.js +113 -0
  20. package/dist/__tests__/tenant-move-scope.test.js.map +1 -0
  21. package/dist/__tests__/test-helpers.d.ts.map +1 -1
  22. package/dist/__tests__/test-helpers.js +13 -0
  23. package/dist/__tests__/test-helpers.js.map +1 -1
  24. package/dist/app.d.ts.map +1 -1
  25. package/dist/app.js +3 -0
  26. package/dist/app.js.map +1 -1
  27. package/dist/middleware/authorize.d.ts.map +1 -1
  28. package/dist/middleware/authorize.js +4 -1
  29. package/dist/middleware/authorize.js.map +1 -1
  30. package/dist/middleware/tenant-scope.d.ts +70 -6
  31. package/dist/middleware/tenant-scope.d.ts.map +1 -1
  32. package/dist/middleware/tenant-scope.js +160 -30
  33. package/dist/middleware/tenant-scope.js.map +1 -1
  34. package/dist/routes/abac.js +1 -1
  35. package/dist/routes/abac.js.map +1 -1
  36. package/dist/routes/api-keys.d.ts.map +1 -1
  37. package/dist/routes/api-keys.js +5 -1
  38. package/dist/routes/api-keys.js.map +1 -1
  39. package/dist/routes/audit-logs.d.ts.map +1 -1
  40. package/dist/routes/audit-logs.js +3 -0
  41. package/dist/routes/audit-logs.js.map +1 -1
  42. package/dist/routes/config-diff.d.ts.map +1 -1
  43. package/dist/routes/config-diff.js +8 -1
  44. package/dist/routes/config-diff.js.map +1 -1
  45. package/dist/routes/config.js +1 -1
  46. package/dist/routes/config.js.map +1 -1
  47. package/dist/routes/consent.js +1 -1
  48. package/dist/routes/consent.js.map +1 -1
  49. package/dist/routes/maintenance.d.ts.map +1 -1
  50. package/dist/routes/maintenance.js +3 -0
  51. package/dist/routes/maintenance.js.map +1 -1
  52. package/dist/routes/permissions.js +1 -1
  53. package/dist/routes/permissions.js.map +1 -1
  54. package/dist/routes/regions.d.ts.map +1 -1
  55. package/dist/routes/regions.js +3 -0
  56. package/dist/routes/regions.js.map +1 -1
  57. package/dist/routes/roles.d.ts.map +1 -1
  58. package/dist/routes/roles.js +49 -6
  59. package/dist/routes/roles.js.map +1 -1
  60. package/dist/routes/tenants.d.ts.map +1 -1
  61. package/dist/routes/tenants.js +14 -4
  62. package/dist/routes/tenants.js.map +1 -1
  63. package/dist/routes/webhooks.js +1 -1
  64. package/dist/routes/webhooks.js.map +1 -1
  65. package/package.json +3 -2
@@ -0,0 +1,113 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const vitest_1 = require("vitest");
4
+ const test_helpers_js_1 = require("./test-helpers.js");
5
+ /**
6
+ * Regression tests for a critical cross-tenant authorization flaw in the move route.
7
+ *
8
+ * The bug: createTenantScopeGuard was registered with the `fromParamId` extractor,
9
+ * which reads only `:id`, the tenant being MOVED. Nothing authorized
10
+ * `body.new_parent_id`, the move DESTINATION.
11
+ *
12
+ * A key scoped to its own tenant therefore passed the guard on the fast path
13
+ * (`apiKey.tenant_id === targetTenantId`) and could graft itself under any tenant
14
+ * in the system. Because Stratum resolves config by walking UP the ancestry path,
15
+ * the attacker's tenant then inherits the victim's config, including `sensitive`
16
+ * values, which are decrypted on resolve, plus the victim's delegated permissions.
17
+ *
18
+ * The library's moveTenant is not at fault: it locks both rows, rejects archived
19
+ * tenants and detects cycles. Authorization is the control plane's job.
20
+ */
21
+ const ATTACKER = "11111111-1111-4111-8111-111111111111";
22
+ const ATTACKER_CHILD = "22222222-2222-4222-8222-222222222222";
23
+ const ATTACKER_GRANDCHILD = "33333333-3333-4333-8333-333333333333";
24
+ const VICTIM = "99999999-9999-4999-8999-999999999999";
25
+ // ancestry_path holds a tenant's ANCESTORS and excludes self, so a root is "".
26
+ const TENANTS = {
27
+ [ATTACKER]: { id: ATTACKER, ancestry_path: "", status: "active" },
28
+ [ATTACKER_CHILD]: {
29
+ id: ATTACKER_CHILD,
30
+ ancestry_path: ATTACKER,
31
+ status: "active",
32
+ },
33
+ [ATTACKER_GRANDCHILD]: {
34
+ id: ATTACKER_GRANDCHILD,
35
+ ancestry_path: `${ATTACKER}/${ATTACKER_CHILD}`,
36
+ status: "active",
37
+ },
38
+ [VICTIM]: { id: VICTIM, ancestry_path: "", status: "active" },
39
+ };
40
+ let app;
41
+ let stratum;
42
+ (0, vitest_1.beforeEach)(async () => {
43
+ stratum = (0, test_helpers_js_1.createMockStratum)();
44
+ // A key scoped to the attacker's own tenant. Not a global key.
45
+ stratum.validateApiKey.mockResolvedValue({
46
+ key_id: "attacker-key",
47
+ tenant_id: ATTACKER,
48
+ scopes: ["read", "write", "admin"],
49
+ rate_limit_max: null,
50
+ rate_limit_window: null,
51
+ });
52
+ stratum.getTenant.mockImplementation(async (id) => {
53
+ const row = TENANTS[id];
54
+ if (!row)
55
+ throw new Error(`Tenant ${id} not found`);
56
+ return row;
57
+ });
58
+ stratum.moveTenant.mockImplementation(async (id) => TENANTS[id]);
59
+ app = await (0, test_helpers_js_1.buildTestApp)(stratum);
60
+ });
61
+ async function move(id, newParentId) {
62
+ return app.inject({
63
+ method: "POST",
64
+ url: `/api/v1/tenants/${id}/move`,
65
+ headers: { ...(0, test_helpers_js_1.authHeaders)(), "content-type": "application/json" },
66
+ payload: { new_parent_id: newParentId },
67
+ });
68
+ }
69
+ (0, vitest_1.describe)("move route authorizes the destination parent, not just the moved tenant", () => {
70
+ (0, vitest_1.it)("refuses grafting your own tenant under an unrelated tenant", async () => {
71
+ const res = await move(ATTACKER, VICTIM);
72
+ (0, vitest_1.expect)(res.statusCode).toBe(403);
73
+ (0, vitest_1.expect)(stratum.moveTenant).not.toHaveBeenCalled();
74
+ });
75
+ (0, vitest_1.it)("refuses grafting a tenant you do own under a tenant you do not", async () => {
76
+ const res = await move(ATTACKER_CHILD, VICTIM);
77
+ (0, vitest_1.expect)(res.statusCode).toBe(403);
78
+ (0, vitest_1.expect)(stratum.moveTenant).not.toHaveBeenCalled();
79
+ });
80
+ (0, vitest_1.it)("allows reorganizing entirely inside your own subtree", async () => {
81
+ const res = await move(ATTACKER_GRANDCHILD, ATTACKER_CHILD);
82
+ (0, vitest_1.expect)(res.statusCode).toBe(200);
83
+ (0, vitest_1.expect)(stratum.moveTenant).toHaveBeenCalledWith(ATTACKER_GRANDCHILD, ATTACKER_CHILD, vitest_1.expect.anything());
84
+ });
85
+ (0, vitest_1.it)("allows moving a descendant up to your own root", async () => {
86
+ const res = await move(ATTACKER_GRANDCHILD, ATTACKER);
87
+ (0, vitest_1.expect)(res.statusCode).toBe(200);
88
+ (0, vitest_1.expect)(stratum.moveTenant).toHaveBeenCalled();
89
+ });
90
+ (0, vitest_1.it)("fails closed when the destination tenant cannot be loaded", async () => {
91
+ const res = await move(ATTACKER, "44444444-4444-4444-8444-444444444444");
92
+ (0, vitest_1.expect)(res.statusCode).toBe(403);
93
+ (0, vitest_1.expect)(stratum.moveTenant).not.toHaveBeenCalled();
94
+ });
95
+ });
96
+ (0, vitest_1.describe)("global keys are unaffected", () => {
97
+ (0, vitest_1.beforeEach)(async () => {
98
+ stratum.validateApiKey.mockResolvedValue({
99
+ key_id: "global-key",
100
+ tenant_id: null,
101
+ scopes: ["read", "write", "admin"],
102
+ rate_limit_max: null,
103
+ rate_limit_window: null,
104
+ });
105
+ app = await (0, test_helpers_js_1.buildTestApp)(stratum);
106
+ });
107
+ (0, vitest_1.it)("still permits an operator key to move a tenant anywhere", async () => {
108
+ const res = await move(ATTACKER, VICTIM);
109
+ (0, vitest_1.expect)(res.statusCode).toBe(200);
110
+ (0, vitest_1.expect)(stratum.moveTenant).toHaveBeenCalled();
111
+ });
112
+ });
113
+ //# sourceMappingURL=tenant-move-scope.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tenant-move-scope.test.js","sourceRoot":"","sources":["../../src/__tests__/tenant-move-scope.test.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"test-helpers.d.ts","sourceRoot":"","sources":["../../src/__tests__/test-helpers.ts"],"names":[],"mappings":"AAAA,OAAgB,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAWnD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAG/C,eAAO,MAAM,eAAe,mCAAmC,CAAC;AAEhE;;;GAGG;AACH,wBAAgB,iBAAiB,IAAI,OAAO,CAoC3C;AAED;;;;;;GAMG;AACH,wBAAsB,YAAY,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,eAAe,CAAC,CAkB7E;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,MAAM,GAAE,MAA4B,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAExF;AAED;;GAEG;AACH,wBAAgB,UAAU,CACxB,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,EACrC,MAAM,GAAE,MAAwB,GAC/B,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAYxB;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAQvD;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAQ1D;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAQvD;AAED,iDAAiD;AACjD,eAAO,MAAM,aAAa;;;;;;;;;;;;;CAazB,CAAC;AAEF,qCAAqC;AACrC,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;CAa/B,CAAC"}
1
+ {"version":3,"file":"test-helpers.d.ts","sourceRoot":"","sources":["../../src/__tests__/test-helpers.ts"],"names":[],"mappings":"AAAA,OAAgB,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAanD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAG/C,eAAO,MAAM,eAAe,mCAAmC,CAAC;AAEhE;;;GAGG;AACH,wBAAgB,iBAAiB,IAAI,OAAO,CA8C3C;AAED;;;;;;GAMG;AACH,wBAAsB,YAAY,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,eAAe,CAAC,CAoB7E;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,MAAM,GAAE,MAA4B,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAExF;AAED;;GAEG;AACH,wBAAgB,UAAU,CACxB,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,EACrC,MAAM,GAAE,MAAwB,GAC/B,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAYxB;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAQvD;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAQ1D;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAQvD;AAED,iDAAiD;AACjD,eAAO,MAAM,aAAa;;;;;;;;;;;;;CAazB,CAAC;AAEF,qCAAqC;AACrC,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;CAa/B,CAAC"}
@@ -17,11 +17,13 @@ const jsonwebtoken_1 = __importDefault(require("jsonwebtoken"));
17
17
  const error_handler_js_1 = require("../middleware/error-handler.js");
18
18
  const auth_js_1 = require("../middleware/auth.js");
19
19
  const authorize_js_1 = require("../middleware/authorize.js");
20
+ const tenant_scope_js_1 = require("../middleware/tenant-scope.js");
20
21
  const health_js_1 = require("../routes/health.js");
21
22
  const tenants_js_1 = require("../routes/tenants.js");
22
23
  const config_js_1 = require("../routes/config.js");
23
24
  const api_keys_js_1 = require("../routes/api-keys.js");
24
25
  const config_diff_js_1 = require("../routes/config-diff.js");
26
+ const roles_js_1 = require("../routes/roles.js");
25
27
  // Must match the JWT_SECRET env var set in vitest.config.ts
26
28
  exports.TEST_JWT_SECRET = "test-jwt-secret-for-unit-tests";
27
29
  /**
@@ -59,7 +61,16 @@ function createMockStratum() {
59
61
  revokeApiKey: vitest_1.vi.fn(),
60
62
  rotateApiKey: vitest_1.vi.fn(),
61
63
  listApiKeys: vitest_1.vi.fn(),
64
+ getApiKey: vitest_1.vi.fn(),
62
65
  listDormantKeys: vitest_1.vi.fn(),
66
+ // Role methods
67
+ createRole: vitest_1.vi.fn(),
68
+ getRole: vitest_1.vi.fn(),
69
+ listRoles: vitest_1.vi.fn(),
70
+ updateRole: vitest_1.vi.fn(),
71
+ deleteRole: vitest_1.vi.fn(),
72
+ assignRoleToKey: vitest_1.vi.fn(),
73
+ removeRoleFromKey: vitest_1.vi.fn(),
63
74
  };
64
75
  }
65
76
  /**
@@ -74,6 +85,7 @@ async function buildTestApp(stratum) {
74
85
  // Wire up the same middleware chain as the real app
75
86
  app.addHook("preHandler", (0, auth_js_1.createAuthMiddleware)(stratum));
76
87
  app.addHook("preHandler", (0, authorize_js_1.createAuthorizeMiddleware)());
88
+ app.addHook("preHandler", (0, tenant_scope_js_1.createTenantScopeEnforcer)(stratum));
77
89
  app.setErrorHandler(error_handler_js_1.errorHandler);
78
90
  // Register routes (pass a stub Redis health checker — Redis is not used in tests)
79
91
  const noopRedisHealth = async () => "not_configured";
@@ -82,6 +94,7 @@ async function buildTestApp(stratum) {
82
94
  await app.register((0, config_js_1.createConfigRoutes)(stratum), { prefix: "/api/v1/tenants/:id/config" });
83
95
  await app.register((0, api_keys_js_1.createApiKeyRoutes)(stratum), { prefix: "/api/v1/api-keys" });
84
96
  await app.register((0, config_diff_js_1.createConfigDiffRoutes)(stratum), { prefix: "/api/v1/config" });
97
+ await app.register((0, roles_js_1.createRoleRoutes)(stratum), { prefix: "/api/v1/roles" });
85
98
  await app.ready();
86
99
  return app;
87
100
  }
@@ -1 +1 @@
1
- {"version":3,"file":"test-helpers.js","sourceRoot":"","sources":["../../src/__tests__/test-helpers.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"test-helpers.js","sourceRoot":"","sources":["../../src/__tests__/test-helpers.ts"],"names":[],"mappings":";;;;;;AAsBA,8CA8CC;AASD,oCAoBC;AAMD,kCAEC;AAKD,gCAeC;AAMD,4CAQC;AAMD,kDAQC;AAMD,4CAQC;AAvKD,sDAAmD;AACnD,mCAA4B;AAC5B,gEAA+B;AAC/B,qEAA8D;AAC9D,mDAA6D;AAC7D,6DAAuE;AACvE,mEAA0E;AAC1E,mDAAmD;AACnD,qDAA0D;AAC1D,mDAAyD;AACzD,uDAA2D;AAC3D,6DAAkE;AAClE,iDAAsD;AAGtD,4DAA4D;AAC/C,QAAA,eAAe,GAAG,gCAAgC,CAAC;AAEhE;;;GAGG;AACH,SAAgB,iBAAiB;IAC/B,OAAO;QACL,iBAAiB;QACjB,YAAY,EAAE,WAAE,CAAC,EAAE,EAAE;QACrB,SAAS,EAAE,WAAE,CAAC,EAAE,EAAE;QAClB,WAAW,EAAE,WAAE,CAAC,EAAE,EAAE;QACpB,YAAY,EAAE,WAAE,CAAC,EAAE,EAAE;QACrB,YAAY,EAAE,WAAE,CAAC,EAAE,EAAE;QACrB,kBAAkB,EAAE,WAAE,CAAC,EAAE,EAAE;QAC3B,UAAU,EAAE,WAAE,CAAC,EAAE,EAAE;QACnB,YAAY,EAAE,WAAE,CAAC,EAAE,EAAE;QACrB,cAAc,EAAE,WAAE,CAAC,EAAE,EAAE;QACvB,WAAW,EAAE,WAAE,CAAC,EAAE,EAAE;QACpB,WAAW,EAAE,WAAE,CAAC,EAAE,EAAE;QACpB,gBAAgB,EAAE,WAAE,CAAC,EAAE,EAAE;QACzB,aAAa,EAAE,WAAE,CAAC,EAAE,EAAE;QAEtB,iBAAiB;QACjB,aAAa,EAAE,WAAE,CAAC,EAAE,EAAE;QACtB,SAAS,EAAE,WAAE,CAAC,EAAE,EAAE;QAClB,YAAY,EAAE,WAAE,CAAC,EAAE,EAAE;QACrB,cAAc,EAAE,WAAE,CAAC,EAAE,EAAE;QACvB,wBAAwB,EAAE,WAAE,CAAC,EAAE,EAAE;QACjC,UAAU,EAAE,WAAE,CAAC,EAAE,EAAE;QAEnB,qBAAqB;QACrB,kBAAkB,EAAE,WAAE,CAAC,EAAE,EAAE;QAE3B,kBAAkB;QAClB,YAAY,EAAE,WAAE,CAAC,EAAE,EAAE;QACrB,cAAc,EAAE,WAAE,CAAC,EAAE,EAAE;QACvB,YAAY,EAAE,WAAE,CAAC,EAAE,EAAE;QACrB,YAAY,EAAE,WAAE,CAAC,EAAE,EAAE;QACrB,WAAW,EAAE,WAAE,CAAC,EAAE,EAAE;QACpB,SAAS,EAAE,WAAE,CAAC,EAAE,EAAE;QAClB,eAAe,EAAE,WAAE,CAAC,EAAE,EAAE;QAExB,eAAe;QACf,UAAU,EAAE,WAAE,CAAC,EAAE,EAAE;QACnB,OAAO,EAAE,WAAE,CAAC,EAAE,EAAE;QAChB,SAAS,EAAE,WAAE,CAAC,EAAE,EAAE;QAClB,UAAU,EAAE,WAAE,CAAC,EAAE,EAAE;QACnB,UAAU,EAAE,WAAE,CAAC,EAAE,EAAE;QACnB,eAAe,EAAE,WAAE,CAAC,EAAE,EAAE;QACxB,iBAAiB,EAAE,WAAE,CAAC,EAAE,EAAE;KACL,CAAC;AAC1B,CAAC;AAED;;;;;;GAMG;AACI,KAAK,UAAU,YAAY,CAAC,OAAgB;IACjD,MAAM,GAAG,GAAG,IAAA,iBAAO,EAAC,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;IAEvC,oDAAoD;IACpD,GAAG,CAAC,OAAO,CAAC,YAAY,EAAE,IAAA,8BAAoB,EAAC,OAAO,CAAC,CAAC,CAAC;IACzD,GAAG,CAAC,OAAO,CAAC,YAAY,EAAE,IAAA,wCAAyB,GAAE,CAAC,CAAC;IACvD,GAAG,CAAC,OAAO,CAAC,YAAY,EAAE,IAAA,2CAAyB,EAAC,OAAO,CAAC,CAAC,CAAC;IAC9D,GAAG,CAAC,eAAe,CAAC,+BAAY,CAAC,CAAC;IAElC,kFAAkF;IAClF,MAAM,eAAe,GAAG,KAAK,IAAI,EAAE,CAAC,gBAAyB,CAAC;IAC9D,MAAM,GAAG,CAAC,QAAQ,CAAC,IAAA,wBAAY,EAAC,eAAe,CAAC,CAAC,CAAC;IAClD,MAAM,GAAG,CAAC,QAAQ,CAAC,IAAA,+BAAkB,EAAC,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,iBAAiB,EAAE,CAAC,CAAC;IAC/E,MAAM,GAAG,CAAC,QAAQ,CAAC,IAAA,8BAAkB,EAAC,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,4BAA4B,EAAE,CAAC,CAAC;IAC1F,MAAM,GAAG,CAAC,QAAQ,CAAC,IAAA,gCAAkB,EAAC,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,kBAAkB,EAAE,CAAC,CAAC;IAChF,MAAM,GAAG,CAAC,QAAQ,CAAC,IAAA,uCAAsB,EAAC,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,gBAAgB,EAAE,CAAC,CAAC;IAClF,MAAM,GAAG,CAAC,QAAQ,CAAC,IAAA,2BAAgB,EAAC,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,eAAe,EAAE,CAAC,CAAC;IAE3E,MAAM,GAAG,CAAC,KAAK,EAAE,CAAC;IAClB,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;GAGG;AACH,SAAgB,WAAW,CAAC,SAAiB,mBAAmB;IAC9D,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,CAAC;AACjC,CAAC;AAED;;GAEG;AACH,SAAgB,UAAU,CACxB,UAAmC,EAAE,EACrC,SAAiB,uBAAe;IAEhC,MAAM,KAAK,GAAG,sBAAG,CAAC,IAAI,CACpB;QACE,GAAG,EAAE,cAAc;QACnB,SAAS,EAAE,qBAAa,CAAC,EAAE;QAC3B,MAAM,EAAE,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC;QAClC,GAAG,OAAO;KACX,EACD,MAAM,EACN,EAAE,SAAS,EAAE,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,CACxC,CAAC;IACF,OAAO,EAAE,aAAa,EAAE,UAAU,KAAK,EAAE,EAAE,CAAC;AAC9C,CAAC;AAED;;;GAGG;AACH,SAAgB,gBAAgB,CAAC,OAAgB;IAC9C,OAAO,CAAC,cAA2C,CAAC,iBAAiB,CAAC;QACrE,MAAM,EAAE,aAAa;QACrB,SAAS,EAAE,IAAI;QACf,MAAM,EAAE,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC;QAClC,cAAc,EAAE,IAAI;QACpB,iBAAiB,EAAE,IAAI;KACxB,CAAC,CAAC;AACL,CAAC;AAED;;;GAGG;AACH,SAAgB,mBAAmB,CAAC,OAAgB;IACjD,OAAO,CAAC,cAA2C,CAAC,iBAAiB,CAAC;QACrE,MAAM,EAAE,sBAAsB;QAC9B,SAAS,EAAE,IAAI;QACf,MAAM,EAAE,CAAC,MAAM,CAAC;QAChB,cAAc,EAAE,IAAI;QACpB,iBAAiB,EAAE,IAAI;KACxB,CAAC,CAAC;AACL,CAAC;AAED;;;GAGG;AACH,SAAgB,gBAAgB,CAAC,OAAgB;IAC9C,OAAO,CAAC,cAA2C,CAAC,iBAAiB,CAAC;QACrE,MAAM,EAAE,mBAAmB;QAC3B,SAAS,EAAE,IAAI;QACf,MAAM,EAAE,CAAC,MAAM,EAAE,OAAO,CAAC;QACzB,cAAc,EAAE,IAAI;QACpB,iBAAiB,EAAE,IAAI;KACxB,CAAC,CAAC;AACL,CAAC;AAED,iDAAiD;AACpC,QAAA,aAAa,GAAG;IAC3B,EAAE,EAAE,sCAAsC;IAC1C,IAAI,EAAE,WAAW;IACjB,IAAI,EAAE,WAAW;IACjB,SAAS,EAAE,IAAI;IACf,aAAa,EAAE,uCAAuC;IACtD,KAAK,EAAE,CAAC;IACR,QAAQ,EAAE,EAAE;IACZ,kBAAkB,EAAE,YAAY;IAChC,SAAS,EAAE,IAAI;IACf,UAAU,EAAE,IAAI,IAAI,CAAC,YAAY,CAAC,CAAC,WAAW,EAAE;IAChD,UAAU,EAAE,IAAI,IAAI,CAAC,YAAY,CAAC,CAAC,WAAW,EAAE;IAChD,UAAU,EAAE,IAAI;CACjB,CAAC;AAEF,qCAAqC;AACxB,QAAA,mBAAmB,GAAG;IACjC,EAAE,EAAE,sCAAsC;IAC1C,IAAI,EAAE,eAAe;IACrB,IAAI,EAAE,eAAe;IACrB,SAAS,EAAE,sCAAsC;IACjD,aAAa,EAAE,4EAA4E;IAC3F,KAAK,EAAE,CAAC;IACR,QAAQ,EAAE,EAAE;IACZ,kBAAkB,EAAE,YAAY;IAChC,SAAS,EAAE,IAAI;IACf,UAAU,EAAE,IAAI,IAAI,CAAC,YAAY,CAAC,CAAC,WAAW,EAAE;IAChD,UAAU,EAAE,IAAI,IAAI,CAAC,YAAY,CAAC,CAAC,WAAW,EAAE;IAChD,UAAU,EAAE,IAAI;CACjB,CAAC"}
package/dist/app.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"AACA,OAAgB,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AA2CnD,wBAAsB,QAAQ,IAAI,OAAO,CAAC,eAAe,CAAC,CA0EzD"}
1
+ {"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"AACA,OAAgB,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AA4CnD,wBAAsB,QAAQ,IAAI,OAAO,CAAC,eAAe,CAAC,CA4EzD"}
package/dist/app.js CHANGED
@@ -14,6 +14,7 @@ const openapi_js_1 = require("./openapi.js");
14
14
  const error_handler_js_1 = require("./middleware/error-handler.js");
15
15
  const auth_js_1 = require("./middleware/auth.js");
16
16
  const authorize_js_1 = require("./middleware/authorize.js");
17
+ const tenant_scope_js_1 = require("./middleware/tenant-scope.js");
17
18
  const per_key_rate_limit_js_1 = require("./middleware/per-key-rate-limit.js");
18
19
  const rate_limit_redis_js_1 = require("./middleware/rate-limit-redis.js");
19
20
  const redis_js_1 = require("./redis.js");
@@ -82,6 +83,8 @@ async function buildApp() {
82
83
  await (0, openapi_js_1.registerOpenApi)(app);
83
84
  app.addHook("preHandler", (0, auth_js_1.createAuthMiddleware)(stratum));
84
85
  app.addHook("preHandler", (0, authorize_js_1.createAuthorizeMiddleware)());
86
+ // Default-deny: a route that declares no tenant scope is refused.
87
+ app.addHook("preHandler", (0, tenant_scope_js_1.createTenantScopeEnforcer)(stratum));
85
88
  // Use Redis-backed rate limiting when REDIS_URL is configured, otherwise in-memory
86
89
  const redisClient = (0, redis_js_1.createRedisClient)();
87
90
  if (redisClient) {
package/dist/app.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"app.js","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"app.js","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"authorize.d.ts","sourceRoot":"","sources":["../../src/middleware/authorize.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAqCvD,wBAAgB,yBAAyB,KAErC,SAAS,cAAc,EACvB,OAAO,YAAY,KAClB,OAAO,CAAC,IAAI,CAAC,CAsBjB"}
1
+ {"version":3,"file":"authorize.d.ts","sourceRoot":"","sources":["../../src/middleware/authorize.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAwCvD,wBAAgB,yBAAyB,KAErC,SAAS,cAAc,EACvB,OAAO,YAAY,KAClB,OAAO,CAAC,IAAI,CAAC,CAsBjB"}
@@ -24,8 +24,11 @@ const ADMIN_ROUTES = [
24
24
  /^\/api\/v1\/tenants\/[^/]+\/context$/,
25
25
  ];
26
26
  function getRequiredScope(method, url) {
27
+ // Match on the request path. Take everything before the first "?" so the
28
+ // route match is evaluated on the normalized path alone.
29
+ const path = url.split("?", 1)[0];
27
30
  for (const pattern of ADMIN_ROUTES) {
28
- if (pattern.test(url)) {
31
+ if (pattern.test(path)) {
29
32
  return "admin";
30
33
  }
31
34
  }
@@ -1 +1 @@
1
- {"version":3,"file":"authorize.js","sourceRoot":"","sources":["../../src/middleware/authorize.ts"],"names":[],"mappings":";;AAqCA,8DA0BC;AA9DD,2CAAqE;AAIrE,SAAS,aAAa,CAAC,MAAc;IACnC,QAAQ,MAAM,CAAC,WAAW,EAAE,EAAE,CAAC;QAC7B,KAAK,KAAK,CAAC;QACX,KAAK,MAAM,CAAC;QACZ,KAAK,SAAS;YACZ,OAAO,MAAM,CAAC;QAChB;YACE,OAAO,OAAO,CAAC;IACnB,CAAC;AACH,CAAC;AAED,0DAA0D;AAC1D,MAAM,YAAY,GAAG;IACnB,sBAAsB;IACtB,wBAAwB;IACxB,yBAAyB;IACzB,qBAAqB;IACrB,oCAAoC;IACpC,qCAAqC;IACrC,6CAA6C;IAC7C,sCAAsC;CACvC,CAAC;AAEF,SAAS,gBAAgB,CAAC,MAAc,EAAE,GAAW;IACnD,KAAK,MAAM,OAAO,IAAI,YAAY,EAAE,CAAC;QACnC,IAAI,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;YACtB,OAAO,OAAO,CAAC;QACjB,CAAC;IACH,CAAC;IACD,OAAO,aAAa,CAAC,MAAM,CAAC,CAAC;AAC/B,CAAC;AAED,SAAgB,yBAAyB;IACvC,OAAO,KAAK,UAAU,mBAAmB,CACvC,OAAuB,EACvB,KAAmB;QAEnB,8CAA8C;QAC9C,IACE,OAAO,CAAC,GAAG,KAAK,gBAAgB;YAChC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,iBAAiB,CAAC;YACzC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,WAAW,CAAC,EACnC,CAAC;YACD,OAAO;QACT,CAAC;QAED,mEAAmE;QACnE,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;YACpB,MAAM,IAAI,wBAAiB,CAAC,yBAAyB,CAAC,CAAC;QACzD,CAAC;QAED,MAAM,aAAa,GAAG,gBAAgB,CAAC,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC;QACpE,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,IAAI,CAAC,MAAM,CAAC,CAAC;QAEjD,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC;YACpC,MAAM,IAAI,qBAAc,CAAC,6CAA6C,CAAC,CAAC;QAC1E,CAAC;IACH,CAAC,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"authorize.js","sourceRoot":"","sources":["../../src/middleware/authorize.ts"],"names":[],"mappings":";;AAwCA,8DA0BC;AAjED,2CAAqE;AAIrE,SAAS,aAAa,CAAC,MAAc;IACnC,QAAQ,MAAM,CAAC,WAAW,EAAE,EAAE,CAAC;QAC7B,KAAK,KAAK,CAAC;QACX,KAAK,MAAM,CAAC;QACZ,KAAK,SAAS;YACZ,OAAO,MAAM,CAAC;QAChB;YACE,OAAO,OAAO,CAAC;IACnB,CAAC;AACH,CAAC;AAED,0DAA0D;AAC1D,MAAM,YAAY,GAAG;IACnB,sBAAsB;IACtB,wBAAwB;IACxB,yBAAyB;IACzB,qBAAqB;IACrB,oCAAoC;IACpC,qCAAqC;IACrC,6CAA6C;IAC7C,sCAAsC;CACvC,CAAC;AAEF,SAAS,gBAAgB,CAAC,MAAc,EAAE,GAAW;IACnD,yEAAyE;IACzE,yDAAyD;IACzD,MAAM,IAAI,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAClC,KAAK,MAAM,OAAO,IAAI,YAAY,EAAE,CAAC;QACnC,IAAI,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YACvB,OAAO,OAAO,CAAC;QACjB,CAAC;IACH,CAAC;IACD,OAAO,aAAa,CAAC,MAAM,CAAC,CAAC;AAC/B,CAAC;AAED,SAAgB,yBAAyB;IACvC,OAAO,KAAK,UAAU,mBAAmB,CACvC,OAAuB,EACvB,KAAmB;QAEnB,8CAA8C;QAC9C,IACE,OAAO,CAAC,GAAG,KAAK,gBAAgB;YAChC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,iBAAiB,CAAC;YACzC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,WAAW,CAAC,EACnC,CAAC;YACD,OAAO;QACT,CAAC;QAED,mEAAmE;QACnE,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;YACpB,MAAM,IAAI,wBAAiB,CAAC,yBAAyB,CAAC,CAAC;QACzD,CAAC;QAED,MAAM,aAAa,GAAG,gBAAgB,CAAC,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC;QACpE,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,IAAI,CAAC,MAAM,CAAC,CAAC;QAEjD,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC;YACpC,MAAM,IAAI,qBAAc,CAAC,6CAA6C,CAAC,CAAC;QAC1E,CAAC;IACH,CAAC,CAAC;AACJ,CAAC"}
@@ -1,20 +1,84 @@
1
- import { FastifyRequest, FastifyReply } from "fastify";
1
+ import { FastifyRequest, FastifyReply, FastifyInstance } from "fastify";
2
2
  import { Stratum } from "@stratum-hq/lib";
3
+ /** Reads the target tenant id from a request, or null when there is none to check. */
4
+ export type TenantIdExtractor = (req: FastifyRequest) => string | null;
3
5
  /**
4
- * Tenant-scope enforcement middleware.
6
+ * A route's tenant-scope declaration:
7
+ * - an extractor: enforce that the caller's key may reach the extracted tenant;
8
+ * - "global": operator-level route with no single tenant target, or one that
9
+ * scopes itself in its handler. The middleware performs no tenant check.
10
+ */
11
+ export type TenantScopeDeclaration = TenantIdExtractor | "global";
12
+ declare module "fastify" {
13
+ interface FastifyContextConfig {
14
+ tenantScope?: TenantScopeDeclaration;
15
+ }
16
+ }
17
+ /**
18
+ * Core tenant-scope check for a single, already-resolved tenant id.
19
+ *
20
+ * Ensures that tenant-scoped API keys can only access data belonging to their
21
+ * own tenant or its descendants in the hierarchy. Global keys (tenant_id ===
22
+ * null) have unrestricted access. A null `tenantId` means there is no tenant to
23
+ * check (for example a global role, or an omitted optional filter) and passes.
24
+ *
25
+ * Exported for routes whose target tenant is not present in the request and
26
+ * must be resolved first (for example a role's owning tenant, looked up by id).
27
+ */
28
+ export declare function assertTenantInScope(stratum: Stratum, request: FastifyRequest, tenantId: string | null): Promise<void>;
29
+ /**
30
+ * Tenant-scope enforcement middleware for a single extractor.
31
+ *
32
+ * Retained for routes that must authorize a second tenant beyond the one the
33
+ * global enforcer already covers (for example, a move's destination parent).
34
+ */
35
+ export declare function createTenantScopeGuard(stratum: Stratum, extractTenantId: TenantIdExtractor): (request: FastifyRequest, _reply: FastifyReply) => Promise<void>;
36
+ /**
37
+ * Guard for POST /tenants: constrain a scoped key's new tenant to its subtree.
38
+ */
39
+ export declare function createTenantCreateGuard(stratum: Stratum): (request: FastifyRequest, _reply: FastifyReply) => Promise<void>;
40
+ /**
41
+ * Guard for POST /tenants/batch: every tenant in the batch is authorized the
42
+ * same way a single create is, so the batch route cannot sidestep the subtree
43
+ * constraint.
44
+ */
45
+ export declare function createTenantBatchCreateGuard(stratum: Stratum): (request: FastifyRequest, _reply: FastifyReply) => Promise<void>;
46
+ /**
47
+ * Declare the tenant scope for every route registered in the current plugin.
5
48
  *
6
- * Ensures that tenant-scoped API keys can only access data belonging
7
- * to their own tenant or its descendants in the hierarchy.
49
+ * Stamps the declaration onto each route's config so the global enforcer can
50
+ * read it. A route may still set its own `config.tenantScope`, which wins.
51
+ */
52
+ export declare function declareTenantScope(app: FastifyInstance, declaration: TenantScopeDeclaration): void;
53
+ /**
54
+ * Default-deny authorization enforcer, registered once as a global preHandler.
8
55
  *
9
- * Global keys (tenant_id === null) have unrestricted access.
56
+ * Every route must declare its tenant scope (see {@link declareTenantScope}). A
57
+ * route that declares none is refused, so a route added without a guard fails
58
+ * closed rather than silently serving data.
10
59
  */
11
- export declare function createTenantScopeGuard(stratum: Stratum, extractTenantId: (req: FastifyRequest) => string | null): (request: FastifyRequest, _reply: FastifyReply) => Promise<void>;
60
+ export declare function createTenantScopeEnforcer(stratum: Stratum): (request: FastifyRequest, _reply: FastifyReply) => Promise<void>;
12
61
  /** Extract :id param (tenant routes, config routes, permission routes) */
13
62
  export declare function fromParamId(req: FastifyRequest): string | null;
14
63
  /** Extract :tenantId param (consent routes) */
15
64
  export declare function fromParamTenantId(req: FastifyRequest): string | null;
16
65
  /** Extract tenant_id from query string */
17
66
  export declare function fromQueryTenantId(req: FastifyRequest): string | null;
67
+ /** Extract tenant_a from query string (config diff, first operand) */
68
+ export declare function fromQueryTenantA(req: FastifyRequest): string | null;
69
+ /** Extract tenant_b from query string (config diff, second operand) */
70
+ export declare function fromQueryTenantB(req: FastifyRequest): string | null;
18
71
  /** Extract tenant_id from request body */
19
72
  export declare function fromBodyTenantId(req: FastifyRequest): string | null;
73
+ /**
74
+ * Extract new_parent_id from a move request body: the move DESTINATION.
75
+ *
76
+ * A move has two tenants to authorize, not one. The route-level `:id` guard
77
+ * only covers the tenant being moved, which a scoped key already owns, so it
78
+ * passes on the fast path. Without authorizing the destination as well, a
79
+ * tenant can graft itself under any other tenant and inherit that tenant's
80
+ * resolved config (including decrypted `sensitive` values) and delegated
81
+ * permissions, because resolution walks UP the ancestry path.
82
+ */
83
+ export declare function fromBodyNewParentId(req: FastifyRequest): string | null;
20
84
  //# sourceMappingURL=tenant-scope.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"tenant-scope.d.ts","sourceRoot":"","sources":["../../src/middleware/tenant-scope.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEvD,OAAO,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAE1C;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,OAAO,EAChB,eAAe,EAAE,CAAC,GAAG,EAAE,cAAc,KAAK,MAAM,GAAG,IAAI,IAGrD,SAAS,cAAc,EACvB,QAAQ,YAAY,KACnB,OAAO,CAAC,IAAI,CAAC,CAkCjB;AAID,0EAA0E;AAC1E,wBAAgB,WAAW,CAAC,GAAG,EAAE,cAAc,GAAG,MAAM,GAAG,IAAI,CAE9D;AAED,+CAA+C;AAC/C,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,cAAc,GAAG,MAAM,GAAG,IAAI,CAEpE;AAED,0CAA0C;AAC1C,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,cAAc,GAAG,MAAM,GAAG,IAAI,CAEpE;AAED,0CAA0C;AAC1C,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,cAAc,GAAG,MAAM,GAAG,IAAI,CAEnE"}
1
+ {"version":3,"file":"tenant-scope.d.ts","sourceRoot":"","sources":["../../src/middleware/tenant-scope.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAExE,OAAO,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAE1C,sFAAsF;AACtF,MAAM,MAAM,iBAAiB,GAAG,CAAC,GAAG,EAAE,cAAc,KAAK,MAAM,GAAG,IAAI,CAAC;AAEvE;;;;;GAKG;AACH,MAAM,MAAM,sBAAsB,GAAG,iBAAiB,GAAG,QAAQ,CAAC;AAElE,OAAO,QAAQ,SAAS,CAAC;IACvB,UAAU,oBAAoB;QAC5B,WAAW,CAAC,EAAE,sBAAsB,CAAC;KACtC;CACF;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE,cAAc,EACvB,QAAQ,EAAE,MAAM,GAAG,IAAI,GACtB,OAAO,CAAC,IAAI,CAAC,CAgCf;AAaD;;;;;GAKG;AACH,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,OAAO,EAChB,eAAe,EAAE,iBAAiB,IAGhC,SAAS,cAAc,EACvB,QAAQ,YAAY,KACnB,OAAO,CAAC,IAAI,CAAC,CAGjB;AA6BD;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,OAAO,IAEpD,SAAS,cAAc,EACvB,QAAQ,YAAY,KACnB,OAAO,CAAC,IAAI,CAAC,CAIjB;AAED;;;;GAIG;AACH,wBAAgB,4BAA4B,CAAC,OAAO,EAAE,OAAO,IAEzD,SAAS,cAAc,EACvB,QAAQ,YAAY,KACnB,OAAO,CAAC,IAAI,CAAC,CASjB;AAYD;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAChC,GAAG,EAAE,eAAe,EACpB,WAAW,EAAE,sBAAsB,GAClC,IAAI,CAON;AAED;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,OAAO,IAEtD,SAAS,cAAc,EACvB,QAAQ,YAAY,KACnB,OAAO,CAAC,IAAI,CAAC,CAWjB;AAID,0EAA0E;AAC1E,wBAAgB,WAAW,CAAC,GAAG,EAAE,cAAc,GAAG,MAAM,GAAG,IAAI,CAE9D;AAED,+CAA+C;AAC/C,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,cAAc,GAAG,MAAM,GAAG,IAAI,CAEpE;AAED,0CAA0C;AAC1C,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,cAAc,GAAG,MAAM,GAAG,IAAI,CAEpE;AAED,sEAAsE;AACtE,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,cAAc,GAAG,MAAM,GAAG,IAAI,CAEnE;AAED,uEAAuE;AACvE,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,cAAc,GAAG,MAAM,GAAG,IAAI,CAEnE;AAED,0CAA0C;AAC1C,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,cAAc,GAAG,MAAM,GAAG,IAAI,CAEnE;AAED;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,cAAc,GAAG,MAAM,GAAG,IAAI,CAEtE"}
@@ -1,50 +1,159 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.assertTenantInScope = assertTenantInScope;
3
4
  exports.createTenantScopeGuard = createTenantScopeGuard;
5
+ exports.createTenantCreateGuard = createTenantCreateGuard;
6
+ exports.createTenantBatchCreateGuard = createTenantBatchCreateGuard;
7
+ exports.declareTenantScope = declareTenantScope;
8
+ exports.createTenantScopeEnforcer = createTenantScopeEnforcer;
4
9
  exports.fromParamId = fromParamId;
5
10
  exports.fromParamTenantId = fromParamTenantId;
6
11
  exports.fromQueryTenantId = fromQueryTenantId;
12
+ exports.fromQueryTenantA = fromQueryTenantA;
13
+ exports.fromQueryTenantB = fromQueryTenantB;
7
14
  exports.fromBodyTenantId = fromBodyTenantId;
15
+ exports.fromBodyNewParentId = fromBodyNewParentId;
8
16
  const core_1 = require("@stratum-hq/core");
9
17
  /**
10
- * Tenant-scope enforcement middleware.
18
+ * Core tenant-scope check for a single, already-resolved tenant id.
11
19
  *
12
- * Ensures that tenant-scoped API keys can only access data belonging
13
- * to their own tenant or its descendants in the hierarchy.
20
+ * Ensures that tenant-scoped API keys can only access data belonging to their
21
+ * own tenant or its descendants in the hierarchy. Global keys (tenant_id ===
22
+ * null) have unrestricted access. A null `tenantId` means there is no tenant to
23
+ * check (for example a global role, or an omitted optional filter) and passes.
14
24
  *
15
- * Global keys (tenant_id === null) have unrestricted access.
25
+ * Exported for routes whose target tenant is not present in the request and
26
+ * must be resolved first (for example a role's owning tenant, looked up by id).
27
+ */
28
+ async function assertTenantInScope(stratum, request, tenantId) {
29
+ const apiKey = request.apiKey;
30
+ if (!apiKey)
31
+ return;
32
+ // Only API keys may have global (null tenant_id) access.
33
+ // JWT auth should never reach here with null tenant_id after the auth middleware
34
+ // fix, but guard defensively anyway.
35
+ if (apiKey.tenant_id === null) {
36
+ if (request.authMethod === "api_key")
37
+ return;
38
+ throw new core_1.ForbiddenError("JWT authentication requires a tenant scope");
39
+ }
40
+ if (!tenantId)
41
+ return;
42
+ // Fast path: exact match
43
+ if (apiKey.tenant_id === tenantId)
44
+ return;
45
+ // Hierarchy check: target must be a descendant of the key's tenant
46
+ try {
47
+ const target = await stratum.getTenant(tenantId);
48
+ const ancestorIds = target.ancestry_path.split("/").filter(Boolean);
49
+ if (ancestorIds.includes(apiKey.tenant_id))
50
+ return;
51
+ }
52
+ catch {
53
+ // Tenant not found: fail closed for scoped keys
54
+ throw new core_1.ForbiddenError("API key tenant scope does not grant access to this tenant");
55
+ }
56
+ throw new core_1.ForbiddenError("API key tenant scope does not grant access to this tenant");
57
+ }
58
+ /**
59
+ * Core tenant-scope check for a tenant id read from the request by `extractTenantId`.
60
+ */
61
+ async function checkTenantScope(stratum, request, extractTenantId) {
62
+ await assertTenantInScope(stratum, request, extractTenantId(request));
63
+ }
64
+ /**
65
+ * Tenant-scope enforcement middleware for a single extractor.
66
+ *
67
+ * Retained for routes that must authorize a second tenant beyond the one the
68
+ * global enforcer already covers (for example, a move's destination parent).
16
69
  */
17
70
  function createTenantScopeGuard(stratum, extractTenantId) {
18
71
  return async function tenantScopeGuard(request, _reply) {
19
- const apiKey = request.apiKey;
20
- if (!apiKey)
21
- return;
22
- // Only API keys may have global (null tenant_id) access.
23
- // JWT auth should never reach here with null tenant_id after the auth middleware
24
- // fix, but guard defensively anyway.
25
- if (apiKey.tenant_id === null) {
26
- if (request.authMethod === "api_key")
27
- return;
28
- throw new core_1.ForbiddenError("JWT authentication requires a tenant scope");
72
+ await checkTenantScope(stratum, request, extractTenantId);
73
+ };
74
+ }
75
+ /**
76
+ * Authorize a single tenant CREATE against the caller's key scope.
77
+ *
78
+ * A scoped key may only create tenants within its own subtree, so the new
79
+ * tenant's parent must be the key's own tenant or a descendant of it. A scoped
80
+ * key may not create a new root (a tenant with no parent). Global (operator)
81
+ * keys are unrestricted and may create roots anywhere.
82
+ */
83
+ async function authorizeCreateUnder(stratum, request, parentId) {
84
+ const apiKey = request.apiKey;
85
+ if (!apiKey)
86
+ return;
87
+ // Only global API keys (null tenant_id) may create roots or create anywhere.
88
+ if (apiKey.tenant_id === null && request.authMethod === "api_key")
89
+ return;
90
+ if (!parentId) {
91
+ throw new core_1.ForbiddenError("API key tenant scope may not create root tenants");
92
+ }
93
+ await checkTenantScope(stratum, request, () => parentId);
94
+ }
95
+ /**
96
+ * Guard for POST /tenants: constrain a scoped key's new tenant to its subtree.
97
+ */
98
+ function createTenantCreateGuard(stratum) {
99
+ return async function tenantCreateGuard(request, _reply) {
100
+ const body = request.body;
101
+ await authorizeCreateUnder(stratum, request, body?.parent_id ?? null);
102
+ };
103
+ }
104
+ /**
105
+ * Guard for POST /tenants/batch: every tenant in the batch is authorized the
106
+ * same way a single create is, so the batch route cannot sidestep the subtree
107
+ * constraint.
108
+ */
109
+ function createTenantBatchCreateGuard(stratum) {
110
+ return async function tenantBatchCreateGuard(request, _reply) {
111
+ const body = request.body;
112
+ const tenants = Array.isArray(body?.tenants) ? body.tenants : [];
113
+ for (const tenant of tenants) {
114
+ await authorizeCreateUnder(stratum, request, tenant?.parent_id ?? null);
29
115
  }
30
- const targetTenantId = extractTenantId(request);
31
- if (!targetTenantId)
32
- return;
33
- // Fast path: exact match
34
- if (apiKey.tenant_id === targetTenantId)
116
+ };
117
+ }
118
+ // Endpoints that carry no authentication and therefore no tenant scope.
119
+ // Kept in step with the same skip list in the auth and authorize middleware.
120
+ function isUnauthenticatedPath(url) {
121
+ return (url === "/api/v1/health" ||
122
+ url.startsWith("/api/v1/health?") ||
123
+ url.startsWith("/api/docs"));
124
+ }
125
+ /**
126
+ * Declare the tenant scope for every route registered in the current plugin.
127
+ *
128
+ * Stamps the declaration onto each route's config so the global enforcer can
129
+ * read it. A route may still set its own `config.tenantScope`, which wins.
130
+ */
131
+ function declareTenantScope(app, declaration) {
132
+ app.addHook("onRoute", (routeOptions) => {
133
+ routeOptions.config = {
134
+ ...routeOptions.config,
135
+ tenantScope: routeOptions.config?.tenantScope ?? declaration,
136
+ };
137
+ });
138
+ }
139
+ /**
140
+ * Default-deny authorization enforcer, registered once as a global preHandler.
141
+ *
142
+ * Every route must declare its tenant scope (see {@link declareTenantScope}). A
143
+ * route that declares none is refused, so a route added without a guard fails
144
+ * closed rather than silently serving data.
145
+ */
146
+ function createTenantScopeEnforcer(stratum) {
147
+ return async function tenantScopeEnforcer(request, _reply) {
148
+ if (isUnauthenticatedPath(request.url))
35
149
  return;
36
- // Hierarchy check: target must be a descendant of the key's tenant
37
- try {
38
- const target = await stratum.getTenant(targetTenantId);
39
- const ancestorIds = target.ancestry_path.split("/").filter(Boolean);
40
- if (ancestorIds.includes(apiKey.tenant_id))
41
- return;
42
- }
43
- catch {
44
- // Tenant not found — fail closed for scoped keys
45
- throw new core_1.ForbiddenError("API key tenant scope does not grant access to this tenant");
150
+ const declaration = request.routeOptions?.config?.tenantScope;
151
+ if (declaration === undefined) {
152
+ throw new core_1.ForbiddenError("Route has no tenant-scope declaration");
46
153
  }
47
- throw new core_1.ForbiddenError("API key tenant scope does not grant access to this tenant");
154
+ if (declaration === "global")
155
+ return;
156
+ await checkTenantScope(stratum, request, declaration);
48
157
  };
49
158
  }
50
159
  // --- Extractors ---
@@ -60,8 +169,29 @@ function fromParamTenantId(req) {
60
169
  function fromQueryTenantId(req) {
61
170
  return req.query.tenant_id ?? null;
62
171
  }
172
+ /** Extract tenant_a from query string (config diff, first operand) */
173
+ function fromQueryTenantA(req) {
174
+ return req.query.tenant_a ?? null;
175
+ }
176
+ /** Extract tenant_b from query string (config diff, second operand) */
177
+ function fromQueryTenantB(req) {
178
+ return req.query.tenant_b ?? null;
179
+ }
63
180
  /** Extract tenant_id from request body */
64
181
  function fromBodyTenantId(req) {
65
182
  return req.body?.tenant_id ?? null;
66
183
  }
184
+ /**
185
+ * Extract new_parent_id from a move request body: the move DESTINATION.
186
+ *
187
+ * A move has two tenants to authorize, not one. The route-level `:id` guard
188
+ * only covers the tenant being moved, which a scoped key already owns, so it
189
+ * passes on the fast path. Without authorizing the destination as well, a
190
+ * tenant can graft itself under any other tenant and inherit that tenant's
191
+ * resolved config (including decrypted `sensitive` values) and delegated
192
+ * permissions, because resolution walks UP the ancestry path.
193
+ */
194
+ function fromBodyNewParentId(req) {
195
+ return req.body?.new_parent_id ?? null;
196
+ }
67
197
  //# sourceMappingURL=tenant-scope.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"tenant-scope.js","sourceRoot":"","sources":["../../src/middleware/tenant-scope.ts"],"names":[],"mappings":";;AAYA,wDAyCC;AAKD,kCAEC;AAGD,8CAEC;AAGD,8CAEC;AAGD,4CAEC;AA1ED,2CAAkD;AAGlD;;;;;;;GAOG;AACH,SAAgB,sBAAsB,CACpC,OAAgB,EAChB,eAAuD;IAEvD,OAAO,KAAK,UAAU,gBAAgB,CACpC,OAAuB,EACvB,MAAoB;QAEpB,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;QAC9B,IAAI,CAAC,MAAM;YAAE,OAAO;QAEpB,yDAAyD;QACzD,iFAAiF;QACjF,qCAAqC;QACrC,IAAI,MAAM,CAAC,SAAS,KAAK,IAAI,EAAE,CAAC;YAC9B,IAAI,OAAO,CAAC,UAAU,KAAK,SAAS;gBAAE,OAAO;YAC7C,MAAM,IAAI,qBAAc,CAAC,4CAA4C,CAAC,CAAC;QACzE,CAAC;QAED,MAAM,cAAc,GAAG,eAAe,CAAC,OAAO,CAAC,CAAC;QAChD,IAAI,CAAC,cAAc;YAAE,OAAO;QAE5B,yBAAyB;QACzB,IAAI,MAAM,CAAC,SAAS,KAAK,cAAc;YAAE,OAAO;QAEhD,mEAAmE;QACnE,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC;YACvD,MAAM,WAAW,GAAG,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;YACpE,IAAI,WAAW,CAAC,QAAQ,CAAC,MAAM,CAAC,SAAS,CAAC;gBAAE,OAAO;QACrD,CAAC;QAAC,MAAM,CAAC;YACP,iDAAiD;YACjD,MAAM,IAAI,qBAAc,CACtB,2DAA2D,CAC5D,CAAC;QACJ,CAAC;QAED,MAAM,IAAI,qBAAc,CACtB,2DAA2D,CAC5D,CAAC;IACJ,CAAC,CAAC;AACJ,CAAC;AAED,qBAAqB;AAErB,0EAA0E;AAC1E,SAAgB,WAAW,CAAC,GAAmB;IAC7C,OAAQ,GAAG,CAAC,MAAiC,CAAC,EAAE,IAAI,IAAI,CAAC;AAC3D,CAAC;AAED,+CAA+C;AAC/C,SAAgB,iBAAiB,CAAC,GAAmB;IACnD,OAAQ,GAAG,CAAC,MAAiC,CAAC,QAAQ,IAAI,IAAI,CAAC;AACjE,CAAC;AAED,0CAA0C;AAC1C,SAAgB,iBAAiB,CAAC,GAAmB;IACnD,OAAQ,GAAG,CAAC,KAAgC,CAAC,SAAS,IAAI,IAAI,CAAC;AACjE,CAAC;AAED,0CAA0C;AAC1C,SAAgB,gBAAgB,CAAC,GAAmB;IAClD,OAAQ,GAAG,CAAC,IAAsC,EAAE,SAAS,IAAI,IAAI,CAAC;AACxE,CAAC"}
1
+ {"version":3,"file":"tenant-scope.js","sourceRoot":"","sources":["../../src/middleware/tenant-scope.ts"],"names":[],"mappings":"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"}
@@ -6,7 +6,7 @@ const tenant_scope_js_1 = require("../middleware/tenant-scope.js");
6
6
  function createAbacRoutes(stratum) {
7
7
  return async function abacRoutes(app) {
8
8
  // Tenant-scoped keys can only access ABAC policies for their own tenant subtree
9
- app.addHook("preHandler", (0, tenant_scope_js_1.createTenantScopeGuard)(stratum, tenant_scope_js_1.fromParamTenantId));
9
+ (0, tenant_scope_js_1.declareTenantScope)(app, tenant_scope_js_1.fromParamTenantId);
10
10
  // POST /api/v1/tenants/:tenantId/abac-policies — Create ABAC policy
11
11
  app.post("/", async (request, reply) => {
12
12
  const input = core_1.CreateAbacPolicyInputSchema.parse(request.body);