@stratum-hq/control-plane 0.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 (133) hide show
  1. package/dist/__tests__/api-keys.test.d.ts +2 -0
  2. package/dist/__tests__/api-keys.test.d.ts.map +1 -0
  3. package/dist/__tests__/api-keys.test.js +240 -0
  4. package/dist/__tests__/api-keys.test.js.map +1 -0
  5. package/dist/__tests__/auth.test.d.ts +2 -0
  6. package/dist/__tests__/auth.test.d.ts.map +1 -0
  7. package/dist/__tests__/auth.test.js +227 -0
  8. package/dist/__tests__/auth.test.js.map +1 -0
  9. package/dist/__tests__/config.test.d.ts +2 -0
  10. package/dist/__tests__/config.test.d.ts.map +1 -0
  11. package/dist/__tests__/config.test.js +201 -0
  12. package/dist/__tests__/config.test.js.map +1 -0
  13. package/dist/__tests__/tenants.test.d.ts +2 -0
  14. package/dist/__tests__/tenants.test.d.ts.map +1 -0
  15. package/dist/__tests__/tenants.test.js +214 -0
  16. package/dist/__tests__/tenants.test.js.map +1 -0
  17. package/dist/__tests__/test-helpers.d.ts +71 -0
  18. package/dist/__tests__/test-helpers.d.ts.map +1 -0
  19. package/dist/__tests__/test-helpers.js +172 -0
  20. package/dist/__tests__/test-helpers.js.map +1 -0
  21. package/dist/app.d.ts +3 -0
  22. package/dist/app.d.ts.map +1 -0
  23. package/dist/app.js +114 -0
  24. package/dist/app.js.map +1 -0
  25. package/dist/config.d.ts +11 -0
  26. package/dist/config.d.ts.map +1 -0
  27. package/dist/config.js +26 -0
  28. package/dist/config.js.map +1 -0
  29. package/dist/db/connection.d.ts +4 -0
  30. package/dist/db/connection.d.ts.map +1 -0
  31. package/dist/db/connection.js +30 -0
  32. package/dist/db/connection.js.map +1 -0
  33. package/dist/db/migrate.d.ts +3 -0
  34. package/dist/db/migrate.d.ts.map +1 -0
  35. package/dist/db/migrate.js +56 -0
  36. package/dist/db/migrate.js.map +1 -0
  37. package/dist/db/regional-pool-router.d.ts +9 -0
  38. package/dist/db/regional-pool-router.d.ts.map +1 -0
  39. package/dist/db/regional-pool-router.js +29 -0
  40. package/dist/db/regional-pool-router.js.map +1 -0
  41. package/dist/index.d.ts +2 -0
  42. package/dist/index.d.ts.map +1 -0
  43. package/dist/index.js +36 -0
  44. package/dist/index.js.map +1 -0
  45. package/dist/middleware/auth.d.ts +21 -0
  46. package/dist/middleware/auth.d.ts.map +1 -0
  47. package/dist/middleware/auth.js +70 -0
  48. package/dist/middleware/auth.js.map +1 -0
  49. package/dist/middleware/authorize.d.ts +3 -0
  50. package/dist/middleware/authorize.d.ts.map +1 -0
  51. package/dist/middleware/authorize.js +54 -0
  52. package/dist/middleware/authorize.js.map +1 -0
  53. package/dist/middleware/error-handler.d.ts +3 -0
  54. package/dist/middleware/error-handler.d.ts.map +1 -0
  55. package/dist/middleware/error-handler.js +48 -0
  56. package/dist/middleware/error-handler.js.map +1 -0
  57. package/dist/middleware/per-key-rate-limit.d.ts +3 -0
  58. package/dist/middleware/per-key-rate-limit.d.ts.map +1 -0
  59. package/dist/middleware/per-key-rate-limit.js +62 -0
  60. package/dist/middleware/per-key-rate-limit.js.map +1 -0
  61. package/dist/middleware/rate-limit-redis.d.ts +16 -0
  62. package/dist/middleware/rate-limit-redis.d.ts.map +1 -0
  63. package/dist/middleware/rate-limit-redis.js +118 -0
  64. package/dist/middleware/rate-limit-redis.js.map +1 -0
  65. package/dist/middleware/telemetry.d.ts +14 -0
  66. package/dist/middleware/telemetry.d.ts.map +1 -0
  67. package/dist/middleware/telemetry.js +81 -0
  68. package/dist/middleware/telemetry.js.map +1 -0
  69. package/dist/middleware/tenant-scope.d.ts +20 -0
  70. package/dist/middleware/tenant-scope.d.ts.map +1 -0
  71. package/dist/middleware/tenant-scope.js +60 -0
  72. package/dist/middleware/tenant-scope.js.map +1 -0
  73. package/dist/openapi.d.ts +3 -0
  74. package/dist/openapi.d.ts.map +1 -0
  75. package/dist/openapi.js +44 -0
  76. package/dist/openapi.js.map +1 -0
  77. package/dist/redis.d.ts +16 -0
  78. package/dist/redis.d.ts.map +1 -0
  79. package/dist/redis.js +71 -0
  80. package/dist/redis.js.map +1 -0
  81. package/dist/routes/api-keys.d.ts +4 -0
  82. package/dist/routes/api-keys.d.ts.map +1 -0
  83. package/dist/routes/api-keys.js +78 -0
  84. package/dist/routes/api-keys.js.map +1 -0
  85. package/dist/routes/audit-logs.d.ts +6 -0
  86. package/dist/routes/audit-logs.d.ts.map +1 -0
  87. package/dist/routes/audit-logs.js +43 -0
  88. package/dist/routes/audit-logs.js.map +1 -0
  89. package/dist/routes/config-diff.d.ts +4 -0
  90. package/dist/routes/config-diff.d.ts.map +1 -0
  91. package/dist/routes/config-diff.js +33 -0
  92. package/dist/routes/config-diff.js.map +1 -0
  93. package/dist/routes/config.d.ts +4 -0
  94. package/dist/routes/config.d.ts.map +1 -0
  95. package/dist/routes/config.js +54 -0
  96. package/dist/routes/config.js.map +1 -0
  97. package/dist/routes/consent.d.ts +4 -0
  98. package/dist/routes/consent.d.ts.map +1 -0
  99. package/dist/routes/consent.js +45 -0
  100. package/dist/routes/consent.js.map +1 -0
  101. package/dist/routes/health.d.ts +9 -0
  102. package/dist/routes/health.d.ts.map +1 -0
  103. package/dist/routes/health.js +32 -0
  104. package/dist/routes/health.js.map +1 -0
  105. package/dist/routes/maintenance.d.ts +4 -0
  106. package/dist/routes/maintenance.d.ts.map +1 -0
  107. package/dist/routes/maintenance.js +35 -0
  108. package/dist/routes/maintenance.js.map +1 -0
  109. package/dist/routes/permissions.d.ts +4 -0
  110. package/dist/routes/permissions.d.ts.map +1 -0
  111. package/dist/routes/permissions.js +36 -0
  112. package/dist/routes/permissions.js.map +1 -0
  113. package/dist/routes/regions.d.ts +4 -0
  114. package/dist/routes/regions.d.ts.map +1 -0
  115. package/dist/routes/regions.js +38 -0
  116. package/dist/routes/regions.js.map +1 -0
  117. package/dist/routes/roles.d.ts +4 -0
  118. package/dist/routes/roles.d.ts.map +1 -0
  119. package/dist/routes/roles.js +95 -0
  120. package/dist/routes/roles.js.map +1 -0
  121. package/dist/routes/tenants.d.ts +4 -0
  122. package/dist/routes/tenants.d.ts.map +1 -0
  123. package/dist/routes/tenants.js +112 -0
  124. package/dist/routes/tenants.js.map +1 -0
  125. package/dist/routes/webhooks.d.ts +4 -0
  126. package/dist/routes/webhooks.d.ts.map +1 -0
  127. package/dist/routes/webhooks.js +116 -0
  128. package/dist/routes/webhooks.js.map +1 -0
  129. package/dist/services/isolation-service.d.ts +22 -0
  130. package/dist/services/isolation-service.d.ts.map +1 -0
  131. package/dist/services/isolation-service.js +94 -0
  132. package/dist/services/isolation-service.js.map +1 -0
  133. package/package.json +48 -0
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=api-keys.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-keys.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/api-keys.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,240 @@
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
+ (0, vitest_1.describe)("API Key Routes", () => {
6
+ let app;
7
+ let stratum;
8
+ (0, vitest_1.beforeEach)(async () => {
9
+ stratum = (0, test_helpers_js_1.createMockStratum)();
10
+ (0, test_helpers_js_1.setupAdminApiKey)(stratum);
11
+ app = await (0, test_helpers_js_1.buildTestApp)(stratum);
12
+ });
13
+ (0, vitest_1.afterEach)(async () => {
14
+ await app.close();
15
+ });
16
+ // ── POST /api/v1/api-keys ──────────────────────────────────────────
17
+ (0, vitest_1.describe)("POST /api/v1/api-keys", () => {
18
+ (0, vitest_1.it)("creates a key and returns plaintext once with 201", async () => {
19
+ const createdKey = {
20
+ id: "key-uuid-1",
21
+ tenant_id: "t-uuid-1",
22
+ plaintext: "sk_test_abc123def456",
23
+ name: "My API Key",
24
+ created_at: new Date().toISOString(),
25
+ };
26
+ stratum.createApiKey.mockResolvedValue(createdKey);
27
+ const response = await app.inject({
28
+ method: "POST",
29
+ url: "/api/v1/api-keys",
30
+ headers: (0, test_helpers_js_1.authHeaders)(),
31
+ payload: { tenant_id: "t-uuid-1", name: "My API Key" },
32
+ });
33
+ (0, vitest_1.expect)(response.statusCode).toBe(201);
34
+ const body = response.json();
35
+ (0, vitest_1.expect)(body.id).toBe("key-uuid-1");
36
+ (0, vitest_1.expect)(body.plaintext).toBe("sk_test_abc123def456");
37
+ (0, vitest_1.expect)(stratum.createApiKey).toHaveBeenCalledOnce();
38
+ (0, vitest_1.expect)(stratum.createApiKey.mock.calls[0][0]).toBe("t-uuid-1");
39
+ });
40
+ (0, vitest_1.it)("returns 400 for missing tenant_id", async () => {
41
+ const response = await app.inject({
42
+ method: "POST",
43
+ url: "/api/v1/api-keys",
44
+ headers: (0, test_helpers_js_1.authHeaders)(),
45
+ payload: { name: "No Tenant" },
46
+ });
47
+ (0, vitest_1.expect)(response.statusCode).toBe(400);
48
+ const body = response.json();
49
+ (0, vitest_1.expect)(body.error.code).toBe("VALIDATION_ERROR");
50
+ });
51
+ (0, vitest_1.it)("returns 400 for invalid tenant_id (not UUID)", async () => {
52
+ const response = await app.inject({
53
+ method: "POST",
54
+ url: "/api/v1/api-keys",
55
+ headers: (0, test_helpers_js_1.authHeaders)(),
56
+ payload: { tenant_id: "not-a-uuid", name: "Bad ID" },
57
+ });
58
+ (0, vitest_1.expect)(response.statusCode).toBe(400);
59
+ });
60
+ (0, vitest_1.it)("creates a key with rate limit options", async () => {
61
+ const createdKey = {
62
+ id: "key-uuid-2",
63
+ tenant_id: "t-uuid-1",
64
+ plaintext: "sk_test_rate_limited",
65
+ name: "Rate Limited Key",
66
+ created_at: new Date().toISOString(),
67
+ };
68
+ stratum.createApiKey.mockResolvedValue(createdKey);
69
+ const response = await app.inject({
70
+ method: "POST",
71
+ url: "/api/v1/api-keys",
72
+ headers: (0, test_helpers_js_1.authHeaders)(),
73
+ payload: {
74
+ tenant_id: "t-uuid-1",
75
+ name: "Rate Limited Key",
76
+ rate_limit_max: 500,
77
+ rate_limit_window: "1 minute",
78
+ },
79
+ });
80
+ (0, vitest_1.expect)(response.statusCode).toBe(201);
81
+ (0, vitest_1.expect)(stratum.createApiKey).toHaveBeenCalledWith("t-uuid-1", {
82
+ name: "Rate Limited Key",
83
+ rateLimitMax: 500,
84
+ rateLimitWindow: "1 minute",
85
+ });
86
+ });
87
+ });
88
+ // ── GET /api/v1/api-keys ───────────────────────────────────────────
89
+ (0, vitest_1.describe)("GET /api/v1/api-keys", () => {
90
+ (0, vitest_1.it)("lists keys without plaintext", async () => {
91
+ const keys = [
92
+ {
93
+ id: "key-uuid-1",
94
+ tenant_id: "t-uuid-1",
95
+ name: "Key 1",
96
+ created_at: new Date().toISOString(),
97
+ last_used_at: null,
98
+ revoked_at: null,
99
+ expires_at: null,
100
+ },
101
+ {
102
+ id: "key-uuid-2",
103
+ tenant_id: "t-uuid-1",
104
+ name: "Key 2",
105
+ created_at: new Date().toISOString(),
106
+ last_used_at: new Date().toISOString(),
107
+ revoked_at: null,
108
+ expires_at: null,
109
+ },
110
+ ];
111
+ stratum.listApiKeys.mockResolvedValue(keys);
112
+ const response = await app.inject({
113
+ method: "GET",
114
+ url: "/api/v1/api-keys",
115
+ headers: (0, test_helpers_js_1.authHeaders)(),
116
+ });
117
+ (0, vitest_1.expect)(response.statusCode).toBe(200);
118
+ const body = response.json();
119
+ (0, vitest_1.expect)(body).toHaveLength(2);
120
+ // Plaintext should never appear in list response
121
+ (0, vitest_1.expect)(body[0]).not.toHaveProperty("plaintext");
122
+ (0, vitest_1.expect)(body[1]).not.toHaveProperty("plaintext");
123
+ (0, vitest_1.expect)(body[0].id).toBe("key-uuid-1");
124
+ });
125
+ (0, vitest_1.it)("lists keys filtered by tenant_id query param", async () => {
126
+ stratum.listApiKeys.mockResolvedValue([]);
127
+ const response = await app.inject({
128
+ method: "GET",
129
+ url: "/api/v1/api-keys?tenant_id=t-uuid-1",
130
+ headers: (0, test_helpers_js_1.authHeaders)(),
131
+ });
132
+ (0, vitest_1.expect)(response.statusCode).toBe(200);
133
+ // The tenant_id is passed through to listApiKeys
134
+ (0, vitest_1.expect)(stratum.listApiKeys).toHaveBeenCalled();
135
+ });
136
+ });
137
+ // ── DELETE /api/v1/api-keys/:id ────────────────────────────────────
138
+ (0, vitest_1.describe)("DELETE /api/v1/api-keys/:id", () => {
139
+ (0, vitest_1.it)("revokes a key and returns 204", async () => {
140
+ stratum.revokeApiKey.mockResolvedValue(true);
141
+ const response = await app.inject({
142
+ method: "DELETE",
143
+ url: "/api/v1/api-keys/key-uuid-1",
144
+ headers: (0, test_helpers_js_1.authHeaders)(),
145
+ });
146
+ (0, vitest_1.expect)(response.statusCode).toBe(204);
147
+ (0, vitest_1.expect)(response.body).toBe("");
148
+ (0, vitest_1.expect)(stratum.revokeApiKey).toHaveBeenCalledWith("key-uuid-1");
149
+ });
150
+ (0, vitest_1.it)("returns 404 when key does not exist", async () => {
151
+ stratum.revokeApiKey.mockResolvedValue(false);
152
+ const response = await app.inject({
153
+ method: "DELETE",
154
+ url: "/api/v1/api-keys/nonexistent-key",
155
+ headers: (0, test_helpers_js_1.authHeaders)(),
156
+ });
157
+ (0, vitest_1.expect)(response.statusCode).toBe(404);
158
+ const body = response.json();
159
+ (0, vitest_1.expect)(body.error.code).toBe("NOT_FOUND");
160
+ });
161
+ });
162
+ // ── POST /api/v1/api-keys/:id/rotate ──────────────────────────────
163
+ (0, vitest_1.describe)("POST /api/v1/api-keys/:id/rotate", () => {
164
+ (0, vitest_1.it)("rotates a key and returns new plaintext with 201", async () => {
165
+ const rotatedKey = {
166
+ id: "key-uuid-new",
167
+ tenant_id: "t-uuid-1",
168
+ plaintext: "sk_test_rotated_xyz789",
169
+ name: "Rotated Key",
170
+ created_at: new Date().toISOString(),
171
+ };
172
+ stratum.rotateApiKey.mockResolvedValue(rotatedKey);
173
+ const response = await app.inject({
174
+ method: "POST",
175
+ url: "/api/v1/api-keys/key-uuid-1/rotate",
176
+ headers: (0, test_helpers_js_1.authHeaders)(),
177
+ payload: {},
178
+ });
179
+ (0, vitest_1.expect)(response.statusCode).toBe(201);
180
+ const body = response.json();
181
+ (0, vitest_1.expect)(body.plaintext).toBe("sk_test_rotated_xyz789");
182
+ (0, vitest_1.expect)(stratum.rotateApiKey).toHaveBeenCalledWith("key-uuid-1", undefined);
183
+ });
184
+ (0, vitest_1.it)("rotates a key with a new name", async () => {
185
+ const rotatedKey = {
186
+ id: "key-uuid-new",
187
+ tenant_id: "t-uuid-1",
188
+ plaintext: "sk_test_rotated_abc",
189
+ name: "New Name",
190
+ created_at: new Date().toISOString(),
191
+ };
192
+ stratum.rotateApiKey.mockResolvedValue(rotatedKey);
193
+ const response = await app.inject({
194
+ method: "POST",
195
+ url: "/api/v1/api-keys/key-uuid-1/rotate",
196
+ headers: (0, test_helpers_js_1.authHeaders)(),
197
+ payload: { name: "New Name" },
198
+ });
199
+ (0, vitest_1.expect)(response.statusCode).toBe(201);
200
+ (0, vitest_1.expect)(response.json().name).toBe("New Name");
201
+ (0, vitest_1.expect)(stratum.rotateApiKey).toHaveBeenCalledWith("key-uuid-1", "New Name");
202
+ });
203
+ });
204
+ // ── Authorization ───────────────────────────────────────────────────
205
+ (0, vitest_1.describe)("Authorization", () => {
206
+ (0, vitest_1.it)("api-keys routes require admin scope", async () => {
207
+ (0, test_helpers_js_1.setupWriteApiKey)(stratum);
208
+ const getResponse = await app.inject({
209
+ method: "GET",
210
+ url: "/api/v1/api-keys",
211
+ headers: (0, test_helpers_js_1.authHeaders)(),
212
+ });
213
+ (0, vitest_1.expect)(getResponse.statusCode).toBe(403);
214
+ const postResponse = await app.inject({
215
+ method: "POST",
216
+ url: "/api/v1/api-keys",
217
+ headers: (0, test_helpers_js_1.authHeaders)(),
218
+ payload: { tenant_id: "t-uuid-1" },
219
+ });
220
+ (0, vitest_1.expect)(postResponse.statusCode).toBe(403);
221
+ });
222
+ (0, vitest_1.it)("read-only key cannot access api-keys routes", async () => {
223
+ (0, test_helpers_js_1.setupReadOnlyApiKey)(stratum);
224
+ const response = await app.inject({
225
+ method: "GET",
226
+ url: "/api/v1/api-keys",
227
+ headers: (0, test_helpers_js_1.authHeaders)(),
228
+ });
229
+ (0, vitest_1.expect)(response.statusCode).toBe(403);
230
+ });
231
+ (0, vitest_1.it)("returns 401 without authentication", async () => {
232
+ const response = await app.inject({
233
+ method: "GET",
234
+ url: "/api/v1/api-keys",
235
+ });
236
+ (0, vitest_1.expect)(response.statusCode).toBe(401);
237
+ });
238
+ });
239
+ });
240
+ //# sourceMappingURL=api-keys.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-keys.test.js","sourceRoot":"","sources":["../../src/__tests__/api-keys.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=auth.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/auth.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,227 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const vitest_1 = require("vitest");
7
+ const jsonwebtoken_1 = __importDefault(require("jsonwebtoken"));
8
+ const test_helpers_js_1 = require("./test-helpers.js");
9
+ (0, vitest_1.describe)("Auth Middleware", () => {
10
+ let app;
11
+ let stratum;
12
+ (0, vitest_1.beforeEach)(async () => {
13
+ stratum = (0, test_helpers_js_1.createMockStratum)();
14
+ app = await (0, test_helpers_js_1.buildTestApp)(stratum);
15
+ });
16
+ (0, vitest_1.afterEach)(async () => {
17
+ await app.close();
18
+ });
19
+ // ── API Key Authentication ──────────────────────────────────────────
20
+ (0, vitest_1.describe)("API Key Authentication", () => {
21
+ (0, vitest_1.it)("valid API key authenticates successfully", async () => {
22
+ (0, test_helpers_js_1.setupAdminApiKey)(stratum);
23
+ stratum.getTenant.mockResolvedValue(test_helpers_js_1.SAMPLE_TENANT);
24
+ const response = await app.inject({
25
+ method: "GET",
26
+ url: `/api/v1/tenants/${test_helpers_js_1.SAMPLE_TENANT.id}`,
27
+ headers: (0, test_helpers_js_1.authHeaders)(),
28
+ });
29
+ (0, vitest_1.expect)(response.statusCode).toBe(200);
30
+ (0, vitest_1.expect)(stratum.validateApiKey).toHaveBeenCalledWith("sk_test_valid_key");
31
+ });
32
+ (0, vitest_1.it)("invalid API key returns 401", async () => {
33
+ stratum.validateApiKey.mockResolvedValue(null);
34
+ const response = await app.inject({
35
+ method: "GET",
36
+ url: `/api/v1/tenants/${test_helpers_js_1.SAMPLE_TENANT.id}`,
37
+ headers: { "x-api-key": "sk_test_bad_key" },
38
+ });
39
+ (0, vitest_1.expect)(response.statusCode).toBe(401);
40
+ const body = response.json();
41
+ (0, vitest_1.expect)(body.error.code).toBe("UNAUTHORIZED");
42
+ (0, vitest_1.expect)(body.error.message).toContain("Invalid or revoked");
43
+ });
44
+ (0, vitest_1.it)("expired API key returns 401 (validateApiKey returns null)", async () => {
45
+ // An expired key causes validateApiKey to return null
46
+ stratum.validateApiKey.mockResolvedValue(null);
47
+ const response = await app.inject({
48
+ method: "GET",
49
+ url: `/api/v1/tenants/${test_helpers_js_1.SAMPLE_TENANT.id}`,
50
+ headers: { "x-api-key": "sk_test_expired_key" },
51
+ });
52
+ (0, vitest_1.expect)(response.statusCode).toBe(401);
53
+ });
54
+ });
55
+ // ── JWT Authentication ──────────────────────────────────────────────
56
+ (0, vitest_1.describe)("JWT Authentication", () => {
57
+ (0, vitest_1.it)("valid JWT authenticates successfully", async () => {
58
+ stratum.getTenant.mockResolvedValue(test_helpers_js_1.SAMPLE_TENANT);
59
+ const response = await app.inject({
60
+ method: "GET",
61
+ url: `/api/v1/tenants/${test_helpers_js_1.SAMPLE_TENANT.id}`,
62
+ headers: (0, test_helpers_js_1.jwtHeaders)({ scopes: ["read", "write", "admin"] }),
63
+ });
64
+ (0, vitest_1.expect)(response.statusCode).toBe(200);
65
+ // validateApiKey should NOT be called for JWT auth
66
+ (0, vitest_1.expect)(stratum.validateApiKey).not.toHaveBeenCalled();
67
+ });
68
+ (0, vitest_1.it)("invalid JWT returns 401", async () => {
69
+ const response = await app.inject({
70
+ method: "GET",
71
+ url: `/api/v1/tenants/${test_helpers_js_1.SAMPLE_TENANT.id}`,
72
+ headers: { authorization: "Bearer invalid.token.here" },
73
+ });
74
+ (0, vitest_1.expect)(response.statusCode).toBe(401);
75
+ const body = response.json();
76
+ (0, vitest_1.expect)(body.error.code).toBe("UNAUTHORIZED");
77
+ (0, vitest_1.expect)(body.error.message).toContain("Invalid or expired");
78
+ });
79
+ (0, vitest_1.it)("expired JWT returns 401", async () => {
80
+ const expiredToken = jsonwebtoken_1.default.sign({ sub: "test-user", scopes: ["read"] }, test_helpers_js_1.TEST_JWT_SECRET, { algorithm: "HS256", expiresIn: "-1h" });
81
+ const response = await app.inject({
82
+ method: "GET",
83
+ url: `/api/v1/tenants/${test_helpers_js_1.SAMPLE_TENANT.id}`,
84
+ headers: { authorization: `Bearer ${expiredToken}` },
85
+ });
86
+ (0, vitest_1.expect)(response.statusCode).toBe(401);
87
+ });
88
+ (0, vitest_1.it)("JWT signed with wrong secret returns 401", async () => {
89
+ const response = await app.inject({
90
+ method: "GET",
91
+ url: `/api/v1/tenants/${test_helpers_js_1.SAMPLE_TENANT.id}`,
92
+ headers: (0, test_helpers_js_1.jwtHeaders)({}, "wrong-secret-key"),
93
+ });
94
+ (0, vitest_1.expect)(response.statusCode).toBe(401);
95
+ });
96
+ });
97
+ // ── No Auth ─────────────────────────────────────────────────────────
98
+ (0, vitest_1.describe)("No Auth", () => {
99
+ (0, vitest_1.it)("returns 401 when no auth header is provided", async () => {
100
+ const response = await app.inject({
101
+ method: "GET",
102
+ url: `/api/v1/tenants/${test_helpers_js_1.SAMPLE_TENANT.id}`,
103
+ });
104
+ (0, vitest_1.expect)(response.statusCode).toBe(401);
105
+ const body = response.json();
106
+ (0, vitest_1.expect)(body.error.code).toBe("UNAUTHORIZED");
107
+ (0, vitest_1.expect)(body.error.message).toContain("Authentication required");
108
+ });
109
+ });
110
+ // ── Exempt endpoints ────────────────────────────────────────────────
111
+ (0, vitest_1.describe)("Exempt endpoints", () => {
112
+ (0, vitest_1.it)("health endpoint skips auth", async () => {
113
+ const response = await app.inject({
114
+ method: "GET",
115
+ url: "/api/v1/health",
116
+ });
117
+ // Health endpoint tries to query the DB, which will fail in test,
118
+ // but it should NOT return 401
119
+ (0, vitest_1.expect)(response.statusCode).not.toBe(401);
120
+ // The response should be 200 (health route handles db errors gracefully)
121
+ (0, vitest_1.expect)(response.statusCode).toBe(200);
122
+ const body = response.json();
123
+ (0, vitest_1.expect)(body.status).toBe("ok");
124
+ });
125
+ (0, vitest_1.it)("swagger docs endpoint skips auth", async () => {
126
+ // We don't register swagger in tests, so the route won't exist,
127
+ // but the auth middleware should NOT fire for /api/docs paths.
128
+ // We can verify by testing that a 404 is returned (not a 401).
129
+ const response = await app.inject({
130
+ method: "GET",
131
+ url: "/api/docs/json",
132
+ });
133
+ // Should be 404 (not registered in test app) rather than 401
134
+ (0, vitest_1.expect)(response.statusCode).not.toBe(401);
135
+ });
136
+ });
137
+ // ── Authorization scope enforcement ─────────────────────────────────
138
+ (0, vitest_1.describe)("Scope enforcement", () => {
139
+ (0, vitest_1.it)("read-scope key cannot access write endpoints", async () => {
140
+ (0, test_helpers_js_1.setupReadOnlyApiKey)(stratum);
141
+ const response = await app.inject({
142
+ method: "POST",
143
+ url: "/api/v1/tenants",
144
+ headers: (0, test_helpers_js_1.authHeaders)(),
145
+ payload: { slug: "test", name: "Test" },
146
+ });
147
+ (0, vitest_1.expect)(response.statusCode).toBe(403);
148
+ (0, vitest_1.expect)(response.json().error.code).toBe("FORBIDDEN");
149
+ });
150
+ (0, vitest_1.it)("read-scope key cannot DELETE", async () => {
151
+ (0, test_helpers_js_1.setupReadOnlyApiKey)(stratum);
152
+ const response = await app.inject({
153
+ method: "DELETE",
154
+ url: `/api/v1/tenants/${test_helpers_js_1.SAMPLE_TENANT.id}`,
155
+ headers: (0, test_helpers_js_1.authHeaders)(),
156
+ });
157
+ (0, vitest_1.expect)(response.statusCode).toBe(403);
158
+ });
159
+ (0, vitest_1.it)("read-scope key cannot PATCH", async () => {
160
+ (0, test_helpers_js_1.setupReadOnlyApiKey)(stratum);
161
+ const response = await app.inject({
162
+ method: "PATCH",
163
+ url: `/api/v1/tenants/${test_helpers_js_1.SAMPLE_TENANT.id}`,
164
+ headers: (0, test_helpers_js_1.authHeaders)(),
165
+ payload: { name: "Updated" },
166
+ });
167
+ (0, vitest_1.expect)(response.statusCode).toBe(403);
168
+ });
169
+ (0, vitest_1.it)("admin-scope key can access all endpoints", async () => {
170
+ (0, test_helpers_js_1.setupAdminApiKey)(stratum);
171
+ stratum.createTenant.mockResolvedValue(test_helpers_js_1.SAMPLE_TENANT);
172
+ stratum.getTenant.mockResolvedValue(test_helpers_js_1.SAMPLE_TENANT);
173
+ stratum.listApiKeys.mockResolvedValue([]);
174
+ // Test write endpoint
175
+ const postResponse = await app.inject({
176
+ method: "POST",
177
+ url: "/api/v1/tenants",
178
+ headers: (0, test_helpers_js_1.authHeaders)(),
179
+ payload: { slug: "test", name: "Test" },
180
+ });
181
+ (0, vitest_1.expect)(postResponse.statusCode).toBe(201);
182
+ // Test read endpoint
183
+ const getResponse = await app.inject({
184
+ method: "GET",
185
+ url: `/api/v1/tenants/${test_helpers_js_1.SAMPLE_TENANT.id}`,
186
+ headers: (0, test_helpers_js_1.authHeaders)(),
187
+ });
188
+ (0, vitest_1.expect)(getResponse.statusCode).toBe(200);
189
+ // Test admin-only endpoint (api-keys)
190
+ const adminResponse = await app.inject({
191
+ method: "GET",
192
+ url: "/api/v1/api-keys",
193
+ headers: (0, test_helpers_js_1.authHeaders)(),
194
+ });
195
+ (0, vitest_1.expect)(adminResponse.statusCode).toBe(200);
196
+ });
197
+ (0, vitest_1.it)("write-scope key cannot access admin-only endpoints (api-keys)", async () => {
198
+ (0, test_helpers_js_1.setupWriteApiKey)(stratum);
199
+ const response = await app.inject({
200
+ method: "GET",
201
+ url: "/api/v1/api-keys",
202
+ headers: (0, test_helpers_js_1.authHeaders)(),
203
+ });
204
+ (0, vitest_1.expect)(response.statusCode).toBe(403);
205
+ (0, vitest_1.expect)(response.json().error.code).toBe("FORBIDDEN");
206
+ });
207
+ (0, vitest_1.it)("JWT with read-only scopes cannot POST", async () => {
208
+ const response = await app.inject({
209
+ method: "POST",
210
+ url: "/api/v1/tenants",
211
+ headers: (0, test_helpers_js_1.jwtHeaders)({ scopes: ["read"] }),
212
+ payload: { slug: "test", name: "Test" },
213
+ });
214
+ (0, vitest_1.expect)(response.statusCode).toBe(403);
215
+ });
216
+ (0, vitest_1.it)("JWT with admin scopes can access admin-only endpoints", async () => {
217
+ stratum.listApiKeys.mockResolvedValue([]);
218
+ const response = await app.inject({
219
+ method: "GET",
220
+ url: "/api/v1/api-keys",
221
+ headers: (0, test_helpers_js_1.jwtHeaders)({ scopes: ["read", "write", "admin"] }),
222
+ });
223
+ (0, vitest_1.expect)(response.statusCode).toBe(200);
224
+ });
225
+ });
226
+ });
227
+ //# sourceMappingURL=auth.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.test.js","sourceRoot":"","sources":["../../src/__tests__/auth.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=config.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/config.test.ts"],"names":[],"mappings":""}