@stratum-hq/lib 0.5.1 → 0.7.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 (54) hide show
  1. package/dist/__tests__/webhook-signature.test.d.ts +2 -0
  2. package/dist/__tests__/webhook-signature.test.d.ts.map +1 -0
  3. package/dist/__tests__/webhook-signature.test.js +103 -0
  4. package/dist/__tests__/webhook-signature.test.js.map +1 -0
  5. package/dist/index.d.ts +1 -0
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +5 -1
  8. package/dist/index.js.map +1 -1
  9. package/dist/migrations/019_rls_policies.sql +236 -0
  10. package/dist/pool-helpers.d.ts.map +1 -1
  11. package/dist/pool-helpers.js +31 -1
  12. package/dist/pool-helpers.js.map +1 -1
  13. package/dist/services/__tests__/api-key-service.test.d.ts +2 -0
  14. package/dist/services/__tests__/api-key-service.test.d.ts.map +1 -0
  15. package/dist/services/__tests__/api-key-service.test.js +76 -0
  16. package/dist/services/__tests__/api-key-service.test.js.map +1 -0
  17. package/dist/services/__tests__/event-service.test.js +32 -0
  18. package/dist/services/__tests__/event-service.test.js.map +1 -1
  19. package/dist/services/__tests__/key-rotation-service.test.d.ts +2 -0
  20. package/dist/services/__tests__/key-rotation-service.test.d.ts.map +1 -0
  21. package/dist/services/__tests__/key-rotation-service.test.js +132 -0
  22. package/dist/services/__tests__/key-rotation-service.test.js.map +1 -0
  23. package/dist/services/__tests__/tenant-service.test.js +34 -0
  24. package/dist/services/__tests__/tenant-service.test.js.map +1 -1
  25. package/dist/services/abac-service.d.ts.map +1 -1
  26. package/dist/services/abac-service.js +7 -3
  27. package/dist/services/abac-service.js.map +1 -1
  28. package/dist/services/api-key-service.d.ts +14 -0
  29. package/dist/services/api-key-service.d.ts.map +1 -1
  30. package/dist/services/api-key-service.js +13 -0
  31. package/dist/services/api-key-service.js.map +1 -1
  32. package/dist/services/event-service.d.ts.map +1 -1
  33. package/dist/services/event-service.js +34 -22
  34. package/dist/services/event-service.js.map +1 -1
  35. package/dist/services/key-rotation-service.d.ts +3 -2
  36. package/dist/services/key-rotation-service.d.ts.map +1 -1
  37. package/dist/services/key-rotation-service.js +17 -7
  38. package/dist/services/key-rotation-service.js.map +1 -1
  39. package/dist/services/permission-service.d.ts.map +1 -1
  40. package/dist/services/permission-service.js +7 -4
  41. package/dist/services/permission-service.js.map +1 -1
  42. package/dist/services/tenant-service.d.ts +21 -1
  43. package/dist/services/tenant-service.d.ts.map +1 -1
  44. package/dist/services/tenant-service.js +24 -3
  45. package/dist/services/tenant-service.js.map +1 -1
  46. package/dist/stratum.d.ts +15 -1
  47. package/dist/stratum.d.ts.map +1 -1
  48. package/dist/stratum.js +12 -4
  49. package/dist/stratum.js.map +1 -1
  50. package/dist/webhook-signature.d.ts +36 -0
  51. package/dist/webhook-signature.d.ts.map +1 -0
  52. package/dist/webhook-signature.js +55 -0
  53. package/dist/webhook-signature.js.map +1 -0
  54. package/package.json +3 -2
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=webhook-signature.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webhook-signature.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/webhook-signature.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,103 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const vitest_1 = require("vitest");
4
+ const webhook_signature_js_1 = require("../webhook-signature.js");
5
+ const SECRET = "whsec_test_secret";
6
+ const PAYLOAD = JSON.stringify({ id: "evt_1", type: "tenant.created" });
7
+ (0, vitest_1.describe)("signWebhookPayload", () => {
8
+ (0, vitest_1.it)("binds the timestamp into the signature", () => {
9
+ const t1 = "2026-07-24T00:00:00.000Z";
10
+ const t2 = "2026-07-24T00:00:01.000Z";
11
+ (0, vitest_1.expect)((0, webhook_signature_js_1.signWebhookPayload)(SECRET, t1, PAYLOAD)).not.toBe((0, webhook_signature_js_1.signWebhookPayload)(SECRET, t2, PAYLOAD));
12
+ });
13
+ (0, vitest_1.it)("produces a sha256= prefixed hex digest", () => {
14
+ const sig = (0, webhook_signature_js_1.signWebhookPayload)(SECRET, "2026-07-24T00:00:00.000Z", PAYLOAD);
15
+ (0, vitest_1.expect)(sig).toMatch(/^sha256=[0-9a-f]{64}$/);
16
+ });
17
+ });
18
+ (0, vitest_1.describe)("verifyWebhookSignature", () => {
19
+ const now = Date.parse("2026-07-24T12:00:00.000Z");
20
+ const timestamp = "2026-07-24T12:00:00.000Z";
21
+ const signature = (0, webhook_signature_js_1.signWebhookPayload)(SECRET, timestamp, PAYLOAD);
22
+ (0, vitest_1.it)("accepts a fresh, correctly signed delivery", () => {
23
+ (0, vitest_1.expect)((0, webhook_signature_js_1.verifyWebhookSignature)({ secret: SECRET, payload: PAYLOAD, signature, timestamp, now })).toBe(true);
24
+ });
25
+ (0, vitest_1.it)("rejects a tampered payload", () => {
26
+ (0, vitest_1.expect)((0, webhook_signature_js_1.verifyWebhookSignature)({
27
+ secret: SECRET,
28
+ payload: PAYLOAD + "x",
29
+ signature,
30
+ timestamp,
31
+ now,
32
+ })).toBe(false);
33
+ });
34
+ (0, vitest_1.it)("rejects a wrong secret", () => {
35
+ (0, vitest_1.expect)((0, webhook_signature_js_1.verifyWebhookSignature)({
36
+ secret: "whsec_wrong",
37
+ payload: PAYLOAD,
38
+ signature,
39
+ timestamp,
40
+ now,
41
+ })).toBe(false);
42
+ });
43
+ (0, vitest_1.it)("rejects a replayed delivery once it ages past the window", () => {
44
+ const stale = now + (webhook_signature_js_1.DEFAULT_WEBHOOK_TOLERANCE_SECONDS + 1) * 1000;
45
+ (0, vitest_1.expect)((0, webhook_signature_js_1.verifyWebhookSignature)({
46
+ secret: SECRET,
47
+ payload: PAYLOAD,
48
+ signature,
49
+ timestamp,
50
+ now: stale,
51
+ })).toBe(false);
52
+ });
53
+ (0, vitest_1.it)("rejects a timestamp too far in the future", () => {
54
+ const future = now - (webhook_signature_js_1.DEFAULT_WEBHOOK_TOLERANCE_SECONDS + 1) * 1000;
55
+ (0, vitest_1.expect)((0, webhook_signature_js_1.verifyWebhookSignature)({
56
+ secret: SECRET,
57
+ payload: PAYLOAD,
58
+ signature,
59
+ timestamp,
60
+ now: future,
61
+ })).toBe(false);
62
+ });
63
+ (0, vitest_1.it)("accepts a delivery at the edge of the window", () => {
64
+ const edge = now + webhook_signature_js_1.DEFAULT_WEBHOOK_TOLERANCE_SECONDS * 1000;
65
+ (0, vitest_1.expect)((0, webhook_signature_js_1.verifyWebhookSignature)({
66
+ secret: SECRET,
67
+ payload: PAYLOAD,
68
+ signature,
69
+ timestamp,
70
+ now: edge,
71
+ })).toBe(true);
72
+ });
73
+ (0, vitest_1.it)("respects a custom tolerance", () => {
74
+ const drift = now + 10_000; // 10s later
75
+ (0, vitest_1.expect)((0, webhook_signature_js_1.verifyWebhookSignature)({
76
+ secret: SECRET,
77
+ payload: PAYLOAD,
78
+ signature,
79
+ timestamp,
80
+ toleranceSeconds: 5,
81
+ now: drift,
82
+ })).toBe(false);
83
+ });
84
+ (0, vitest_1.it)("fails closed on a malformed timestamp", () => {
85
+ (0, vitest_1.expect)((0, webhook_signature_js_1.verifyWebhookSignature)({
86
+ secret: SECRET,
87
+ payload: PAYLOAD,
88
+ signature,
89
+ timestamp: "not-a-date",
90
+ now,
91
+ })).toBe(false);
92
+ });
93
+ (0, vitest_1.it)("rejects a malformed signature without throwing", () => {
94
+ (0, vitest_1.expect)((0, webhook_signature_js_1.verifyWebhookSignature)({
95
+ secret: SECRET,
96
+ payload: PAYLOAD,
97
+ signature: "sha256=deadbeef",
98
+ timestamp,
99
+ now,
100
+ })).toBe(false);
101
+ });
102
+ });
103
+ //# sourceMappingURL=webhook-signature.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webhook-signature.test.js","sourceRoot":"","sources":["../../src/__tests__/webhook-signature.test.ts"],"names":[],"mappings":";;AAAA,mCAA8C;AAC9C,kEAIiC;AAEjC,MAAM,MAAM,GAAG,mBAAmB,CAAC;AACnC,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,gBAAgB,EAAE,CAAC,CAAC;AAExE,IAAA,iBAAQ,EAAC,oBAAoB,EAAE,GAAG,EAAE;IAClC,IAAA,WAAE,EAAC,wCAAwC,EAAE,GAAG,EAAE;QAChD,MAAM,EAAE,GAAG,0BAA0B,CAAC;QACtC,MAAM,EAAE,GAAG,0BAA0B,CAAC;QACtC,IAAA,eAAM,EAAC,IAAA,yCAAkB,EAAC,MAAM,EAAE,EAAE,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CACtD,IAAA,yCAAkB,EAAC,MAAM,EAAE,EAAE,EAAE,OAAO,CAAC,CACxC,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,IAAA,WAAE,EAAC,wCAAwC,EAAE,GAAG,EAAE;QAChD,MAAM,GAAG,GAAG,IAAA,yCAAkB,EAAC,MAAM,EAAE,0BAA0B,EAAE,OAAO,CAAC,CAAC;QAC5E,IAAA,eAAM,EAAC,GAAG,CAAC,CAAC,OAAO,CAAC,uBAAuB,CAAC,CAAC;IAC/C,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,IAAA,iBAAQ,EAAC,wBAAwB,EAAE,GAAG,EAAE;IACtC,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,0BAA0B,CAAC,CAAC;IACnD,MAAM,SAAS,GAAG,0BAA0B,CAAC;IAC7C,MAAM,SAAS,GAAG,IAAA,yCAAkB,EAAC,MAAM,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC;IAEjE,IAAA,WAAE,EAAC,4CAA4C,EAAE,GAAG,EAAE;QACpD,IAAA,eAAM,EACJ,IAAA,6CAAsB,EAAC,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC,CACxF,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACf,CAAC,CAAC,CAAC;IAEH,IAAA,WAAE,EAAC,4BAA4B,EAAE,GAAG,EAAE;QACpC,IAAA,eAAM,EACJ,IAAA,6CAAsB,EAAC;YACrB,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,OAAO,GAAG,GAAG;YACtB,SAAS;YACT,SAAS;YACT,GAAG;SACJ,CAAC,CACH,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAChB,CAAC,CAAC,CAAC;IAEH,IAAA,WAAE,EAAC,wBAAwB,EAAE,GAAG,EAAE;QAChC,IAAA,eAAM,EACJ,IAAA,6CAAsB,EAAC;YACrB,MAAM,EAAE,aAAa;YACrB,OAAO,EAAE,OAAO;YAChB,SAAS;YACT,SAAS;YACT,GAAG;SACJ,CAAC,CACH,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAChB,CAAC,CAAC,CAAC;IAEH,IAAA,WAAE,EAAC,0DAA0D,EAAE,GAAG,EAAE;QAClE,MAAM,KAAK,GAAG,GAAG,GAAG,CAAC,wDAAiC,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC;QACnE,IAAA,eAAM,EACJ,IAAA,6CAAsB,EAAC;YACrB,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,OAAO;YAChB,SAAS;YACT,SAAS;YACT,GAAG,EAAE,KAAK;SACX,CAAC,CACH,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAChB,CAAC,CAAC,CAAC;IAEH,IAAA,WAAE,EAAC,2CAA2C,EAAE,GAAG,EAAE;QACnD,MAAM,MAAM,GAAG,GAAG,GAAG,CAAC,wDAAiC,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC;QACpE,IAAA,eAAM,EACJ,IAAA,6CAAsB,EAAC;YACrB,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,OAAO;YAChB,SAAS;YACT,SAAS;YACT,GAAG,EAAE,MAAM;SACZ,CAAC,CACH,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAChB,CAAC,CAAC,CAAC;IAEH,IAAA,WAAE,EAAC,8CAA8C,EAAE,GAAG,EAAE;QACtD,MAAM,IAAI,GAAG,GAAG,GAAG,wDAAiC,GAAG,IAAI,CAAC;QAC5D,IAAA,eAAM,EACJ,IAAA,6CAAsB,EAAC;YACrB,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,OAAO;YAChB,SAAS;YACT,SAAS;YACT,GAAG,EAAE,IAAI;SACV,CAAC,CACH,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACf,CAAC,CAAC,CAAC;IAEH,IAAA,WAAE,EAAC,6BAA6B,EAAE,GAAG,EAAE;QACrC,MAAM,KAAK,GAAG,GAAG,GAAG,MAAM,CAAC,CAAC,YAAY;QACxC,IAAA,eAAM,EACJ,IAAA,6CAAsB,EAAC;YACrB,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,OAAO;YAChB,SAAS;YACT,SAAS;YACT,gBAAgB,EAAE,CAAC;YACnB,GAAG,EAAE,KAAK;SACX,CAAC,CACH,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAChB,CAAC,CAAC,CAAC;IAEH,IAAA,WAAE,EAAC,uCAAuC,EAAE,GAAG,EAAE;QAC/C,IAAA,eAAM,EACJ,IAAA,6CAAsB,EAAC;YACrB,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,OAAO;YAChB,SAAS;YACT,SAAS,EAAE,YAAY;YACvB,GAAG;SACJ,CAAC,CACH,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAChB,CAAC,CAAC,CAAC;IAEH,IAAA,WAAE,EAAC,gDAAgD,EAAE,GAAG,EAAE;QACxD,IAAA,eAAM,EACJ,IAAA,6CAAsB,EAAC;YACrB,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,OAAO;YAChB,SAAS,EAAE,iBAAiB;YAC5B,SAAS;YACT,GAAG;SACJ,CAAC,CACH,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAChB,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
package/dist/index.d.ts CHANGED
@@ -2,6 +2,7 @@ export { Stratum, type StratumOptions } from "./stratum.js";
2
2
  export { migrate, type MigrateOptions } from "./migrate.js";
