@astram/guard 0.1.1 → 0.3.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/auth/account.controller.d.ts +245 -0
- package/dist/auth/account.controller.d.ts.map +1 -0
- package/dist/auth/account.controller.js +673 -0
- package/dist/auth/account.controller.js.map +1 -0
- package/dist/auth/auth.controller.d.ts +316 -0
- package/dist/auth/auth.controller.d.ts.map +1 -0
- package/dist/auth/auth.controller.js +1091 -0
- package/dist/auth/auth.controller.js.map +1 -0
- package/dist/auth/auth.module.d.ts +202 -0
- package/dist/auth/auth.module.d.ts.map +1 -0
- package/dist/auth/auth.module.js +610 -0
- package/dist/auth/auth.module.js.map +1 -0
- package/dist/auth/connections.d.ts +61 -0
- package/dist/auth/connections.d.ts.map +1 -0
- package/dist/auth/connections.js +116 -0
- package/dist/auth/connections.js.map +1 -0
- package/dist/auth/dto.d.ts +154 -0
- package/dist/auth/dto.d.ts.map +1 -0
- package/dist/auth/dto.js +29 -0
- package/dist/auth/dto.js.map +1 -0
- package/dist/auth/pending-mfa-store.d.ts +72 -0
- package/dist/auth/pending-mfa-store.d.ts.map +1 -0
- package/dist/auth/pending-mfa-store.js +106 -0
- package/dist/auth/pending-mfa-store.js.map +1 -0
- package/dist/auth/persistence.module.d.ts +42 -0
- package/dist/auth/persistence.module.d.ts.map +1 -0
- package/dist/auth/persistence.module.js +94 -0
- package/dist/auth/persistence.module.js.map +1 -0
- package/dist/auth/ports/audit-sink.d.ts +47 -0
- package/dist/auth/ports/audit-sink.d.ts.map +1 -0
- package/dist/auth/ports/audit-sink.js +20 -0
- package/dist/auth/ports/audit-sink.js.map +1 -0
- package/dist/auth/ports/credential-writer.d.ts +23 -0
- package/dist/auth/ports/credential-writer.d.ts.map +1 -0
- package/dist/auth/ports/credential-writer.js +2 -0
- package/dist/auth/ports/credential-writer.js.map +1 -0
- package/dist/auth/ports/email-sender.d.ts +14 -0
- package/dist/auth/ports/email-sender.d.ts.map +1 -0
- package/dist/auth/ports/email-sender.js +2 -0
- package/dist/auth/ports/email-sender.js.map +1 -0
- package/dist/auth/ports/mfa-device-store.d.ts +45 -0
- package/dist/auth/ports/mfa-device-store.d.ts.map +1 -0
- package/dist/auth/ports/mfa-device-store.js +13 -0
- package/dist/auth/ports/mfa-device-store.js.map +1 -0
- package/dist/auth/ports/profile-writer.d.ts +12 -0
- package/dist/auth/ports/profile-writer.d.ts.map +1 -0
- package/dist/auth/ports/profile-writer.js +2 -0
- package/dist/auth/ports/profile-writer.js.map +1 -0
- package/dist/auth/ports/recovery-code-store.d.ts +10 -0
- package/dist/auth/ports/recovery-code-store.d.ts.map +1 -0
- package/dist/auth/ports/recovery-code-store.js +2 -0
- package/dist/auth/ports/recovery-code-store.js.map +1 -0
- package/dist/auth/ports/reset-token-store.d.ts +12 -0
- package/dist/auth/ports/reset-token-store.d.ts.map +1 -0
- package/dist/auth/ports/reset-token-store.js +2 -0
- package/dist/auth/ports/reset-token-store.js.map +1 -0
- package/dist/auth/ports/session-facts-projector.d.ts +44 -0
- package/dist/auth/ports/session-facts-projector.d.ts.map +1 -0
- package/dist/auth/ports/session-facts-projector.js +30 -0
- package/dist/auth/ports/session-facts-projector.js.map +1 -0
- package/dist/auth/ports/session-sweeper.d.ts +12 -0
- package/dist/auth/ports/session-sweeper.d.ts.map +1 -0
- package/dist/auth/ports/session-sweeper.js +2 -0
- package/dist/auth/ports/session-sweeper.js.map +1 -0
- package/dist/auth/profile-resolver.d.ts +73 -0
- package/dist/auth/profile-resolver.d.ts.map +1 -0
- package/dist/auth/profile-resolver.js +28 -0
- package/dist/auth/profile-resolver.js.map +1 -0
- package/dist/auth/rate-limit/attempt-limiter.d.ts +91 -0
- package/dist/auth/rate-limit/attempt-limiter.d.ts.map +1 -0
- package/dist/auth/rate-limit/attempt-limiter.js +133 -0
- package/dist/auth/rate-limit/attempt-limiter.js.map +1 -0
- package/dist/auth/tokens.d.ts +236 -0
- package/dist/auth/tokens.d.ts.map +1 -0
- package/dist/auth/tokens.js +254 -0
- package/dist/auth/tokens.js.map +1 -0
- package/dist/auth/totp-enrollment.d.ts +42 -0
- package/dist/auth/totp-enrollment.d.ts.map +1 -0
- package/dist/auth/totp-enrollment.js +96 -0
- package/dist/auth/totp-enrollment.js.map +1 -0
- package/dist/authentication/argon2id-password-hasher.js.map +1 -0
- package/dist/authentication/mariadb-credential-resolver.d.ts +110 -0
- package/dist/authentication/mariadb-credential-resolver.d.ts.map +1 -0
- package/dist/authentication/mariadb-credential-resolver.js +170 -0
- package/dist/authentication/mariadb-credential-resolver.js.map +1 -0
- package/dist/authz/cross-tenant-grant-writer.d.ts +259 -0
- package/dist/authz/cross-tenant-grant-writer.d.ts.map +1 -0
- package/dist/authz/cross-tenant-grant-writer.js +397 -0
- package/dist/authz/cross-tenant-grant-writer.js.map +1 -0
- package/dist/authz/manifest-operation-authority-adapter.d.ts +65 -0
- package/dist/authz/manifest-operation-authority-adapter.d.ts.map +1 -0
- package/dist/authz/manifest-operation-authority-adapter.js +108 -0
- package/dist/authz/manifest-operation-authority-adapter.js.map +1 -0
- package/dist/authz/mariadb-cross-tenant-grant-adapter.d.ts +90 -0
- package/dist/authz/mariadb-cross-tenant-grant-adapter.d.ts.map +1 -0
- package/dist/authz/mariadb-cross-tenant-grant-adapter.js +211 -0
- package/dist/authz/mariadb-cross-tenant-grant-adapter.js.map +1 -0
- package/dist/authz/mariadb-record-rule-adapter.d.ts +60 -0
- package/dist/authz/mariadb-record-rule-adapter.d.ts.map +1 -0
- package/dist/authz/mariadb-record-rule-adapter.js +154 -0
- package/dist/authz/mariadb-record-rule-adapter.js.map +1 -0
- package/dist/authz/mariadb-record-share-adapter.d.ts +75 -0
- package/dist/authz/mariadb-record-share-adapter.d.ts.map +1 -0
- package/dist/authz/mariadb-record-share-adapter.js +106 -0
- package/dist/authz/mariadb-record-share-adapter.js.map +1 -0
- package/dist/authz/record-share-cascade.d.ts +52 -0
- package/dist/authz/record-share-cascade.d.ts.map +1 -0
- package/dist/authz/record-share-cascade.js +49 -0
- package/dist/authz/record-share-cascade.js.map +1 -0
- package/dist/authz/record-share-writer.d.ts +175 -0
- package/dist/authz/record-share-writer.d.ts.map +1 -0
- package/dist/authz/record-share-writer.js +225 -0
- package/dist/authz/record-share-writer.js.map +1 -0
- package/dist/authz/wire-record-authorization.d.ts +66 -0
- package/dist/authz/wire-record-authorization.d.ts.map +1 -0
- package/dist/authz/wire-record-authorization.js +34 -0
- package/dist/authz/wire-record-authorization.js.map +1 -0
- package/dist/boot/boot-sequence.js.map +1 -0
- package/dist/boot/boot.module.js.map +1 -0
- package/dist/completeness/catalog-reconciler.d.ts +21 -0
- package/dist/completeness/catalog-reconciler.d.ts.map +1 -0
- package/dist/completeness/catalog-reconciler.js +74 -0
- package/dist/completeness/catalog-reconciler.js.map +1 -0
- package/dist/completeness/operation-inventory-scanner.d.ts +17 -0
- package/dist/completeness/operation-inventory-scanner.d.ts.map +1 -0
- package/dist/completeness/operation-inventory-scanner.js +79 -0
- package/dist/completeness/operation-inventory-scanner.js.map +1 -0
- package/dist/completeness/ports/catalog-store.d.ts +33 -0
- package/dist/completeness/ports/catalog-store.d.ts.map +1 -0
- package/dist/completeness/ports/catalog-store.js +2 -0
- package/dist/completeness/ports/catalog-store.js.map +1 -0
- package/dist/config/app-config.d.ts +134 -1
- package/dist/config/app-config.d.ts.map +1 -1
- package/dist/config/app-config.js +144 -2
- package/dist/config/app-config.js.map +1 -0
- package/dist/config/config.module.js.map +1 -0
- package/dist/enforcement/classification.decorator.d.ts +33 -14
- package/dist/enforcement/classification.decorator.d.ts.map +1 -1
- package/dist/enforcement/classification.decorator.js +34 -14
- package/dist/enforcement/classification.decorator.js.map +1 -0
- package/dist/enforcement/core-seam.js.map +1 -0
- package/dist/enforcement/enforcement.module.js.map +1 -0
- package/dist/enforcement/global-enforcement.guard.d.ts +29 -19
- package/dist/enforcement/global-enforcement.guard.d.ts.map +1 -1
- package/dist/enforcement/global-enforcement.guard.js +108 -25
- package/dist/enforcement/global-enforcement.guard.js.map +1 -0
- package/dist/enforcement/reenroll-allowlist.d.ts +49 -0
- package/dist/enforcement/reenroll-allowlist.d.ts.map +1 -0
- package/dist/enforcement/reenroll-allowlist.js +77 -0
- package/dist/enforcement/reenroll-allowlist.js.map +1 -0
- package/dist/index.d.ts +43 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +198 -1
- package/dist/index.js.map +1 -0
- package/dist/module/shield-tokens.d.ts +15 -0
- package/dist/module/shield-tokens.d.ts.map +1 -0
- package/dist/module/shield-tokens.js +17 -0
- package/dist/module/shield-tokens.js.map +1 -0
- package/dist/module/shield.module.d.ts +203 -8
- package/dist/module/shield.module.d.ts.map +1 -1
- package/dist/module/shield.module.js +232 -14
- package/dist/module/shield.module.js.map +1 -0
- package/dist/request-auth/request-principal.d.ts +42 -0
- package/dist/request-auth/request-principal.d.ts.map +1 -0
- package/dist/request-auth/request-principal.js +87 -0
- package/dist/request-auth/request-principal.js.map +1 -0
- package/dist/request-auth/session-facts-als.d.ts +65 -0
- package/dist/request-auth/session-facts-als.d.ts.map +1 -0
- package/dist/request-auth/session-facts-als.js +57 -0
- package/dist/request-auth/session-facts-als.js.map +1 -0
- package/dist/request-auth/session-token-binder.d.ts +130 -0
- package/dist/request-auth/session-token-binder.d.ts.map +1 -0
- package/dist/request-auth/session-token-binder.js +277 -0
- package/dist/request-auth/session-token-binder.js.map +1 -0
- package/dist/request-auth/tokens.d.ts +14 -0
- package/dist/request-auth/tokens.d.ts.map +1 -0
- package/dist/request-auth/tokens.js +16 -0
- package/dist/request-auth/tokens.js.map +1 -0
- package/dist/session/crypto-adapters.js.map +1 -0
- package/dist/session/index.js.map +1 -0
- package/dist/session/mariadb-session-record-store.js.map +1 -0
- package/dist/session/redis-hot-session-store.js.map +1 -0
- package/package.json +2 -2
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `buildRecordAuthorization` — the ONE place the four framework-owned record-tier
|
|
3
|
+
* guard adapters are constructed and handed to core's `createWiredDecisionAuthority`
|
|
4
|
+
* (design §9, Phase 5 — "the framework pre-wires").
|
|
5
|
+
*
|
|
6
|
+
* ── WHY THIS FILE EXISTS (the record-tier ownership invariant, ADR-0003 / the
|
|
7
|
+
* "framework-owns-the-data-layer" initiative): before Phase 5, the CONSUMER app
|
|
8
|
+
* hand-constructed `MariaDbRecordPermissionRuleAdapter` / `MariaDbRecordShareAdapter`
|
|
9
|
+
* / `MariaDbCrossTenantGrantAdapter` / `ManifestOperationAuthorityAdapter` and called
|
|
10
|
+
* core's `createWiredDecisionAuthority` itself. That meant the app COULD swap in a
|
|
11
|
+
* fail-OPEN record adapter — the exact hole the initiative closes. Phase 5 moves that
|
|
12
|
+
* construction HERE, inside the framework: the app supplies ONLY the DB pool + the two
|
|
13
|
+
* app-owned ports (`permissionFacts`, `sessionFacts`) + the module registry + the
|
|
14
|
+
* operation-manifest DATA. The four record-tier read adapters are framework-built and
|
|
15
|
+
* UN-overridable — a planted fail-open adapter is now impossible.
|
|
16
|
+
*
|
|
17
|
+
* ── WHY IT IS NOT STATICALLY IMPORTED BY shield.module.ts (the enforcement-only
|
|
18
|
+
* invariant): this file value-imports `@astram/core` (`createWiredDecisionAuthority`)
|
|
19
|
+
* and the adapter classes (which themselves value-import core). `shield.module.ts` is
|
|
20
|
+
* deliberately kept core-free in its OWN compiled output (see its header) so the
|
|
21
|
+
* enforcement-only path is provably free of a top-level `require('@astram/core')`.
|
|
22
|
+
* So `shield.module.ts` reaches `buildRecordAuthorization` ONLY through a LAZY dynamic
|
|
23
|
+
* import inside the `SHIELD_DECISION_AUTHORITY` async factory — which runs ONLY when a
|
|
24
|
+
* consumer opts into `recordAuthorization`. This file (and thus core) loads only then.
|
|
25
|
+
*/
|
|
26
|
+
import type { DecisionAuthority, ModuleRegistry, PermissionFactsPort, SessionFactsReader } from '@astram/core';
|
|
27
|
+
import { type RuleQueryable } from './mariadb-record-rule-adapter.js';
|
|
28
|
+
import { type OperationManifestEntry } from './manifest-operation-authority-adapter.js';
|
|
29
|
+
/**
|
|
30
|
+
* The pieces a consumer supplies for the framework to build the real record-tier
|
|
31
|
+
* DecisionAuthority. The app owns ONLY these — the pool, the two app-owned ports, the
|
|
32
|
+
* module registry, and the operation-manifest DATA. The four record-tier read adapters
|
|
33
|
+
* are framework-constructed from `pool` and are DELIBERATELY NOT part of this shape
|
|
34
|
+
* (they cannot be overridden — the Phase-5 acceptance criterion).
|
|
35
|
+
*/
|
|
36
|
+
export interface RecordAuthorizationInputs {
|
|
37
|
+
/**
|
|
38
|
+
* The MariaDB pool the three DB-backed record-tier adapters read through. Typed
|
|
39
|
+
* structurally (`RuleQueryable`: `{ query(sql, params?) }`) — a `mariadb` `Pool`
|
|
40
|
+
* satisfies it — so the guard module signature does not force a hard `mariadb` type
|
|
41
|
+
* on consumers that inject a custom queryable. The framework builds the adapters over
|
|
42
|
+
* THIS pool; the app never constructs them.
|
|
43
|
+
*/
|
|
44
|
+
readonly pool: RuleQueryable;
|
|
45
|
+
/** APP-OWNED port: the principal's coarse grants for the object-type gate (gate 5). */
|
|
46
|
+
readonly permissionFacts: PermissionFactsPort;
|
|
47
|
+
/** APP-OWNED port: per-request cached session facts (null-slot until the Redis hot path). */
|
|
48
|
+
readonly sessionFacts: SessionFactsReader;
|
|
49
|
+
/** APP-OWNED: the module registry (object types + actions + tiers), bridged from the app's registrations. */
|
|
50
|
+
readonly registry: ModuleRegistry;
|
|
51
|
+
/**
|
|
52
|
+
* APP-SUPPLIED DATA (not an adapter): the declared trusted-operation manifest entries.
|
|
53
|
+
* The framework constructs the `ManifestOperationAuthorityAdapter` over them. Empty
|
|
54
|
+
* (default) ⇒ every delegation lookup is pass-through (undefined). The app supplies the
|
|
55
|
+
* ENTRIES; the framework owns the ADAPTER.
|
|
56
|
+
*/
|
|
57
|
+
readonly operationManifest?: readonly OperationManifestEntry[];
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Construct the four framework-owned record-tier adapters over the supplied pool +
|
|
61
|
+
* manifest, and return the fully-wired core {@link DecisionAuthority}. Behavior-identical
|
|
62
|
+
* to what the consumer's `buildDecisionAuthority` did before Phase 5 (same adapters, same
|
|
63
|
+
* pool, same registry, same ports) — this is a wiring MOVE, not a logic change.
|
|
64
|
+
*/
|
|
65
|
+
export declare function buildRecordAuthorization(inputs: RecordAuthorizationInputs): DecisionAuthority;
|
|
66
|
+
//# sourceMappingURL=wire-record-authorization.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wire-record-authorization.d.ts","sourceRoot":"","sources":["../../src/authz/wire-record-authorization.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,OAAO,KAAK,EACV,iBAAiB,EACjB,cAAc,EACd,mBAAmB,EACnB,kBAAkB,EACnB,MAAM,cAAc,CAAC;AAEtB,OAAO,EAEL,KAAK,aAAa,EACnB,MAAM,kCAAkC,CAAC;AAG1C,OAAO,EAEL,KAAK,sBAAsB,EAC5B,MAAM,2CAA2C,CAAC;AAEnD;;;;;;GAMG;AACH,MAAM,WAAW,yBAAyB;IACxC;;;;;;OAMG;IACH,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;IAC7B,uFAAuF;IACvF,QAAQ,CAAC,eAAe,EAAE,mBAAmB,CAAC;IAC9C,6FAA6F;IAC7F,QAAQ,CAAC,YAAY,EAAE,kBAAkB,CAAC;IAC1C,6GAA6G;IAC7G,QAAQ,CAAC,QAAQ,EAAE,cAAc,CAAC;IAClC;;;;;OAKG;IACH,QAAQ,CAAC,iBAAiB,CAAC,EAAE,SAAS,sBAAsB,EAAE,CAAC;CAChE;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,yBAAyB,GAAG,iBAAiB,CAmB7F"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.buildRecordAuthorization = buildRecordAuthorization;
|
|
4
|
+
const core_1 = require("@astram/core");
|
|
5
|
+
const mariadb_record_rule_adapter_js_1 = require("./mariadb-record-rule-adapter.js");
|
|
6
|
+
const mariadb_record_share_adapter_js_1 = require("./mariadb-record-share-adapter.js");
|
|
7
|
+
const mariadb_cross_tenant_grant_adapter_js_1 = require("./mariadb-cross-tenant-grant-adapter.js");
|
|
8
|
+
const manifest_operation_authority_adapter_js_1 = require("./manifest-operation-authority-adapter.js");
|
|
9
|
+
/**
|
|
10
|
+
* Construct the four framework-owned record-tier adapters over the supplied pool +
|
|
11
|
+
* manifest, and return the fully-wired core {@link DecisionAuthority}. Behavior-identical
|
|
12
|
+
* to what the consumer's `buildDecisionAuthority` did before Phase 5 (same adapters, same
|
|
13
|
+
* pool, same registry, same ports) — this is a wiring MOVE, not a logic change.
|
|
14
|
+
*/
|
|
15
|
+
function buildRecordAuthorization(inputs) {
|
|
16
|
+
return (0, core_1.createWiredDecisionAuthority)({
|
|
17
|
+
registry: inputs.registry,
|
|
18
|
+
permissionFacts: inputs.permissionFacts,
|
|
19
|
+
sessionFacts: inputs.sessionFacts,
|
|
20
|
+
// ── The FOUR framework-owned record-tier adapters — constructed HERE, and ONLY here.
|
|
21
|
+
// Record-permit ADMIN rules over `shield_authz.record_permission_rule` (widen the
|
|
22
|
+
// core-owned owner baseline, deny-wins). Empty table ⇒ owner-only (NOT a lockout).
|
|
23
|
+
recordRule: new mariadb_record_rule_adapter_js_1.MariaDbRecordPermissionRuleAdapter(inputs.pool),
|
|
24
|
+
// Per-record SHARE source over `shield_authz.record_share` (widening permit, union
|
|
25
|
+
// with baseline under deny-wins). No share ⇒ false (baseline still governs).
|
|
26
|
+
recordShare: new mariadb_record_share_adapter_js_1.MariaDbRecordShareAdapter(inputs.pool),
|
|
27
|
+
// Cross-tenant consented grants over `shield_authz.cross_tenant_grant`. No active
|
|
28
|
+
// grant ⇒ null (deny-by-default for the cross-tenant reach).
|
|
29
|
+
crossTenantGrant: new mariadb_cross_tenant_grant_adapter_js_1.MariaDbCrossTenantGrantAdapter(inputs.pool),
|
|
30
|
+
// Delegation / trusted-operation authority over the DECLARED manifest (no DB).
|
|
31
|
+
// Empty ⇒ pass-through. The app supplies the entries; the framework owns the adapter.
|
|
32
|
+
operationAuthority: new manifest_operation_authority_adapter_js_1.ManifestOperationAuthorityAdapter(inputs.operationManifest ?? []),
|
|
33
|
+
});
|
|
34
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wire-record-authorization.js","sourceRoot":"","sources":["../../src/authz/wire-record-authorization.ts"],"names":[],"mappings":";;AAgFA,4DAmBC;AApED,uCAA4D;AAC5D,qFAG0C;AAC1C,uFAA8E;AAC9E,mGAAyF;AACzF,uGAGmD;AAiCnD;;;;;GAKG;AACH,SAAgB,wBAAwB,CAAC,MAAiC;IACxE,OAAO,IAAA,mCAA4B,EAAC;QAClC,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,eAAe,EAAE,MAAM,CAAC,eAAe;QACvC,YAAY,EAAE,MAAM,CAAC,YAAY;QACjC,sFAAsF;QACtF,kFAAkF;QAClF,mFAAmF;QACnF,UAAU,EAAE,IAAI,mEAAkC,CAAC,MAAM,CAAC,IAAI,CAAC;QAC/D,mFAAmF;QACnF,6EAA6E;QAC7E,WAAW,EAAE,IAAI,2DAAyB,CAAC,MAAM,CAAC,IAAI,CAAC;QACvD,kFAAkF;QAClF,6DAA6D;QAC7D,gBAAgB,EAAE,IAAI,sEAA8B,CAAC,MAAM,CAAC,IAAI,CAAC;QACjE,+EAA+E;QAC/E,sFAAsF;QACtF,kBAAkB,EAAE,IAAI,2EAAiC,CAAC,MAAM,CAAC,iBAAiB,IAAI,EAAE,CAAC;KAC1F,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"boot-sequence.js","sourceRoot":"","sources":["../../src/boot/boot-sequence.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAoDA,4CAuBC;AA3ED,2CAAiF;AACjF,iEAAwD;AACxD,2DAAoG;AAEpG;;;;;;;;;;;;;;GAcG;AAEI,IAAM,YAAY,GAAlB,MAAM,YAAY;IAC0B;IAAjD,YAAiD,MAAiB;QAAjB,WAAM,GAAN,MAAM,CAAW;IAAG,CAAC;IAEtE,KAAK,CAAC,sBAAsB;QAC1B,MAAM,IAAI,CAAC,yBAAyB,EAAE,CAAC;QACvC,8DAA8D;IAChE,CAAC;IAED;;;;;;;;;OASG;IACK,KAAK,CAAC,yBAAyB;QACrC,gBAAgB,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QACnC,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;IAC3B,CAAC;CACF,CAAA;AAtBY,oCAAY;uBAAZ,YAAY;IADxB,IAAA,mBAAU,GAAE;IAEE,WAAA,IAAA,eAAM,EAAC,6BAAU,CAAC,CAAA;;GADpB,YAAY,CAsBxB;AAED;;;;;;;GAOG;AACH,SAAgB,gBAAgB,CAAC,GAAqB;IACpD,MAAM,CAAC,GAAG,IAAA,kCAAkB,EAAC,GAAG,CAAC,CAAC;IAElC,IAAI,CAAC,CAAC,CAAC,sBAAsB,EAAE,CAAC;QAC9B,MAAM,IAAI,KAAK,CACb,6DAA6D;YAC3D,iCAAiC,GAAG,CAAC,aAAa,CAAC,iBAAiB,IAAI;YACxE,uEAAuE;YACvE,4CAA4C,CAC/C,CAAC;IACJ,CAAC;IAED,IAAI,CAAC,CAAC,CAAC,YAAY,EAAE,CAAC;QACpB,MAAM,IAAI,KAAK,CACb,sEAAsE;YACpE,eAAe,CAAC,CAAC,mBAAmB,0BAA0B;YAC9D,GAAG,GAAG,CAAC,cAAc,sBAAsB,GAAG,CAAC,OAAO,MAAM;YAC5D,2BAA2B,CAAC,CAAC,oBAAoB,eAAe;YAChE,GAAG,GAAG,CAAC,QAAQ,OAAO,CAAC,CAAC,mBAAmB,MAAM,GAAG,CAAC,cAAc,IAAI;YACvE,4DAA4D;YAC5D,6DAA6D,CAChE,CAAC;IACJ,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"boot.module.js","sourceRoot":"","sources":["../../src/boot/boot.module.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAAwC;AACxC,yDAAkD;AAElD;;;;GAIG;AAII,IAAM,UAAU,GAAhB,MAAM,UAAU;CAAG,CAAA;AAAb,gCAAU;qBAAV,UAAU;IAHtB,IAAA,eAAM,EAAC;QACN,SAAS,EAAE,CAAC,+BAAY,CAAC;KAC1B,CAAC;GACW,UAAU,CAAG"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { OperationInventory, ModuleRegistry } from '@astram/core';
|
|
2
|
+
import type { CatalogStore, ReconcileReport } from './ports/catalog-store.js';
|
|
3
|
+
/** A @Classified route could not be gated (stranded or key-not-registered). Boot must
|
|
4
|
+
* abort — an ungatable route may never serve traffic (ADR-0002 fail-closed). */
|
|
5
|
+
export declare class CatalogGatabilityError extends Error {
|
|
6
|
+
constructor(message: string);
|
|
7
|
+
}
|
|
8
|
+
export declare class CatalogReconciler {
|
|
9
|
+
/**
|
|
10
|
+
* BOOT — read-only, fail-closed. Throws if any non-public route is stranded (no key)
|
|
11
|
+
* or unclassified (declares a key the registry doesn't know). No DB, no writes.
|
|
12
|
+
*/
|
|
13
|
+
verifyGatable(inventory: OperationInventory, registry: ModuleRegistry): void;
|
|
14
|
+
/**
|
|
15
|
+
* CRON — mutating. Auto-adds an ACTIVE catalog row per registered non-public action,
|
|
16
|
+
* marks orphaned any stored row with no registered action, reactivates revived ones.
|
|
17
|
+
* Idempotent. Returns a report for logging + /health/catalog.
|
|
18
|
+
*/
|
|
19
|
+
reconcile(registry: ModuleRegistry, store: CatalogStore, nowIso: string): Promise<ReconcileReport>;
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=catalog-reconciler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"catalog-reconciler.d.ts","sourceRoot":"","sources":["../../src/completeness/catalog-reconciler.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACvE,OAAO,KAAK,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAE9E;iFACiF;AACjF,qBAAa,sBAAuB,SAAQ,KAAK;gBACnC,OAAO,EAAE,MAAM;CAI5B;AAED,qBAAa,iBAAiB;IAC5B;;;OAGG;IACH,aAAa,CAAC,SAAS,EAAE,kBAAkB,EAAE,QAAQ,EAAE,cAAc,GAAG,IAAI;IAgB5E;;;;OAIG;IACG,SAAS,CAAC,QAAQ,EAAE,cAAc,EAAE,KAAK,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC;CAoCzG"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CatalogReconciler = exports.CatalogGatabilityError = void 0;
|
|
4
|
+
// astram-framework/packages/guard/src/completeness/catalog-reconciler.ts
|
|
5
|
+
const core_1 = require("@astram/core");
|
|
6
|
+
/** A @Classified route could not be gated (stranded or key-not-registered). Boot must
|
|
7
|
+
* abort — an ungatable route may never serve traffic (ADR-0002 fail-closed). */
|
|
8
|
+
class CatalogGatabilityError extends Error {
|
|
9
|
+
constructor(message) {
|
|
10
|
+
super(message);
|
|
11
|
+
this.name = 'CatalogGatabilityError';
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
exports.CatalogGatabilityError = CatalogGatabilityError;
|
|
15
|
+
class CatalogReconciler {
|
|
16
|
+
/**
|
|
17
|
+
* BOOT — read-only, fail-closed. Throws if any non-public route is stranded (no key)
|
|
18
|
+
* or unclassified (declares a key the registry doesn't know). No DB, no writes.
|
|
19
|
+
*/
|
|
20
|
+
verifyGatable(inventory, registry) {
|
|
21
|
+
const result = (0, core_1.checkCompleteness)(inventory, registry);
|
|
22
|
+
if (result.strandedOperations.length > 0 || result.unclassifiedOperations.length > 0) {
|
|
23
|
+
const stranded = result.strandedOperations.map((o) => o.operationId);
|
|
24
|
+
const unclassified = result.unclassifiedOperations.map((o) => `${o.operationId}${o.declaredPermissionKey ? ` (${o.declaredPermissionKey})` : ''}`);
|
|
25
|
+
throw new CatalogGatabilityError(`Shield: ${stranded.length} stranded + ${unclassified.length} unclassified route(s) — cannot boot. ` +
|
|
26
|
+
`Stranded (no @Classified): ${stranded.join(', ') || 'none'}. ` +
|
|
27
|
+
`Unclassified (key not registered): ${unclassified.join(', ') || 'none'}. ` +
|
|
28
|
+
`Classify the route or register the action.`);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* CRON — mutating. Auto-adds an ACTIVE catalog row per registered non-public action,
|
|
33
|
+
* marks orphaned any stored row with no registered action, reactivates revived ones.
|
|
34
|
+
* Idempotent. Returns a report for logging + /health/catalog.
|
|
35
|
+
*/
|
|
36
|
+
async reconcile(registry, store, nowIso) {
|
|
37
|
+
const stored = await store.listPermissions();
|
|
38
|
+
const storedByKey = new Map(stored.map((r) => [r.permissionKey, r]));
|
|
39
|
+
const registered = registry.listActions().filter((a) => a.tier !== 'public');
|
|
40
|
+
const registeredKeys = new Set(registered.map((a) => a.permissionKey));
|
|
41
|
+
// code → catalog: add missing rows; revive orphaned-but-now-registered.
|
|
42
|
+
const added = [];
|
|
43
|
+
const reactivated = [];
|
|
44
|
+
for (const a of registered) {
|
|
45
|
+
const key = a.permissionKey;
|
|
46
|
+
const existing = storedByKey.get(key);
|
|
47
|
+
if (!existing) {
|
|
48
|
+
const inserted = await store.upsertPermission({
|
|
49
|
+
permissionKey: key,
|
|
50
|
+
moduleKey: a.moduleKey,
|
|
51
|
+
typeKey: a.action.typeKey,
|
|
52
|
+
action: a.action.actionKey,
|
|
53
|
+
label: `${a.action.actionKey} ${a.action.typeKey}`,
|
|
54
|
+
tier: a.tier,
|
|
55
|
+
});
|
|
56
|
+
if (inserted)
|
|
57
|
+
added.push(key);
|
|
58
|
+
}
|
|
59
|
+
else if (existing.status === 'orphaned') {
|
|
60
|
+
reactivated.push(key);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
if (reactivated.length)
|
|
64
|
+
await store.markActive(reactivated);
|
|
65
|
+
// catalog → code: mark orphaned any active stored row with no registered action.
|
|
66
|
+
const orphaned = stored
|
|
67
|
+
.filter((r) => r.status === 'active' && !registeredKeys.has(r.permissionKey))
|
|
68
|
+
.map((r) => r.permissionKey);
|
|
69
|
+
if (orphaned.length)
|
|
70
|
+
await store.markOrphaned(orphaned);
|
|
71
|
+
return { added, orphaned, reactivated, at: nowIso };
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
exports.CatalogReconciler = CatalogReconciler;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"catalog-reconciler.js","sourceRoot":"","sources":["../../src/completeness/catalog-reconciler.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { DiscoveryService, MetadataScanner, Reflector } from '@nestjs/core';
|
|
2
|
+
import type { OperationInventory } from '@astram/core';
|
|
3
|
+
/**
|
|
4
|
+
* Reflects every controller handler at boot and emits an OperationInventory for core's
|
|
5
|
+
* checkCompleteness. operationId = `${ControllerClass.name}#${method}` (core's contract).
|
|
6
|
+
* A handler's permissionKey is `${moduleKey}:${typeKey}:${action}` from its @Classified;
|
|
7
|
+
* @Public handlers carry isPublic:true; an unclassified non-public handler carries no
|
|
8
|
+
* permissionKey (→ core reports it stranded).
|
|
9
|
+
*/
|
|
10
|
+
export declare class OperationInventoryScanner {
|
|
11
|
+
private readonly discovery;
|
|
12
|
+
private readonly scanner;
|
|
13
|
+
private readonly reflector;
|
|
14
|
+
constructor(discovery: DiscoveryService, scanner: MetadataScanner, reflector: Reflector);
|
|
15
|
+
scan(moduleKey: string): OperationInventory;
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=operation-inventory-scanner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"operation-inventory-scanner.d.ts","sourceRoot":"","sources":["../../src/completeness/operation-inventory-scanner.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAE5E,OAAO,KAAK,EAAE,kBAAkB,EAAuB,MAAM,cAAc,CAAC;AAO5E;;;;;;GAMG;AACH,qBACa,yBAAyB;IAElC,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,SAAS;gBAFT,SAAS,EAAE,gBAAgB,EAC3B,OAAO,EAAE,eAAe,EACxB,SAAS,EAAE,SAAS;IAGvC,IAAI,CAAC,SAAS,EAAE,MAAM,GAAG,kBAAkB;CAyC5C"}
|
|
@@ -0,0 +1,79 @@
|
|
|
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
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.OperationInventoryScanner = void 0;
|
|
13
|
+
const common_1 = require("@nestjs/common");
|
|
14
|
+
const constants_1 = require("@nestjs/common/constants");
|
|
15
|
+
const core_1 = require("@nestjs/core");
|
|
16
|
+
const core_2 = require("@astram/core");
|
|
17
|
+
const classification_decorator_js_1 = require("../enforcement/classification.decorator.js");
|
|
18
|
+
/**
|
|
19
|
+
* Reflects every controller handler at boot and emits an OperationInventory for core's
|
|
20
|
+
* checkCompleteness. operationId = `${ControllerClass.name}#${method}` (core's contract).
|
|
21
|
+
* A handler's permissionKey is `${moduleKey}:${typeKey}:${action}` from its @Classified;
|
|
22
|
+
* @Public handlers carry isPublic:true; an unclassified non-public handler carries no
|
|
23
|
+
* permissionKey (→ core reports it stranded).
|
|
24
|
+
*/
|
|
25
|
+
let OperationInventoryScanner = class OperationInventoryScanner {
|
|
26
|
+
discovery;
|
|
27
|
+
scanner;
|
|
28
|
+
reflector;
|
|
29
|
+
constructor(discovery, scanner, reflector) {
|
|
30
|
+
this.discovery = discovery;
|
|
31
|
+
this.scanner = scanner;
|
|
32
|
+
this.reflector = reflector;
|
|
33
|
+
}
|
|
34
|
+
scan(moduleKey) {
|
|
35
|
+
const operations = [];
|
|
36
|
+
for (const wrapper of this.discovery.getControllers()) {
|
|
37
|
+
const { instance, metatype } = wrapper;
|
|
38
|
+
if (!instance || !metatype)
|
|
39
|
+
continue;
|
|
40
|
+
const controllerName = metatype.name;
|
|
41
|
+
const prototype = Object.getPrototypeOf(instance);
|
|
42
|
+
for (const method of this.scanner.getAllMethodNames(prototype)) {
|
|
43
|
+
const handler = prototype[method];
|
|
44
|
+
// Only real HTTP route handlers carry route metadata (set by @Get/@Post/etc.).
|
|
45
|
+
// Private/helper methods (e.g. buildQuery()) are emitted by getAllMethodNames but
|
|
46
|
+
// carry no PATH_METADATA — skipping them prevents core from stranding them and
|
|
47
|
+
// aborting boot. This matches what the guard actually enforces at runtime, which
|
|
48
|
+
// only ever runs on mapped handlers via context.getHandler().
|
|
49
|
+
if (Reflect.getMetadata(constants_1.PATH_METADATA, handler) === undefined)
|
|
50
|
+
continue;
|
|
51
|
+
// Mirror the guard's precedence: method metadata overrides class-level.
|
|
52
|
+
const isPublic = this.reflector.getAllAndOverride(classification_decorator_js_1.CLASSIFICATION_METADATA.PUBLIC, [
|
|
53
|
+
handler,
|
|
54
|
+
metatype,
|
|
55
|
+
]) === true;
|
|
56
|
+
const raw = this.reflector.getAllAndOverride(classification_decorator_js_1.CLASSIFICATION_METADATA.CLASSIFIED, [handler, metatype]);
|
|
57
|
+
const classification = (0, classification_decorator_js_1.normalizeClassification)(raw);
|
|
58
|
+
// Single-source the key format via core's derivePermissionKey (returns the
|
|
59
|
+
// branded PermissionKey) rather than a hand-built template string.
|
|
60
|
+
const permissionKey = !isPublic && classification
|
|
61
|
+
? (0, core_2.derivePermissionKey)(moduleKey, classification.typeKey, classification.action)
|
|
62
|
+
: undefined;
|
|
63
|
+
operations.push({
|
|
64
|
+
operationId: `${controllerName}#${method}`,
|
|
65
|
+
isPublic,
|
|
66
|
+
...(permissionKey ? { permissionKey } : {}),
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return { operations };
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
exports.OperationInventoryScanner = OperationInventoryScanner;
|
|
74
|
+
exports.OperationInventoryScanner = OperationInventoryScanner = __decorate([
|
|
75
|
+
(0, common_1.Injectable)(),
|
|
76
|
+
__metadata("design:paramtypes", [core_1.DiscoveryService,
|
|
77
|
+
core_1.MetadataScanner,
|
|
78
|
+
core_1.Reflector])
|
|
79
|
+
], OperationInventoryScanner);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"operation-inventory-scanner.js","sourceRoot":"","sources":["../../src/completeness/operation-inventory-scanner.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,2CAA4C;AAC5C,wDAAyD;AACzD,uCAA4E;AAC5E,uCAAmD;AAEnD,4FAIoD;AAEpD;;;;;;GAMG;AAEI,IAAM,yBAAyB,GAA/B,MAAM,yBAAyB;IAEjB;IACA;IACA;IAHnB,YACmB,SAA2B,EAC3B,OAAwB,EACxB,SAAoB;QAFpB,cAAS,GAAT,SAAS,CAAkB;QAC3B,YAAO,GAAP,OAAO,CAAiB;QACxB,cAAS,GAAT,SAAS,CAAW;IACpC,CAAC;IAEJ,IAAI,CAAC,SAAiB;QACpB,MAAM,UAAU,GAA0B,EAAE,CAAC;QAC7C,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,SAAS,CAAC,cAAc,EAAE,EAAE,CAAC;YACtD,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC;YACvC,IAAI,CAAC,QAAQ,IAAI,CAAC,QAAQ;gBAAE,SAAS;YACrC,MAAM,cAAc,GAAG,QAAQ,CAAC,IAAI,CAAC;YACrC,MAAM,SAAS,GAAG,MAAM,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC;YAClD,KAAK,MAAM,MAAM,IAAI,IAAI,CAAC,OAAO,CAAC,iBAAiB,CAAC,SAAS,CAAC,EAAE,CAAC;gBAC/D,MAAM,OAAO,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC;gBAClC,+EAA+E;gBAC/E,kFAAkF;gBAClF,+EAA+E;gBAC/E,iFAAiF;gBACjF,8DAA8D;gBAC9D,IAAI,OAAO,CAAC,WAAW,CAAC,yBAAa,EAAE,OAAO,CAAC,KAAK,SAAS;oBAAE,SAAS;gBACxE,wEAAwE;gBACxE,MAAM,QAAQ,GACZ,IAAI,CAAC,SAAS,CAAC,iBAAiB,CAAU,qDAAuB,CAAC,MAAM,EAAE;oBACxE,OAAO;oBACP,QAAQ;iBACT,CAAC,KAAK,IAAI,CAAC;gBACd,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,iBAAiB,CAC1C,qDAAuB,CAAC,UAAU,EAClC,CAAC,OAAO,EAAE,QAAQ,CAAC,CACpB,CAAC;gBACF,MAAM,cAAc,GAAG,IAAA,qDAAuB,EAAC,GAAG,CAAC,CAAC;gBACpD,2EAA2E;gBAC3E,mEAAmE;gBACnE,MAAM,aAAa,GACjB,CAAC,QAAQ,IAAI,cAAc;oBACzB,CAAC,CAAC,IAAA,0BAAmB,EAAC,SAAS,EAAE,cAAc,CAAC,OAAO,EAAE,cAAc,CAAC,MAAM,CAAC;oBAC/E,CAAC,CAAC,SAAS,CAAC;gBAChB,UAAU,CAAC,IAAI,CAAC;oBACd,WAAW,EAAE,GAAG,cAAc,IAAI,MAAM,EAAE;oBAC1C,QAAQ;oBACR,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;iBAC5C,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QACD,OAAO,EAAE,UAAU,EAAE,CAAC;IACxB,CAAC;CACF,CAAA;AAhDY,8DAAyB;oCAAzB,yBAAyB;IADrC,IAAA,mBAAU,GAAE;qCAGmB,uBAAgB;QAClB,sBAAe;QACb,gBAAS;GAJ5B,yBAAyB,CAgDrC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The DB seam for the catalog reconciler. The framework defines the interface only;
|
|
3
|
+
* the consumer app supplies the implementation (ADR-0003 — guard does no DB). A row is
|
|
4
|
+
* keyed by its permission key (`moduleKey:typeKey:actionKey`); `status` is the soft
|
|
5
|
+
* active/orphaned marker (never hard-delete).
|
|
6
|
+
*/
|
|
7
|
+
export interface CatalogPermissionRow {
|
|
8
|
+
readonly permissionKey: string;
|
|
9
|
+
readonly moduleKey: string;
|
|
10
|
+
readonly typeKey: string;
|
|
11
|
+
readonly action: string;
|
|
12
|
+
readonly label: string;
|
|
13
|
+
readonly tier: string;
|
|
14
|
+
readonly status: 'active' | 'orphaned';
|
|
15
|
+
}
|
|
16
|
+
/** The result of one mutating reconcile pass — surfaced via /health/catalog + logged. */
|
|
17
|
+
export interface ReconcileReport {
|
|
18
|
+
readonly added: readonly string[];
|
|
19
|
+
readonly orphaned: readonly string[];
|
|
20
|
+
readonly reactivated: readonly string[];
|
|
21
|
+
readonly at: string;
|
|
22
|
+
}
|
|
23
|
+
export interface CatalogStore {
|
|
24
|
+
/** All catalog rows (both active + orphaned). */
|
|
25
|
+
listPermissions(): Promise<CatalogPermissionRow[]>;
|
|
26
|
+
/** Idempotent insert of an ACTIVE row (no-op if the key already exists as active). */
|
|
27
|
+
upsertPermission(row: Omit<CatalogPermissionRow, 'status'>): Promise<boolean>;
|
|
28
|
+
/** Mark keys orphaned (soft). No-op for keys already orphaned. */
|
|
29
|
+
markOrphaned(keys: readonly string[]): Promise<void>;
|
|
30
|
+
/** Flip keys orphaned → active (a route returned). */
|
|
31
|
+
markActive(keys: readonly string[]): Promise<void>;
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=catalog-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"catalog-store.d.ts","sourceRoot":"","sources":["../../../src/completeness/ports/catalog-store.ts"],"names":[],"mappings":"AACA;;;;;GAKG;AACH,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,QAAQ,GAAG,UAAU,CAAC;CACxC;AAED,yFAAyF;AACzF,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IAClC,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC,QAAQ,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;IACxC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,YAAY;IAC3B,iDAAiD;IACjD,eAAe,IAAI,OAAO,CAAC,oBAAoB,EAAE,CAAC,CAAC;IACnD,sFAAsF;IACtF,gBAAgB,CAAC,GAAG,EAAE,IAAI,CAAC,oBAAoB,EAAE,QAAQ,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC9E,kEAAkE;IAClE,YAAY,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACrD,sDAAsD;IACtD,UAAU,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACpD"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"catalog-store.js","sourceRoot":"","sources":["../../../src/completeness/ports/catalog-store.ts"],"names":[],"mappings":""}
|
|
@@ -30,6 +30,76 @@ export interface AppConfig {
|
|
|
30
30
|
readonly environment: 'development' | 'test' | 'production';
|
|
31
31
|
/** ADR-0018 connection-pool budget (validated at boot, fail-closed). */
|
|
32
32
|
readonly pool: PoolBudgetConfig;
|
|
33
|
+
/**
|
|
34
|
+
* The runtime MariaDB connection descriptor (the `shield_core` account — DML on
|
|
35
|
+
* `shield_identity` where the session + credential tables live). Consumed by
|
|
36
|
+
* the Phase 0b persistence provider that creates the ONE live `mariadb` Pool.
|
|
37
|
+
*/
|
|
38
|
+
readonly db: DbConfig;
|
|
39
|
+
/**
|
|
40
|
+
* The Redis (hot session tier, ADR-0013) connection descriptor. Consumed by the
|
|
41
|
+
* Phase 0b persistence provider that creates the ONE live `ioredis` client.
|
|
42
|
+
*/
|
|
43
|
+
readonly redis: RedisConfig;
|
|
44
|
+
/**
|
|
45
|
+
* The keyed-HMAC secret for the refresh-token hasher (`SHIELD_REFRESH_HMAC_KEY`).
|
|
46
|
+
* ⛔ REQUIRED FOR AUTH — this is a SECRET (a leaked DB would be offline-brute-
|
|
47
|
+
* forceable without it). {@link loadAppConfig} reads it but does NOT throw when
|
|
48
|
+
* blank, so the ENFORCEMENT-ONLY scaffold (example-backend / a freshly-scaffolded
|
|
49
|
+
* app with no auth wired) still boots with no `.env`. The FAIL-CLOSED gate is
|
|
50
|
+
* {@link assertRefreshHmacKey}, invoked by the auth composition (AuthModule /
|
|
51
|
+
* persistence factory) at the moment auth is actually wired — so a blank key can
|
|
52
|
+
* never produce a working-looking authenticator, while a non-auth app is
|
|
53
|
+
* unaffected. Never logged, never returned to a client.
|
|
54
|
+
*/
|
|
55
|
+
readonly refreshHmacKey: string;
|
|
56
|
+
/**
|
|
57
|
+
* Optional session/token lifetime overrides (ADR-0015). Any omitted field
|
|
58
|
+
* defaults in `@astram/core`'s `resolveLifetimes` to 15 min access / 14 d idle /
|
|
59
|
+
* 60 d absolute cap. `Partial` so the composition can hand it straight to
|
|
60
|
+
* `createSessionAuthority({ lifetimes })`.
|
|
61
|
+
*/
|
|
62
|
+
readonly lifetimes: SessionLifetimeOverrides;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* The runtime MariaDB connection descriptor. Non-secret host/port/user/database
|
|
66
|
+
* plus the account password (a secret — supplied via env/secrets-manager, NEVER
|
|
67
|
+
* committed). Maps 1:1 onto `mariadb`'s `createPool({ host, port, user, password,
|
|
68
|
+
* database, connectionLimit })`. The pool cap comes from the ADR-0018 budget
|
|
69
|
+
* (`pool.perAccountMax.shield_core`), NOT duplicated here.
|
|
70
|
+
*/
|
|
71
|
+
export interface DbConfig {
|
|
72
|
+
readonly host: string;
|
|
73
|
+
readonly port: number;
|
|
74
|
+
readonly user: string;
|
|
75
|
+
/** ⛔ Secret — resolved from env/secrets-manager; never logged. */
|
|
76
|
+
readonly password: string;
|
|
77
|
+
readonly database: string;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* The Redis connection descriptor. A single `url` (e.g. `redis://host:6379`) is
|
|
81
|
+
* the canonical form `ioredis` accepts directly; host/port are provided as a
|
|
82
|
+
* convenience fallback the persistence provider composes into a url when `url` is
|
|
83
|
+
* absent.
|
|
84
|
+
*/
|
|
85
|
+
export interface RedisConfig {
|
|
86
|
+
/** Full connection url (`redis://[:password@]host:port[/db]`). Preferred. */
|
|
87
|
+
readonly url: string;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Optional per-deployment overrides for the three ADR-0015 session lifetimes.
|
|
91
|
+
* Shape mirrors `@astram/core`'s `Partial<SessionLifetimeConfig>` so it is passed
|
|
92
|
+
* straight into `createSessionAuthority({ lifetimes })` — omitted fields take the
|
|
93
|
+
* core defaults. Kept as a local shape (not a core import) so this config file
|
|
94
|
+
* stays a plain env-reader; the composition owns the core wiring.
|
|
95
|
+
*/
|
|
96
|
+
export interface SessionLifetimeOverrides {
|
|
97
|
+
/** Access-token TTL in ms (core default 15 min). Omitted ⇒ core default. */
|
|
98
|
+
readonly accessTtlMs?: number;
|
|
99
|
+
/** Sliding refresh idle window in ms (core default 14 days). */
|
|
100
|
+
readonly refreshIdleMs?: number;
|
|
101
|
+
/** Absolute session cap in ms (core default 60 days). */
|
|
102
|
+
readonly refreshAbsoluteCapMs?: number;
|
|
33
103
|
}
|
|
34
104
|
/**
|
|
35
105
|
* The ADR-0018 connection-pool budget surface. Every field is configurable per
|
|
@@ -84,9 +154,72 @@ export declare const SCHEMA_SVC_POOL_HARD_CAP = 2;
|
|
|
84
154
|
* perAccountMax.shield_schema_svc ← SHIELD_POOL_MAX_SCHEMA_SVC
|
|
85
155
|
*/
|
|
86
156
|
export declare function loadPoolBudget(env?: NodeJS.ProcessEnv): PoolBudgetConfig;
|
|
157
|
+
/** Documented defaults for the runtime MariaDB descriptor (local docker substrate). */
|
|
158
|
+
export declare const DEFAULT_DB_CONFIG: Omit<DbConfig, 'password'>;
|
|
159
|
+
/** Documented default Redis url (local docker substrate). */
|
|
160
|
+
export declare const DEFAULT_REDIS_URL = "redis://localhost:6379";
|
|
161
|
+
/**
|
|
162
|
+
* Build the runtime {@link DbConfig} from env with documented defaults.
|
|
163
|
+
* Field ↔ env name:
|
|
164
|
+
* host ← SHIELD_DB_HOST port ← SHIELD_DB_PORT
|
|
165
|
+
* user ← SHIELD_DB_USER password ← SHIELD_DB_PASSWORD (secret)
|
|
166
|
+
* database ← SHIELD_DB_NAME
|
|
167
|
+
* The password defaults to '' when absent — a live connection then fails at
|
|
168
|
+
* connect time (loud), which is correct for a runtime that needs real creds; the
|
|
169
|
+
* secret is deliberately NOT hard-required at config load (unlike the HMAC key,
|
|
170
|
+
* which is a fail-closed security invariant even for unit tests).
|
|
171
|
+
*/
|
|
172
|
+
export declare function loadDbConfig(env?: NodeJS.ProcessEnv): DbConfig;
|
|
173
|
+
/**
|
|
174
|
+
* Build the {@link RedisConfig} from env. Prefers `SHIELD_REDIS_URL`; falls back
|
|
175
|
+
* to composing `redis://host:port` from `SHIELD_REDIS_HOST`/`SHIELD_REDIS_PORT`,
|
|
176
|
+
* else the documented default.
|
|
177
|
+
*/
|
|
178
|
+
export declare function loadRedisConfig(env?: NodeJS.ProcessEnv): RedisConfig;
|
|
179
|
+
/**
|
|
180
|
+
* Build the optional {@link SessionLifetimeOverrides} from env. Every field is
|
|
181
|
+
* optional (omitted ⇒ core ADR-0015 default). The bounds validation is the
|
|
182
|
+
* core's `resolveLifetimes` job (throws LOUD at composition) — this loader only
|
|
183
|
+
* reads the numbers.
|
|
184
|
+
* Field ↔ env name:
|
|
185
|
+
* accessTtlMs ← SHIELD_ACCESS_TTL_MS
|
|
186
|
+
* refreshIdleMs ← SHIELD_REFRESH_IDLE_MS
|
|
187
|
+
* refreshAbsoluteCapMs ← SHIELD_REFRESH_ABSOLUTE_CAP_MS
|
|
188
|
+
*/
|
|
189
|
+
export declare function loadSessionLifetimes(env?: NodeJS.ProcessEnv): SessionLifetimeOverrides;
|
|
190
|
+
/**
|
|
191
|
+
* Read the refresh-token HMAC key from env (raw; `''` when absent/blank). Total —
|
|
192
|
+
* does NOT throw, so {@link loadAppConfig} stays boot-safe for a non-auth scaffold.
|
|
193
|
+
* The FAIL-CLOSED enforcement lives in {@link assertRefreshHmacKey}. Never logs
|
|
194
|
+
* the key's value.
|
|
195
|
+
*/
|
|
196
|
+
export declare function loadRefreshHmacKey(env?: NodeJS.ProcessEnv): string;
|
|
197
|
+
/**
|
|
198
|
+
* ⛔ FAIL-CLOSED GATE for the refresh-token HMAC key. Called by the auth
|
|
199
|
+
* composition (AuthModule / persistence factory) at the moment auth is wired:
|
|
200
|
+
* throws LOUD when the key is blank so the app can NEVER compose a working-looking
|
|
201
|
+
* authenticator/session-authority on an empty HMAC key (a leaked DB would then be
|
|
202
|
+
* offline-brute-forceable, and every refresh-token hash would be unkeyed). Mirrors
|
|
203
|
+
* `Sha256RefreshTokenHasher`'s constructor guard but surfaces a clear composition
|
|
204
|
+
* error. Returns the validated non-empty key. NEVER logs the key's value.
|
|
205
|
+
*
|
|
206
|
+
* WHY here and not in `loadAppConfig`: an enforcement-only app (example-backend, a
|
|
207
|
+
* freshly-scaffolded app with no auth wired) must still boot with no `.env`
|
|
208
|
+
* (`create-astram-app/template/_env.example` promises exactly this). Gating at the
|
|
209
|
+
* auth boundary keeps that promise while making auth fail closed the instant it is
|
|
210
|
+
* actually composed.
|
|
211
|
+
*/
|
|
212
|
+
export declare function assertRefreshHmacKey(key: string): string;
|
|
87
213
|
/**
|
|
88
214
|
* Build the {@link AppConfig} from `process.env` (or an injected env bag, for
|
|
89
|
-
* testability). Pure
|
|
215
|
+
* testability). Pure, total, and side-effect-free — trivially unit-testable and
|
|
216
|
+
* boot-safe with NO `.env`.
|
|
217
|
+
*
|
|
218
|
+
* Every Phase 0b field has a documented default (DB/Redis descriptors, lifetimes)
|
|
219
|
+
* and `refreshHmacKey` is read-but-not-required HERE, so existing callers
|
|
220
|
+
* (example-backend / template `main.ts`, which read only `.port`) are unaffected.
|
|
221
|
+
* The refresh-key fail-closed check is deferred to {@link assertRefreshHmacKey} at
|
|
222
|
+
* auth-composition time (see its doc).
|
|
90
223
|
*/
|
|
91
224
|
export declare function loadAppConfig(env?: NodeJS.ProcessEnv): AppConfig;
|
|
92
225
|
/** Result of evaluating a {@link PoolBudgetConfig} against the ADR-0018 budget. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app-config.d.ts","sourceRoot":"","sources":["../../src/config/app-config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,WAAW,SAAS;IACxB,yCAAyC;IACzC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,oEAAoE;IACpE,QAAQ,CAAC,WAAW,EAAE,aAAa,GAAG,MAAM,GAAG,YAAY,CAAC;IAC5D,wEAAwE;IACxE,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"app-config.d.ts","sourceRoot":"","sources":["../../src/config/app-config.ts"],"names":[],"mappings":"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"}
|