@astram/identity 0.11.0 → 0.13.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 (96) hide show
  1. package/dist/cross-tenant-grant.object.d.ts.map +1 -1
  2. package/dist/cross-tenant-grant.object.js +3 -2
  3. package/dist/features/audit/directory-label-resolver.d.ts +4 -1
  4. package/dist/features/audit/directory-label-resolver.d.ts.map +1 -1
  5. package/dist/features/audit/directory-label-resolver.js +8 -5
  6. package/dist/features/audit/mariadb-audit-reader.d.ts +5 -1
  7. package/dist/features/audit/mariadb-audit-reader.d.ts.map +1 -1
  8. package/dist/features/audit/mariadb-audit-reader.js +10 -2
  9. package/dist/features/authz/access-bundle-reconcile.job.d.ts +4 -1
  10. package/dist/features/authz/access-bundle-reconcile.job.d.ts.map +1 -1
  11. package/dist/features/authz/access-bundle-reconcile.job.js +7 -4
  12. package/dist/features/authz/access-bundle-store.d.ts +4 -1
  13. package/dist/features/authz/access-bundle-store.d.ts.map +1 -1
  14. package/dist/features/authz/access-bundle-store.js +19 -16
  15. package/dist/features/authz/catalog-reconcile.job.d.ts +3 -1
  16. package/dist/features/authz/catalog-reconcile.job.d.ts.map +1 -1
  17. package/dist/features/authz/catalog-reconcile.job.js +3 -2
  18. package/dist/features/authz/db-permission-facts.adapter.d.ts +9 -3
  19. package/dist/features/authz/db-permission-facts.adapter.d.ts.map +1 -1
  20. package/dist/features/authz/db-permission-facts.adapter.js +22 -16
  21. package/dist/features/authz/grant-admin.service.d.ts +4 -1
  22. package/dist/features/authz/grant-admin.service.d.ts.map +1 -1
  23. package/dist/features/authz/grant-admin.service.js +32 -37
  24. package/dist/features/authz/grant-ceiling.d.ts +6 -1
  25. package/dist/features/authz/grant-ceiling.d.ts.map +1 -1
  26. package/dist/features/authz/grant-ceiling.js +19 -16
  27. package/dist/features/authz/mariadb-catalog-store.d.ts +4 -1
  28. package/dist/features/authz/mariadb-catalog-store.d.ts.map +1 -1
  29. package/dist/features/authz/mariadb-catalog-store.js +10 -7
  30. package/dist/features/authz/permission-version.bumper.d.ts +6 -1
  31. package/dist/features/authz/permission-version.bumper.d.ts.map +1 -1
  32. package/dist/features/authz/permission-version.bumper.js +13 -11
  33. package/dist/features/authz/record-authorization.d.ts +16 -2
  34. package/dist/features/authz/record-authorization.d.ts.map +1 -1
  35. package/dist/features/authz/record-authorization.js +29 -5
  36. package/dist/features/authz/role-binding.d.ts +3 -2
  37. package/dist/features/authz/role-binding.d.ts.map +1 -1
  38. package/dist/features/authz/role-binding.js +7 -8
  39. package/dist/features/company/company-hierarchy.service.d.ts +6 -1
  40. package/dist/features/company/company-hierarchy.service.d.ts.map +1 -1
  41. package/dist/features/company/company-hierarchy.service.js +17 -16
  42. package/dist/features/cross-tenant/cross-tenant-grant-read.service.d.ts +5 -1
  43. package/dist/features/cross-tenant/cross-tenant-grant-read.service.d.ts.map +1 -1
  44. package/dist/features/cross-tenant/cross-tenant-grant-read.service.js +18 -14
  45. package/dist/features/framework-schemas.token.d.ts +8 -0
  46. package/dist/features/framework-schemas.token.d.ts.map +1 -0
  47. package/dist/features/framework-schemas.token.js +10 -0
  48. package/dist/features/identity-feature.module.d.ts +36 -2
  49. package/dist/features/identity-feature.module.d.ts.map +1 -1
  50. package/dist/features/identity-feature.module.js +142 -34
  51. package/dist/features/membership/membership-checker.d.ts +7 -1
  52. package/dist/features/membership/membership-checker.d.ts.map +1 -1
  53. package/dist/features/membership/membership-checker.js +9 -4
  54. package/dist/features/migration-ledger-check.d.ts +15 -0
  55. package/dist/features/migration-ledger-check.d.ts.map +1 -0
  56. package/dist/features/migration-ledger-check.js +26 -0
  57. package/dist/features/scope/scope-closure.service.d.ts +8 -1
  58. package/dist/features/scope/scope-closure.service.d.ts.map +1 -1
  59. package/dist/features/scope/scope-closure.service.js +22 -19
  60. package/dist/features/scope/scope-subtree.resolver.d.ts +7 -1
  61. package/dist/features/scope/scope-subtree.resolver.d.ts.map +1 -1
  62. package/dist/features/scope/scope-subtree.resolver.js +9 -4
  63. package/dist/features/service-account/lock-service-accounts.d.ts +3 -1
  64. package/dist/features/service-account/lock-service-accounts.d.ts.map +1 -1
  65. package/dist/features/service-account/lock-service-accounts.js +4 -4
  66. package/dist/features/service-account/no-expiry-key-report.d.ts +9 -3
  67. package/dist/features/service-account/no-expiry-key-report.d.ts.map +1 -1
  68. package/dist/features/service-account/no-expiry-key-report.js +17 -10
  69. package/dist/features/service-account/service-account.store.d.ts +8 -1
  70. package/dist/features/service-account/service-account.store.d.ts.map +1 -1
  71. package/dist/features/service-account/service-account.store.js +19 -14
  72. package/dist/features/user/user.service.d.ts +7 -3
  73. package/dist/features/user/user.service.d.ts.map +1 -1
  74. package/dist/features/user/user.service.js +12 -4
  75. package/dist/record-share.object.d.ts.map +1 -1
  76. package/dist/record-share.object.js +3 -2
  77. package/dist/schema.d.ts +15 -2
  78. package/dist/schema.d.ts.map +1 -1
  79. package/dist/schema.js +17 -2
  80. package/migrations/1710000000001-CreateIdentityOrgModel.cjs +14 -4
  81. package/migrations/1710000000002-CreateMembershipAndPostings.cjs +14 -4
  82. package/migrations/1710000000003-CreateIdentityCredential.cjs +14 -4
  83. package/migrations/1710000000004-CreateSessionTables.cjs +14 -4
  84. package/migrations/1710000000005-CreateMfaAndTokenSurface.cjs +14 -4
  85. package/migrations/1710000000010-CreateAuditLog.cjs +14 -4
  86. package/migrations/1710000000011-CreateCrossTenantGrant.cjs +15 -4
  87. package/migrations/1710000000012-SeedCrossTenantGrantPerms.cjs +15 -4
  88. package/migrations/1710000000013-CreateSharedResource.cjs +14 -4
  89. package/migrations/1710000000018-CreateServiceAccount.cjs +13 -4
  90. package/migrations/1710000000019-AddSessionMustReenroll.cjs +14 -4
  91. package/migrations/1710000000020-CreateEmailChangeToken.cjs +15 -5
  92. package/migrations/1710000000021-AddUsersEmailUniqueIndex.cjs +24 -13
  93. package/migrations/1710000000022-CreateStoredFile.cjs +14 -4
  94. package/migrations/1710000000099-SeedDevIdentity.cjs +14 -6
  95. package/migrations/1710000000100-SeedDevTenantBAndRoot.cjs +14 -6
  96. package/package.json +4 -4
@@ -40,10 +40,7 @@ exports.quarantineCycles = quarantineCycles;
40
40
  */