3
3
  export { migrateAllSchemas, type MigrateSchemasOptions, type MigrateSchemasResult, } from "./migrate-schemas.js";
4
4
  export { withClient, withTransaction } from "./pool-helpers.js";
5
+ export { verifyWebhookSignature, signWebhookPayload, DEFAULT_WEBHOOK_TOLERANCE_SECONDS, type VerifyWebhookOptions, } from "./webhook-signature.js";
5
6
  export { traced, getTracer, isTracingEnabled } from "./telemetry.js";
6
7
  export type { TenantNode, TenantContext, CreateTenantInput, UpdateTenantInput, MoveTenantInput, PaginationInput, PaginatedResult, ConfigEntry, SetConfigInput, ResolvedConfigEntry, ResolvedConfig, PermissionPolicy, CreatePermissionInput, UpdatePermissionInput, ResolvedPermission, } from "@stratum-hq/core";
7
8
  export type { ApiKeyRecord, CreatedApiKey, ValidatedApiKey, CreateApiKeyOptions } from "./services/api-key-service.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,cAAc,CAAC;AAC5D,OAAO,EAAE,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,cAAc,CAAC;AAC5D,OAAO,EACL,iBAAiB,EACjB,KAAK,qBAAqB,EAC1B,KAAK,oBAAoB,GAC1B,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAChE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAGrE,YAAY,EACV,UAAU,EACV,aAAa,EACb,iBAAiB,EACjB,iBAAiB,EACjB,eAAe,EACf,eAAe,EACf,eAAe,EACf,WAAW,EACX,cAAc,EACd,mBAAmB,EACnB,cAAc,EACd,gBAAgB,EAChB,qBAAqB,EACrB,qBAAqB,EACrB,kBAAkB,GACnB,MAAM,kBAAkB,CAAC;AAE1B,YAAY,EAAE,YAAY,EAAE,aAAa,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,+BAA+B,CAAC;AACvH,YAAY,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AACtE,YAAY,EAAE,iBAAiB,EAAE,MAAM,oCAAoC,CAAC;AAC5E,YAAY,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AACjE,YAAY,EAAE,IAAI,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAGzF,YAAY,EAAE,YAAY,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEhF,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACxD,YAAY,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,cAAc,CAAC;AAC5D,OAAO,EAAE,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,cAAc,CAAC;AAC5D,OAAO,EACL,iBAAiB,EACjB,KAAK,qBAAqB,EAC1B,KAAK,oBAAoB,GAC1B,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAChE,OAAO,EACL,sBAAsB,EACtB,kBAAkB,EAClB,iCAAiC,EACjC,KAAK,oBAAoB,GAC1B,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAGrE,YAAY,EACV,UAAU,EACV,aAAa,EACb,iBAAiB,EACjB,iBAAiB,EACjB,eAAe,EACf,eAAe,EACf,eAAe,EACf,WAAW,EACX,cAAc,EACd,mBAAmB,EACnB,cAAc,EACd,gBAAgB,EAChB,qBAAqB,EACrB,qBAAqB,EACrB,kBAAkB,GACnB,MAAM,kBAAkB,CAAC;AAE1B,YAAY,EAAE,YAAY,EAAE,aAAa,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,+BAA+B,CAAC;AACvH,YAAY,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AACtE,YAAY,EAAE,iBAAiB,EAAE,MAAM,oCAAoC,CAAC;AAC5E,YAAY,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AACjE,YAAY,EAAE,IAAI,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAGzF,YAAY,EAAE,YAAY,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEhF,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACxD,YAAY,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC"}
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.noopLogger = exports.defaultLogger = exports.isTracingEnabled = exports.getTracer = exports.traced = exports.withTransaction = exports.withClient = exports.migrateAllSchemas = exports.migrate = exports.Stratum = void 0;
3
+ exports.noopLogger = exports.defaultLogger = exports.isTracingEnabled = exports.getTracer = exports.traced = exports.DEFAULT_WEBHOOK_TOLERANCE_SECONDS = exports.signWebhookPayload = exports.verifyWebhookSignature = exports.withTransaction = exports.withClient = exports.migrateAllSchemas = exports.migrate = exports.Stratum = void 0;
4
4
  var stratum_js_1 = require("./stratum.js");
