@astram/identity 0.11.0 → 0.12.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.
- package/dist/cross-tenant-grant.object.d.ts.map +1 -1
- package/dist/cross-tenant-grant.object.js +3 -2
- package/dist/features/audit/directory-label-resolver.d.ts +4 -1
- package/dist/features/audit/directory-label-resolver.d.ts.map +1 -1
- package/dist/features/audit/directory-label-resolver.js +8 -5
- package/dist/features/audit/mariadb-audit-reader.d.ts +5 -1
- package/dist/features/audit/mariadb-audit-reader.d.ts.map +1 -1
- package/dist/features/audit/mariadb-audit-reader.js +10 -2
- package/dist/features/authz/access-bundle-reconcile.job.d.ts +4 -1
- package/dist/features/authz/access-bundle-reconcile.job.d.ts.map +1 -1
- package/dist/features/authz/access-bundle-reconcile.job.js +7 -4
- package/dist/features/authz/access-bundle-store.d.ts +4 -1
- package/dist/features/authz/access-bundle-store.d.ts.map +1 -1
- package/dist/features/authz/access-bundle-store.js +19 -16
- package/dist/features/authz/catalog-reconcile.job.d.ts +3 -1
- package/dist/features/authz/catalog-reconcile.job.d.ts.map +1 -1
- package/dist/features/authz/catalog-reconcile.job.js +3 -2
- package/dist/features/authz/db-permission-facts.adapter.d.ts +9 -3
- package/dist/features/authz/db-permission-facts.adapter.d.ts.map +1 -1
- package/dist/features/authz/db-permission-facts.adapter.js +22 -16
- package/dist/features/authz/grant-admin.service.d.ts +4 -1
- package/dist/features/authz/grant-admin.service.d.ts.map +1 -1
- package/dist/features/authz/grant-admin.service.js +32 -37
- package/dist/features/authz/grant-ceiling.d.ts +6 -1
- package/dist/features/authz/grant-ceiling.d.ts.map +1 -1
- package/dist/features/authz/grant-ceiling.js +19 -16
- package/dist/features/authz/mariadb-catalog-store.d.ts +4 -1
- package/dist/features/authz/mariadb-catalog-store.d.ts.map +1 -1
- package/dist/features/authz/mariadb-catalog-store.js +10 -7
- package/dist/features/authz/permission-version.bumper.d.ts +6 -1
- package/dist/features/authz/permission-version.bumper.d.ts.map +1 -1
- package/dist/features/authz/permission-version.bumper.js +13 -11
- package/dist/features/authz/record-authorization.d.ts +8 -2
- package/dist/features/authz/record-authorization.d.ts.map +1 -1
- package/dist/features/authz/record-authorization.js +8 -4
- package/dist/features/authz/role-binding.d.ts +3 -2
- package/dist/features/authz/role-binding.d.ts.map +1 -1
- package/dist/features/authz/role-binding.js +7 -8
- package/dist/features/company/company-hierarchy.service.d.ts +6 -1
- package/dist/features/company/company-hierarchy.service.d.ts.map +1 -1
- package/dist/features/company/company-hierarchy.service.js +17 -16
- package/dist/features/cross-tenant/cross-tenant-grant-read.service.d.ts +5 -1
- package/dist/features/cross-tenant/cross-tenant-grant-read.service.d.ts.map +1 -1
- package/dist/features/cross-tenant/cross-tenant-grant-read.service.js +18 -14
- package/dist/features/framework-schemas.token.d.ts +8 -0
- package/dist/features/framework-schemas.token.d.ts.map +1 -0
- package/dist/features/framework-schemas.token.js +10 -0
- package/dist/features/identity-feature.module.d.ts +29 -1
- package/dist/features/identity-feature.module.d.ts.map +1 -1
- package/dist/features/identity-feature.module.js +134 -33
- package/dist/features/membership/membership-checker.d.ts +7 -1
- package/dist/features/membership/membership-checker.d.ts.map +1 -1
- package/dist/features/membership/membership-checker.js +9 -4
- package/dist/features/migration-ledger-check.d.ts +15 -0
- package/dist/features/migration-ledger-check.d.ts.map +1 -0
- package/dist/features/migration-ledger-check.js +26 -0
- package/dist/features/scope/scope-closure.service.d.ts +8 -1
- package/dist/features/scope/scope-closure.service.d.ts.map +1 -1
- package/dist/features/scope/scope-closure.service.js +22 -19
- package/dist/features/scope/scope-subtree.resolver.d.ts +7 -1
- package/dist/features/scope/scope-subtree.resolver.d.ts.map +1 -1
- package/dist/features/scope/scope-subtree.resolver.js +9 -4
- package/dist/features/service-account/lock-service-accounts.d.ts +3 -1
- package/dist/features/service-account/lock-service-accounts.d.ts.map +1 -1
- package/dist/features/service-account/lock-service-accounts.js +4 -4
- package/dist/features/service-account/no-expiry-key-report.d.ts +9 -3
- package/dist/features/service-account/no-expiry-key-report.d.ts.map +1 -1
- package/dist/features/service-account/no-expiry-key-report.js +17 -10
- package/dist/features/service-account/service-account.store.d.ts +8 -1
- package/dist/features/service-account/service-account.store.d.ts.map +1 -1
- package/dist/features/service-account/service-account.store.js +19 -14
- package/dist/features/user/user.service.d.ts +7 -3
- package/dist/features/user/user.service.d.ts.map +1 -1
- package/dist/features/user/user.service.js +12 -4
- package/dist/record-share.object.d.ts.map +1 -1
- package/dist/record-share.object.js +3 -2
- package/dist/schema.d.ts +15 -2
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +17 -2
- package/migrations/1710000000001-CreateIdentityOrgModel.cjs +14 -4
- package/migrations/1710000000002-CreateMembershipAndPostings.cjs +14 -4
- package/migrations/1710000000003-CreateIdentityCredential.cjs +14 -4
- package/migrations/1710000000004-CreateSessionTables.cjs +14 -4
- package/migrations/1710000000005-CreateMfaAndTokenSurface.cjs +14 -4
- package/migrations/1710000000010-CreateAuditLog.cjs +14 -4
- package/migrations/1710000000011-CreateCrossTenantGrant.cjs +15 -4
- package/migrations/1710000000012-SeedCrossTenantGrantPerms.cjs +15 -4
- package/migrations/1710000000013-CreateSharedResource.cjs +14 -4
- package/migrations/1710000000018-CreateServiceAccount.cjs +13 -4
- package/migrations/1710000000019-AddSessionMustReenroll.cjs +14 -4
- package/migrations/1710000000020-CreateEmailChangeToken.cjs +15 -5
- package/migrations/1710000000021-AddUsersEmailUniqueIndex.cjs +24 -13
- package/migrations/1710000000022-CreateStoredFile.cjs +14 -4
- package/migrations/1710000000099-SeedDevIdentity.cjs +14 -6
- package/migrations/1710000000100-SeedDevTenantBAndRoot.cjs +14 -6
- package/package.json +4 -4
|
@@ -23,9 +23,17 @@
|
|
|
23
23
|
* Idempotent (CREATE TABLE IF NOT EXISTS).
|
|
24
24
|
*/
|
|
25
25
|
|
|
26
|
-
const
|
|
26
|
+
const { frameworkSchemasForMigration } = require('@astram/core');
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
// Database names come from `ctx.schemas` (SHIELD_DB_NAMESPACE, ADR-0037); under an older
|
|
29
|
+
// @astram/migrate without it, the default names apply only while the namespace is unset.
|
|
30
|
+
// replacesChecksums: every checksum this file had in a published release (git release tags), so
|
|
31
|
+
// an existing ledger row is accepted and updated, not reported as drift (ADR-0037).
|
|
32
|
+
const replacesChecksums = ['882c6700cb00a977a1dc5038de0a1e107a279a28312a44359f5c8f8efa595c83'];
|
|
33
|
+
|
|
34
|
+
async function up(ctx) {
|
|
35
|
+
const { query } = ctx;
|
|
36
|
+
const SCHEMA = frameworkSchemasForMigration(ctx, process.env).identity;
|
|
29
37
|
// session — the authoritative session record (written at login; read/updated
|
|
30
38
|
// at refresh + revocation). s_absolute_expires_at_ms anchors the ADR-0015
|
|
31
39
|
// absolute cap (from login, never reset). Status ∈ active|rotated|revoked|expired.
|
|
@@ -70,10 +78,12 @@ async function up({ query }) {
|
|
|
70
78
|
);
|
|
71
79
|
}
|
|
72
80
|
|
|
73
|
-
async function down(
|
|
81
|
+
async function down(ctx) {
|
|
82
|
+
const { query } = ctx;
|
|
83
|
+
const SCHEMA = frameworkSchemasForMigration(ctx, process.env).identity;
|
|
74
84
|
// Child before parent — refresh_token FK-references session.
|
|
75
85
|
await query(`DROP TABLE IF EXISTS \`${SCHEMA}\`.\`refresh_token\``);
|
|
76
86
|
await query(`DROP TABLE IF EXISTS \`${SCHEMA}\`.\`session\``);
|
|
77
87
|
}
|
|
78
88
|
|
|
79
|
-
module.exports = { up, down };
|
|
89
|
+
module.exports = { up, down, replacesChecksums };
|
|
@@ -39,9 +39,17 @@
|
|
|
39
39
|
* Idempotent (CREATE TABLE IF NOT EXISTS).
|
|
40
40
|
*/
|
|
41
41
|
|
|
42
|
-
const
|
|
42
|
+
const { frameworkSchemasForMigration } = require('@astram/core');
|
|
43
43
|
|
|
44
|
-
|
|
44
|
+
// Database names come from `ctx.schemas` (SHIELD_DB_NAMESPACE, ADR-0037); under an older
|
|
45
|
+
// @astram/migrate without it, the default names apply only while the namespace is unset.
|
|
46
|
+
// replacesChecksums: every checksum this file had in a published release (git release tags), so
|
|
47
|
+
// an existing ledger row is accepted and updated, not reported as drift (ADR-0037).
|
|
48
|
+
const replacesChecksums = ['47015938e94c86373d0947828f6cb5019aff90d414391eccb8c52b40c81d7612'];
|
|
49
|
+
|
|
50
|
+
async function up(ctx) {
|
|
51
|
+
const { query } = ctx;
|
|
52
|
+
const SCHEMA = frameworkSchemasForMigration(ctx, process.env).identity;
|
|
45
53
|
await query(
|
|
46
54
|
`CREATE TABLE IF NOT EXISTS \`${SCHEMA}\`.\`mfa_device\` (
|
|
47
55
|
md_id VARCHAR(36) NOT NULL,
|
|
@@ -79,10 +87,12 @@ async function up({ query }) {
|
|
|
79
87
|
);
|
|
80
88
|
}
|
|
81
89
|
|
|
82
|
-
async function down(
|
|
90
|
+
async function down(ctx) {
|
|
91
|
+
const { query } = ctx;
|
|
92
|
+
const SCHEMA = frameworkSchemasForMigration(ctx, process.env).identity;
|
|
83
93
|
for (const t of ['mfa_recovery_code', 'password_reset_token', 'mfa_device']) {
|
|
84
94
|
await query(`DROP TABLE IF EXISTS \`${SCHEMA}\`.\`${t}\``);
|
|
85
95
|
}
|
|
86
96
|
}
|
|
87
97
|
|
|
88
|
-
module.exports = { up, down };
|
|
98
|
+
module.exports = { up, down, replacesChecksums };
|
|
@@ -13,9 +13,17 @@
|
|
|
13
13
|
* server/migrations/1720000000002-CreateAuditLog.js. Idempotent.
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
|
-
const
|
|
16
|
+
const { frameworkSchemasForMigration } = require('@astram/core');
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
// Database names come from `ctx.schemas` (SHIELD_DB_NAMESPACE, ADR-0037); under an older
|
|
19
|
+
// @astram/migrate without it, the default names apply only while the namespace is unset.
|
|
20
|
+
// replacesChecksums: every checksum this file had in a published release (git release tags), so
|
|
21
|
+
// an existing ledger row is accepted and updated, not reported as drift (ADR-0037).
|
|
22
|
+
const replacesChecksums = ['da5fa4187db370cf9f70d97a94e27e54055bcb5bf9e8cfd6305a9bcfef748703'];
|
|
23
|
+
|
|
24
|
+
async function up(ctx) {
|
|
25
|
+
const { query } = ctx;
|
|
26
|
+
const SCHEMA = frameworkSchemasForMigration(ctx, process.env).audit;
|
|
19
27
|
await query(`CREATE SCHEMA IF NOT EXISTS \`${SCHEMA}\` DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci`);
|
|
20
28
|
|
|
21
29
|
await query(`CREATE TABLE IF NOT EXISTS \`${SCHEMA}\`.\`audit_log\` (
|
|
@@ -35,8 +43,10 @@ async function up({ query }) {
|
|
|
35
43
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci`);
|
|
36
44
|
}
|
|
37
45
|
|
|
38
|
-
async function down(
|
|
46
|
+
async function down(ctx) {
|
|
47
|
+
const { query } = ctx;
|
|
48
|
+
const SCHEMA = frameworkSchemasForMigration(ctx, process.env).audit;
|
|
39
49
|
await query(`DROP TABLE IF EXISTS \`${SCHEMA}\`.\`audit_log\``);
|
|
40
50
|
}
|
|
41
51
|
|
|
42
|
-
module.exports = { up, down };
|
|
52
|
+
module.exports = { up, down, replacesChecksums };
|
|
@@ -28,10 +28,19 @@
|
|
|
28
28
|
* table. Timestamp 1710000000011 sorts after audit (...010) and before the dev seed (...099).
|
|
29
29
|
*/
|
|
30
30
|
|
|
31
|
-
const
|
|
31
|
+
const { frameworkSchemasForMigration } = require('@astram/core');
|
|
32
|
+
|
|
33
|
+
// Database names come from `ctx.schemas` (SHIELD_DB_NAMESPACE, ADR-0037); under an older
|
|
34
|
+
// @astram/migrate without it, the default names apply only while the namespace is unset.
|
|
35
|
+
// replacesChecksums: every checksum this file had in a published release (git release tags), so
|
|
36
|
+
// an existing ledger row is accepted and updated, not reported as drift (ADR-0037).
|
|
37
|
+
const replacesChecksums = ['3672b420280dc95cf15faab0a0a75cf7cdbf7d4b63cd3634bbe1508bf48d93a4'];
|
|
38
|
+
|
|
32
39
|
const TS = 'TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP';
|
|
33
40
|
|
|
34
|
-
async function up(
|
|
41
|
+
async function up(ctx) {
|
|
42
|
+
const { query } = ctx;
|
|
43
|
+
const SCHEMA = frameworkSchemasForMigration(ctx, process.env).authz;
|
|
35
44
|
await query(`CREATE TABLE IF NOT EXISTS \`${SCHEMA}\`.\`cross_tenant_grant\` (
|
|
36
45
|
ctg_uuid VARCHAR(36) NOT NULL, -- PK (grant uuid)
|
|
37
46
|
ctg_owning_tenant_uuid VARCHAR(36) NOT NULL, -- tenant whose data is reached into / who consents
|
|
@@ -59,8 +68,10 @@ async function up({ query }) {
|
|
|
59
68
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci`);
|
|
60
69
|
}
|
|
61
70
|
|
|
62
|
-
async function down(
|
|
71
|
+
async function down(ctx) {
|
|
72
|
+
const { query } = ctx;
|
|
73
|
+
const SCHEMA = frameworkSchemasForMigration(ctx, process.env).authz;
|
|
63
74
|
await query(`DROP TABLE IF EXISTS \`${SCHEMA}\`.\`cross_tenant_grant\``);
|
|
64
75
|
}
|
|
65
76
|
|
|
66
|
-
module.exports = { up, down };
|
|
77
|
+
module.exports = { up, down, replacesChecksums };
|
|
@@ -35,7 +35,14 @@
|
|
|
35
35
|
* optional at grant-write time; `role_permission` has no FK to `permission`).
|
|
36
36
|
*/
|
|
37
37
|
|
|
38
|
-
const
|
|
38
|
+
const { frameworkSchemasForMigration } = require('@astram/core');
|
|
39
|
+
|
|
40
|
+
// Database names come from `ctx.schemas` (SHIELD_DB_NAMESPACE, ADR-0037); under an older
|
|
41
|
+
// @astram/migrate without it, the default names apply only while the namespace is unset.
|
|
42
|
+
// replacesChecksums: every checksum this file had in a published release (git release tags), so
|
|
43
|
+
// an existing ledger row is accepted and updated, not reported as drift (ADR-0037).
|
|
44
|
+
const replacesChecksums = ['10cd7ad4323cc79408a0dab2334b76d0cae289c25a29838257515c776e0b04e6'];
|
|
45
|
+
|
|
39
46
|
const MODULE = 'identity';
|
|
40
47
|
const TYPE_KEY = 'cross_tenant_grant';
|
|
41
48
|
const NEW_ACTIONS = ['share', 'accept', 'revoke'];
|
|
@@ -51,7 +58,9 @@ const OLD_ADMIN_KEYS = [
|
|
|
51
58
|
'identity',
|
|
52
59
|
];
|
|
53
60
|
|
|
54
|
-
async function up(
|
|
61
|
+
async function up(ctx) {
|
|
62
|
+
const { query } = ctx;
|
|
63
|
+
const AUTHZ = frameworkSchemasForMigration(ctx, process.env).authz;
|
|
55
64
|
// Every DISTINCT role currently holding ANY of the coarse identity-admin keys.
|
|
56
65
|
const oldAdminKeyPlaceholders = OLD_ADMIN_KEYS.map(() => '?').join(', ');
|
|
57
66
|
const adminRoles = await query(
|
|
@@ -75,7 +84,9 @@ async function up({ query }) {
|
|
|
75
84
|
}
|
|
76
85
|
}
|
|
77
86
|
|
|
78
|
-
async function down(
|
|
87
|
+
async function down(ctx) {
|
|
88
|
+
const { query } = ctx;
|
|
89
|
+
const AUTHZ = frameworkSchemasForMigration(ctx, process.env).authz;
|
|
79
90
|
const keyPlaceholders = NEW_KEYS.map(() => '?').join(', ');
|
|
80
91
|
await query(
|
|
81
92
|
`DELETE FROM \`${AUTHZ}\`.\`role_permission\` WHERE rp_perm_key IN (${keyPlaceholders})`,
|
|
@@ -83,4 +94,4 @@ async function down({ query }) {
|
|
|
83
94
|
);
|
|
84
95
|
}
|
|
85
96
|
|
|
86
|
-
module.exports = { up, down };
|
|
97
|
+
module.exports = { up, down, replacesChecksums };
|
|
@@ -11,9 +11,17 @@
|
|
|
11
11
|
* only the table, not the schema. Idempotent (IF NOT EXISTS); down() drops the table.
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
|
-
const
|
|
14
|
+
const { frameworkSchemasForMigration } = require('@astram/core');
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
// Database names come from `ctx.schemas` (SHIELD_DB_NAMESPACE, ADR-0037); under an older
|
|
17
|
+
// @astram/migrate without it, the default names apply only while the namespace is unset.
|
|
18
|
+
// replacesChecksums: every checksum this file had in a published release (git release tags), so
|
|
19
|
+
// an existing ledger row is accepted and updated, not reported as drift (ADR-0037).
|
|
20
|
+
const replacesChecksums = ['a7ae9649c125ecc1565363def7b0d0fc69a313230bec67bfc4025af80e898c04'];
|
|
21
|
+
|
|
22
|
+
async function up(ctx) {
|
|
23
|
+
const { query } = ctx;
|
|
24
|
+
const SCHEMA = frameworkSchemasForMigration(ctx, process.env).app;
|
|
17
25
|
await query(`CREATE TABLE IF NOT EXISTS \`${SCHEMA}\`.\`shared_resource\` (
|
|
18
26
|
sr_uuid VARCHAR(36) NOT NULL,
|
|
19
27
|
sr_tenant_id VARCHAR(36) NOT NULL,
|
|
@@ -23,8 +31,10 @@ async function up({ query }) {
|
|
|
23
31
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci`);
|
|
24
32
|
}
|
|
25
33
|
|
|
26
|
-
async function down(
|
|
34
|
+
async function down(ctx) {
|
|
35
|
+
const { query } = ctx;
|
|
36
|
+
const SCHEMA = frameworkSchemasForMigration(ctx, process.env).app;
|
|
27
37
|
await query(`DROP TABLE IF EXISTS \`${SCHEMA}\`.\`shared_resource\``);
|
|
28
38
|
}
|
|
29
39
|
|
|
30
|
-
module.exports = { up, down };
|
|
40
|
+
module.exports = { up, down, replacesChecksums };
|
|
@@ -20,13 +20,20 @@
|
|
|
20
20
|
*/
|
|
21
21
|
const { ServiceAccount } = require('@astram/identity');
|
|
22
22
|
const { columnForRole, reflectObjectType } = require('@astram/engine');
|
|
23
|
+
const { frameworkSchemasForMigration } = require('@astram/core');
|
|
23
24
|
|
|
24
|
-
|
|
25
|
+
// Database names come from `ctx.schemas` (SHIELD_DB_NAMESPACE, ADR-0037); under an older
|
|
26
|
+
// @astram/migrate without it, the default names apply only while the namespace is unset.
|
|
27
|
+
// replacesChecksums: every checksum this file had in a published release (git release tags), so
|
|
28
|
+
// an existing ledger row is accepted and updated, not reported as drift (ADR-0037).
|
|
29
|
+
const replacesChecksums = ['848b0ff08ec31c851dec3c891e0c87920ba956c8ad2989ee03bc8509c2e28c20'];
|
|
25
30
|
|
|
26
31
|
const SaReg = reflectObjectType(ServiceAccount);
|
|
27
32
|
const col = (role) => columnForRole(SaReg, role);
|
|
28
33
|
|
|
29
|
-
async function up(
|
|
34
|
+
async function up(ctx) {
|
|
35
|
+
const { query } = ctx;
|
|
36
|
+
const SCHEMA = frameworkSchemasForMigration(ctx, process.env).app;
|
|
30
37
|
// Only `primaryKey` + `status` are engine ROLES (single-sourced via col()); the other columns
|
|
31
38
|
// carry no role, so they are named literally — matching their `@Field({ column })` on the object
|
|
32
39
|
// (sa_tenant_id/sa_label/sa_created_at_ms) or are store-only (sa_scope_subtree/sa_role_ids/…).
|
|
@@ -46,8 +53,10 @@ async function up({ query }) {
|
|
|
46
53
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci`);
|
|
47
54
|
}
|
|
48
55
|
|
|
49
|
-
async function down(
|
|
56
|
+
async function down(ctx) {
|
|
57
|
+
const { query } = ctx;
|
|
58
|
+
const SCHEMA = frameworkSchemasForMigration(ctx, process.env).app;
|
|
50
59
|
await query(`DROP TABLE IF EXISTS \`${SCHEMA}\`.\`${SaReg.table}\``);
|
|
51
60
|
}
|
|
52
61
|
|
|
53
|
-
module.exports = { up, down };
|
|
62
|
+
module.exports = { up, down, replacesChecksums };
|
|
@@ -19,17 +19,27 @@
|
|
|
19
19
|
* change).
|
|
20
20
|
*/
|
|
21
21
|
|
|
22
|
-
const
|
|
22
|
+
const { frameworkSchemasForMigration } = require('@astram/core');
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
// Database names come from `ctx.schemas` (SHIELD_DB_NAMESPACE, ADR-0037); under an older
|
|
25
|
+
// @astram/migrate without it, the default names apply only while the namespace is unset.
|
|
26
|
+
// replacesChecksums: every checksum this file had in a published release (git release tags), so
|
|
27
|
+
// an existing ledger row is accepted and updated, not reported as drift (ADR-0037).
|
|
28
|
+
const replacesChecksums = ['a734be029c84615378c41aca1b0dc0cfac00d4213c87f0ea11700902a8319c0d'];
|
|
29
|
+
|
|
30
|
+
async function up(ctx) {
|
|
31
|
+
const { query } = ctx;
|
|
32
|
+
const SCHEMA = frameworkSchemasForMigration(ctx, process.env).identity;
|
|
25
33
|
await query(
|
|
26
34
|
`ALTER TABLE \`${SCHEMA}\`.\`session\`
|
|
27
35
|
ADD COLUMN IF NOT EXISTS \`s_must_reenroll\` TINYINT(1) NOT NULL DEFAULT 0`,
|
|
28
36
|
);
|
|
29
37
|
}
|
|
30
38
|
|
|
31
|
-
async function down(
|
|
39
|
+
async function down(ctx) {
|
|
40
|
+
const { query } = ctx;
|
|
41
|
+
const SCHEMA = frameworkSchemasForMigration(ctx, process.env).identity;
|
|
32
42
|
await query(`ALTER TABLE \`${SCHEMA}\`.\`session\` DROP COLUMN IF EXISTS \`s_must_reenroll\``);
|
|
33
43
|
}
|
|
34
44
|
|
|
35
|
-
module.exports = { up, down };
|
|
45
|
+
module.exports = { up, down, replacesChecksums };
|
|
@@ -30,9 +30,17 @@
|
|
|
30
30
|
* names. Idempotent (CREATE TABLE IF NOT EXISTS / DROP TABLE IF EXISTS).
|
|
31
31
|
*/
|
|
32
32
|
|
|
33
|
-
const
|
|
33
|
+
const { frameworkSchemasForMigration } = require('@astram/core');
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
// Database names come from `ctx.schemas` (SHIELD_DB_NAMESPACE, ADR-0037); under an older
|
|
36
|
+
// @astram/migrate without it, the default names apply only while the namespace is unset.
|
|
37
|
+
// replacesChecksums: every checksum this file had in a published release (git release tags), so
|
|
38
|
+
// an existing ledger row is accepted and updated, not reported as drift (ADR-0037).
|
|
39
|
+
const replacesChecksums = ['978e80f32ad2103c6e298ed70fb8b73fab557448a376e80650f1d1c9f892aa39'];
|
|
40
|
+
|
|
41
|
+
async function up(ctx) {
|
|
42
|
+
const { query } = ctx;
|
|
43
|
+
const { identity: SCHEMA, app: APP } = frameworkSchemasForMigration(ctx, process.env);
|
|
36
44
|
await query(
|
|
37
45
|
`CREATE TABLE IF NOT EXISTS \`${SCHEMA}\`.\`email_change_token\` (
|
|
38
46
|
ect_token_hash VARCHAR(64) NOT NULL,
|
|
@@ -49,14 +57,16 @@ async function up({ query }) {
|
|
|
49
57
|
INDEX idx_ect_principal (ect_principal_id),
|
|
50
58
|
INDEX idx_ect_expires (ect_expires_at_ms),
|
|
51
59
|
CONSTRAINT FK_email_change_token_user
|
|
52
|
-
FOREIGN KEY (ect_principal_id) REFERENCES
|
|
60
|
+
FOREIGN KEY (ect_principal_id) REFERENCES \`${APP}\`.\`users\` (u_uuid)
|
|
53
61
|
ON DELETE CASCADE
|
|
54
62
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci`,
|
|
55
63
|
);
|
|
56
64
|
}
|
|
57
65
|
|
|
58
|
-
async function down(
|
|
66
|
+
async function down(ctx) {
|
|
67
|
+
const { query } = ctx;
|
|
68
|
+
const SCHEMA = frameworkSchemasForMigration(ctx, process.env).identity;
|
|
59
69
|
await query(`DROP TABLE IF EXISTS \`${SCHEMA}\`.\`email_change_token\``);
|
|
60
70
|
}
|
|
61
71
|
|
|
62
|
-
module.exports = { up, down };
|
|
72
|
+
module.exports = { up, down, replacesChecksums };
|
|
@@ -38,7 +38,14 @@
|
|
|
38
38
|
* (`...099`/`...100`, distinct addresses).
|
|
39
39
|
*/
|
|
40
40
|
|
|
41
|
-
const
|
|
41
|
+
const { frameworkSchemasForMigration } = require('@astram/core');
|
|
42
|
+
|
|
43
|
+
// Database names come from `ctx.schemas` (SHIELD_DB_NAMESPACE, ADR-0037); under an older
|
|
44
|
+
// @astram/migrate without it, the default names apply only while the namespace is unset.
|
|
45
|
+
// replacesChecksums: every checksum this file had in a published release (git release tags), so
|
|
46
|
+
// an existing ledger row is accepted and updated, not reported as drift (ADR-0037).
|
|
47
|
+
const replacesChecksums = ['a08085e726ff0c2ec24c069cf099097a0bdefd06d0cab22c7d528280753de3f0'];
|
|
48
|
+
|
|
42
49
|
const TABLE = 'users';
|
|
43
50
|
const COLUMN = 'u_email';
|
|
44
51
|
const INDEX = 'uq_users_email';
|
|
@@ -47,7 +54,7 @@ const MIGRATION = '1710000000021-AddUsersEmailUniqueIndex';
|
|
|
47
54
|
const MAX_LISTED_GROUPS = 50;
|
|
48
55
|
const ER_DUP_ENTRY = 1062;
|
|
49
56
|
|
|
50
|
-
/** Same rule as `@astram/guard` `maskEmail` (kept local:
|
|
57
|
+
/** Same rule as `@astram/guard` `maskEmail` (kept local: the migration loads only `@astram/core`, which has no such helper). */
|
|
51
58
|
function maskEmail(value) {
|
|
52
59
|
const at = value.lastIndexOf('@');
|
|
53
60
|
if (at <= 0 || at === value.length - 1) return '***';
|
|
@@ -55,7 +62,7 @@ function maskEmail(value) {
|
|
|
55
62
|
}
|
|
56
63
|
|
|
57
64
|
/** `null` = no index of that name; otherwise whether it is UNIQUE. */
|
|
58
|
-
async function indexState(query) {
|
|
65
|
+
async function indexState(query, SCHEMA) {
|
|
59
66
|
const rows = await query(
|
|
60
67
|
`SELECT NON_UNIQUE AS non_unique
|
|
61
68
|
FROM information_schema.STATISTICS
|
|
@@ -68,7 +75,7 @@ async function indexState(query) {
|
|
|
68
75
|
}
|
|
69
76
|
|
|
70
77
|
/** Duplicate groups by the column collation: `[{ masked, count }]`, largest first. */
|
|
71
|
-
async function duplicateGroups(query) {
|
|
78
|
+
async function duplicateGroups(query, SCHEMA) {
|
|
72
79
|
const rows = await query(
|
|
73
80
|
`SELECT ${COLUMN} AS sample, COUNT(*) AS n
|
|
74
81
|
FROM \`${SCHEMA}\`.\`${TABLE}\`
|
|
@@ -84,7 +91,7 @@ async function duplicateGroups(query) {
|
|
|
84
91
|
}));
|
|
85
92
|
}
|
|
86
93
|
|
|
87
|
-
function duplicateError(groups, emptiesNormalised) {
|
|
94
|
+
function duplicateError(groups, emptiesNormalised, SCHEMA) {
|
|
88
95
|
const listed = groups.slice(0, MAX_LISTED_GROUPS).map((g) => ` - ${g.masked}: ${g.count} users`);
|
|
89
96
|
if (groups.length > MAX_LISTED_GROUPS) {
|
|
90
97
|
listed.push(` - ... and ${groups.length - MAX_LISTED_GROUPS} more group(s)`);
|
|
@@ -104,8 +111,10 @@ function duplicateError(groups, emptiesNormalised) {
|
|
|
104
111
|
);
|
|
105
112
|
}
|
|
106
113
|
|
|
107
|
-
async function up(
|
|
108
|
-
const
|
|
114
|
+
async function up(ctx) {
|
|
115
|
+
const { query } = ctx;
|
|
116
|
+
const SCHEMA = frameworkSchemasForMigration(ctx, process.env).app;
|
|
117
|
+
const state = await indexState(query, SCHEMA);
|
|
109
118
|
if (state !== null) {
|
|
110
119
|
if (state.unique) return; // already applied (idempotent re-run)
|
|
111
120
|
throw new Error(
|
|
@@ -120,8 +129,8 @@ async function up({ query }) {
|
|
|
120
129
|
WHERE ${COLUMN} IS NOT NULL AND ${COLUMN} REGEXP '^[[:space:]]*$'`,
|
|
121
130
|
);
|
|
122
131
|
|
|
123
|
-
const groups = await duplicateGroups(query);
|
|
124
|
-
if (groups.length > 0) throw duplicateError(groups, false);
|
|
132
|
+
const groups = await duplicateGroups(query, SCHEMA);
|
|
133
|
+
if (groups.length > 0) throw duplicateError(groups, false, SCHEMA);
|
|
125
134
|
|
|
126
135
|
try {
|
|
127
136
|
await query(
|
|
@@ -130,16 +139,18 @@ async function up({ query }) {
|
|
|
130
139
|
} catch (err) {
|
|
131
140
|
if (err === null || typeof err !== 'object' || err.errno !== ER_DUP_ENTRY) throw err;
|
|
132
141
|
// A duplicate was written after the pre-check. Never surface the driver message (full address).
|
|
133
|
-
const late = await duplicateGroups(query);
|
|
134
|
-
if (late.length > 0) throw duplicateError(late, true);
|
|
142
|
+
const late = await duplicateGroups(query, SCHEMA);
|
|
143
|
+
if (late.length > 0) throw duplicateError(late, true, SCHEMA);
|
|
135
144
|
throw new Error(
|
|
136
145
|
`${MIGRATION}: a duplicate ${COLUMN} was written while the index was built; re-run astram-migrate.`,
|
|
137
146
|
);
|
|
138
147
|
}
|
|
139
148
|
}
|
|
140
149
|
|
|
141
|
-
async function down(
|
|
150
|
+
async function down(ctx) {
|
|
151
|
+
const { query } = ctx;
|
|
152
|
+
const SCHEMA = frameworkSchemasForMigration(ctx, process.env).app;
|
|
142
153
|
await query(`ALTER TABLE \`${SCHEMA}\`.\`${TABLE}\` DROP INDEX IF EXISTS \`${INDEX}\``);
|
|
143
154
|
}
|
|
144
155
|
|
|
145
|
-
module.exports = { up, down };
|
|
156
|
+
module.exports = { up, down, replacesChecksums };
|
|
@@ -16,9 +16,17 @@
|
|
|
16
16
|
* No seed, no hard-coded ids.
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
|
-
const
|
|
19
|
+
const { frameworkSchemasForMigration } = require('@astram/core');
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
// Database names come from `ctx.schemas` (SHIELD_DB_NAMESPACE, ADR-0037); under an older
|
|
22
|
+
// @astram/migrate without it, the default names apply only while the namespace is unset.
|
|
23
|
+
// replacesChecksums: every checksum this file had in a published release (git release tags), so
|
|
24
|
+
// an existing ledger row is accepted and updated, not reported as drift (ADR-0037).
|
|
25
|
+
const replacesChecksums = ['e2af5c4329d6b312ebbe1f8d61e8043ec578554e9ba59e18647ed7a8eb650d18'];
|
|
26
|
+
|
|
27
|
+
async function up(ctx) {
|
|
28
|
+
const { query } = ctx;
|
|
29
|
+
const SCHEMA = frameworkSchemasForMigration(ctx, process.env).app;
|
|
22
30
|
await query(`CREATE TABLE IF NOT EXISTS \`${SCHEMA}\`.\`stored_file\` (
|
|
23
31
|
sf_uuid VARCHAR(36) NOT NULL,
|
|
24
32
|
sf_tenant_id VARCHAR(36) NOT NULL,
|
|
@@ -36,8 +44,10 @@ async function up({ query }) {
|
|
|
36
44
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci`);
|
|
37
45
|
}
|
|
38
46
|
|
|
39
|
-
async function down(
|
|
47
|
+
async function down(ctx) {
|
|
48
|
+
const { query } = ctx;
|
|
49
|
+
const SCHEMA = frameworkSchemasForMigration(ctx, process.env).app;
|
|
40
50
|
await query(`DROP TABLE IF EXISTS \`${SCHEMA}\`.\`stored_file\``);
|
|
41
51
|
}
|
|
42
52
|
|
|
43
|
-
module.exports = { up, down };
|
|
53
|
+
module.exports = { up, down, replacesChecksums };
|
|
@@ -20,9 +20,13 @@
|
|
|
20
20
|
* by business key). down() removes the chain by business key.
|
|
21
21
|
*/
|
|
22
22
|
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
|
|
23
|
+
const { frameworkSchemasForMigration } = require('@astram/core');
|
|
24
|
+
|
|
25
|
+
// Database names come from `ctx.schemas` (SHIELD_DB_NAMESPACE, ADR-0037); under an older
|
|
26
|
+
// @astram/migrate without it, the default names apply only while the namespace is unset.
|
|
27
|
+
// replacesChecksums: every checksum this file had in a published release (git release tags), so
|
|
28
|
+
// an existing ledger row is accepted and updated, not reported as drift (ADR-0037).
|
|
29
|
+
const replacesChecksums = ['9b8a1ed3b967b95ae784396d9f14ee87dfc64253f3389ca4d413ca16f4f229d9'];
|
|
26
30
|
|
|
27
31
|
const COMPANY = 'Astram Dev Co';
|
|
28
32
|
const USERNAME = 'admin';
|
|
@@ -38,7 +42,9 @@ function seedEnabled() {
|
|
|
38
42
|
return process.env.NODE_ENV === 'development' || process.env.ASTRAM_SEED_DEV === '1';
|
|
39
43
|
}
|
|
40
44
|
|
|
41
|
-
async function up(
|
|
45
|
+
async function up(ctx) {
|
|
46
|
+
const { query } = ctx;
|
|
47
|
+
const { app: APP, identity: IDENT, authz: AUTHZ } = frameworkSchemasForMigration(ctx, process.env);
|
|
42
48
|
if (!seedEnabled()) return; // production / non-dev → no-op
|
|
43
49
|
|
|
44
50
|
// 1) company (tenant)
|
|
@@ -109,7 +115,9 @@ async function up({ query }) {
|
|
|
109
115
|
);
|
|
110
116
|
}
|
|
111
117
|
|
|
112
|
-
async function down(
|
|
118
|
+
async function down(ctx) {
|
|
119
|
+
const { query } = ctx;
|
|
120
|
+
const { app: APP, identity: IDENT, authz: AUTHZ } = frameworkSchemasForMigration(ctx, process.env);
|
|
113
121
|
// Remove by business key (safe whether or not seed ran). Order: dependents first.
|
|
114
122
|
const [role] = await query(`SELECT r_uuid FROM \`${APP}\`.\`roles\` WHERE r_name = ? LIMIT 1`, [ROLE]);
|
|
115
123
|
if (role) {
|
|
@@ -127,4 +135,4 @@ async function down({ query }) {
|
|
|
127
135
|
await query(`DELETE FROM \`${APP}\`.\`companies\` WHERE c_name = ?`, [COMPANY]);
|
|
128
136
|
}
|
|
129
137
|
|
|
130
|
-
module.exports = { up, down };
|
|
138
|
+
module.exports = { up, down, replacesChecksums };
|
|
@@ -50,9 +50,13 @@
|
|
|
50
50
|
* expansion for admin-b's accept authority.
|
|
51
51
|
*/
|
|
52
52
|
|
|
53
|
-
const
|
|
54
|
-
|
|
55
|
-
|
|
53
|
+
const { frameworkSchemasForMigration } = require('@astram/core');
|
|
54
|
+
|
|
55
|
+
// Database names come from `ctx.schemas` (SHIELD_DB_NAMESPACE, ADR-0037); under an older
|
|
56
|
+
// @astram/migrate without it, the default names apply only while the namespace is unset.
|
|
57
|
+
// replacesChecksums: every checksum this file had in a published release (git release tags), so
|
|
58
|
+
// an existing ledger row is accepted and updated, not reported as drift (ADR-0037).
|
|
59
|
+
const replacesChecksums = ['4444a96f5690c434ada14ba0df70641f983625bbb956070425b5ba6867a49199'];
|
|
56
60
|
|
|
57
61
|
// --- Part A: tenant-b ---
|
|
58
62
|
const COMPANY_B = 'Astram Tenant B';
|
|
@@ -76,7 +80,9 @@ function seedEnabled() {
|
|
|
76
80
|
return process.env.NODE_ENV === 'development' || process.env.ASTRAM_SEED_DEV === '1';
|
|
77
81
|
}
|
|
78
82
|
|
|
79
|
-
async function up(
|
|
83
|
+
async function up(ctx) {
|
|
84
|
+
const { query } = ctx;
|
|
85
|
+
const { app: APP, identity: IDENT, authz: AUTHZ } = frameworkSchemasForMigration(ctx, process.env);
|
|
80
86
|
if (!seedEnabled()) return; // production / non-dev → no-op
|
|
81
87
|
|
|
82
88
|
// ── PART A: tenant-b ────────────────────────────────────────────────────────────────────
|
|
@@ -183,7 +189,9 @@ async function up({ query }) {
|
|
|
183
189
|
);
|
|
184
190
|
}
|
|
185
191
|
|
|
186
|
-
async function down(
|
|
192
|
+
async function down(ctx) {
|
|
193
|
+
const { query } = ctx;
|
|
194
|
+
const { app: APP, identity: IDENT, authz: AUTHZ } = frameworkSchemasForMigration(ctx, process.env);
|
|
187
195
|
// Reverse PART A (dependents first) — this migration's OWN 'Administrator B' role (+ its
|
|
188
196
|
// identity:* grant) is reversed too; the shared 'Administrator' role + tenant-a (from `...099`)
|
|
189
197
|
// are left untouched.
|
|
@@ -209,4 +217,4 @@ async function down({ query }) {
|
|
|
209
217
|
await query(`DELETE FROM \`${APP}\`.\`users\` WHERE u_username = ?`, [ROOT_USERNAME]);
|
|
210
218
|
}
|
|
211
219
|
|
|
212
|
-
module.exports = { up, down };
|
|
220
|
+
module.exports = { up, down, replacesChecksums };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@astram/identity",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "Astram framework — the framework-owned identity + tenancy model. Hosts the identity @ObjectType classes (user, company, membership, posting), framework-authored identity migrations, and the identity resolver. Top of the dependency graph: depends on @astram/engine (for @ObjectType/@Field decorators) + @astram/guard / @astram/core (for the auth ports).",
|
|
6
6
|
"type": "commonjs",
|
|
@@ -36,9 +36,9 @@
|
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
38
|
"mariadb": "^3.5.4",
|
|
39
|
-
"@astram/core": "1.
|
|
40
|
-
"@astram/
|
|
41
|
-
"@astram/
|
|
39
|
+
"@astram/core": "1.7.0",
|
|
40
|
+
"@astram/engine": "0.8.0",
|
|
41
|
+
"@astram/guard": "0.15.0"
|
|
42
42
|
},
|
|
43
43
|
"peerDependencies": {
|
|
44
44
|
"@nestjs/common": "^11",
|