41
41
  const core_1 = require("@astram/core");
42
42
  const guard_1 = require("@astram/guard");
43
- /** Schema the node tree (`companies`) lives in. */
44
- const APP = 'shield_app';
45
- /** Schema the closure table lives in (ADR-0011 / Task 1.1). */
46
- const AUTHZ = 'shield_authz';
43
+ const schema_js_1 = require("../../schema.js");
47
44
  /** The named lock every hierarchy writer holds (security review F3). */
48
45
  const TREE_LOCK = 'shield_scope_closure';
49
46
  /** Seconds to wait for it before failing closed. */
@@ -51,9 +48,16 @@ const TREE_LOCK_TIMEOUT_S = 10;
51
48
  class ScopeClosureService {
52
49
  pool;
53
50
  bumper;
54
- constructor(pool, bumper) {
51
+ schemas;
52
+ /**
53
+ * @param schemas resolved framework names: the node tree (`companies`) lives in `schemas.app`,
54
+ * the closure table in `schemas.authz` (ADR-0011 / Task 1.1). Absent ⇒ resolved from the
55
+ * namespace, once, here.
56
+ */
57
+ constructor(pool, bumper, schemas = (0, schema_js_1.frameworkSchemasFromEnv)()) {
55
58
  this.pool = pool;
56
59
  this.bumper = bumper;
60
+ this.schemas = schemas;
57
61
  }
58
62
  /**
59
63
  * Rebuild `scope_closure` from the current `companies.c_parent_uuid` edges. Idempotent
@@ -183,7 +187,7 @@ class ScopeClosureService {
183
187
  if (newParentUuid !== null) {
184
188
  // Cycle guard: the new parent must NOT be at/under the moved node. A closure hit means
185
189
  // newParent is a descendant of node → re-parenting node under it would form a cycle.
186
- const cyclic = (await conn.query(`SELECT 1 FROM \`${AUTHZ}\`.\`scope_closure\`
190
+ const cyclic = (await conn.query(`SELECT 1 FROM \`${this.schemas.authz}\`.\`scope_closure\`
187
191
  WHERE ancestor_uuid = ? AND descendant_uuid = ? LIMIT 1`, [nodeUuid, newParentUuid]));
188
192
  if (cyclic.length > 0) {
189
193
  throw new guard_1.ScopeCycleError(nodeUuid);
@@ -191,14 +195,14 @@ class ScopeClosureService {
191
195
  }
192
196
  // The moved subtree — the nodes whose ancestry changes (node + all descendants). Read
193
197
  // BEFORE the update (the move doesn't change the subtree's internal membership).
194
- const subtreeRows = (await conn.query(`SELECT descendant_uuid FROM \`${AUTHZ}\`.\`scope_closure\` WHERE ancestor_uuid = ?`, [nodeUuid]));
198
+ const subtreeRows = (await conn.query(`SELECT descendant_uuid FROM \`${this.schemas.authz}\`.\`scope_closure\` WHERE ancestor_uuid = ?`, [nodeUuid]));
195
199
  // The FORMER-PARENT ANCESTRY — the nodes ABOVE `node` in the OLD tree (its ancestors,
196
200
  // excluding self). They just LOST `node`'s subtree from their reach, so their admins' cached
197
201
  // session subtrees are now stale (they'd otherwise keep reaching the moved-away tenant — the
198
202
  // HIGH stale-subtree-after-move leak). Read BEFORE the update (the pre-move closure has the
199
203
  // old ancestry). Bump these too so those sessions re-derive their (now-smaller) subtree at
200
204
  // their next refresh (ADR-0011 bound — no forced re-login).
201
- const formerAncestryRows = (await conn.query(`SELECT ancestor_uuid FROM \`${AUTHZ}\`.\`scope_closure\`
205
+ const formerAncestryRows = (await conn.query(`SELECT ancestor_uuid FROM \`${this.schemas.authz}\`.\`scope_closure\`
202
206
  WHERE descendant_uuid = ? AND ancestor_uuid <> ?`, [nodeUuid, nodeUuid]));
203
207
  // Fall back to the node itself if the closure has no self-row yet (pre-first-reconcile).
204
208
  const movedSubtree = subtreeRows.length > 0 ? subtreeRows.map((r) => r.descendant_uuid) : [nodeUuid];
@@ -209,10 +213,7 @@ class ScopeClosureService {
209
213
  ];
210
214
  {
211
215
  // 1) Re-parent the edge.
212
- await conn.query(`UPDATE \`${APP}\`.\`companies\` SET c_parent_uuid = ? WHERE c_uuid = ?`, [
213
- newParentUuid,
214
- nodeUuid,
215
- ]);
216
+ await conn.query(`UPDATE \`${this.schemas.app}\`.\`companies\` SET c_parent_uuid = ? WHERE c_uuid = ?`, [newParentUuid, nodeUuid]);
216
217
  // 2) Rebuild the whole closure from the now-updated edges (full rebuild — safe + simple;
217
218
  // a targeted subtree rebuild is a later optimization). Re-reads edges over the SAME tx
218
219
  // connection so it sees the UPDATE. Fail-loud propagates → the whole move rolls back.
@@ -267,20 +268,22 @@ class ScopeClosureService {
267
268
  // Under the tree lock (review F3): a concurrent move cannot hang a child under this node
268
269
  // between the children check and the delete.
269
270
  await this.inTreeLock(async (conn) => {
270
- const children = (await conn.query(`SELECT 1 FROM \`${APP}\`.\`companies\` WHERE c_parent_uuid = ? LIMIT 1`, [nodeUuid]));
271
+ const children = (await conn.query(`SELECT 1 FROM \`${this.schemas.app}\`.\`companies\` WHERE c_parent_uuid = ? LIMIT 1`, [nodeUuid]));
271
272
  if (children.length > 0) {
272
273
  throw new NodeHasChildrenError(nodeUuid);
273
274
  }
274
275
  const touched = (beforeDelete ? await beforeDelete(conn) : undefined) ?? [];
275
276
  // The former-parent ancestry — the deleted node's ancestors (excluding self). They lose the
276
277
  // node from their reach → bump so their sessions re-derive. Read BEFORE the delete.
277
- const formerAncestryRows = (await conn.query(`SELECT ancestor_uuid FROM \`${AUTHZ}\`.\`scope_closure\`
278
+ const formerAncestryRows = (await conn.query(`SELECT ancestor_uuid FROM \`${this.schemas.authz}\`.\`scope_closure\`
278
279
  WHERE descendant_uuid = ? AND ancestor_uuid <> ?`, [nodeUuid, nodeUuid]));
279
280
  // Remove the node's closure rows (self-row + any it appears in as ancestor/descendant).
280
- await conn.query(`DELETE FROM \`${AUTHZ}\`.\`scope_closure\`
281
+ await conn.query(`DELETE FROM \`${this.schemas.authz}\`.\`scope_closure\`
281
282
  WHERE ancestor_uuid = ? OR descendant_uuid = ?`, [nodeUuid, nodeUuid]);
282
283
  // Remove the company row itself.
283
- await conn.query(`DELETE FROM \`${APP}\`.\`companies\` WHERE c_uuid = ?`, [nodeUuid]);
284
+ await conn.query(`DELETE FROM \`${this.schemas.app}\`.\`companies\` WHERE c_uuid = ?`, [
285
+ nodeUuid,
286
+ ]);
284
287
  // Bump the former-parent ancestry so their cached subtrees re-derive at next refresh, and the
285
288
  // deleted node's OWN tenant (Phase 8 #3): its memberships and postings cascade away, so
286
289
  // sessions cached in it must reload (and find nothing). A leaf has no descendants to bump.
@@ -299,7 +302,7 @@ class ScopeClosureService {
299
302
  }
300
303
  /** Read the node forest's parent edges (`c_uuid` → `c_parent_uuid`) as `ScopeEdge[]`. */
301
304
  async readEdges(q) {
302
- const rows = (await q.query(`SELECT c_uuid, c_parent_uuid FROM \`${APP}\`.\`companies\``));
305
+ const rows = (await q.query(`SELECT c_uuid, c_parent_uuid FROM \`${this.schemas.app}\`.\`companies\``));
303
306
  return rows.map((r) => ({ node: r.c_uuid, parent: r.c_parent_uuid ?? null }));
304
307
  }
305
308
  /**
@@ -308,7 +311,7 @@ class ScopeClosureService {
308
311
  * idempotent (a re-run writes the identical target set) and correct for a full rebuild.
309
312
  */
310
313
  async rewriteClosure(conn, rows) {
311
- await conn.query(`DELETE FROM \`${AUTHZ}\`.\`scope_closure\``);
314
+ await conn.query(`DELETE FROM \`${this.schemas.authz}\`.\`scope_closure\``);
312
315
  if (rows.length === 0)
313
316
  return;
314
317
  const placeholders = rows.map(() => '(?, ?, ?)').join(', ');
@@ -316,7 +319,7 @@ class ScopeClosureService {
316
319
  for (const r of rows) {
317
320
  params.push(r.ancestor, r.descendant, r.depth);
318
321
  }
319
- await conn.query(`INSERT INTO \`${AUTHZ}\`.\`scope_closure\` (ancestor_uuid, descendant_uuid, depth)
322
+ await conn.query(`INSERT INTO \`${this.schemas.authz}\`.\`scope_closure\` (ancestor_uuid, descendant_uuid, depth)
320
323
  VALUES ${placeholders}`, params);
321
324
  }
322
325
  }
@@ -33,9 +33,15 @@
33
33
  * `shield_authz`; the shared authz pool reaches it.
34
34
  */
35
35
  import type { Pool } from 'mariadb';
36
+ import { type IdentitySchemaNames } from '../../schema.js';
36
37
  export declare class DbScopeSubtreeResolver {
37
38
  private readonly pool;
38
- constructor(pool: Pool);
39
+ private readonly schemas;
40
+ /**
41
+ * @param schemas resolved framework names; the closure table lives in `schemas.authz`
42
+ * (Task 1.1 / ADR-0011). Absent ⇒ resolved from the namespace, once, here.
43
+ */
44
+ constructor(pool: Pool, schemas?: IdentitySchemaNames);
39
45
  /**
40
46
  * Resolve the active-scope subtree for `nodeId` — the node itself plus every
41
47
  * descendant — from `scope_closure`. Returns `[nodeId]` (self-node, non-widening)
@@ -1 +1 @@
1
- {"version":3,"file":"scope-subtree.resolver.d.ts","sourceRoot":"","sources":["../../../src/features/scope/scope-subtree.resolver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAKpC,qBAAa,sBAAsB;IACrB,OAAO,CAAC,QAAQ,CAAC,IAAI;gBAAJ,IAAI,EAAE,IAAI;IAEvC;;;;;OAKG;IACG,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,MAAM,EAAE,CAAC;CAQjE"}
1
+ {"version":3,"file":"scope-subtree.resolver.d.ts","sourceRoot":"","sources":["../../../src/features/scope/scope-subtree.resolver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,EAA2B,KAAK,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAEpF,qBAAa,sBAAsB;IAM/B,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,OAAO,CAAC,QAAQ,CAAC,OAAO;IAN1B;;;OAGG;gBAEgB,IAAI,EAAE,IAAI,EACV,OAAO,GAAE,mBAA+C;IAG3E;;;;;OAKG;IACG,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,MAAM,EAAE,CAAC;CAQjE"}
@@ -1,12 +1,17 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.DbScopeSubtreeResolver = void 0;
4
- /** Schema the closure table lives in (Task 1.1 / ADR-0011). */
5
- const AUTHZ = 'shield_authz';
4
+ const schema_js_1 = require("../../schema.js");
6
5
  class DbScopeSubtreeResolver {
7
6
  pool;
8
- constructor(pool) {
7
+ schemas;
8
+ /**
9
+ * @param schemas resolved framework names; the closure table lives in `schemas.authz`
10
+ * (Task 1.1 / ADR-0011). Absent ⇒ resolved from the namespace, once, here.
11
+ */
12
+ constructor(pool, schemas = (0, schema_js_1.frameworkSchemasFromEnv)()) {
9
13
  this.pool = pool;
14
+ this.schemas = schemas;
10
15
  }
11
16
  /**
12
17
  * Resolve the active-scope subtree for `nodeId` — the node itself plus every
@@ -15,7 +20,7 @@ class DbScopeSubtreeResolver {
15
20
  * store outage (the login path swallows it → self-node fallback per request).
16
21
  */
17
22
  async resolveSubtree(nodeId) {
18
- const rows = (await this.pool.query(`SELECT descendant_uuid FROM \`${AUTHZ}\`.\`scope_closure\` WHERE ancestor_uuid = ?`, [nodeId]));
23
+ const rows = (await this.pool.query(`SELECT descendant_uuid FROM \`${this.schemas.authz}\`.\`scope_closure\` WHERE ancestor_uuid = ?`, [nodeId]));
19
24
  if (rows.length === 0)
20
25
  return [nodeId]; // pre-first-reconcile → self-node (non-widening).
21
26
  return rows.map((r) => r.descendant_uuid);
@@ -18,12 +18,14 @@
18
18
  * `columns` and `where.sql` are fixed SQL written by the caller (never client input); every value
19
19
  * is `?`-bound.
20
20
  */
21
+ import type { IdentitySchemaNames } from '../../schema.js';
21
22
  /** The connection surface: one transaction's `query`. */
22
23
  export interface LockConn {
23
24
  query(sql: string, params?: readonly unknown[]): Promise<unknown>;
24
25
  }
26
+ /** @param schemas resolved framework names; `service_account` lives in `schemas.app`. */
25
27
  export declare function lockServiceAccountsWhere<T>(conn: LockConn, columns: string, where: {
26
28
  readonly sql: string;
27
29
  readonly params: readonly unknown[];
28
- }): Promise<T[]>;
30
+ }, schemas: IdentitySchemaNames): Promise<T[]>;
29
31
  //# sourceMappingURL=lock-service-accounts.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"lock-service-accounts.d.ts","sourceRoot":"","sources":["../../../src/features/service-account/lock-service-accounts.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAIH,yDAAyD;AACzD,MAAM,WAAW,QAAQ;IACvB,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,SAAS,OAAO,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CACnE;AAED,wBAAsB,wBAAwB,CAAC,CAAC,EAC9C,IAAI,EAAE,QAAQ,EACd,OAAO,EAAE,MAAM,EACf,KAAK,EAAE;IAAE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,SAAS,OAAO,EAAE,CAAA;CAAE,GACnE,OAAO,CAAC,CAAC,EAAE,CAAC,CAed"}
1
+ {"version":3,"file":"lock-service-accounts.d.ts","sourceRoot":"","sources":["../../../src/features/service-account/lock-service-accounts.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAE3D,yDAAyD;AACzD,MAAM,WAAW,QAAQ;IACvB,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,SAAS,OAAO,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CACnE;AAED,yFAAyF;AACzF,wBAAsB,wBAAwB,CAAC,CAAC,EAC9C,IAAI,EAAE,QAAQ,EACd,OAAO,EAAE,MAAM,EACf,KAAK,EAAE;IAAE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,SAAS,OAAO,EAAE,CAAA;CAAE,EACpE,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,CAAC,EAAE,CAAC,CAed"}
@@ -21,14 +21,14 @@
21
21
  */
22
22
  Object.defineProperty(exports, "__esModule", { value: true });
23
23
  exports.lockServiceAccountsWhere = lockServiceAccountsWhere;
24
- const APP = 'shield_app';
25
- async function lockServiceAccountsWhere(conn, columns, where) {
26
- const candidates = (await conn.query(`SELECT sa_id FROM \`${APP}\`.\`service_account\` WHERE ${where.sql}`, [...where.params]));
24
+ /** @param schemas resolved framework names; `service_account` lives in `schemas.app`. */
25
+ async function lockServiceAccountsWhere(conn, columns, where, schemas) {
26
+ const candidates = (await conn.query(`SELECT sa_id FROM \`${schemas.app}\`.\`service_account\` WHERE ${where.sql}`, [...where.params]));
27
27
  const ids = [...new Set(candidates.map((r) => r.sa_id))].sort();
28
28
  if (ids.length === 0)
29
29
  return [];
30
30
  return (await conn.query(`SELECT ${columns}
31
- FROM \`${APP}\`.\`service_account\`
31
+ FROM \`${schemas.app}\`.\`service_account\`
32
32
  WHERE sa_id IN (${ids.map(() => '?').join(', ')}) AND (${where.sql})
33
33
  ORDER BY sa_id
34
34
  FOR UPDATE`, [...ids, ...where.params]));
@@ -7,8 +7,12 @@
7
7
  * lists each agent's CURRENT, unrevoked key with no expiry so an operator can rotate it with an
8
8
  * expiry. It prints labels and company names only: never a secret, a hash or a raw id.
9
9
  */
10
- /** Read-only: the current unrevoked key of each agent that has no expiry, with display names. */
11
- export declare const NO_EXPIRY_KEY_REPORT_SQL = "SELECT sa.sa_label AS label, c.c_name AS company,\n sa.sa_status AS status, k.sak_version AS version, k.sak_created_at_ms AS issuedAtMs\n FROM shield_authz.service_account_key k\n LEFT JOIN shield_app.service_account sa ON sa.sa_id = k.sak_account_id\n LEFT JOIN shield_app.companies c ON c.c_uuid = k.sak_tenant_id\n WHERE k.sak_expires_at_ms IS NULL\n AND k.sak_revoked_at_ms IS NULL\n AND k.sak_version = (SELECT MAX(v.sak_version)\n FROM shield_authz.service_account_key v\n WHERE v.sak_account_id = k.sak_account_id)\n ORDER BY k.sak_created_at_ms";
10
+ import { type IdentitySchemaNames } from '../../schema.js';
11
+ /**
12
+ * Read-only: the current unrevoked key of each agent that has no expiry, with display names, over
13
+ * the resolved framework names (validated identifiers, never input).
14
+ */
15
+ export declare function noExpiryKeyReportSql({ app, authz }: IdentitySchemaNames): string;
12
16
  /** One non-expiring key, as printed (no ids, no secrets). */
13
17
  export interface NonExpiringKey {
14
18
  /** The agent's label; `null` when the agent row no longer exists. */
@@ -24,7 +28,7 @@ export interface ReportQueryable {
24
28
  query(sql: string, params?: unknown[]): Promise<unknown>;
25
29
  }
26
30
  /** Run the report query and map the rows. Read-only. */
27
- export declare function findNonExpiringKeys(db: ReportQueryable): Promise<NonExpiringKey[]>;
31
+ export declare function findNonExpiringKeys(db: ReportQueryable, schemas: IdentitySchemaNames): Promise<NonExpiringKey[]>;
28
32
  /** Human-readable report text (one line per key, plus a summary line). */
29
33
  export declare function formatNonExpiringKeyReport(keys: readonly NonExpiringKey[]): string;
30
34
  /** The bin's behaviour, testable without a process: returns the exit code. */
@@ -35,5 +39,7 @@ export declare function runNonExpiringKeyReport(opts: {
35
39
  };
36
40
  readonly out: (text: string) => void;
37
41
  readonly err: (text: string) => void;
42
+ /** Resolved framework names; absent ⇒ resolved from `SHIELD_DB_NAMESPACE` once per run. */
43
+ readonly schemas?: IdentitySchemaNames;
38
44
  }): Promise<number>;
39
45
  //# sourceMappingURL=no-expiry-key-report.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"no-expiry-key-report.d.ts","sourceRoot":"","sources":["../../../src/features/service-account/no-expiry-key-report.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,iGAAiG;AACjG,eAAO,MAAM,wBAAwB,2mBAUP,CAAC;AAE/B,6DAA6D;AAC7D,MAAM,WAAW,cAAc;IAC7B,qEAAqE;IACrE,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,2EAA2E;IAC3E,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CACpC;AAED,wFAAwF;AACxF,MAAM,WAAW,eAAe;IAC9B,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAC1D;AAMD,wDAAwD;AACxD,wBAAsB,mBAAmB,CAAC,EAAE,EAAE,eAAe,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC,CASxF;AAED,0EAA0E;AAC1E,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,SAAS,cAAc,EAAE,GAAG,MAAM,CAalF;AAcD,8EAA8E;AAC9E,wBAAsB,uBAAuB,CAAC,IAAI,EAAE;IAClD,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC,QAAQ,CAAC,MAAM,EAAE,MAAM,eAAe,GAAG;QAAE,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;KAAE,CAAC;IAClE,QAAQ,CAAC,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,QAAQ,CAAC,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CACtC,GAAG,OAAO,CAAC,MAAM,CAAC,CAwBlB"}
1
+ {"version":3,"file":"no-expiry-key-report.d.ts","sourceRoot":"","sources":["../../../src/features/service-account/no-expiry-key-report.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAA2B,KAAK,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAEpF;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,EAAE,mBAAmB,GAAG,MAAM,CAYhF;AAED,6DAA6D;AAC7D,MAAM,WAAW,cAAc;IAC7B,qEAAqE;IACrE,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,2EAA2E;IAC3E,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CACpC;AAED,wFAAwF;AACxF,MAAM,WAAW,eAAe;IAC9B,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAC1D;AAMD,wDAAwD;AACxD,wBAAsB,mBAAmB,CACvC,EAAE,EAAE,eAAe,EACnB,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,cAAc,EAAE,CAAC,CAS3B;AAED,0EAA0E;AAC1E,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,SAAS,cAAc,EAAE,GAAG,MAAM,CAalF;AAcD,8EAA8E;AAC9E,wBAAsB,uBAAuB,CAAC,IAAI,EAAE;IAClD,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC,QAAQ,CAAC,MAAM,EAAE,MAAM,eAAe,GAAG;QAAE,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;KAAE,CAAC;IAClE,QAAQ,CAAC,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,QAAQ,CAAC,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,2FAA2F;IAC3F,QAAQ,CAAC,OAAO,CAAC,EAAE,mBAAmB,CAAC;CACxC,GAAG,OAAO,CAAC,MAAM,CAAC,CAyBlB"}
@@ -9,27 +9,33 @@
9
9
  * expiry. It prints labels and company names only: never a secret, a hash or a raw id.
10
10
  */
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.NO_EXPIRY_KEY_REPORT_SQL = void 0;
12
+ exports.noExpiryKeyReportSql = noExpiryKeyReportSql;
13
13
  exports.findNonExpiringKeys = findNonExpiringKeys;
14
14
  exports.formatNonExpiringKeyReport = formatNonExpiringKeyReport;
15
15
  exports.runNonExpiringKeyReport = runNonExpiringKeyReport;
16
- /** Read-only: the current unrevoked key of each agent that has no expiry, with display names. */
17
- exports.NO_EXPIRY_KEY_REPORT_SQL = `SELECT sa.sa_label AS label, c.c_name AS company,
16
+ const schema_js_1 = require("../../schema.js");
17
+ /**
18
+ * Read-only: the current unrevoked key of each agent that has no expiry, with display names, over
19
+ * the resolved framework names (validated identifiers, never input).
20
+ */
21
+ function noExpiryKeyReportSql({ app, authz }) {
22
+ return `SELECT sa.sa_label AS label, c.c_name AS company,
18
23
  sa.sa_status AS status, k.sak_version AS version, k.sak_created_at_ms AS issuedAtMs
19
- FROM shield_authz.service_account_key k
20
- LEFT JOIN shield_app.service_account sa ON sa.sa_id = k.sak_account_id
21
- LEFT JOIN shield_app.companies c ON c.c_uuid = k.sak_tenant_id
24
+ FROM ${authz}.service_account_key k
25
+ LEFT JOIN ${app}.service_account sa ON sa.sa_id = k.sak_account_id
26
+ LEFT JOIN ${app}.companies c ON c.c_uuid = k.sak_tenant_id
22
27
  WHERE k.sak_expires_at_ms IS NULL
23
28
  AND k.sak_revoked_at_ms IS NULL
24
29
  AND k.sak_version = (SELECT MAX(v.sak_version)
25
- FROM shield_authz.service_account_key v
30
+ FROM ${authz}.service_account_key v
26
31
  WHERE v.sak_account_id = k.sak_account_id)
27
32
  ORDER BY k.sak_created_at_ms`;
33
+ }
28
34
  const str = (v) => (v === null || v === undefined ? null : String(v));
29
35
  const num = (v) => v === null || v === undefined || !Number.isFinite(Number(v)) ? null : Number(v);
30
36
  /** Run the report query and map the rows. Read-only. */
31
- async function findNonExpiringKeys(db) {
32
- const rows = (await db.query(exports.NO_EXPIRY_KEY_REPORT_SQL));
37
+ async function findNonExpiringKeys(db, schemas) {
38
+ const rows = (await db.query(noExpiryKeyReportSql(schemas)));
33
39
  return rows.map((r) => ({
34
40
  label: str(r.label),
35
41
  company: str(r.company),
@@ -75,8 +81,9 @@ async function runNonExpiringKeyReport(opts) {
75
81
  }
76
82
  let db;
77
83
  try {
84
+ const schemas = opts.schemas ?? (0, schema_js_1.frameworkSchemasFromEnv)();
78
85
  db = opts.openDb();
79
- const keys = await findNonExpiringKeys(db);
86
+ const keys = await findNonExpiringKeys(db, schemas);
80
87
  opts.out(formatNonExpiringKeyReport(keys));
81
88
  return keys.length > 0 && opts.argv.includes('--fail-on-found') ? 1 : 0;
82
89
  }
@@ -12,6 +12,7 @@
12
12
  * stamped `sa_tenant_id` (from the session) on create — never client input.
13
13
  */
14
14
  import type { Pool } from 'mariadb';
15
+ import { type IdentitySchemaNames } from '../../schema.js';
15
16
  /** The status of an account's current key (no hash, no secret). Epoch-ms; `null` = not set. */
16
17
  export interface ServiceAccountKeyRow {
17
18
  readonly accountId: string;
@@ -50,7 +51,13 @@ export interface ScopeNodeOption {
50
51
  }
51
52
  export declare class ServiceAccountStore {
52
53
  private readonly pool;
53
- constructor(pool: Pool);
54
+ private readonly schemas;
55
+ /**
56
+ * @param schemas resolved framework names: accounts in `schemas.app`; guard's key table
57
+ * (`1710000000017-CreateServiceAccountKey.cjs`, read-only here) in `schemas.authz`. Absent ⇒
58
+ * resolved from the namespace, once, here.
59
+ */
60
+ constructor(pool: Pool, schemas?: IdentitySchemaNames);
54
61
  /** Roles by id (unknown ids are simply absent — the caller supplies a fallback label). */
55
62
  rolesByIds(ids: readonly string[]): Promise<RoleOption[]>;
56
63
  /** Every role in the catalog (ROOT's assignable set). */
@@ -1 +1 @@
1
- {"version":3,"file":"service-account.store.d.ts","sourceRoot":"","sources":["../../../src/features/service-account/service-account.store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAMpC,+FAA+F;AAC/F,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAC9B;AAUD,kGAAkG;AAClG,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;CAC1B;AAED,qGAAqG;AACrG,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,mBAAmB,EAAE,SAAS,MAAM,EAAE,CAAC;IAChD,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CACrC;AA2DD,kGAAkG;AAClG,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED,iGAAiG;AACjG,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CAClC;AAOD,qBAAa,mBAAmB;IAClB,OAAO,CAAC,QAAQ,CAAC,IAAI;gBAAJ,IAAI,EAAE,IAAI;IAMvC,0FAA0F;IACpF,UAAU,CAAC,GAAG,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC;IAU/D,yDAAyD;IACnD,QAAQ,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;IAQvC,uFAAuF;IACjF,UAAU,CAAC,GAAG,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;IAUpE,kEAAkE;IAC5D,QAAQ,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC;IAQ5C;;;;;OAKG;IACG,WAAW,CAAC,UAAU,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,oBAAoB,EAAE,CAAC;IAwBjF,2EAA2E;IACrE,IAAI,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,iBAAiB,EAAE,CAAC;IAS7D,kGAAkG;IAC5F,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC;IASjF;;;;OAIG;IACG,MAAM,CAAC,KAAK,EAAE;QAClB,EAAE,EAAE,MAAM,CAAC;QACX,QAAQ,EAAE,MAAM,CAAC;QACjB,KAAK,EAAE,MAAM,CAAC;QACd,mBAAmB,EAAE,SAAS,MAAM,EAAE,CAAC;QACvC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;QAC3B,MAAM,EAAE,MAAM,CAAC;QACf,SAAS,EAAE,MAAM,CAAC;QAClB,WAAW,EAAE,MAAM,CAAC;KACrB,GAAG,OAAO,CAAC,IAAI,CAAC;IAmBjB;;;;OAIG;IACG,MAAM,CACV,EAAE,EAAE,MAAM,EACV,KAAK,EAAE,YAAY,EACnB,KAAK,EAAE;QACL,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,mBAAmB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;QACxC,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;QAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB,EACD,WAAW,EAAE,MAAM;IACnB;;;;OAIG;IACH,mBAAmB,CAAC,EAAE,MAAM,GAAG,IAAI,GAClC,OAAO,CAAC,MAAM,CAAC;CAgCnB"}
1
+ {"version":3,"file":"service-account.store.d.ts","sourceRoot":"","sources":["../../../src/features/service-account/service-account.store.ts"],"names":[],"mappings":"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"}
@@ -1,9 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ServiceAccountStore = void 0;
4
- const APP = 'shield_app';
5
- /** Guard's key table lives here (`1710000000017-CreateServiceAccountKey.cjs`); read-only here. */
6
- const AUTHZ = 'shield_authz';
4
+ const schema_js_1 = require("../../schema.js");
7
5
  /** Normalize a JSON-array column (driver returns array OR string) → string[]. Fail-safe to []. */
8
6
  function jsonArray(v) {
9
7
  const arr = Array.isArray(v)
@@ -53,8 +51,15 @@ function uniqueIds(ids) {
53
51
  }
54
52
  class ServiceAccountStore {
55
53
  pool;
56
- constructor(pool) {
54
+ schemas;
55
+ /**
56
+ * @param schemas resolved framework names: accounts in `schemas.app`; guard's key table
57
+ * (`1710000000017-CreateServiceAccountKey.cjs`, read-only here) in `schemas.authz`. Absent ⇒
58
+ * resolved from the namespace, once, here.
59
+ */
60
+ constructor(pool, schemas = (0, schema_js_1.frameworkSchemasFromEnv)()) {
57
61
  this.pool = pool;
62
+ this.schemas = schemas;
58
63
  }
59
64
  // ── directory reads (names for the picker, the view labels and the ceiling messages) ─────
60
65
  // Read-only lookups over the global role catalog + the company tree (`shield_app.roles`,
@@ -64,12 +69,12 @@ class ServiceAccountStore {
64
69
  const u = uniqueIds(ids);
65
70
  if (u.length === 0)
66
71
  return [];
67
- const rows = (await this.pool.query(`SELECT r_uuid AS id, r_name AS name FROM \`${APP}\`.\`roles\` WHERE r_uuid IN (${u.map(() => '?').join(', ')}) ORDER BY r_name`, u));
72
+ const rows = (await this.pool.query(`SELECT r_uuid AS id, r_name AS name FROM \`${this.schemas.app}\`.\`roles\` WHERE r_uuid IN (${u.map(() => '?').join(', ')}) ORDER BY r_name`, u));
68
73
  return rows.map((r) => ({ id: r.id, name: r.name }));
69
74
  }
70
75
  /** Every role in the catalog (ROOT's assignable set). */
71
76
  async allRoles() {
72
- const rows = (await this.pool.query(`SELECT r_uuid AS id, r_name AS name FROM \`${APP}\`.\`roles\` ORDER BY r_name`, []));
77
+ const rows = (await this.pool.query(`SELECT r_uuid AS id, r_name AS name FROM \`${this.schemas.app}\`.\`roles\` ORDER BY r_name`, []));
73
78
  return rows.map((r) => ({ id: r.id, name: r.name }));
74
79
  }
75
80
  /** Companies (scope nodes) by id, with their parent handle. Unknown ids are absent. */
@@ -77,12 +82,12 @@ class ServiceAccountStore {
77
82
  const u = uniqueIds(ids);
78
83
  if (u.length === 0)
79
84
  return [];
80
- const rows = (await this.pool.query(`SELECT c_uuid AS id, c_name AS name, c_parent_uuid AS parentId FROM \`${APP}\`.\`companies\` WHERE c_uuid IN (${u.map(() => '?').join(', ')}) ORDER BY c_name`, u));
85
+ const rows = (await this.pool.query(`SELECT c_uuid AS id, c_name AS name, c_parent_uuid AS parentId FROM \`${this.schemas.app}\`.\`companies\` WHERE c_uuid IN (${u.map(() => '?').join(', ')}) ORDER BY c_name`, u));
81
86
  return rows.map((r) => ({ id: r.id, name: r.name, parentId: r.parentId ?? null }));
82
87
  }
83
88
  /** Every company (ROOT's assignable scope — root reaches all). */
84
89
  async allNodes() {
85
- const rows = (await this.pool.query(`SELECT c_uuid AS id, c_name AS name, c_parent_uuid AS parentId FROM \`${APP}\`.\`companies\` ORDER BY c_name`, []));
90
+ const rows = (await this.pool.query(`SELECT c_uuid AS id, c_name AS name, c_parent_uuid AS parentId FROM \`${this.schemas.app}\`.\`companies\` ORDER BY c_name`, []));
86
91
  return rows.map((r) => ({ id: r.id, name: r.name, parentId: r.parentId ?? null }));
87
92
  }
88
93
  /**
@@ -97,9 +102,9 @@ class ServiceAccountStore {
97
102
  return [];
98
103
  const rows = (await this.pool.query(`SELECT k.sak_account_id, k.sak_version, k.sak_expires_at_ms, k.sak_revoked_at_ms,
99
104
  k.sak_created_at_ms
100
- FROM \`${AUTHZ}\`.\`service_account_key\` k
105
+ FROM \`${this.schemas.authz}\`.\`service_account_key\` k
101
106
  JOIN (SELECT sak_account_id, MAX(sak_version) AS v
102
- FROM \`${AUTHZ}\`.\`service_account_key\`
107
+ FROM \`${this.schemas.authz}\`.\`service_account_key\`
103
108
  WHERE sak_account_id IN (${u.map(() => '?').join(', ')})
104
109
  GROUP BY sak_account_id) m
105
110
  ON m.sak_account_id = k.sak_account_id AND m.v = k.sak_version`, u));
@@ -115,13 +120,13 @@ class ServiceAccountStore {
115
120
  /** List the caller's own-tenant accounts (newest first). Root sees all. */
116
121
  async list(scope) {
117
122
  const t = tenantScope(scope);
118
- const rows = (await this.pool.query(`SELECT ${COLS} FROM \`${APP}\`.\`service_account\` WHERE 1=1${t.sql} ORDER BY sa_created_at_ms DESC`, t.params));
123
+ const rows = (await this.pool.query(`SELECT ${COLS} FROM \`${this.schemas.app}\`.\`service_account\` WHERE 1=1${t.sql} ORDER BY sa_created_at_ms DESC`, t.params));
119
124
  return rows.map(toRow);
120
125
  }
121
126
  /** Fetch one account BY id, scoped to the caller's subtree. Cross-tenant/unknown → null (404). */
122
127
  async getById(id, scope) {
123
128
  const t = tenantScope(scope);
124
- const rows = (await this.pool.query(`SELECT ${COLS} FROM \`${APP}\`.\`service_account\` WHERE sa_id = ?${t.sql} LIMIT 1`, [id, ...t.params]));
129
+ const rows = (await this.pool.query(`SELECT ${COLS} FROM \`${this.schemas.app}\`.\`service_account\` WHERE sa_id = ?${t.sql} LIMIT 1`, [id, ...t.params]));
125
130
  return rows[0] ? toRow(rows[0]) : null;
126
131
  }
127
132
  /**
@@ -130,7 +135,7 @@ class ServiceAccountStore {
130
135
  * per create); the id is unique by construction.
131
136
  */
132
137
  async insert(input) {
133
- await this.pool.query(`INSERT INTO \`${APP}\`.\`service_account\`
138
+ await this.pool.query(`INSERT INTO \`${this.schemas.app}\`.\`service_account\`
134
139
  (sa_id, sa_tenant_id, sa_label, sa_scope_subtree, sa_role_ids, sa_status,
135
140
  sa_created_by, sa_created_at_ms, sa_updated_at_ms)
136
141
  VALUES (?, ?, ?, ?, ?, ?, ?, ?, NULL)`, [
@@ -180,7 +185,7 @@ class ServiceAccountStore {
180
185
  const t = tenantScope(scope);
181
186
  const guard = expectedUpdatedAtMs !== undefined ? ' AND sa_updated_at_ms <=> ?' : '';
182
187
  const guardParams = expectedUpdatedAtMs !== undefined ? [expectedUpdatedAtMs] : [];
183
- const res = (await this.pool.query(`UPDATE \`${APP}\`.\`service_account\` SET ${sets.join(', ')} WHERE sa_id = ?${t.sql}${guard}`, [...params, id, ...t.params, ...guardParams]));
188
+ const res = (await this.pool.query(`UPDATE \`${this.schemas.app}\`.\`service_account\` SET ${sets.join(', ')} WHERE sa_id = ?${t.sql}${guard}`, [...params, id, ...t.params, ...guardParams]));
184
189
  return res.affectedRows ?? 0;
185
190
  }
186
191
  }
@@ -1,5 +1,5 @@
1
1
  import { RecordsService, type RecordId } from '@astram/engine';
2
- import type { Principal } from '@astram/core';
2
+ import type { FrameworkSchemas, Principal } from '@astram/core';
3
3
  import { type EmailAddressChanger, type EmailSender, type ResetTokenStore, type SessionSweeper } from '@astram/guard';
4
4
  import { type PostingVersionBump } from '../membership/posting-version-bump.js';
5
5
  import { type ListParams } from '../shared/list-query.js';
@@ -38,9 +38,13 @@ export declare class UserService {
38
38
  private readonly versionBump?;
39
39
  private readonly emailAddresses?;
40
40
  private readonly logger;
41
- /** The engine's audit sink, used on the email helper's transaction (no pool of its own). */
41
+ /**
42
+ * The engine's audit sink, used on the email helper's transaction (no pool of its own), on the
43
+ * audit database forRoot resolved (`IDENTITY_FRAMEWORK_SCHEMAS`); absent (a hand-built
44
+ * service) ⇒ the sink resolves `SHIELD_DB_NAMESPACE` itself.
45
+ */
42
46
  private readonly emailAudit;
43
- constructor(records: RecordsService, ceiling: GrantCeiling, resetTokens?: (ResetTokenStore | null) | undefined, emailSender?: (EmailSender | null) | undefined, sessions?: (SessionSweeper | null) | undefined, versionBump?: (PostingVersionBump | null) | undefined, emailAddresses?: (EmailAddressChanger | null) | undefined);
47
+ constructor(records: RecordsService, ceiling: GrantCeiling, resetTokens?: (ResetTokenStore | null) | undefined, emailSender?: (EmailSender | null) | undefined, sessions?: (SessionSweeper | null) | undefined, versionBump?: (PostingVersionBump | null) | undefined, emailAddresses?: (EmailAddressChanger | null) | undefined, schemas?: FrameworkSchemas | null);
44
48
  /**
45
49
  * Create a user. With `companyUuid`, the user is created AND attached (one active membership) in
46
50
  * ONE transaction — the onboarding path for a non-root admin, whose membership create is checked
@@ -1 +1 @@
1
- {"version":3,"file":"user.service.d.ts","sourceRoot":"","sources":["../../../src/features/user/user.service.ts"],"names":[],"mappings":"AACA,OAAO,EAAoB,cAAc,EAAE,KAAK,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AACjF,OAAO,KAAK,EAAc,SAAS,EAAE,MAAM,cAAc,CAAC;AAC1D,OAAO,EAOL,KAAK,mBAAmB,EAExB,KAAK,WAAW,EAChB,KAAK,eAAe,EACpB,KAAK,cAAc,EACpB,MAAM,eAAe,CAAC;AACvB,OAAO,EAEL,KAAK,kBAAkB,EACxB,MAAM,uCAAuC,CAAC;AAC/C,OAAO,EAAkB,KAAK,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAC1E,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAqCzD,4EAA4E;AAC5E,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,qBACa,WAAW;IAMpB,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,OAAO;IAGxB,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC;IACY,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC;IAMtE,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC;IAK1B,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC;IAI7B,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC;IAzBlC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAgC;IACvD,4FAA4F;IAC5F,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA4B;gBAGpC,OAAO,EAAE,cAAc,EACvB,OAAO,EAAE,YAAY,EAGrB,WAAW,CAAC,GAAE,eAAe,GAAG,IAAI,aAAA,EACK,WAAW,CAAC,GAAE,WAAW,GAAG,IAAI,aAAA,EAMzE,QAAQ,CAAC,GAAE,cAAc,GAAG,IAAI,aAAA,EAKhC,WAAW,CAAC,GAAE,kBAAkB,GAAG,IAAI,aAAA,EAIvC,cAAc,CAAC,GAAE,mBAAmB,GAAG,IAAI,aAAA;IAG9D;;;;;;;;;;OAUG;IACG,UAAU,CACd,KAAK,EAAE,SAAS,EAChB,KAAK,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;KAAE,GACxF,OAAO,CAAC,QAAQ,CAAC;IAsBpB,uEAAuE;IACvE,SAAS,CAAC,MAAM,CAAC,EAAE,UAAU;IAI7B,0BAA0B;IAC1B,OAAO,CAAC,IAAI,EAAE,MAAM;IAIpB,mGAAmG;IAC7F,UAAU,CAAC,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;IAsCjF;;;;;;OAMG;YACW,WAAW;IAyBzB,uFAAuF;IACvF,OAAO,CAAC,gBAAgB;IA8BxB;;;;;;;;;OASG;YACW,iBAAiB;IAY/B,uDAAuD;IACjD,UAAU,CAAC,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAO/D,6FAA6F;YAC/E,kBAAkB;CAkBjC"}
1
+ {"version":3,"file":"user.service.d.ts","sourceRoot":"","sources":["../../../src/features/user/user.service.ts"],"names":[],"mappings":"AACA,OAAO,EAAoB,cAAc,EAAE,KAAK,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AACjF,OAAO,KAAK,EAAc,gBAAgB,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAC5E,OAAO,EAOL,KAAK,mBAAmB,EAExB,KAAK,WAAW,EAChB,KAAK,eAAe,EACpB,KAAK,cAAc,EACpB,MAAM,eAAe,CAAC;AACvB,OAAO,EAEL,KAAK,kBAAkB,EACxB,MAAM,uCAAuC,CAAC;AAC/C,OAAO,EAAkB,KAAK,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAC1E,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAsCzD,4EAA4E;AAC5E,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,qBACa,WAAW;IAUpB,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,OAAO;IAGxB,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC;IACY,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC;IAMtE,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC;IAK1B,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC;IAI7B,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC;IA7BlC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAgC;IACvD;;;;OAIG;IACH,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAmB;gBAG3B,OAAO,EAAE,cAAc,EACvB,OAAO,EAAE,YAAY,EAGrB,WAAW,CAAC,GAAE,eAAe,GAAG,IAAI,aAAA,EACK,WAAW,CAAC,GAAE,WAAW,GAAG,IAAI,aAAA,EAMzE,QAAQ,CAAC,GAAE,cAAc,GAAG,IAAI,aAAA,EAKhC,WAAW,CAAC,GAAE,kBAAkB,GAAG,IAAI,aAAA,EAIvC,cAAc,CAAC,GAAE,mBAAmB,GAAG,IAAI,aAAA,EAI5D,OAAO,CAAC,EAAE,gBAAgB,GAAG,IAAI;IAKnC;;;;;;;;;;OAUG;IACG,UAAU,CACd,KAAK,EAAE,SAAS,EAChB,KAAK,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;KAAE,GACxF,OAAO,CAAC,QAAQ,CAAC;IAsBpB,uEAAuE;IACvE,SAAS,CAAC,MAAM,CAAC,EAAE,UAAU;IAI7B,0BAA0B;IAC1B,OAAO,CAAC,IAAI,EAAE,MAAM;IAIpB,mGAAmG;IAC7F,UAAU,CAAC,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;IAsCjF;;;;;;OAMG;YACW,WAAW;IAyBzB,uFAAuF;IACvF,OAAO,CAAC,gBAAgB;IA8BxB;;;;;;;;;OASG;YACW,iBAAiB;IAY/B,uDAAuD;IACjD,UAAU,CAAC,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAO/D,6FAA6F;YAC/E,kBAAkB;CAkBjC"}
@@ -22,6 +22,7 @@ const list_query_js_1 = require("../shared/list-query.js");
22
22
  const grant_ceiling_js_1 = require("../authz/grant-ceiling.js");
23
23
  const identity_errors_js_1 = require("../shared/identity-errors.js");
24
24
  const email_address_changer_token_js_1 = require("./email-address-changer.token.js");
25
+ const framework_schemas_token_js_1 = require("../framework-schemas.token.js");
25
26
  /**
26
27
  * KI #87: `users` has two unique keys besides the PK, `IDX_users_username` (migration 001) and
27
28
  * `uq_users_email` (021, `utf8mb4_unicode_ci`: folds case, accents, width, trailing spaces). The
@@ -77,9 +78,13 @@ let UserService = UserService_1 = class UserService {
77
78
  versionBump;
78
79
  emailAddresses;
79
80
  logger = new common_1.Logger(UserService_1.name);
80
- /** The engine's audit sink, used on the email helper's transaction (no pool of its own). */
81
- emailAudit = new engine_1.MariaDbAuditSink({});
82
- constructor(records, ceiling, resetTokens, emailSender, sessions, versionBump, emailAddresses) {
81
+ /**
82
+ * The engine's audit sink, used on the email helper's transaction (no pool of its own), on the
83
+ * audit database forRoot resolved (`IDENTITY_FRAMEWORK_SCHEMAS`); absent (a hand-built
84
+ * service) ⇒ the sink resolves `SHIELD_DB_NAMESPACE` itself.
85
+ */
86
+ emailAudit;
87
+ constructor(records, ceiling, resetTokens, emailSender, sessions, versionBump, emailAddresses, schemas) {
83
88
  this.records = records;
84
89
  this.ceiling = ceiling;
85
90
  this.resetTokens = resetTokens;
@@ -87,6 +92,7 @@ let UserService = UserService_1 = class UserService {
87
92
  this.sessions = sessions;
88
93
  this.versionBump = versionBump;
89
94
  this.emailAddresses = emailAddresses;
95
+ this.emailAudit = new engine_1.MariaDbAuditSink(schemas ? { schema: schemas.audit } : {});
90
96
  }
91
97
  /**
92
98
  * Create a user. With `companyUuid`, the user is created AND attached (one active membership) in
@@ -288,6 +294,8 @@ exports.UserService = UserService = UserService_1 = __decorate([
288
294
  __param(5, (0, common_1.Inject)(posting_version_bump_js_1.POSTING_VERSION_BUMP)),
289
295
  __param(6, (0, common_1.Optional)()),
290
296
  __param(6, (0, common_1.Inject)(email_address_changer_token_js_1.IDENTITY_EMAIL_ADDRESS_CHANGER)),
297
+ __param(7, (0, common_1.Optional)()),
298
+ __param(7, (0, common_1.Inject)(framework_schemas_token_js_1.IDENTITY_FRAMEWORK_SCHEMAS)),
291
299
  __metadata("design:paramtypes", [engine_1.RecordsService,
292
- grant_ceiling_js_1.GrantCeiling, Object, Object, Object, Object, Object])
300
+ grant_ceiling_js_1.GrantCeiling, Object, Object, Object, Object, Object, Object])
293
301
  ], UserService);
@@ -1 +1 @@
1
- {"version":3,"file":"record-share.object.d.ts","sourceRoot":"","sources":["../src/record-share.object.ts"],"names":[],"mappings":"AAMA;;;;;;;;;;;;;;;;;GAiBG;AACH,qBASa,WAAW;IAEtB,IAAI,EAAG,MAAM,CAAC;IAGd,UAAU,EAAG,MAAM,CAAC;IAGpB,UAAU,EAAG,MAAM,CAAC;CACrB"}
1
+ {"version":3,"file":"record-share.object.d.ts","sourceRoot":"","sources":["../src/record-share.object.ts"],"names":[],"mappings":"AAOA;;;;;;;;;;;;;;;;;GAiBG;AACH,qBASa,WAAW;IAEtB,IAAI,EAAG,MAAM,CAAC;IAGd,UAAU,EAAG,MAAM,CAAC;IAGpB,UAAU,EAAG,MAAM,CAAC;CACrB"}
@@ -12,8 +12,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.RecordShare = void 0;
13
13
  const engine_1 = require("@astram/engine");
14
14
  const guard_1 = require("@astram/guard");
15
- /** The physical schema `record_share` lives in (migration 1710000000014). */
16
- const SCHEMA = 'shield_authz';
15
+ /** The authz-database token `record_share` lives in (migration 1710000000014); the engine
16
+ * resolves it at registration (ADR-0037). */
17
+ const SCHEMA = engine_1.FRAMEWORK_SCHEMA.authz;
17
18
  /**
18
19
  * `record_share` — an AUTHORITY-ONLY @ObjectType, never CRUD'd through the RecordEngine pipe
19
20
  * (list-scoping engine Phase 6, §9.2). Its sole purpose is to give `record_share` an entry in the
package/dist/schema.d.ts CHANGED
@@ -1,3 +1,16 @@
1
- /** The physical schema every identity table lives in (single-source). */
2
- export declare const SCHEMA = "shield_app";
1
+ import { type FrameworkSchemas } from '@astram/core';
2
+ /**
3
+ * The schema every identity table declares (single-source): the app-database token, resolved by
4
+ * the engine at registration to `<namespace>_app` (configurable-framework-db, ADR-0037). It is
5
+ * never a database name: SQL built outside the engine uses {@link IdentitySchemaNames}.
6
+ */
7
+ export declare const SCHEMA: "{{framework_schema:app}}";
8
+ /** The resolved framework database names identity SQL needs (`FrameworkSchemas` fits). */
9
+ export type IdentitySchemaNames = Pick<FrameworkSchemas, 'app' | 'authz'>;
10
+ /**
11
+ * The framework database names from `SHIELD_DB_NAMESPACE` (unset ⇒ `shield_*`), for a class built
12
+ * without explicit names. Call at construction (boot) only, never per request; an invalid
13
+ * namespace throws (fail closed). `IdentityFeatureModule.forRoot` always passes its names.
14
+ */
15
+ export declare function frameworkSchemasFromEnv(): FrameworkSchemas;
3
16
  //# sourceMappingURL=schema.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAAA,yEAAyE;AACzE,eAAO,MAAM,MAAM,eAAe,CAAC"}
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAA2B,KAAK,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAG9E;;;;GAIG;AACH,eAAO,MAAM,MAAM,4BAAuB,CAAC;AAE3C,0FAA0F;AAC1F,MAAM,MAAM,mBAAmB,GAAG,IAAI,CAAC,gBAAgB,EAAE,KAAK,GAAG,OAAO,CAAC,CAAC;AAE1E;;;;GAIG;AACH,wBAAgB,uBAAuB,IAAI,gBAAgB,CAE1D"}
package/dist/schema.js CHANGED
@@ -1,5 +1,20 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.SCHEMA = void 0;
4
- /** The physical schema every identity table lives in (single-source). */
5
- exports.SCHEMA = 'shield_app';
4
+ exports.frameworkSchemasFromEnv = frameworkSchemasFromEnv;
5
+ const core_1 = require("@astram/core");
6
+ const engine_1 = require("@astram/engine");
7
+ /**
8
+ * The schema every identity table declares (single-source): the app-database token, resolved by
9
+ * the engine at registration to `<namespace>_app` (configurable-framework-db, ADR-0037). It is
10
+ * never a database name: SQL built outside the engine uses {@link IdentitySchemaNames}.
11
+ */
12
+ exports.SCHEMA = engine_1.FRAMEWORK_SCHEMA.app;
13
+ /**
14
+ * The framework database names from `SHIELD_DB_NAMESPACE` (unset ⇒ `shield_*`), for a class built
15
+ * without explicit names. Call at construction (boot) only, never per request; an invalid
16
+ * namespace throws (fail closed). `IdentityFeatureModule.forRoot` always passes its names.
17
+ */
18
+ function frameworkSchemasFromEnv() {
19
+ return (0, core_1.resolveFrameworkSchemas)(process.env);
20
+ }