5
5
  Object.defineProperty(exports, "Stratum", { enumerable: true, get: function () { return stratum_js_1.Stratum; } });
6
6
  var migrate_js_1 = require("./migrate.js");
@@ -10,6 +10,10 @@ Object.defineProperty(exports, "migrateAllSchemas", { enumerable: true, get: fun
10
10
  var pool_helpers_js_1 = require("./pool-helpers.js");
11
11
  Object.defineProperty(exports, "withClient", { enumerable: true, get: function () { return pool_helpers_js_1.withClient; } });
12
12
  Object.defineProperty(exports, "withTransaction", { enumerable: true, get: function () { return pool_helpers_js_1.withTransaction; } });
13
+ var webhook_signature_js_1 = require("./webhook-signature.js");
14
+ Object.defineProperty(exports, "verifyWebhookSignature", { enumerable: true, get: function () { return webhook_signature_js_1.verifyWebhookSignature; } });
15
+ Object.defineProperty(exports, "signWebhookPayload", { enumerable: true, get: function () { return webhook_signature_js_1.signWebhookPayload; } });
16
+ Object.defineProperty(exports, "DEFAULT_WEBHOOK_TOLERANCE_SECONDS", { enumerable: true, get: function () { return webhook_signature_js_1.DEFAULT_WEBHOOK_TOLERANCE_SECONDS; } });
13
17
  var telemetry_js_1 = require("./telemetry.js");
14
18
  Object.defineProperty(exports, "traced", { enumerable: true, get: function () { return telemetry_js_1.traced; } });
15
19
  Object.defineProperty(exports, "getTracer", { enumerable: true, get: function () { return telemetry_js_1.getTracer; } });
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,2CAA4D;AAAnD,qGAAA,OAAO,OAAA;AAChB,2CAA4D;AAAnD,qGAAA,OAAO,OAAA;AAChB,2DAI8B;AAH5B,uHAAA,iBAAiB,OAAA;AAInB,qDAAgE;AAAvD,6GAAA,UAAU,OAAA;AAAE,kHAAA,eAAe,OAAA;AACpC,+CAAqE;AAA5D,sGAAA,MAAM,OAAA;AAAE,yGAAA,SAAS,OAAA;AAAE,gHAAA,gBAAgB,OAAA;AA8B5C,yCAAwD;AAA/C,0GAAA,aAAa,OAAA;AAAE,uGAAA,UAAU,OAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,2CAA4D;AAAnD,qGAAA,OAAO,OAAA;AAChB,2CAA4D;AAAnD,qGAAA,OAAO,OAAA;AAChB,2DAI8B;AAH5B,uHAAA,iBAAiB,OAAA;AAInB,qDAAgE;AAAvD,6GAAA,UAAU,OAAA;AAAE,kHAAA,eAAe,OAAA;AACpC,+DAKgC;AAJ9B,8HAAA,sBAAsB,OAAA;AACtB,0HAAA,kBAAkB,OAAA;AAClB,yIAAA,iCAAiC,OAAA;AAGnC,+CAAqE;AAA5D,sGAAA,MAAM,OAAA;AAAE,yGAAA,SAAS,OAAA;AAAE,gHAAA,gBAAgB,OAAA;AA8B5C,yCAAwD;AAA/C,0GAAA,aAAa,OAAA;AAAE,uGAAA,UAAU,OAAA"}
@@ -0,0 +1,236 @@
1
+ -- Migration 019: Real Postgres row-level security for the SHARED_RLS strategy.
2
+ --
3
+ -- Backs the `isolation_strategy = 'SHARED_RLS'` literal (001_init.sql) with
4
+ -- database-enforced tenant isolation. This is a SECOND, independent layer; the
5
+ -- application control-plane authorization stays the primary enforcement. See
6
+ -- docs/adr/0001-postgres-rls-defense-in-depth.md for the full design.
7
+ --
8
+ -- Context model:
9
+ -- * Tenant context: SET LOCAL app.current_tenant_id (transaction scoped).
10
+ -- * System bypass: SET LOCAL app.bypass_rls = 'on' (control-plane path).
11
+ -- Both are set with set_config(..., true) / SET LOCAL so they cannot leak
12
+ -- across pooled connections.
13
+ --
14
+ -- Every policy is fail closed: with no context set,
15
+ -- NULLIF(current_setting('app.current_tenant_id', true), '')::uuid -> NULL,
16
+ -- so the scope predicate is NULL (not true) and zero rows are visible; a write
17
+ -- with no context is rejected. current_setting(name, true) returns NULL instead
18
+ -- of raising when the GUC is unset.
19
+ --
20
+ -- ENABLE + FORCE: FORCE applies the policy to the table owner too. Note that a
21
+ -- Postgres SUPERUSER or a role with BYPASSRLS always skips RLS regardless of
22
+ -- FORCE; the application role must be neither (see docker/init-db.sql:
23
+ -- stratum_app is NOSUPERUSER NOBYPASSRLS).
24
+ --
25
+ -- DROP POLICY IF EXISTS before CREATE makes the migration safe to re-run.
26
+
27
+ -- Reusable predicate (documented once; inlined per policy below because Postgres
28
+ -- policies cannot reference a shared expression):
29
+ -- current_setting('app.bypass_rls', true) = 'on'
30
+ -- OR tenant_id = NULLIF(current_setting('app.current_tenant_id', true), '')::uuid
31
+
32
+ -- ---------------------------------------------------------------------------
33
+ -- Direct tenant_id tables: exact-tenant scope.
34
+ -- ---------------------------------------------------------------------------
35
+
36
+ -- config_entries
37
+ ALTER TABLE config_entries ENABLE ROW LEVEL SECURITY;
38
+ ALTER TABLE config_entries FORCE ROW LEVEL SECURITY;
39
+ DROP POLICY IF EXISTS tenant_isolation ON config_entries;
40
+ CREATE POLICY tenant_isolation ON config_entries FOR ALL
41
+ USING (
42
+ current_setting('app.bypass_rls', true) = 'on'
43
+ OR tenant_id = NULLIF(current_setting('app.current_tenant_id', true), '')::uuid
44
+ )
45
+ WITH CHECK (
46
+ current_setting('app.bypass_rls', true) = 'on'
47
+ OR tenant_id = NULLIF(current_setting('app.current_tenant_id', true), '')::uuid
48
+ );
49
+
50
+ -- permission_policies
51
+ ALTER TABLE permission_policies ENABLE ROW LEVEL SECURITY;
52
+ ALTER TABLE permission_policies FORCE ROW LEVEL SECURITY;
53
+ DROP POLICY IF EXISTS tenant_isolation ON permission_policies;
54
+ CREATE POLICY tenant_isolation ON permission_policies FOR ALL
55
+ USING (
56
+ current_setting('app.bypass_rls', true) = 'on'
57
+ OR tenant_id = NULLIF(current_setting('app.current_tenant_id', true), '')::uuid
58
+ )
59
+ WITH CHECK (
60
+ current_setting('app.bypass_rls', true) = 'on'
61
+ OR tenant_id = NULLIF(current_setting('app.current_tenant_id', true), '')::uuid
62
+ );
63
+
64
+ -- audit_logs (tenant_id nullable: ON DELETE SET NULL; NULL rows visible only under bypass)
65
+ ALTER TABLE audit_logs ENABLE ROW LEVEL SECURITY;
66
+ ALTER TABLE audit_logs FORCE ROW LEVEL SECURITY;
67
+ DROP POLICY IF EXISTS tenant_isolation ON audit_logs;
68
+ CREATE POLICY tenant_isolation ON audit_logs FOR ALL
69
+ USING (
70
+ current_setting('app.bypass_rls', true) = 'on'
71
+ OR tenant_id = NULLIF(current_setting('app.current_tenant_id', true), '')::uuid
72
+ )
73
+ WITH CHECK (
74
+ current_setting('app.bypass_rls', true) = 'on'
75
+ OR tenant_id = NULLIF(current_setting('app.current_tenant_id', true), '')::uuid
76
+ );
77
+
78
+ -- webhook_events
79
+ ALTER TABLE webhook_events ENABLE ROW LEVEL SECURITY;
80
+ ALTER TABLE webhook_events FORCE ROW LEVEL SECURITY;
81
+ DROP POLICY IF EXISTS tenant_isolation ON webhook_events;
82
+ CREATE POLICY tenant_isolation ON webhook_events FOR ALL
83
+ USING (
84
+ current_setting('app.bypass_rls', true) = 'on'
85
+ OR tenant_id = NULLIF(current_setting('app.current_tenant_id', true), '')::uuid
86
+ )
87
+ WITH CHECK (
88
+ current_setting('app.bypass_rls', true) = 'on'
89
+ OR tenant_id = NULLIF(current_setting('app.current_tenant_id', true), '')::uuid
90
+ );
91
+
92
+ -- webhooks (tenant_id nullable)
93
+ ALTER TABLE webhooks ENABLE ROW LEVEL SECURITY;
94
+ ALTER TABLE webhooks FORCE ROW LEVEL SECURITY;
95
+ DROP POLICY IF EXISTS tenant_isolation ON webhooks;
96
+ CREATE POLICY tenant_isolation ON webhooks FOR ALL
97
+ USING (
98
+ current_setting('app.bypass_rls', true) = 'on'
99
+ OR tenant_id = NULLIF(current_setting('app.current_tenant_id', true), '')::uuid
100
+ )
101
+ WITH CHECK (
102
+ current_setting('app.bypass_rls', true) = 'on'
103
+ OR tenant_id = NULLIF(current_setting('app.current_tenant_id', true), '')::uuid
104
+ );
105
+
106
+ -- consent_records
107
+ ALTER TABLE consent_records ENABLE ROW LEVEL SECURITY;
108
+ ALTER TABLE consent_records FORCE ROW LEVEL SECURITY;
109
+ DROP POLICY IF EXISTS tenant_isolation ON consent_records;
110
+ CREATE POLICY tenant_isolation ON consent_records FOR ALL
111
+ USING (
112
+ current_setting('app.bypass_rls', true) = 'on'
113
+ OR tenant_id = NULLIF(current_setting('app.current_tenant_id', true), '')::uuid
114
+ )
115
+ WITH CHECK (
116
+ current_setting('app.bypass_rls', true) = 'on'
117
+ OR tenant_id = NULLIF(current_setting('app.current_tenant_id', true), '')::uuid
118
+ );
119
+
120
+ -- abac_policies
121
+ ALTER TABLE abac_policies ENABLE ROW LEVEL SECURITY;
122
+ ALTER TABLE abac_policies FORCE ROW LEVEL SECURITY;
123
+ DROP POLICY IF EXISTS tenant_isolation ON abac_policies;
124
+ CREATE POLICY tenant_isolation ON abac_policies FOR ALL
125
+ USING (
126
+ current_setting('app.bypass_rls', true) = 'on'
127
+ OR tenant_id = NULLIF(current_setting('app.current_tenant_id', true), '')::uuid
128
+ )
129
+ WITH CHECK (
130
+ current_setting('app.bypass_rls', true) = 'on'
131
+ OR tenant_id = NULLIF(current_setting('app.current_tenant_id', true), '')::uuid
132
+ );
133
+
134
+ -- api_keys (auth table; tenant_id nullable. Read by the control plane before a
135
+ -- tenant context exists, so it is safe only because the control plane bypasses.
136
+ -- Global keys (tenant_id NULL) are visible only under bypass.)
137
+ ALTER TABLE api_keys ENABLE ROW LEVEL SECURITY;
138
+ ALTER TABLE api_keys FORCE ROW LEVEL SECURITY;
139
+ DROP POLICY IF EXISTS tenant_isolation ON api_keys;
140
+ CREATE POLICY tenant_isolation ON api_keys FOR ALL
141
+ USING (
142
+ current_setting('app.bypass_rls', true) = 'on'
143
+ OR tenant_id = NULLIF(current_setting('app.current_tenant_id', true), '')::uuid
144
+ )
145
+ WITH CHECK (
146
+ current_setting('app.bypass_rls', true) = 'on'
147
+ OR tenant_id = NULLIF(current_setting('app.current_tenant_id', true), '')::uuid
148
+ );
149
+
150
+ -- roles (auth table; tenant_id nullable for global roles, visible only under bypass)
151
+ ALTER TABLE roles ENABLE ROW LEVEL SECURITY;
152
+ ALTER TABLE roles FORCE ROW LEVEL SECURITY;
153
+ DROP POLICY IF EXISTS tenant_isolation ON roles;
154
+ CREATE POLICY tenant_isolation ON roles FOR ALL
155
+ USING (
156
+ current_setting('app.bypass_rls', true) = 'on'
157
+ OR tenant_id = NULLIF(current_setting('app.current_tenant_id', true), '')::uuid
158
+ )
159
+ WITH CHECK (
160
+ current_setting('app.bypass_rls', true) = 'on'
161
+ OR tenant_id = NULLIF(current_setting('app.current_tenant_id', true), '')::uuid
162
+ );
163
+
164
+ -- ---------------------------------------------------------------------------
165
+ -- tenants registry: self-scope on id. The ancestry source; no tenant_id column.
166
+ -- A data-plane context reads only its own registry row and cannot enumerate the
167
+ -- tree. All tree / ancestry mutations are control-plane and run under bypass.
168
+ -- ---------------------------------------------------------------------------
169
+ ALTER TABLE tenants ENABLE ROW LEVEL SECURITY;
170
+ ALTER TABLE tenants FORCE ROW LEVEL SECURITY;
171
+ DROP POLICY IF EXISTS tenant_isolation ON tenants;
172
+ CREATE POLICY tenant_isolation ON tenants FOR ALL
173
+ USING (
174
+ current_setting('app.bypass_rls', true) = 'on'
175
+ OR id = NULLIF(current_setting('app.current_tenant_id', true), '')::uuid
176
+ )
177
+ WITH CHECK (
178
+ current_setting('app.bypass_rls', true) = 'on'
179
+ OR id = NULLIF(current_setting('app.current_tenant_id', true), '')::uuid
180
+ );
181
+
182
+ -- ---------------------------------------------------------------------------
183
+ -- Indirect tables (no tenant_id): scoped through their tenant-bearing parent.
184
+ -- The parent subquery is itself RLS-filtered under a tenant context, which
185
+ -- composes correctly. No policy recursion: neither parent references back.
186
+ -- ---------------------------------------------------------------------------
187
+
188
+ -- webhook_deliveries -> webhook_events.tenant_id
189
+ ALTER TABLE webhook_deliveries ENABLE ROW LEVEL SECURITY;
190
+ ALTER TABLE webhook_deliveries FORCE ROW LEVEL SECURITY;
191
+ DROP POLICY IF EXISTS tenant_isolation ON webhook_deliveries;
192
+ CREATE POLICY tenant_isolation ON webhook_deliveries FOR ALL
193
+ USING (
194
+ current_setting('app.bypass_rls', true) = 'on'
195
+ OR EXISTS (
196
+ SELECT 1 FROM webhook_events we
197
+ WHERE we.id = webhook_deliveries.event_id
198
+ AND we.tenant_id = NULLIF(current_setting('app.current_tenant_id', true), '')::uuid
199
+ )
200
+ )
201
+ WITH CHECK (
202
+ current_setting('app.bypass_rls', true) = 'on'
203
+ OR EXISTS (
204
+ SELECT 1 FROM webhook_events we
205
+ WHERE we.id = webhook_deliveries.event_id
206
+ AND we.tenant_id = NULLIF(current_setting('app.current_tenant_id', true), '')::uuid
207
+ )
208
+ );
209
+
210
+ -- principal_roles -> roles.tenant_id (global-role assignments visible only under bypass)
211
+ ALTER TABLE principal_roles ENABLE ROW LEVEL SECURITY;
212
+ ALTER TABLE principal_roles FORCE ROW LEVEL SECURITY;
213
+ DROP POLICY IF EXISTS tenant_isolation ON principal_roles;
214
+ CREATE POLICY tenant_isolation ON principal_roles FOR ALL
215
+ USING (
216
+ current_setting('app.bypass_rls', true) = 'on'
217
+ OR EXISTS (
218
+ SELECT 1 FROM roles r
219
+ WHERE r.id = principal_roles.role_id
220
+ AND r.tenant_id = NULLIF(current_setting('app.current_tenant_id', true), '')::uuid
221
+ )
222
+ )
223
+ WITH CHECK (
224
+ current_setting('app.bypass_rls', true) = 'on'
225
+ OR EXISTS (
226
+ SELECT 1 FROM roles r
227
+ WHERE r.id = principal_roles.role_id
228
+ AND r.tenant_id = NULLIF(current_setting('app.current_tenant_id', true), '')::uuid
229
+ )
230
+ );
231
+
232
+ -- ---------------------------------------------------------------------------
233
+ -- Intentionally NOT protected (documented in the ADR):
234
+ -- * regions -- global infrastructure catalog, no tenant_id, not tenant-private
235
+ -- * _migrations -- internal migration bookkeeping
236
+ -- ---------------------------------------------------------------------------
@@ -1 +1 @@
1
- {"version":3,"file":"pool-helpers.d.ts","sourceRoot":"","sources":["../src/pool-helpers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAC;AAEpB,wBAAsB,UAAU,CAAC,CAAC,EAChC,IAAI,EAAE,EAAE,CAAC,IAAI,EACb,EAAE,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,UAAU,KAAK,OAAO,CAAC,CAAC,CAAC,GACxC,OAAO,CAAC,CAAC,CAAC,CAOZ;AAED,wBAAsB,eAAe,CAAC,CAAC,EACrC,IAAI,EAAE,EAAE,CAAC,IAAI,EACb,EAAE,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,UAAU,KAAK,OAAO,CAAC,CAAC,CAAC,GACxC,OAAO,CAAC,CAAC,CAAC,CAaZ"}
1
+ {"version":3,"file":"pool-helpers.d.ts","sourceRoot":"","sources":["../src/pool-helpers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAC;AAyBpB,wBAAsB,UAAU,CAAC,CAAC,EAChC,IAAI,EAAE,EAAE,CAAC,IAAI,EACb,EAAE,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,UAAU,KAAK,OAAO,CAAC,CAAC,CAAC,GACxC,OAAO,CAAC,CAAC,CAAC,CAcZ;AAED,wBAAsB,eAAe,CAAC,CAAC,EACrC,IAAI,EAAE,EAAE,CAAC,IAAI,EACb,EAAE,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,UAAU,KAAK,OAAO,CAAC,CAAC,CAAC,GACxC,OAAO,CAAC,CAAC,CAAC,CAcZ"}
@@ -2,10 +2,39 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.withClient = withClient;
4
4
  exports.withTransaction = withTransaction;
5
+ // The Stratum library is the trusted CONTROL PLANE: it manages the whole tenant
6
+ // tree (authenticating keys before any tenant is known, resolving inherited
7
+ // config up the ancestry chain, listing descendants, moving subtrees, cascade
8
+ // ops). By construction it reads and writes across tenant boundaries, so it runs
9
+ // under the RLS bypass.
10
+ //
11
+ // Both helpers open a transaction and issue `SET LOCAL app.bypass_rls = 'on'`
12
+ // before running the caller's work. SET LOCAL (set_config third arg `true`) is
13
+ // transaction scoped, so the flag cannot leak into a later request that reuses
14
+ // the same pooled connection. Row-level security stays enforced on the separate
15
+ // data-plane path (packages/db-adapters, withTenantContext); see
16
+ // docs/adr/0001-postgres-rls-defense-in-depth.md.
17
+ //
18
+ // This is the single chokepoint for all lib database access: every service goes
19
+ // through withClient / withTransaction, so no service function needs to change.
20
+ async function enterBypass(client) {
21
+ // SET LOCAL (not session SET) so the flag is transaction scoped and cannot
22
+ // leak across pooled connections. Equivalent to
23
+ // set_config('app.bypass_rls', 'on', true).
24
+ await client.query("SET LOCAL app.bypass_rls = 'on'");
25
+ }
5
26
  async function withClient(pool, fn) {
6
27
  const client = await pool.connect();
7
28
  try {
8
- return await fn(client);
29
+ await client.query("BEGIN");
30
+ await enterBypass(client);
31
+ const result = await fn(client);
32
+ await client.query("COMMIT");
33
+ return result;
34
+ }
35
+ catch (err) {
36
+ await client.query("ROLLBACK");
37
+ throw err;
9
38
  }
10
39
  finally {
11
40
  client.release();
@@ -15,6 +44,7 @@ async function withTransaction(pool, fn) {
15
44
  const client = await pool.connect();
16
45
  try {
17
46
  await client.query("BEGIN");
47
+ await enterBypass(client);
18
48
  const result = await fn(client);
19
49
  await client.query("COMMIT");
20
50
  return result;
@@ -1 +1 @@
1
- {"version":3,"file":"pool-helpers.js","sourceRoot":"","sources":["../src/pool-helpers.ts"],"names":[],"mappings":";;AAEA,gCAUC;AAED,0CAgBC;AA5BM,KAAK,UAAU,UAAU,CAC9B,IAAa,EACb,EAAyC;IAEzC,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC;IACpC,IAAI,CAAC;QACH,OAAO,MAAM,EAAE,CAAC,MAAM,CAAC,CAAC;IAC1B,CAAC;YAAS,CAAC;QACT,MAAM,CAAC,OAAO,EAAE,CAAC;IACnB,CAAC;AACH,CAAC;AAEM,KAAK,UAAU,eAAe,CACnC,IAAa,EACb,EAAyC;IAEzC,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC;IACpC,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAC5B,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,MAAM,CAAC,CAAC;QAChC,MAAM,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QAC7B,OAAO,MAAM,CAAC;IAChB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;QAC/B,MAAM,GAAG,CAAC;IACZ,CAAC;YAAS,CAAC;QACT,MAAM,CAAC,OAAO,EAAE,CAAC;IACnB,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"pool-helpers.js","sourceRoot":"","sources":["../src/pool-helpers.ts"],"names":[],"mappings":";;AAyBA,gCAiBC;AAED,0CAiBC;AA3DD,gFAAgF;AAChF,4EAA4E;AAC5E,8EAA8E;AAC9E,iFAAiF;AACjF,wBAAwB;AACxB,EAAE;AACF,8EAA8E;AAC9E,+EAA+E;AAC/E,+EAA+E;AAC/E,gFAAgF;AAChF,iEAAiE;AACjE,kDAAkD;AAClD,EAAE;AACF,gFAAgF;AAChF,gFAAgF;AAEhF,KAAK,UAAU,WAAW,CAAC,MAAqB;IAC9C,2EAA2E;IAC3E,gDAAgD;IAChD,4CAA4C;IAC5C,MAAM,MAAM,CAAC,KAAK,CAAC,iCAAiC,CAAC,CAAC;AACxD,CAAC;AAEM,KAAK,UAAU,UAAU,CAC9B,IAAa,EACb,EAAyC;IAEzC,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC;IACpC,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAC5B,MAAM,WAAW,CAAC,MAAM,CAAC,CAAC;QAC1B,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,MAAM,CAAC,CAAC;QAChC,MAAM,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QAC7B,OAAO,MAAM,CAAC;IAChB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;QAC/B,MAAM,GAAG,CAAC;IACZ,CAAC;YAAS,CAAC;QACT,MAAM,CAAC,OAAO,EAAE,CAAC;IACnB,CAAC;AACH,CAAC;AAEM,KAAK,UAAU,eAAe,CACnC,IAAa,EACb,EAAyC;IAEzC,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC;IACpC,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAC5B,MAAM,WAAW,CAAC,MAAM,CAAC,CAAC;QAC1B,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,MAAM,CAAC,CAAC;QAChC,MAAM,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QAC7B,OAAO,MAAM,CAAC;IAChB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;QAC/B,MAAM,GAAG,CAAC;IACZ,CAAC;YAAS,CAAC;QACT,MAAM,CAAC,OAAO,EAAE,CAAC;IACnB,CAAC;AACH,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=api-key-service.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-key-service.test.d.ts","sourceRoot":"","sources":["../../../src/services/__tests__/api-key-service.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,76 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ const vitest_1 = require("vitest");
37
+ // Mock pool-helpers before importing api-key-service
38
+ vitest_1.vi.mock("../../pool-helpers.js", () => ({
39
+ withClient: vitest_1.vi.fn(),
40
+ withTransaction: vitest_1.vi.fn(),
41
+ }));
42
+ const poolHelpers = __importStar(require("../../pool-helpers.js"));
43
+ const apiKeyService = __importStar(require("../api-key-service.js"));
44
+ const test_helpers_js_1 = require("./test-helpers.js");
45
+ /** Wire withClient to call the callback with a { query } client. */
46
+ function withMockQuery(mockQuery) {
47
+ vitest_1.vi.mocked(poolHelpers.withClient).mockImplementation(async (_pool, fn) => {
48
+ const client = { query: mockQuery };
49
+ return fn(client);
50
+ });
51
+ }
52
+ (0, vitest_1.beforeEach)(() => {
53
+ vitest_1.vi.clearAllMocks();
54
+ });
55
+ (0, vitest_1.describe)("getApiKey", () => {
56
+ (0, vitest_1.it)("selects a key by id and returns its owning tenant", async () => {
57
+ const pool = (0, test_helpers_js_1.makeMockPool)();
58
+ const row = { id: "key-1", tenant_id: "tenant-1", name: null, created_at: new Date(), last_used_at: null, revoked_at: null, expires_at: null };
59
+ const mockQuery = vitest_1.vi.fn().mockResolvedValueOnce({ rows: [row] });
60
+ withMockQuery(mockQuery);
61
+ const result = await apiKeyService.getApiKey(pool, "key-1");
62
+ (0, vitest_1.expect)(result).toEqual(row);
63
+ const [sql, params] = mockQuery.mock.calls[0];
64
+ (0, vitest_1.expect)(sql).toContain("FROM api_keys WHERE id = $1");
65
+ (0, vitest_1.expect)(sql).toContain("tenant_id");
66
+ (0, vitest_1.expect)(params).toEqual(["key-1"]);
67
+ });
68
+ (0, vitest_1.it)("returns null when no key has that id", async () => {
69
+ const pool = (0, test_helpers_js_1.makeMockPool)();
70
+ const mockQuery = vitest_1.vi.fn().mockResolvedValueOnce({ rows: [] });
71
+ withMockQuery(mockQuery);
72
+ const result = await apiKeyService.getApiKey(pool, "ghost");
73
+ (0, vitest_1.expect)(result).toBeNull();
74
+ });
75
+ });
76
+ //# sourceMappingURL=api-key-service.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-key-service.test.js","sourceRoot":"","sources":["../../../src/services/__tests__/api-key-service.test.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,mCAA8D;AAE9D,qDAAqD;AACrD,WAAE,CAAC,IAAI,CAAC,uBAAuB,EAAE,GAAG,EAAE,CAAC,CAAC;IACtC,UAAU,EAAE,WAAE,CAAC,EAAE,EAAE;IACnB,eAAe,EAAE,WAAE,CAAC,EAAE,EAAE;CACzB,CAAC,CAAC,CAAC;AAEJ,mEAAqD;AACrD,qEAAuD;AACvD,uDAAiD;AAEjD,oEAAoE;AACpE,SAAS,aAAa,CAAC,SAAmC;IACxD,WAAE,CAAC,MAAM,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC,kBAAkB,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE;QACvE,MAAM,MAAM,GAAG,EAAE,KAAK,EAAE,SAAS,EAAwC,CAAC;QAC1E,OAAO,EAAE,CAAC,MAAM,CAAC,CAAC;IACpB,CAAC,CAAC,CAAC;AACL,CAAC;AAED,IAAA,mBAAU,EAAC,GAAG,EAAE;IACd,WAAE,CAAC,aAAa,EAAE,CAAC;AACrB,CAAC,CAAC,CAAC;AAEH,IAAA,iBAAQ,EAAC,WAAW,EAAE,GAAG,EAAE;IACzB,IAAA,WAAE,EAAC,mDAAmD,EAAE,KAAK,IAAI,EAAE;QACjE,MAAM,IAAI,GAAG,IAAA,8BAAY,GAAE,CAAC;QAC5B,MAAM,GAAG,GAAG,EAAE,EAAE,EAAE,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,IAAI,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,IAAI,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC;QAC/I,MAAM,SAAS,GAAG,WAAE,CAAC,EAAE,EAAE,CAAC,qBAAqB,CAAC,EAAE,IAAI,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACjE,aAAa,CAAC,SAAS,CAAC,CAAC;QAEzB,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,SAAS,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QAE5D,IAAA,eAAM,EAAC,MAAM,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QAC5B,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,GAAG,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAC9C,IAAA,eAAM,EAAC,GAAG,CAAC,CAAC,SAAS,CAAC,6BAA6B,CAAC,CAAC;QACrD,IAAA,eAAM,EAAC,GAAG,CAAC,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;QACnC,IAAA,eAAM,EAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;IACpC,CAAC,CAAC,CAAC;IAEH,IAAA,WAAE,EAAC,sCAAsC,EAAE,KAAK,IAAI,EAAE;QACpD,MAAM,IAAI,GAAG,IAAA,8BAAY,GAAE,CAAC;QAC5B,MAAM,SAAS,GAAG,WAAE,CAAC,EAAE,EAAE,CAAC,qBAAqB,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;QAC9D,aAAa,CAAC,SAAS,CAAC,CAAC;QAEzB,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,SAAS,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QAC5D,IAAA,eAAM,EAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,CAAC;IAC5B,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -82,6 +82,38 @@ function signPayload(secret, payload) {
82
82
  (0, vitest_1.expect)(sig1).not.toBe(sig2);
83
83
  });
84
84
  });
85
+ (0, vitest_1.describe)("webhook egress filter (SSRF protection)", () => {
86
+ // Regression: bracketed IPv6 literals must be rejected in every notation.
87
+ // The URL parser exposes IPv6 hosts wrapped in brackets, so a filter that
88
+ // only matches the unbracketed textual form lets internal targets through.
89
+ const mustReject = [
90
+ ["bracketed IPv6 loopback", "http://[::1]/hook"],
91
+ ["expanded IPv6 loopback", "http://[0:0:0:0:0:0:0:1]/hook"],
92
+ ["IPv6 link-local", "http://[fe80::1]/hook"],
93
+ ["IPv6 unique-local", "http://[fd00:ec2::254]/hook"],
94
+ ["IPv4-mapped loopback", "http://[::ffff:127.0.0.1]/hook"],
95
+ ["IPv4-mapped metadata address", "http://[::ffff:169.254.169.254]/hook"],
96
+ ["unspecified IPv6 address", "http://[::]/hook"],
97
+ ["integer-coerced loopback", "http://2130706433/hook"],
98
+ ];
99
+ for (const [label, url] of mustReject) {
100
+ (0, vitest_1.it)(`rejects ${label}`, () => {
101
+ (0, vitest_1.expect)(() => eventService.validateWebhookUrl(url)).toThrow();
102
+ });
103
+ }
104
+ // Unbracketed forms that already worked must keep working.
105
+ (0, vitest_1.it)("still rejects IPv4 loopback and metadata", () => {
106
+ (0, vitest_1.expect)(() => eventService.validateWebhookUrl("http://127.0.0.1/hook")).toThrow();
107
+ (0, vitest_1.expect)(() => eventService.validateWebhookUrl("http://169.254.169.254/hook")).toThrow();
108
+ (0, vitest_1.expect)(() => eventService.validateWebhookUrl("http://localhost/hook")).toThrow();
109
+ });
110
+ (0, vitest_1.it)("allows a public https target", () => {
111
+ (0, vitest_1.expect)(() => eventService.validateWebhookUrl("https://example.com/hook")).not.toThrow();
112
+ });
113
+ (0, vitest_1.it)("fails closed on an unparseable URL", () => {
114
+ (0, vitest_1.expect)(() => eventService.validateWebhookUrl("http://[not-an-ip/hook")).toThrow();
115
+ });
116
+ });
85
117
  (0, vitest_1.describe)("retry backoff calculation", () => {
86
118
  // attempts^2 * 5000ms
87
119
  const cases = [
@@ -1 +1 @@
1
- {"version":3,"file":"event-service.test.js","sourceRoot":"","sources":["../../../src/services/__tests__/event-service.test.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"event-service.test.js","sourceRoot":"","sources":["../../../src/services/__tests__/event-service.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=key-rotation-service.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"key-rotation-service.test.d.ts","sourceRoot":"","sources":["../../../src/services/__tests__/key-rotation-service.test.ts"],"names":[],"mappings":""}