@astram/identity 0.16.0 → 0.17.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/branch.object.d.ts +9 -1
- package/dist/branch.object.d.ts.map +1 -1
- package/dist/branch.object.js +14 -1
- package/dist/company-branch.object.d.ts +5 -4
- package/dist/company-branch.object.d.ts.map +1 -1
- package/dist/company-branch.object.js +6 -4
- package/dist/company-department.object.d.ts +6 -6
- package/dist/company-department.object.d.ts.map +1 -1
- package/dist/company-department.object.js +7 -6
- package/dist/department.object.d.ts +9 -1
- package/dist/department.object.d.ts.map +1 -1
- package/dist/department.object.js +14 -1
- package/dist/features/access/access-admin.access.d.ts.map +1 -1
- package/dist/features/access/access-admin.access.js +8 -1
- package/dist/features/access/index.d.ts +1 -0
- package/dist/features/access/index.d.ts.map +1 -1
- package/dist/features/access/index.js +10 -2
- package/dist/features/access/org-structure.access.d.ts +3 -0
- package/dist/features/access/org-structure.access.d.ts.map +1 -0
- package/dist/features/access/org-structure.access.js +41 -0
- package/dist/features/access/user-management.access.d.ts.map +1 -1
- package/dist/features/access/user-management.access.js +5 -0
- package/dist/features/audit/audit-read.service.d.ts +32 -1
- package/dist/features/audit/audit-read.service.d.ts.map +1 -1
- package/dist/features/audit/audit-read.service.js +67 -14
- package/dist/features/audit/auth-audit-sink.d.ts +19 -0
- package/dist/features/audit/auth-audit-sink.d.ts.map +1 -0
- package/dist/features/audit/auth-audit-sink.js +24 -0
- package/dist/features/audit/directory-label-resolver.d.ts +10 -1
- package/dist/features/audit/directory-label-resolver.d.ts.map +1 -1
- package/dist/features/audit/directory-label-resolver.js +28 -1
- package/dist/features/authz/grant-admin.controller.d.ts +4 -4
- package/dist/features/authz/grant-admin.controller.js +4 -4
- package/dist/features/authz/grant-admin.service.d.ts +9 -8
- package/dist/features/authz/grant-admin.service.d.ts.map +1 -1
- package/dist/features/authz/grant-admin.service.js +20 -24
- package/dist/features/authz/grant-ceiling.d.ts +35 -16
- package/dist/features/authz/grant-ceiling.d.ts.map +1 -1
- package/dist/features/authz/grant-ceiling.js +44 -29
- package/dist/features/authz/role-binding.d.ts +25 -24
- package/dist/features/authz/role-binding.d.ts.map +1 -1
- package/dist/features/authz/role-binding.js +31 -44
- package/dist/features/identity-feature.module.d.ts +0 -11
- package/dist/features/identity-feature.module.d.ts.map +1 -1
- package/dist/features/identity-feature.module.js +90 -1
- package/dist/features/membership/membership.controller.d.ts.map +1 -1
- package/dist/features/membership/membership.controller.js +20 -6
- package/dist/features/membership/membership.service.d.ts +16 -10
- package/dist/features/membership/membership.service.d.ts.map +1 -1
- package/dist/features/membership/membership.service.js +61 -21
- package/dist/features/membership/posting.service.d.ts +25 -6
- package/dist/features/membership/posting.service.d.ts.map +1 -1
- package/dist/features/membership/posting.service.js +63 -16
- package/dist/features/org-bootstrap/org-bootstrap-file.d.ts +6 -2
- package/dist/features/org-bootstrap/org-bootstrap-file.d.ts.map +1 -1
- package/dist/features/org-bootstrap/org-bootstrap-file.js +54 -11
- package/dist/features/org-bootstrap/org-bootstrap-plan.d.ts +30 -11
- package/dist/features/org-bootstrap/org-bootstrap-plan.d.ts.map +1 -1
- package/dist/features/org-bootstrap/org-bootstrap-plan.js +172 -68
- package/dist/features/org-bootstrap/org-state.reader.d.ts.map +1 -1
- package/dist/features/org-bootstrap/org-state.reader.js +56 -49
- package/dist/features/org-bootstrap/run-org-bootstrap.d.ts +6 -1
- package/dist/features/org-bootstrap/run-org-bootstrap.d.ts.map +1 -1
- package/dist/features/org-bootstrap/run-org-bootstrap.js +81 -92
- package/dist/features/org-structure/org-catalog.controller.d.ts +29 -6
- package/dist/features/org-structure/org-catalog.controller.d.ts.map +1 -1
- package/dist/features/org-structure/org-catalog.controller.js +105 -17
- package/dist/features/org-structure/org-catalog.service.d.ts +99 -18
- package/dist/features/org-structure/org-catalog.service.d.ts.map +1 -1
- package/dist/features/org-structure/org-catalog.service.js +327 -51
- package/dist/features/org-structure/org-unit-name.d.ts +31 -0
- package/dist/features/org-structure/org-unit-name.d.ts.map +1 -0
- package/dist/features/org-structure/org-unit-name.js +50 -0
- package/dist/features/role/role.controller.d.ts +28 -13
- package/dist/features/role/role.controller.d.ts.map +1 -1
- package/dist/features/role/role.controller.js +54 -14
- package/dist/features/role/role.service.d.ts +76 -21
- package/dist/features/role/role.service.d.ts.map +1 -1
- package/dist/features/role/role.service.js +204 -27
- package/dist/features/security-policy/security-policy-version-bump.d.ts +41 -0
- package/dist/features/security-policy/security-policy-version-bump.d.ts.map +1 -0
- package/dist/features/security-policy/security-policy-version-bump.js +65 -0
- package/dist/features/security-policy/security-policy.controller.d.ts +51 -0
- package/dist/features/security-policy/security-policy.controller.d.ts.map +1 -0
- package/dist/features/security-policy/security-policy.controller.js +121 -0
- package/dist/features/security-policy/security-policy.service.d.ts +94 -0
- package/dist/features/security-policy/security-policy.service.d.ts.map +1 -0
- package/dist/features/security-policy/security-policy.service.js +429 -0
- package/dist/features/service-account/service-account.service.d.ts +13 -3
- package/dist/features/service-account/service-account.service.d.ts.map +1 -1
- package/dist/features/service-account/service-account.service.js +48 -10
- package/dist/features/service-account/service-account.store.d.ts +11 -1
- package/dist/features/service-account/service-account.store.d.ts.map +1 -1
- package/dist/features/service-account/service-account.store.js +20 -1
- package/dist/features/user/signin-admin.tokens.d.ts +11 -0
- package/dist/features/user/signin-admin.tokens.d.ts.map +1 -0
- package/dist/features/user/signin-admin.tokens.js +13 -0
- package/dist/features/user/user-mfa-status.d.ts +38 -0
- package/dist/features/user/user-mfa-status.d.ts.map +1 -0
- package/dist/features/user/user-mfa-status.js +47 -0
- package/dist/features/user/user-signin-admin.service.d.ts +48 -0
- package/dist/features/user/user-signin-admin.service.d.ts.map +1 -0
- package/dist/features/user/user-signin-admin.service.js +232 -0
- package/dist/features/user/user.controller.d.ts +29 -2
- package/dist/features/user/user.controller.d.ts.map +1 -1
- package/dist/features/user/user.controller.js +71 -3
- package/dist/features/user/user.service.d.ts +40 -14
- package/dist/features/user/user.service.d.ts.map +1 -1
- package/dist/features/user/user.service.js +143 -10
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/objects.d.ts.map +1 -1
- package/dist/objects.js +2 -0
- package/dist/role.object.d.ts +1 -1
- package/dist/role.object.d.ts.map +1 -1
- package/dist/role.object.js +6 -15
- package/dist/security-policy.object.d.ts +43 -0
- package/dist/security-policy.object.d.ts.map +1 -0
- package/dist/security-policy.object.js +107 -0
- package/dist/user.object.d.ts +6 -0
- package/dist/user.object.d.ts.map +1 -1
- package/dist/user.object.js +13 -1
- package/migrations/1710000000103-AddUserLoginName.cjs +87 -0
- package/migrations/1710000000104-CreateSecurityPolicy.cjs +90 -0
- package/migrations/1710000000105-OwnDepartmentsAndBranches.cjs +327 -0
- package/migrations/1710000000106-OwnRolesPerCompany.cjs +622 -0
- package/package.json +4 -4
package/dist/branch.object.d.ts
CHANGED
|
@@ -1,6 +1,14 @@
|
|
|
1
|
-
/**
|
|
1
|
+
/**
|
|
2
|
+
* branches — a company's own branches (G-012, spec §4/§5.B). Each row belongs to exactly one
|
|
3
|
+
* company (`b_company_uuid`, migration `1710000000105-OwnDepartmentsAndBranches`), names are unique
|
|
4
|
+
* per company, and no row is shared between companies. The owner is stamped server-side from the
|
|
5
|
+
* reached route company and never changes (`immutable`). Read wall (ADR-0027): a non-root
|
|
6
|
+
* list/get sees only rows owned by a company in its reachable subtree; a non-root create is
|
|
7
|
+
* walled the same way (ADR-0034). A legacy row with no owner (NULL) is visible to root only.
|
|
8
|
+
*/
|
|
2
9
|
export declare class Branch {
|
|
3
10
|
uuid: string;
|
|
4
11
|
name: string;
|
|
12
|
+
companyUuid: string;
|
|
5
13
|
}
|
|
6
14
|
//# sourceMappingURL=branch.object.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"branch.object.d.ts","sourceRoot":"","sources":["../src/branch.object.ts"],"names":[],"mappings":"AAGA
|
|
1
|
+
{"version":3,"file":"branch.object.d.ts","sourceRoot":"","sources":["../src/branch.object.ts"],"names":[],"mappings":"AAGA;;;;;;;GAOG;AACH,qBAQa,MAAM;IAEjB,IAAI,EAAG,MAAM,CAAC;IAGd,IAAI,EAAG,MAAM,CAAC;IAGd,WAAW,EAAG,MAAM,CAAC;CACtB"}
|
package/dist/branch.object.js
CHANGED
|
@@ -12,10 +12,18 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
12
12
|
exports.Branch = void 0;
|
|
13
13
|
const engine_1 = require("@astram/engine");
|
|
14
14
|
const schema_1 = require("./schema");
|
|
15
|
-
/**
|
|
15
|
+
/**
|
|
16
|
+
* branches — a company's own branches (G-012, spec §4/§5.B). Each row belongs to exactly one
|
|
17
|
+
* company (`b_company_uuid`, migration `1710000000105-OwnDepartmentsAndBranches`), names are unique
|
|
18
|
+
* per company, and no row is shared between companies. The owner is stamped server-side from the
|
|
19
|
+
* reached route company and never changes (`immutable`). Read wall (ADR-0027): a non-root
|
|
20
|
+
* list/get sees only rows owned by a company in its reachable subtree; a non-root create is
|
|
21
|
+
* walled the same way (ADR-0034). A legacy row with no owner (NULL) is visible to root only.
|
|
22
|
+
*/
|
|
16
23
|
let Branch = class Branch {
|
|
17
24
|
uuid;
|
|
18
25
|
name;
|
|
26
|
+
companyUuid;
|
|
19
27
|
};
|
|
20
28
|
exports.Branch = Branch;
|
|
21
29
|
__decorate([
|
|
@@ -26,12 +34,17 @@ __decorate([
|
|
|
26
34
|
(0, engine_1.Field)({ column: 'b_name', type: 'string', required: true }),
|
|
27
35
|
__metadata("design:type", String)
|
|
28
36
|
], Branch.prototype, "name", void 0);
|
|
37
|
+
__decorate([
|
|
38
|
+
(0, engine_1.Field)({ column: 'b_company_uuid', type: 'uuid', immutable: true }),
|
|
39
|
+
__metadata("design:type", String)
|
|
40
|
+
], Branch.prototype, "companyUuid", void 0);
|
|
29
41
|
exports.Branch = Branch = __decorate([
|
|
30
42
|
(0, engine_1.ObjectType)({
|
|
31
43
|
typeKey: 'branch',
|
|
32
44
|
table: 'branches',
|
|
33
45
|
schema: schema_1.SCHEMA,
|
|
34
46
|
access: { plane: 'control', system: true },
|
|
47
|
+
readScope: { kind: 'nodeColumn', column: 'b_company_uuid' },
|
|
35
48
|
}),
|
|
36
49
|
(0, engine_1.PrimaryKey)({ kind: 'uuid', column: 'b_uuid' })
|
|
37
50
|
], Branch);
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* company_branches — the
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
2
|
+
* company_branches — the company → branch junction. Same shape and role as
|
|
3
|
+
* `company_department`: since G-012 (migration `1710000000105-OwnDepartmentsAndBranches`) every
|
|
4
|
+
* branch is owned by one company and has exactly one junction row, to its owner. Read wall
|
|
5
|
+
* (ADR-0027) on `cb_company_uuid`, so a non-root junction read or write is bounded to the caller's
|
|
6
|
+
* reachable subtree (create walled too, ADR-0034).
|
|
6
7
|
*/
|
|
7
8
|
export declare class CompanyBranch {
|
|
8
9
|
companyUuid: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"company-branch.object.d.ts","sourceRoot":"","sources":["../src/company-branch.object.ts"],"names":[],"mappings":"AAGA
|
|
1
|
+
{"version":3,"file":"company-branch.object.d.ts","sourceRoot":"","sources":["../src/company-branch.object.ts"],"names":[],"mappings":"AAGA;;;;;;GAMG;AACH,qBAQa,aAAa;IAExB,WAAW,EAAG,MAAM,CAAC;IAGrB,UAAU,EAAG,MAAM,CAAC;CACrB"}
|
|
@@ -13,10 +13,11 @@ exports.CompanyBranch = void 0;
|
|
|
13
13
|
const engine_1 = require("@astram/engine");
|
|
14
14
|
const schema_1 = require("./schema");
|
|
15
15
|
/**
|
|
16
|
-
* company_branches — the
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
16
|
+
* company_branches — the company → branch junction. Same shape and role as
|
|
17
|
+
* `company_department`: since G-012 (migration `1710000000105-OwnDepartmentsAndBranches`) every
|
|
18
|
+
* branch is owned by one company and has exactly one junction row, to its owner. Read wall
|
|
19
|
+
* (ADR-0027) on `cb_company_uuid`, so a non-root junction read or write is bounded to the caller's
|
|
20
|
+
* reachable subtree (create walled too, ADR-0034).
|
|
20
21
|
*/
|
|
21
22
|
let CompanyBranch = class CompanyBranch {
|
|
22
23
|
companyUuid;
|
|
@@ -37,6 +38,7 @@ exports.CompanyBranch = CompanyBranch = __decorate([
|
|
|
37
38
|
table: 'company_branches',
|
|
38
39
|
schema: schema_1.SCHEMA,
|
|
39
40
|
access: { plane: 'control', system: true },
|
|
41
|
+
readScope: { kind: 'nodeColumn', column: 'cb_company_uuid' },
|
|
40
42
|
}),
|
|
41
43
|
(0, engine_1.PrimaryKey)({ kind: 'composite', columns: ['cb_company_uuid', 'cb_branch_uuid'] })
|
|
42
44
|
], CompanyBranch);
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* company_departments — the
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* `
|
|
6
|
-
* (
|
|
7
|
-
*
|
|
2
|
+
* company_departments — the company → department junction. Since G-012 (migration
|
|
3
|
+
* `1710000000105-OwnDepartmentsAndBranches`) every department is owned by one company and has
|
|
4
|
+
* exactly one junction row, to its owner; the junction stays so existing readers
|
|
5
|
+
* (`GrantCeiling.assertOrgUnitsInCompany`, the org bootstrap) keep working. A composite-PK type;
|
|
6
|
+
* read wall (ADR-0027) on `cd_company_uuid`, so a non-root junction read or write is bounded to
|
|
7
|
+
* the caller's reachable subtree (create walled too, ADR-0034).
|
|
8
8
|
*/
|
|
9
9
|
export declare class CompanyDepartment {
|
|
10
10
|
companyUuid: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"company-department.object.d.ts","sourceRoot":"","sources":["../src/company-department.object.ts"],"names":[],"mappings":"AAGA;;;;;;;GAOG;AACH,
|
|
1
|
+
{"version":3,"file":"company-department.object.d.ts","sourceRoot":"","sources":["../src/company-department.object.ts"],"names":[],"mappings":"AAGA;;;;;;;GAOG;AACH,qBAQa,iBAAiB;IAE5B,WAAW,EAAG,MAAM,CAAC;IAGrB,cAAc,EAAG,MAAM,CAAC;CACzB"}
|
|
@@ -13,12 +13,12 @@ exports.CompanyDepartment = void 0;
|
|
|
13
13
|
const engine_1 = require("@astram/engine");
|
|
14
14
|
const schema_1 = require("./schema");
|
|
15
15
|
/**
|
|
16
|
-
* company_departments — the
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* `
|
|
20
|
-
* (
|
|
21
|
-
*
|
|
16
|
+
* company_departments — the company → department junction. Since G-012 (migration
|
|
17
|
+
* `1710000000105-OwnDepartmentsAndBranches`) every department is owned by one company and has
|
|
18
|
+
* exactly one junction row, to its owner; the junction stays so existing readers
|
|
19
|
+
* (`GrantCeiling.assertOrgUnitsInCompany`, the org bootstrap) keep working. A composite-PK type;
|
|
20
|
+
* read wall (ADR-0027) on `cd_company_uuid`, so a non-root junction read or write is bounded to
|
|
21
|
+
* the caller's reachable subtree (create walled too, ADR-0034).
|
|
22
22
|
*/
|
|
23
23
|
let CompanyDepartment = class CompanyDepartment {
|
|
24
24
|
companyUuid;
|
|
@@ -39,6 +39,7 @@ exports.CompanyDepartment = CompanyDepartment = __decorate([
|
|
|
39
39
|
table: 'company_departments',
|
|
40
40
|
schema: schema_1.SCHEMA,
|
|
41
41
|
access: { plane: 'control', system: true },
|
|
42
|
+
readScope: { kind: 'nodeColumn', column: 'cd_company_uuid' },
|
|
42
43
|
}),
|
|
43
44
|
(0, engine_1.PrimaryKey)({ kind: 'composite', columns: ['cd_company_uuid', 'cd_department_uuid'] })
|
|
44
45
|
], CompanyDepartment);
|
|
@@ -1,6 +1,14 @@
|
|
|
1
|
-
/**
|
|
1
|
+
/**
|
|
2
|
+
* departments — a company's own departments (G-012, spec §4/§5.B). Each row belongs to exactly one
|
|
3
|
+
* company (`d_company_uuid`, migration `1710000000105-OwnDepartmentsAndBranches`), names are unique
|
|
4
|
+
* per company, and no row is shared between companies. The owner is stamped server-side from the
|
|
5
|
+
* reached route company and never changes (`immutable`). Read wall (ADR-0027): a non-root
|
|
6
|
+
* list/get sees only rows owned by a company in its reachable subtree; a non-root create is
|
|
7
|
+
* walled the same way (ADR-0034). A legacy row with no owner (NULL) is visible to root only.
|
|
8
|
+
*/
|
|
2
9
|
export declare class Department {
|
|
3
10
|
uuid: string;
|
|
4
11
|
name: string;
|
|
12
|
+
companyUuid: string;
|
|
5
13
|
}
|
|
6
14
|
//# sourceMappingURL=department.object.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"department.object.d.ts","sourceRoot":"","sources":["../src/department.object.ts"],"names":[],"mappings":"AAGA
|
|
1
|
+
{"version":3,"file":"department.object.d.ts","sourceRoot":"","sources":["../src/department.object.ts"],"names":[],"mappings":"AAGA;;;;;;;GAOG;AACH,qBAQa,UAAU;IAErB,IAAI,EAAG,MAAM,CAAC;IAGd,IAAI,EAAG,MAAM,CAAC;IAGd,WAAW,EAAG,MAAM,CAAC;CACtB"}
|
|
@@ -12,10 +12,18 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
12
12
|
exports.Department = void 0;
|
|
13
13
|
const engine_1 = require("@astram/engine");
|
|
14
14
|
const schema_1 = require("./schema");
|
|
15
|
-
/**
|
|
15
|
+
/**
|
|
16
|
+
* departments — a company's own departments (G-012, spec §4/§5.B). Each row belongs to exactly one
|
|
17
|
+
* company (`d_company_uuid`, migration `1710000000105-OwnDepartmentsAndBranches`), names are unique
|
|
18
|
+
* per company, and no row is shared between companies. The owner is stamped server-side from the
|
|
19
|
+
* reached route company and never changes (`immutable`). Read wall (ADR-0027): a non-root
|
|
20
|
+
* list/get sees only rows owned by a company in its reachable subtree; a non-root create is
|
|
21
|
+
* walled the same way (ADR-0034). A legacy row with no owner (NULL) is visible to root only.
|
|
22
|
+
*/
|
|
16
23
|
let Department = class Department {
|
|
17
24
|
uuid;
|
|
18
25
|
name;
|
|
26
|
+
companyUuid;
|
|
19
27
|
};
|
|
20
28
|
exports.Department = Department;
|
|
21
29
|
__decorate([
|
|
@@ -26,12 +34,17 @@ __decorate([
|
|
|
26
34
|
(0, engine_1.Field)({ column: 'd_name', type: 'string', required: true }),
|
|
27
35
|
__metadata("design:type", String)
|
|
28
36
|
], Department.prototype, "name", void 0);
|
|
37
|
+
__decorate([
|
|
38
|
+
(0, engine_1.Field)({ column: 'd_company_uuid', type: 'uuid', immutable: true }),
|
|
39
|
+
__metadata("design:type", String)
|
|
40
|
+
], Department.prototype, "companyUuid", void 0);
|
|
29
41
|
exports.Department = Department = __decorate([
|
|
30
42
|
(0, engine_1.ObjectType)({
|
|
31
43
|
typeKey: 'department',
|
|
32
44
|
table: 'departments',
|
|
33
45
|
schema: schema_1.SCHEMA,
|
|
34
46
|
access: { plane: 'control', system: true },
|
|
47
|
+
readScope: { kind: 'nodeColumn', column: 'd_company_uuid' },
|
|
35
48
|
}),
|
|
36
49
|
(0, engine_1.PrimaryKey)({ kind: 'uuid', column: 'd_uuid' })
|
|
37
50
|
], Department);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"access-admin.access.d.ts","sourceRoot":"","sources":["../../../src/features/access/access-admin.access.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"access-admin.access.d.ts","sourceRoot":"","sources":["../../../src/features/access/access-admin.access.ts"],"names":[],"mappings":"AAWA,qBAUa,iBAAiB;CAAG"}
|
|
@@ -11,6 +11,10 @@ exports.AccessAdminAccess = void 0;
|
|
|
11
11
|
* `access-admin` — the role-administration seed bundle from design §6. Full role
|
|
12
12
|
* lifecycle (managing roles + the access granted to them). Every key resolves to a
|
|
13
13
|
* REAL registered `identity:<type>:<action>`.
|
|
14
|
+
*
|
|
15
|
+
* G-013 (spec §6): roles are owned per company, so every company role route reaches the company
|
|
16
|
+
* through the walled `company` read first, and the Roles page's company picker lists companies:
|
|
17
|
+
* the bundle carries `company: read` (the G-012 KI #13 lesson).
|
|
14
18
|
*/
|
|
15
19
|
const engine_1 = require("@astram/engine");
|
|
16
20
|
let AccessAdminAccess = class AccessAdminAccess {
|
|
@@ -22,6 +26,9 @@ exports.AccessAdminAccess = AccessAdminAccess = __decorate([
|
|
|
22
26
|
module: 'identity',
|
|
23
27
|
label: 'Access Administration',
|
|
24
28
|
description: 'Manage roles and the access granted to them.',
|
|
25
|
-
permissions: [
|
|
29
|
+
permissions: [
|
|
30
|
+
{ typeKey: 'role', actions: ['read', 'create', 'update', 'delete'] },
|
|
31
|
+
{ typeKey: 'company', actions: ['read'] },
|
|
32
|
+
],
|
|
26
33
|
})
|
|
27
34
|
], AccessAdminAccess);
|
|
@@ -10,6 +10,7 @@ import { UserManagementAccess } from './user-management.access';
|
|
|
10
10
|
export { UserManagementAccess } from './user-management.access';
|
|
11
11
|
export { CompanyAdminAccess } from './company-admin.access';
|
|
12
12
|
export { AccessAdminAccess } from './access-admin.access';
|
|
13
|
+
export { OrgStructureAccess } from './org-structure.access';
|
|
13
14
|
/** All identity access bundles, collected into the engine at boot. */
|
|
14
15
|
export declare const identityAccessBundles: (typeof UserManagementAccess)[];
|
|
15
16
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/features/access/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/features/access/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAKhE,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAE5D,sEAAsE;AACtE,eAAO,MAAM,qBAAqB,iCAKjC,CAAC"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.identityAccessBundles = exports.AccessAdminAccess = exports.CompanyAdminAccess = exports.UserManagementAccess = void 0;
|
|
3
|
+
exports.identityAccessBundles = exports.OrgStructureAccess = exports.AccessAdminAccess = exports.CompanyAdminAccess = exports.UserManagementAccess = void 0;
|
|
4
4
|
/**
|
|
5
5
|
* Identity access-bundles barrel. Each `@AccessBundle` class is declared in its own
|
|
6
6
|
* `<bundle>.access.ts` (co-located with the feature it grants, per the design's
|
|
@@ -12,11 +12,19 @@ exports.identityAccessBundles = exports.AccessAdminAccess = exports.CompanyAdmin
|
|
|
12
12
|
const user_management_access_1 = require("./user-management.access");
|
|
13
13
|
const company_admin_access_1 = require("./company-admin.access");
|
|
14
14
|
const access_admin_access_1 = require("./access-admin.access");
|
|
15
|
+
const org_structure_access_1 = require("./org-structure.access");
|
|
15
16
|
var user_management_access_2 = require("./user-management.access");
|
|
16
17
|
Object.defineProperty(exports, "UserManagementAccess", { enumerable: true, get: function () { return user_management_access_2.UserManagementAccess; } });
|
|
17
18
|
var company_admin_access_2 = require("./company-admin.access");
|
|
18
19
|
Object.defineProperty(exports, "CompanyAdminAccess", { enumerable: true, get: function () { return company_admin_access_2.CompanyAdminAccess; } });
|
|
19
20
|
var access_admin_access_2 = require("./access-admin.access");
|
|
20
21
|
Object.defineProperty(exports, "AccessAdminAccess", { enumerable: true, get: function () { return access_admin_access_2.AccessAdminAccess; } });
|
|
22
|
+
var org_structure_access_2 = require("./org-structure.access");
|
|
23
|
+
Object.defineProperty(exports, "OrgStructureAccess", { enumerable: true, get: function () { return org_structure_access_2.OrgStructureAccess; } });
|
|
21
24
|
/** All identity access bundles, collected into the engine at boot. */
|
|
22
|
-
exports.identityAccessBundles = [
|
|
25
|
+
exports.identityAccessBundles = [
|
|
26
|
+
user_management_access_1.UserManagementAccess,
|
|
27
|
+
company_admin_access_1.CompanyAdminAccess,
|
|
28
|
+
access_admin_access_1.AccessAdminAccess,
|
|
29
|
+
org_structure_access_1.OrgStructureAccess,
|
|
30
|
+
];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"org-structure.access.d.ts","sourceRoot":"","sources":["../../../src/features/access/org-structure.access.ts"],"names":[],"mappings":"AASA,qBAmBa,kBAAkB;CAAG"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.OrgStructureAccess = void 0;
|
|
10
|
+
/**
|
|
11
|
+
* `org-structure` (G-012, spec §5.C) — create, rename and delete a company's own departments and
|
|
12
|
+
* branches, as ONE named unit. `company:read` lets every route reach the company and the page pick
|
|
13
|
+
* one; the junction reads gate the two list routes, the junction creates the create routes; the posting read lets
|
|
14
|
+
* the list show `usedBy` (without it the list still answers, with `usedBy` omitted). The delete's
|
|
15
|
+
* in-use check needs no posting key: it is a complete count inside the service (spec §5.A).
|
|
16
|
+
*/
|
|
17
|
+
const engine_1 = require("@astram/engine");
|
|
18
|
+
let OrgStructureAccess = class OrgStructureAccess {
|
|
19
|
+
};
|
|
20
|
+
exports.OrgStructureAccess = OrgStructureAccess;
|
|
21
|
+
exports.OrgStructureAccess = OrgStructureAccess = __decorate([
|
|
22
|
+
(0, engine_1.AccessBundle)({
|
|
23
|
+
key: 'org-structure',
|
|
24
|
+
module: 'identity',
|
|
25
|
+
label: 'Org Structure',
|
|
26
|
+
description: 'Create, rename and delete departments and branches.',
|
|
27
|
+
permissions: [
|
|
28
|
+
// `company:read`: every route reaches the company through the walled read first, and the Org
|
|
29
|
+
// structure page's company picker lists the companies the caller can reach (G-012 live proof).
|
|
30
|
+
{ typeKey: 'company', actions: ['read'] },
|
|
31
|
+
{ typeKey: 'department', actions: ['read', 'create', 'update', 'delete'] },
|
|
32
|
+
{ typeKey: 'branch', actions: ['read', 'create', 'update', 'delete'] },
|
|
33
|
+
// `create` on the junctions: creating a department or branch also writes its one junction row
|
|
34
|
+
// through the engine pipe, which gates `identity:company_department|company_branch:create`
|
|
35
|
+
// (security review P1). Deletes need no junction key: the junction row cascades.
|
|
36
|
+
{ typeKey: 'company_department', actions: ['read', 'create'] },
|
|
37
|
+
{ typeKey: 'company_branch', actions: ['read', 'create'] },
|
|
38
|
+
{ typeKey: 'membership_posting', actions: ['read'] },
|
|
39
|
+
],
|
|
40
|
+
})
|
|
41
|
+
], OrgStructureAccess);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"user-management.access.d.ts","sourceRoot":"","sources":["../../../src/features/access/user-management.access.ts"],"names":[],"mappings":"AAQA,
|
|
1
|
+
{"version":3,"file":"user-management.access.d.ts","sourceRoot":"","sources":["../../../src/features/access/user-management.access.ts"],"names":[],"mappings":"AAQA,qBAmBa,oBAAoB;CAAG"}
|
|
@@ -25,9 +25,14 @@ exports.UserManagementAccess = UserManagementAccess = __decorate([
|
|
|
25
25
|
description: 'Create, edit and assign users to companies.',
|
|
26
26
|
permissions: [
|
|
27
27
|
{ typeKey: 'user', actions: ['read', 'create', 'update', 'delete'] },
|
|
28
|
+
// G-012: the department/branch lists reach the company through the walled company read first.
|
|
29
|
+
{ typeKey: 'company', actions: ['read'] },
|
|
28
30
|
{ typeKey: 'role', actions: ['read'] },
|
|
29
31
|
{ typeKey: 'department', actions: ['read'] },
|
|
30
32
|
{ typeKey: 'branch', actions: ['read'] },
|
|
33
|
+
// G-012: the posting editor lists a company's departments and branches through these.
|
|
34
|
+
{ typeKey: 'company_department', actions: ['read'] },
|
|
35
|
+
{ typeKey: 'company_branch', actions: ['read'] },
|
|
31
36
|
{ typeKey: 'company_membership', actions: ['read', 'create', 'update', 'delete'] },
|
|
32
37
|
{ typeKey: 'membership_posting', actions: ['read', 'update'] },
|
|
33
38
|
],
|
|
@@ -1,7 +1,24 @@
|
|
|
1
1
|
import type { AuditEvent, LabelResolver } from '@astram/core';
|
|
2
|
+
/**
|
|
3
|
+
* What kind of actor wrote an audit row (KI #140): a user, a service account (API key), a framework
|
|
4
|
+
* operation (org bootstrap, audit retention prune), or an id found nowhere (`'unknown'`, shown as
|
|
5
|
+
* "Deleted user").
|
|
6
|
+
*/
|
|
7
|
+
export type AuditActorKind = 'user' | 'service_account' | 'operation' | 'unknown';
|
|
8
|
+
/** A directory lookup of an actor id: never an operation (those are labelled without a lookup). */
|
|
9
|
+
export interface ResolvedActor {
|
|
10
|
+
readonly kind: Exclude<AuditActorKind, 'operation'>;
|
|
11
|
+
readonly label: string;
|
|
12
|
+
}
|
|
13
|
+
/** The actor directory port (`DirectoryLabelResolver` implements it). A throw propagates. */
|
|
14
|
+
export interface ActorLabelResolver {
|
|
15
|
+
resolveActor(actorId: string): Promise<ResolvedActor>;
|
|
16
|
+
}
|
|
2
17
|
export interface AuditRow {
|
|
3
18
|
readonly occurredAt: number;
|
|
4
19
|
readonly actorLabel: string;
|
|
20
|
+
/** Additive (KI #140): lets the viewer badge non-user actors. */
|
|
21
|
+
readonly actorKind: AuditActorKind;
|
|
5
22
|
readonly action: string;
|
|
6
23
|
readonly tenantLabel: string;
|
|
7
24
|
readonly detail: Record<string, unknown>;
|
|
@@ -63,7 +80,11 @@ export declare class AuditReadService {
|
|
|
63
80
|
private readonly reader;
|
|
64
81
|
private readonly labels;
|
|
65
82
|
private readonly actorNameResolver;
|
|
66
|
-
|
|
83
|
+
/** Absent ⇒ every non-operation actor resolves as a user via `labels` (the pre-KI #140 shape). */
|
|
84
|
+
private readonly actors?;
|
|
85
|
+
constructor(reader: PagedAuditReader, labels: LabelResolver, actorNameResolver: ActorNameResolver,
|
|
86
|
+
/** Absent ⇒ every non-operation actor resolves as a user via `labels` (the pre-KI #140 shape). */
|
|
87
|
+
actors?: ActorLabelResolver | undefined);
|
|
67
88
|
/**
|
|
68
89
|
* A numbered (offset + total) audit page. Scope is derived from the PRINCIPAL ALONE — a
|
|
69
90
|
* non-root is pinned to its own tenant (tenantFilter ignored); a root gets the all-tenants
|
|
@@ -83,6 +104,16 @@ export declare class AuditReadService {
|
|
|
83
104
|
page: number;
|
|
84
105
|
limit: number;
|
|
85
106
|
}>;
|
|
107
|
+
/**
|
|
108
|
+
* The actor of one row (KI #140). A reserved operation principal (guard's registry) and an
|
|
109
|
+
* audit-prune row are labelled without any lookup, naming the human operator from the row's own
|
|
110
|
+
* free text (`onBehalfOf` / the prune actor), never an id; everything else goes to the directory.
|
|
111
|
+
*/
|
|
112
|
+
private resolveActor;
|
|
113
|
+
/** A prune row: one of the prune's own types on the platform tenant (`'*'`). */
|
|
114
|
+
private isAuditPrune;
|
|
115
|
+
/** Free-text operator name, verbatim; absent, blank or uuid-shaped ⇒ "unknown operator". */
|
|
116
|
+
private operatorName;
|
|
86
117
|
/**
|
|
87
118
|
* Remove obvious raw-uuid-bearing keys from the attributes detail so no raw id leaks.
|
|
88
119
|
* Keeps non-id fields; drops keys ending in `Uuid`/`Id`/`_uuid`/`_id` and any uuid-shaped value.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"audit-read.service.d.ts","sourceRoot":"","sources":["../../../src/features/audit/audit-read.service.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"audit-read.service.d.ts","sourceRoot":"","sources":["../../../src/features/audit/audit-read.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,8 +1,17 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.AuditReadService = void 0;
|
|
4
|
+
const guard_1 = require("@astram/guard");
|
|
4
5
|
const ALL_TENANTS = '*';
|
|
5
6
|
const DEFAULT_LIMIT = 50;
|
|
7
|
+
const UUID_SHAPED = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
8
|
+
/** `al_type` of the rows `astram-migrate audit:prune` writes (tenant `'*'`, actor = operator). */
|
|
9
|
+
const AUDIT_PRUNE_TYPES = new Set([
|
|
10
|
+
'audit.retention_prune_started',
|
|
11
|
+
'audit.retention_pruned',
|
|
12
|
+
]);
|
|
13
|
+
const PLATFORM_TENANT_LABEL = 'Platform';
|
|
14
|
+
const UNKNOWN_OPERATOR = 'unknown operator';
|
|
6
15
|
const MAX_LIMIT = 200;
|
|
7
16
|
/**
|
|
8
17
|
* The audit viewer read-model wrapper (design §2, §3): derives scope from the PRINCIPAL
|
|
@@ -15,10 +24,14 @@ class AuditReadService {
|
|
|
15
24
|
reader;
|
|
16
25
|
labels;
|
|
17
26
|
actorNameResolver;
|
|
18
|
-
|
|
27
|
+
actors;
|
|
28
|
+
constructor(reader, labels, actorNameResolver,
|
|
29
|
+
/** Absent ⇒ every non-operation actor resolves as a user via `labels` (the pre-KI #140 shape). */
|
|
30
|
+
actors) {
|
|
19
31
|
this.reader = reader;
|
|
20
32
|
this.labels = labels;
|
|
21
33
|
this.actorNameResolver = actorNameResolver;
|
|
34
|
+
this.actors = actors;
|
|
22
35
|
}
|
|
23
36
|
/**
|
|
24
37
|
* A numbered (offset + total) audit page. Scope is derived from the PRINCIPAL ALONE — a
|
|
@@ -70,26 +83,66 @@ class AuditReadService {
|
|
|
70
83
|
this.reader.count(scopeQuery),
|
|
71
84
|
this.reader.read({ ...scopeQuery, limit, offset }),
|
|
72
85
|
]);
|
|
73
|
-
// Resolve labels DIRECTLY (the core `auditView` engine is no longer in this path):
|
|
74
|
-
//
|
|
75
|
-
//
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
86
|
+
// Resolve labels DIRECTLY (the core `auditView` engine is no longer in this path): the actor by
|
|
87
|
+
// kind (operation registry, then the actor directory) and tenantLabel via
|
|
88
|
+
// labels.resolve('tenant', ...) — no raw id is ever a label. A resolver throw propagates
|
|
89
|
+
// (fail-closed).
|
|
90
|
+
const rows = await Promise.all(events.map(async (event) => {
|
|
91
|
+
const prune = this.isAuditPrune(event);
|
|
92
|
+
const actor = await this.resolveActor(event, prune);
|
|
93
|
+
const actionKey = event.action?.key ??
|
|
94
|
+
event.action;
|
|
95
|
+
return {
|
|
96
|
+
occurredAt: event.occurredAtMs,
|
|
97
|
+
actorLabel: actor.label,
|
|
98
|
+
actorKind: actor.kind,
|
|
99
|
+
action: actionKey ?? (prune ? String(event.type) : '(event)'),
|
|
100
|
+
tenantLabel: event.tenantId === ALL_TENANTS
|
|
101
|
+
? PLATFORM_TENANT_LABEL
|
|
102
|
+
: await this.labels.resolve('tenant', event.tenantId),
|
|
103
|
+
detail: this.stripIds(event.attributes ?? {}),
|
|
104
|
+
};
|
|
105
|
+
}));
|
|
85
106
|
return { rows, total, page, limit };
|
|
86
107
|
}
|
|
108
|
+
/**
|
|
109
|
+
* The actor of one row (KI #140). A reserved operation principal (guard's registry) and an
|
|
110
|
+
* audit-prune row are labelled without any lookup, naming the human operator from the row's own
|
|
111
|
+
* free text (`onBehalfOf` / the prune actor), never an id; everything else goes to the directory.
|
|
112
|
+
*/
|
|
113
|
+
async resolveActor(event, prune) {
|
|
114
|
+
const reserved = (0, guard_1.reservedOperationPrincipal)(event.actorId);
|
|
115
|
+
if (reserved) {
|
|
116
|
+
const operator = this.operatorName(event.attributes?.['onBehalfOf']);
|
|
117
|
+
return { kind: 'operation', label: `${reserved.label} (on behalf of ${operator})` };
|
|
118
|
+
}
|
|
119
|
+
if (prune) {
|
|
120
|
+
return {
|
|
121
|
+
kind: 'operation',
|
|
122
|
+
label: `Audit retention prune (${this.operatorName(event.actorId)})`,
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
if (this.actors)
|
|
126
|
+
return this.actors.resolveActor(event.actorId);
|
|
127
|
+
return { kind: 'user', label: await this.labels.resolve('principal', event.actorId) };
|
|
128
|
+
}
|
|
129
|
+
/** A prune row: one of the prune's own types on the platform tenant (`'*'`). */
|
|
130
|
+
isAuditPrune(event) {
|
|
131
|
+
return event.tenantId === ALL_TENANTS && AUDIT_PRUNE_TYPES.has(String(event.type));
|
|
132
|
+
}
|
|
133
|
+
/** Free-text operator name, verbatim; absent, blank or uuid-shaped ⇒ "unknown operator". */
|
|
134
|
+
operatorName(value) {
|
|
135
|
+
if (typeof value !== 'string')
|
|
136
|
+
return UNKNOWN_OPERATOR;
|
|
137
|
+
const name = value.trim();
|
|
138
|
+
return name.length === 0 || UUID_SHAPED.test(name) ? UNKNOWN_OPERATOR : name;
|
|
139
|
+
}
|
|
87
140
|
/**
|
|
88
141
|
* Remove obvious raw-uuid-bearing keys from the attributes detail so no raw id leaks.
|
|
89
142
|
* Keeps non-id fields; drops keys ending in `Uuid`/`Id`/`_uuid`/`_id` and any uuid-shaped value.
|
|
90
143
|
*/
|
|
91
144
|
stripIds(attrs) {
|
|
92
|
-
const UUID =
|
|
145
|
+
const UUID = UUID_SHAPED;
|
|
93
146
|
const out = {};
|
|
94
147
|
for (const [k, val] of Object.entries(attrs)) {
|
|
95
148
|
if (/uuid$|Id$|_id$/i.test(k))
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The framework default for guard's auth `AuditSink` (R12.1, B-3).
|
|
3
|
+
*
|
|
4
|
+
* `IdentityFeatureModule.forRoot` binds it on guard's `SHIELD_DEFAULT_AUTH_AUDIT_SINK`; guard's
|
|
5
|
+
* `SHIELD_AUDIT_SINK` uses it when the app supplied no `auditSink`. It maps guard's
|
|
6
|
+
* `AuthAuditEvent` onto the engine `MariaDbAuditSink` row (`<ns>_audit.audit_log`, the table the
|
|
7
|
+
* G3 sealer chains per tenant, ADR-0044), written with its own autocommit query, outside any
|
|
8
|
+
* business transaction.
|
|
9
|
+
*
|
|
10
|
+
* - An event without an actor or a tenant is skipped: `audit_log` requires both, and a row must
|
|
11
|
+
* be attributable to a tenant chain. (Guard's per-IP lockout and the pre-auth forgot-password
|
|
12
|
+
* throttles carry neither; they stay counters.)
|
|
13
|
+
* - Best-effort: an error is swallowed. Guard's emit is fire-and-forget, so sign-in never waits
|
|
14
|
+
* on, or fails because of, this write.
|
|
15
|
+
*/
|
|
16
|
+
import type { AuditSink } from '@astram/guard';
|
|
17
|
+
import type { MariaDbAuditSink, QueryFn } from '@astram/engine';
|
|
18
|
+
export declare function createDefaultAuthAuditSink(engineSink: Pick<MariaDbAuditSink, 'record'>, query: QueryFn): AuditSink;
|
|
19
|
+
//# sourceMappingURL=auth-audit-sink.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth-audit-sink.d.ts","sourceRoot":"","sources":["../../../src/features/audit/auth-audit-sink.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,KAAK,EAAE,SAAS,EAAkB,MAAM,eAAe,CAAC;AAC/D,OAAO,KAAK,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAEhE,wBAAgB,0BAA0B,CACxC,UAAU,EAAE,IAAI,CAAC,gBAAgB,EAAE,QAAQ,CAAC,EAC5C,KAAK,EAAE,OAAO,GACb,SAAS,CAqBX"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createDefaultAuthAuditSink = createDefaultAuthAuditSink;
|
|
4
|
+
function createDefaultAuthAuditSink(engineSink, query) {
|
|
5
|
+
return {
|
|
6
|
+
async record(event) {
|
|
7
|
+
if (!event.actorId || !event.tenantId)
|
|
8
|
+
return;
|
|
9
|
+
try {
|
|
10
|
+
await engineSink.record({
|
|
11
|
+
type: event.type,
|
|
12
|
+
occurredAtMs: event.occurredAtMs,
|
|
13
|
+
actorId: event.actorId,
|
|
14
|
+
tenantId: event.tenantId,
|
|
15
|
+
action: { key: event.action },
|
|
16
|
+
...(event.attributes !== undefined ? { attributes: event.attributes } : {}),
|
|
17
|
+
}, query);
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
// Best-effort: an audit write failure never reaches the auth flow.
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
};
|
|
24
|
+
}
|