@astram/guard 0.1.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/LICENSE +21 -0
- package/README.md +84 -0
- package/dist/authentication/argon2id-password-hasher.d.ts +61 -0
- package/dist/authentication/argon2id-password-hasher.d.ts.map +1 -0
- package/dist/authentication/argon2id-password-hasher.js +108 -0
- package/dist/boot/boot-sequence.d.ts +43 -0
- package/dist/boot/boot-sequence.d.ts.map +1 -0
- package/dist/boot/boot-sequence.js +90 -0
- package/dist/boot/boot.module.d.ts +8 -0
- package/dist/boot/boot.module.d.ts.map +1 -0
- package/dist/boot/boot.module.js +24 -0
- package/dist/config/app-config.d.ts +112 -0
- package/dist/config/app-config.d.ts.map +1 -0
- package/dist/config/app-config.js +94 -0
- package/dist/config/config.module.d.ts +12 -0
- package/dist/config/config.module.d.ts.map +1 -0
- package/dist/config/config.module.js +35 -0
- package/dist/enforcement/classification.decorator.d.ts +41 -0
- package/dist/enforcement/classification.decorator.d.ts.map +1 -0
- package/dist/enforcement/classification.decorator.js +46 -0
- package/dist/enforcement/core-seam.d.ts +40 -0
- package/dist/enforcement/core-seam.d.ts.map +1 -0
- package/dist/enforcement/core-seam.js +38 -0
- package/dist/enforcement/enforcement.module.d.ts +18 -0
- package/dist/enforcement/enforcement.module.d.ts.map +1 -0
- package/dist/enforcement/enforcement.module.js +40 -0
- package/dist/enforcement/global-enforcement.guard.d.ts +31 -0
- package/dist/enforcement/global-enforcement.guard.d.ts.map +1 -0
- package/dist/enforcement/global-enforcement.guard.js +76 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +88 -0
- package/dist/module/shield.module.d.ts +79 -0
- package/dist/module/shield.module.d.ts.map +1 -0
- package/dist/module/shield.module.js +108 -0
- package/dist/session/crypto-adapters.d.ts +60 -0
- package/dist/session/crypto-adapters.d.ts.map +1 -0
- package/dist/session/crypto-adapters.js +80 -0
- package/dist/session/index.d.ts +17 -0
- package/dist/session/index.d.ts.map +1 -0
- package/dist/session/index.js +32 -0
- package/dist/session/mariadb-session-record-store.d.ts +50 -0
- package/dist/session/mariadb-session-record-store.d.ts.map +1 -0
- package/dist/session/mariadb-session-record-store.js +162 -0
- package/dist/session/redis-hot-session-store.d.ts +30 -0
- package/dist/session/redis-hot-session-store.d.ts.map +1 -0
- package/dist/session/redis-hot-session-store.js +102 -0
- package/package.json +52 -0
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SCHEMA_SVC_POOL_HARD_CAP = exports.DEFAULT_POOL_BUDGET = void 0;
|
|
4
|
+
exports.loadPoolBudget = loadPoolBudget;
|
|
5
|
+
exports.loadAppConfig = loadAppConfig;
|
|
6
|
+
exports.evaluatePoolBudget = evaluatePoolBudget;
|
|
7
|
+
/** Documented MVP single-node defaults (see the class doc + my.cnf). */
|
|
8
|
+
exports.DEFAULT_POOL_BUDGET = {
|
|
9
|
+
workers: 8,
|
|
10
|
+
maxConnections: 250,
|
|
11
|
+
headroom: 40,
|
|
12
|
+
perAccountMax: {
|
|
13
|
+
shield_core: 12,
|
|
14
|
+
shield_app_crud: 8,
|
|
15
|
+
shield_schema_svc: 1,
|
|
16
|
+
},
|
|
17
|
+
};
|
|
18
|
+
/** Upper bound the schema-service pool must never exceed (ADR-0018 §2: 1–2). */
|
|
19
|
+
exports.SCHEMA_SVC_POOL_HARD_CAP = 2;
|
|
20
|
+
function parsePort(raw, fallback) {
|
|
21
|
+
if (raw === undefined || raw.trim() === '')
|
|
22
|
+
return fallback;
|
|
23
|
+
const n = Number.parseInt(raw, 10);
|
|
24
|
+
return Number.isInteger(n) && n > 0 && n < 65_536 ? n : fallback;
|
|
25
|
+
}
|
|
26
|
+
function parseEnvironment(raw) {
|
|
27
|
+
if (raw === 'production' || raw === 'test')
|
|
28
|
+
return raw;
|
|
29
|
+
return 'development';
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Parse a positive integer from env with a fallback. Returns the fallback for
|
|
33
|
+
* missing/blank/non-integer/≤0 values — the boot assertion is the authority on
|
|
34
|
+
* whether the RESULTING budget is valid, so parsing stays lenient + total.
|
|
35
|
+
*/
|
|
36
|
+
function parsePositiveInt(raw, fallback) {
|
|
37
|
+
if (raw === undefined || raw.trim() === '')
|
|
38
|
+
return fallback;
|
|
39
|
+
const n = Number.parseInt(raw, 10);
|
|
40
|
+
return Number.isInteger(n) && n > 0 ? n : fallback;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Build the {@link PoolBudgetConfig} from env with documented defaults.
|
|
44
|
+
* Field ↔ env name:
|
|
45
|
+
* workers ← SHIELD_POOL_WORKERS
|
|
46
|
+
* maxConnections ← SHIELD_DB_MAX_CONNECTIONS
|
|
47
|
+
* headroom ← SHIELD_POOL_HEADROOM
|
|
48
|
+
* perAccountMax.shield_core ← SHIELD_POOL_MAX_CORE
|
|
49
|
+
* perAccountMax.shield_app_crud ← SHIELD_POOL_MAX_APP_CRUD
|
|
50
|
+
* perAccountMax.shield_schema_svc ← SHIELD_POOL_MAX_SCHEMA_SVC
|
|
51
|
+
*/
|
|
52
|
+
function loadPoolBudget(env = process.env) {
|
|
53
|
+
return {
|
|
54
|
+
workers: parsePositiveInt(env.SHIELD_POOL_WORKERS, exports.DEFAULT_POOL_BUDGET.workers),
|
|
55
|
+
maxConnections: parsePositiveInt(env.SHIELD_DB_MAX_CONNECTIONS, exports.DEFAULT_POOL_BUDGET.maxConnections),
|
|
56
|
+
headroom: parsePositiveInt(env.SHIELD_POOL_HEADROOM, exports.DEFAULT_POOL_BUDGET.headroom),
|
|
57
|
+
perAccountMax: {
|
|
58
|
+
shield_core: parsePositiveInt(env.SHIELD_POOL_MAX_CORE, exports.DEFAULT_POOL_BUDGET.perAccountMax.shield_core),
|
|
59
|
+
shield_app_crud: parsePositiveInt(env.SHIELD_POOL_MAX_APP_CRUD, exports.DEFAULT_POOL_BUDGET.perAccountMax.shield_app_crud),
|
|
60
|
+
shield_schema_svc: parsePositiveInt(env.SHIELD_POOL_MAX_SCHEMA_SVC, exports.DEFAULT_POOL_BUDGET.perAccountMax.shield_schema_svc),
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Build the {@link AppConfig} from `process.env` (or an injected env bag, for
|
|
66
|
+
* testability). Pure + side-effect-free so it is trivially unit-testable.
|
|
67
|
+
*/
|
|
68
|
+
function loadAppConfig(env = process.env) {
|
|
69
|
+
return {
|
|
70
|
+
port: parsePort(env.PORT, 3000),
|
|
71
|
+
environment: parseEnvironment(env.NODE_ENV),
|
|
72
|
+
pool: loadPoolBudget(env),
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Evaluate a pool budget. Pure: no throwing, no I/O — the caller decides how to
|
|
77
|
+
* react (the boot assertion throws; tests inspect the fields).
|
|
78
|
+
*/
|
|
79
|
+
function evaluatePoolBudget(cfg) {
|
|
80
|
+
const perWorkerConnections = cfg.perAccountMax.shield_core +
|
|
81
|
+
cfg.perAccountMax.shield_app_crud +
|
|
82
|
+
cfg.perAccountMax.shield_schema_svc;
|
|
83
|
+
const runtimeConnections = cfg.workers * perWorkerConnections;
|
|
84
|
+
const requiredConnections = runtimeConnections + cfg.headroom;
|
|
85
|
+
const slack = cfg.maxConnections - requiredConnections;
|
|
86
|
+
return {
|
|
87
|
+
perWorkerConnections,
|
|
88
|
+
runtimeConnections,
|
|
89
|
+
requiredConnections,
|
|
90
|
+
slack,
|
|
91
|
+
withinBudget: requiredConnections <= cfg.maxConnections,
|
|
92
|
+
schemaSvcWithinHardCap: cfg.perAccountMax.shield_schema_svc <= exports.SCHEMA_SVC_POOL_HARD_CAP,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/** DI token for the resolved {@link AppConfig}. */
|
|
2
|
+
export declare const APP_CONFIG: unique symbol;
|
|
3
|
+
/**
|
|
4
|
+
* Minimal config module (Scaffold).
|
|
5
|
+
*
|
|
6
|
+
* Provides the resolved {@link AppConfig} under {@link APP_CONFIG} so any
|
|
7
|
+
* provider can inject it. `@Global()` so it need not be re-imported everywhere.
|
|
8
|
+
* A richer, validated config system replaces this in the Infrastructure layer.
|
|
9
|
+
*/
|
|
10
|
+
export declare class ConfigModule {
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=config.module.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.module.d.ts","sourceRoot":"","sources":["../../src/config/config.module.ts"],"names":[],"mappings":"AAGA,mDAAmD;AACnD,eAAO,MAAM,UAAU,eAAuB,CAAC;AAE/C;;;;;;GAMG;AACH,qBAUa,YAAY;CAAG"}
|
|
@@ -0,0 +1,35 @@
|
|
|
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.ConfigModule = exports.APP_CONFIG = void 0;
|
|
10
|
+
const common_1 = require("@nestjs/common");
|
|
11
|
+
const app_config_js_1 = require("./app-config.js");
|
|
12
|
+
/** DI token for the resolved {@link AppConfig}. */
|
|
13
|
+
exports.APP_CONFIG = Symbol('APP_CONFIG');
|
|
14
|
+
/**
|
|
15
|
+
* Minimal config module (Scaffold).
|
|
16
|
+
*
|
|
17
|
+
* Provides the resolved {@link AppConfig} under {@link APP_CONFIG} so any
|
|
18
|
+
* provider can inject it. `@Global()` so it need not be re-imported everywhere.
|
|
19
|
+
* A richer, validated config system replaces this in the Infrastructure layer.
|
|
20
|
+
*/
|
|
21
|
+
let ConfigModule = class ConfigModule {
|
|
22
|
+
};
|
|
23
|
+
exports.ConfigModule = ConfigModule;
|
|
24
|
+
exports.ConfigModule = ConfigModule = __decorate([
|
|
25
|
+
(0, common_1.Global)(),
|
|
26
|
+
(0, common_1.Module)({
|
|
27
|
+
providers: [
|
|
28
|
+
{
|
|
29
|
+
provide: exports.APP_CONFIG,
|
|
30
|
+
useFactory: () => (0, app_config_js_1.loadAppConfig)(),
|
|
31
|
+
},
|
|
32
|
+
],
|
|
33
|
+
exports: [exports.APP_CONFIG],
|
|
34
|
+
})
|
|
35
|
+
], ConfigModule);
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Route-classification metadata keys (ADR-0002).
|
|
3
|
+
*
|
|
4
|
+
* Every HTTP handler in Shield must carry a classification. The global
|
|
5
|
+
* enforcement guard (see {@link GlobalEnforcementGuard}) reads these keys and,
|
|
6
|
+
* for any route WITHOUT one, denies the request (deny-by-default). This is the
|
|
7
|
+
* structurally-unavoidable, fail-closed posture ADR-0002 mandates — present from
|
|
8
|
+
* day one, even though the Scaffold stub does not yet consult a real decision
|
|
9
|
+
* authority.
|
|
10
|
+
*/
|
|
11
|
+
export declare const CLASSIFICATION_METADATA: {
|
|
12
|
+
/** Marks a route as an explicit, code-reviewed public opt-out. */
|
|
13
|
+
readonly PUBLIC: "shield:classification:public";
|
|
14
|
+
/**
|
|
15
|
+
* Marks a route as classified against a permission/tier. In the Scaffold this
|
|
16
|
+
* is a placeholder value only — a LATER layer (ADR-0004 tiers, ADR-0012
|
|
17
|
+
* authoring) resolves it to a real decision. Its mere PRESENCE is what the
|
|
18
|
+
* stub guard checks: a classified route is "declared", an undeclared route is
|
|
19
|
+
* denied.
|
|
20
|
+
*/
|
|
21
|
+
readonly CLASSIFIED: "shield:classification:classified";
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* `@Public()` — the explicit, deny-by-default opt-OUT (ADR-0002).
|
|
25
|
+
*
|
|
26
|
+
* A route marked `@Public()` is reachable without a classification. This is the
|
|
27
|
+
* ONLY sanctioned way to make a route publicly reachable; it is intended to be
|
|
28
|
+
* rare and code-reviewed. Everything not `@Public()` and not `@Classified()` is
|
|
29
|
+
* denied by the global guard.
|
|
30
|
+
*/
|
|
31
|
+
export declare const Public: () => MethodDecorator & ClassDecorator;
|
|
32
|
+
/**
|
|
33
|
+
* `@Classified(...)` — declare a route's permission/tier classification.
|
|
34
|
+
*
|
|
35
|
+
* SCAFFOLD STUB: this only records that the route was classified; it does not
|
|
36
|
+
* yet gate on a real permission. A later authorization layer replaces the stub
|
|
37
|
+
* with an actual decision. Present here so business routes can be authored with
|
|
38
|
+
* the final API shape from the start.
|
|
39
|
+
*/
|
|
40
|
+
export declare const Classified: (classification: string) => MethodDecorator & ClassDecorator;
|
|
41
|
+
//# sourceMappingURL=classification.decorator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"classification.decorator.d.ts","sourceRoot":"","sources":["../../src/enforcement/classification.decorator.ts"],"names":[],"mappings":"AAEA;;;;;;;;;GASG;AACH,eAAO,MAAM,uBAAuB;IAClC,kEAAkE;;IAElE;;;;;;OAMG;;CAEK,CAAC;AAEX;;;;;;;GAOG;AACH,eAAO,MAAM,MAAM,QAAO,eAAe,GAAG,cACO,CAAC;AAEpD;;;;;;;GAOG;AACH,eAAO,MAAM,UAAU,GAAI,gBAAgB,MAAM,KAAG,eAAe,GAAG,cACL,CAAC"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Classified = exports.Public = exports.CLASSIFICATION_METADATA = void 0;
|
|
4
|
+
const common_1 = require("@nestjs/common");
|
|
5
|
+
/**
|
|
6
|
+
* Route-classification metadata keys (ADR-0002).
|
|
7
|
+
*
|
|
8
|
+
* Every HTTP handler in Shield must carry a classification. The global
|
|
9
|
+
* enforcement guard (see {@link GlobalEnforcementGuard}) reads these keys and,
|
|
10
|
+
* for any route WITHOUT one, denies the request (deny-by-default). This is the
|
|
11
|
+
* structurally-unavoidable, fail-closed posture ADR-0002 mandates — present from
|
|
12
|
+
* day one, even though the Scaffold stub does not yet consult a real decision
|
|
13
|
+
* authority.
|
|
14
|
+
*/
|
|
15
|
+
exports.CLASSIFICATION_METADATA = {
|
|
16
|
+
/** Marks a route as an explicit, code-reviewed public opt-out. */
|
|
17
|
+
PUBLIC: 'shield:classification:public',
|
|
18
|
+
/**
|
|
19
|
+
* Marks a route as classified against a permission/tier. In the Scaffold this
|
|
20
|
+
* is a placeholder value only — a LATER layer (ADR-0004 tiers, ADR-0012
|
|
21
|
+
* authoring) resolves it to a real decision. Its mere PRESENCE is what the
|
|
22
|
+
* stub guard checks: a classified route is "declared", an undeclared route is
|
|
23
|
+
* denied.
|
|
24
|
+
*/
|
|
25
|
+
CLASSIFIED: 'shield:classification:classified',
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* `@Public()` — the explicit, deny-by-default opt-OUT (ADR-0002).
|
|
29
|
+
*
|
|
30
|
+
* A route marked `@Public()` is reachable without a classification. This is the
|
|
31
|
+
* ONLY sanctioned way to make a route publicly reachable; it is intended to be
|
|
32
|
+
* rare and code-reviewed. Everything not `@Public()` and not `@Classified()` is
|
|
33
|
+
* denied by the global guard.
|
|
34
|
+
*/
|
|
35
|
+
const Public = () => (0, common_1.SetMetadata)(exports.CLASSIFICATION_METADATA.PUBLIC, true);
|
|
36
|
+
exports.Public = Public;
|
|
37
|
+
/**
|
|
38
|
+
* `@Classified(...)` — declare a route's permission/tier classification.
|
|
39
|
+
*
|
|
40
|
+
* SCAFFOLD STUB: this only records that the route was classified; it does not
|
|
41
|
+
* yet gate on a real permission. A later authorization layer replaces the stub
|
|
42
|
+
* with an actual decision. Present here so business routes can be authored with
|
|
43
|
+
* the final API shape from the start.
|
|
44
|
+
*/
|
|
45
|
+
const Classified = (classification) => (0, common_1.SetMetadata)(exports.CLASSIFICATION_METADATA.CLASSIFIED, classification);
|
|
46
|
+
exports.Classified = Classified;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Integration seam to @astram/core (ADR-0003).
|
|
3
|
+
*
|
|
4
|
+
* The NestJS layer is a THIN integration that CALLS the framework-agnostic Core;
|
|
5
|
+
* it contains no security logic itself. This module is the single, clearly-named
|
|
6
|
+
* place where the Core's decision authority is wired into the global enforcement
|
|
7
|
+
* guard.
|
|
8
|
+
*
|
|
9
|
+
* It imports REAL Core types from the published `@astram/core` package barrel —
|
|
10
|
+
* proving the ADR-0003 integration seam compiles against the actual Core
|
|
11
|
+
* contract (`DecisionAuthority`, `Decision`, `Principal`). These are TYPE-ONLY
|
|
12
|
+
* imports, so this layer takes on no runtime dependency on Core internals yet.
|
|
13
|
+
*
|
|
14
|
+
* The Scaffold guard does NOT consult a real authority yet (ADR-0002: the stub
|
|
15
|
+
* below only proves deny-by-default). When the Authorization layer lands, wire
|
|
16
|
+
* the Core `DecisionAuthority` in here — the guard code above this seam is
|
|
17
|
+
* unchanged.
|
|
18
|
+
*/
|
|
19
|
+
import type { DecisionAuthority as CoreDecisionAuthority, Decision as CoreDecision, Principal } from '@astram/core';
|
|
20
|
+
/** Re-export the Core contracts this layer wires against, for local consumers. */
|
|
21
|
+
export type { CoreDecisionAuthority, CoreDecision, Principal };
|
|
22
|
+
/**
|
|
23
|
+
* The fail-closed default effect (ADR-0002): if a decision cannot be rendered,
|
|
24
|
+
* the system denies. Mirrors the Core `Decision.effect` vocabulary.
|
|
25
|
+
*/
|
|
26
|
+
export type Effect = 'allow' | 'deny';
|
|
27
|
+
/**
|
|
28
|
+
* Fail-closed placeholder authority for the Scaffold.
|
|
29
|
+
*
|
|
30
|
+
* SCAFFOLD STUB: returns a `deny_by_default` `Decision` for every classified
|
|
31
|
+
* route so that "classified but not yet backed by a real policy" cannot silently
|
|
32
|
+
* open a door. `@Public()` routes never reach this — they are the explicit,
|
|
33
|
+
* code-reviewed opt-out handled by the guard before any authority is consulted.
|
|
34
|
+
*
|
|
35
|
+
* Typed as the full Core `DecisionAuthority` so it stays a true drop-in if the
|
|
36
|
+
* interface grows — replacing it with the real Core authority later is a
|
|
37
|
+
* one-line swap in the guard's DI.
|
|
38
|
+
*/
|
|
39
|
+
export declare const stubDecisionAuthority: CoreDecisionAuthority;
|
|
40
|
+
//# sourceMappingURL=core-seam.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"core-seam.d.ts","sourceRoot":"","sources":["../../src/enforcement/core-seam.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAMH,OAAO,KAAK,EACV,iBAAiB,IAAI,qBAAqB,EAC1C,QAAQ,IAAI,YAAY,EACxB,SAAS,EACV,MAAM,cAAc,CAAC;AAEtB,kFAAkF;AAClF,YAAY,EAAE,qBAAqB,EAAE,YAAY,EAAE,SAAS,EAAE,CAAC;AAE/D;;;GAGG;AACH,MAAM,MAAM,MAAM,GAAG,OAAO,GAAG,MAAM,CAAC;AAEtC;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,qBAAqB,EAAE,qBAInC,CAAC"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Integration seam to @astram/core (ADR-0003).
|
|
4
|
+
*
|
|
5
|
+
* The NestJS layer is a THIN integration that CALLS the framework-agnostic Core;
|
|
6
|
+
* it contains no security logic itself. This module is the single, clearly-named
|
|
7
|
+
* place where the Core's decision authority is wired into the global enforcement
|
|
8
|
+
* guard.
|
|
9
|
+
*
|
|
10
|
+
* It imports REAL Core types from the published `@astram/core` package barrel —
|
|
11
|
+
* proving the ADR-0003 integration seam compiles against the actual Core
|
|
12
|
+
* contract (`DecisionAuthority`, `Decision`, `Principal`). These are TYPE-ONLY
|
|
13
|
+
* imports, so this layer takes on no runtime dependency on Core internals yet.
|
|
14
|
+
*
|
|
15
|
+
* The Scaffold guard does NOT consult a real authority yet (ADR-0002: the stub
|
|
16
|
+
* below only proves deny-by-default). When the Authorization layer lands, wire
|
|
17
|
+
* the Core `DecisionAuthority` in here — the guard code above this seam is
|
|
18
|
+
* unchanged.
|
|
19
|
+
*/
|
|
20
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
|
+
exports.stubDecisionAuthority = void 0;
|
|
22
|
+
/**
|
|
23
|
+
* Fail-closed placeholder authority for the Scaffold.
|
|
24
|
+
*
|
|
25
|
+
* SCAFFOLD STUB: returns a `deny_by_default` `Decision` for every classified
|
|
26
|
+
* route so that "classified but not yet backed by a real policy" cannot silently
|
|
27
|
+
* open a door. `@Public()` routes never reach this — they are the explicit,
|
|
28
|
+
* code-reviewed opt-out handled by the guard before any authority is consulted.
|
|
29
|
+
*
|
|
30
|
+
* Typed as the full Core `DecisionAuthority` so it stays a true drop-in if the
|
|
31
|
+
* interface grows — replacing it with the real Core authority later is a
|
|
32
|
+
* one-line swap in the guard's DI.
|
|
33
|
+
*/
|
|
34
|
+
exports.stubDecisionAuthority = {
|
|
35
|
+
decide() {
|
|
36
|
+
return Promise.resolve({ effect: 'deny', reason: 'deny_by_default' });
|
|
37
|
+
},
|
|
38
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The SOLE definition of the global `APP_GUARD` binding (ADR-0002).
|
|
3
|
+
*
|
|
4
|
+
* Registering {@link GlobalEnforcementGuard} as an `APP_GUARD` makes it apply to
|
|
5
|
+
* EVERY route across the whole application — it is impossible to opt a route out
|
|
6
|
+
* of enforcement by omission. The only sanctioned opt-out is the explicit,
|
|
7
|
+
* code-reviewed `@Public()` decorator. This is the "one global mechanism through
|
|
8
|
+
* which all requests pass" ADR-0002 mandates.
|
|
9
|
+
*
|
|
10
|
+
* INTERNAL — this module is NOT public API and is NOT exported from the package
|
|
11
|
+
* barrel. It is composed internally by {@link ShieldModule.forRoot} (the ONE
|
|
12
|
+
* registration seam, ADR-0023 §4); consumers must NOT import it directly. Keeping
|
|
13
|
+
* this the single `APP_GUARD` definition (instead of re-inlining it in
|
|
14
|
+
* `ShieldModule`) guarantees exactly one wiring path for the guard.
|
|
15
|
+
*/
|
|
16
|
+
export declare class EnforcementModule {
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=enforcement.module.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"enforcement.module.d.ts","sourceRoot":"","sources":["../../src/enforcement/enforcement.module.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;GAcG;AACH,qBAQa,iBAAiB;CAAG"}
|
|
@@ -0,0 +1,40 @@
|
|
|
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.EnforcementModule = void 0;
|
|
10
|
+
const common_1 = require("@nestjs/common");
|
|
11
|
+
const core_1 = require("@nestjs/core");
|
|
12
|
+
const global_enforcement_guard_js_1 = require("./global-enforcement.guard.js");
|
|
13
|
+
/**
|
|
14
|
+
* The SOLE definition of the global `APP_GUARD` binding (ADR-0002).
|
|
15
|
+
*
|
|
16
|
+
* Registering {@link GlobalEnforcementGuard} as an `APP_GUARD` makes it apply to
|
|
17
|
+
* EVERY route across the whole application — it is impossible to opt a route out
|
|
18
|
+
* of enforcement by omission. The only sanctioned opt-out is the explicit,
|
|
19
|
+
* code-reviewed `@Public()` decorator. This is the "one global mechanism through
|
|
20
|
+
* which all requests pass" ADR-0002 mandates.
|
|
21
|
+
*
|
|
22
|
+
* INTERNAL — this module is NOT public API and is NOT exported from the package
|
|
23
|
+
* barrel. It is composed internally by {@link ShieldModule.forRoot} (the ONE
|
|
24
|
+
* registration seam, ADR-0023 §4); consumers must NOT import it directly. Keeping
|
|
25
|
+
* this the single `APP_GUARD` definition (instead of re-inlining it in
|
|
26
|
+
* `ShieldModule`) guarantees exactly one wiring path for the guard.
|
|
27
|
+
*/
|
|
28
|
+
let EnforcementModule = class EnforcementModule {
|
|
29
|
+
};
|
|
30
|
+
exports.EnforcementModule = EnforcementModule;
|
|
31
|
+
exports.EnforcementModule = EnforcementModule = __decorate([
|
|
32
|
+
(0, common_1.Module)({
|
|
33
|
+
providers: [
|
|
34
|
+
{
|
|
35
|
+
provide: core_1.APP_GUARD,
|
|
36
|
+
useClass: global_enforcement_guard_js_1.GlobalEnforcementGuard,
|
|
37
|
+
},
|
|
38
|
+
],
|
|
39
|
+
})
|
|
40
|
+
], EnforcementModule);
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { CanActivate, ExecutionContext } from '@nestjs/common';
|
|
2
|
+
import { Reflector } from '@nestjs/core';
|
|
3
|
+
/**
|
|
4
|
+
* Global, fail-closed enforcement guard (ADR-0002).
|
|
5
|
+
*
|
|
6
|
+
* This guard is the SINGLE, structurally-unavoidable point every request passes
|
|
7
|
+
* through. It is bound as an `APP_GUARD` through the ONE registration seam,
|
|
8
|
+
* `ShieldModule.forRoot()` (which composes the internal `EnforcementModule` that
|
|
9
|
+
* holds the sole binding) — NOT opt-in per controller — so no endpoint can escape
|
|
10
|
+
* it. Its posture is **deny-by-default**:
|
|
11
|
+
*
|
|
12
|
+
* - A route marked `@Public()` → ALLOWED (explicit, code-reviewed opt-out).
|
|
13
|
+
* - A route marked `@Classified()` → allowed to PROCEED in the Scaffold stub
|
|
14
|
+
* (a LATER layer will consult the real Core `DecisionAuthority` here; see
|
|
15
|
+
* {@link ../enforcement/core-seam.ts}). Its presence proves the route was
|
|
16
|
+
* declared.
|
|
17
|
+
* - A route with NO classification → DENIED (403). A forgotten declaration
|
|
18
|
+
* locks the door instead of opening it.
|
|
19
|
+
*
|
|
20
|
+
* SCAFFOLD SCOPE: this does not yet perform real authorization. It only proves
|
|
21
|
+
* the fail-closed, globally-unavoidable, deny-by-default seam exists from day
|
|
22
|
+
* one. When the Authorization layer lands, the `@Classified` branch calls the
|
|
23
|
+
* Core decision authority (wired via the core-seam) — the deny-by-default
|
|
24
|
+
* structure here does not change.
|
|
25
|
+
*/
|
|
26
|
+
export declare class GlobalEnforcementGuard implements CanActivate {
|
|
27
|
+
private readonly reflector;
|
|
28
|
+
constructor(reflector: Reflector);
|
|
29
|
+
canActivate(context: ExecutionContext): boolean;
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=global-enforcement.guard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"global-enforcement.guard.d.ts","sourceRoot":"","sources":["../../src/enforcement/global-enforcement.guard.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAkC,MAAM,gBAAgB,CAAC;AAC/F,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAGzC;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,qBACa,sBAAuB,YAAW,WAAW;IAC5C,OAAO,CAAC,QAAQ,CAAC,SAAS;gBAAT,SAAS,EAAE,SAAS;IAEjD,WAAW,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO;CAsChD"}
|
|
@@ -0,0 +1,76 @@
|
|
|
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.GlobalEnforcementGuard = void 0;
|
|
13
|
+
const common_1 = require("@nestjs/common");
|
|
14
|
+
const core_1 = require("@nestjs/core");
|
|
15
|
+
const classification_decorator_js_1 = require("./classification.decorator.js");
|
|
16
|
+
/**
|
|
17
|
+
* Global, fail-closed enforcement guard (ADR-0002).
|
|
18
|
+
*
|
|
19
|
+
* This guard is the SINGLE, structurally-unavoidable point every request passes
|
|
20
|
+
* through. It is bound as an `APP_GUARD` through the ONE registration seam,
|
|
21
|
+
* `ShieldModule.forRoot()` (which composes the internal `EnforcementModule` that
|
|
22
|
+
* holds the sole binding) — NOT opt-in per controller — so no endpoint can escape
|
|
23
|
+
* it. Its posture is **deny-by-default**:
|
|
24
|
+
*
|
|
25
|
+
* - A route marked `@Public()` → ALLOWED (explicit, code-reviewed opt-out).
|
|
26
|
+
* - A route marked `@Classified()` → allowed to PROCEED in the Scaffold stub
|
|
27
|
+
* (a LATER layer will consult the real Core `DecisionAuthority` here; see
|
|
28
|
+
* {@link ../enforcement/core-seam.ts}). Its presence proves the route was
|
|
29
|
+
* declared.
|
|
30
|
+
* - A route with NO classification → DENIED (403). A forgotten declaration
|
|
31
|
+
* locks the door instead of opening it.
|
|
32
|
+
*
|
|
33
|
+
* SCAFFOLD SCOPE: this does not yet perform real authorization. It only proves
|
|
34
|
+
* the fail-closed, globally-unavoidable, deny-by-default seam exists from day
|
|
35
|
+
* one. When the Authorization layer lands, the `@Classified` branch calls the
|
|
36
|
+
* Core decision authority (wired via the core-seam) — the deny-by-default
|
|
37
|
+
* structure here does not change.
|
|
38
|
+
*/
|
|
39
|
+
let GlobalEnforcementGuard = class GlobalEnforcementGuard {
|
|
40
|
+
reflector;
|
|
41
|
+
constructor(reflector) {
|
|
42
|
+
this.reflector = reflector;
|
|
43
|
+
}
|
|
44
|
+
canActivate(context) {
|
|
45
|
+
// Only HTTP requests are classified here. Non-HTTP contexts (if ever added)
|
|
46
|
+
// must be handled explicitly rather than silently allowed.
|
|
47
|
+
if (context.getType() !== 'http') {
|
|
48
|
+
throw new common_1.ForbiddenException('Shield enforcement: non-HTTP execution context is not classified (deny-by-default).');
|
|
49
|
+
}
|
|
50
|
+
const handler = context.getHandler();
|
|
51
|
+
const controller = context.getClass();
|
|
52
|
+
// 1. Explicit public opt-out wins. Method-level OR class-level @Public().
|
|
53
|
+
const isPublic = this.reflector.getAllAndOverride(classification_decorator_js_1.CLASSIFICATION_METADATA.PUBLIC, [
|
|
54
|
+
handler,
|
|
55
|
+
controller,
|
|
56
|
+
]);
|
|
57
|
+
if (isPublic === true) {
|
|
58
|
+
return true;
|
|
59
|
+
}
|
|
60
|
+
// 2. Classified route → declared. Scaffold stub lets it proceed (a real
|
|
61
|
+
// decision authority is wired in a later layer via the core-seam).
|
|
62
|
+
const classification = this.reflector.getAllAndOverride(classification_decorator_js_1.CLASSIFICATION_METADATA.CLASSIFIED, [handler, controller]);
|
|
63
|
+
if (typeof classification === 'string' && classification.length > 0) {
|
|
64
|
+
return true;
|
|
65
|
+
}
|
|
66
|
+
// 3. No classification at all → DENY (ADR-0002 deny-by-default / fail-closed).
|
|
67
|
+
throw new common_1.ForbiddenException('Shield enforcement: this route carries no access classification. ' +
|
|
68
|
+
'It is denied by default (ADR-0002). Mark it @Public() to opt out, or ' +
|
|
69
|
+
'@Classified(...) to declare its permission.');
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
exports.GlobalEnforcementGuard = GlobalEnforcementGuard;
|
|
73
|
+
exports.GlobalEnforcementGuard = GlobalEnforcementGuard = __decorate([
|
|
74
|
+
(0, common_1.Injectable)(),
|
|
75
|
+
__metadata("design:paramtypes", [core_1.Reflector])
|
|
76
|
+
], GlobalEnforcementGuard);
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@astram/guard` — the thin NestJS integration for the Shield framework
|
|
3
|
+
* (ADR-0023 §1, ADR-0003).
|
|
4
|
+
*
|
|
5
|
+
* This is the shippable, consumer-INSTALLED framework glue: the global
|
|
6
|
+
* deny-by-default enforcement guard (ADR-0002), its `@Public()`/`@Classified()`
|
|
7
|
+
* classification decorators, the ADR-0018 boot-pool assertion, and the ONE
|
|
8
|
+
* registration seam — {@link ShieldModule}`.forRoot()` / `.forRootAsync()`.
|
|
9
|
+
*
|
|
10
|
+
* A consumer app depends on this package and `@astram/core`, imports
|
|
11
|
+
* `ShieldModule.forRoot({...})` once, and builds features in its own editable
|
|
12
|
+
* `src/`. It never edits the framework; upgrades flow through `npm update`.
|
|
13
|
+
*
|
|
14
|
+
* Depends on `@astram/core` (workspace); PEER-depends on `@nestjs/common`,
|
|
15
|
+
* `@nestjs/core`, `reflect-metadata`, `rxjs` so the host owns one copy of each.
|
|
16
|
+
*/
|
|
17
|
+
export { ShieldModule, SHIELD_DECISION_AUTHORITY, type ShieldModuleOptions, type ShieldModuleAsyncOptions, } from './module/shield.module.js';
|
|
18
|
+
export { Public, Classified, CLASSIFICATION_METADATA, } from './enforcement/classification.decorator.js';
|
|
19
|
+
export { GlobalEnforcementGuard } from './enforcement/global-enforcement.guard.js';
|
|
20
|
+
export { stubDecisionAuthority, type Effect, type CoreDecisionAuthority, type CoreDecision, type Principal, } from './enforcement/core-seam.js';
|
|
21
|
+
export { Argon2idPasswordHasher, argon2idHasherProvider, SHIELD_PASSWORD_HASHER, type Argon2idParams, } from './authentication/argon2id-password-hasher.js';
|
|
22
|
+
export { MariaDbSessionRecordStore, SHIELD_SESSION_RECORD_STORE, RedisHotSessionStore, SHIELD_HOT_SESSION_STORE, CryptoTokenGenerator, Sha256RefreshTokenHasher, SystemClock, cryptoTokenGeneratorProvider, refreshHasherProvider, systemClockProvider, SHIELD_TOKEN_GENERATOR, SHIELD_REFRESH_HASHER, SHIELD_CLOCK, } from './session/index.js';
|
|
23
|
+
export { BootSequence, assertPoolBudget } from './boot/boot-sequence.js';
|
|
24
|
+
export { APP_CONFIG } from './config/config.module.js';
|
|
25
|
+
export { loadAppConfig, loadPoolBudget, evaluatePoolBudget, DEFAULT_POOL_BUDGET, SCHEMA_SVC_POOL_HARD_CAP, type AppConfig, type PoolBudgetConfig, type PoolBudgetEvaluation, type RuntimeAccountPools, } from './config/app-config.js';
|
|
26
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,OAAO,EACL,YAAY,EACZ,yBAAyB,EACzB,KAAK,mBAAmB,EACxB,KAAK,wBAAwB,GAC9B,MAAM,2BAA2B,CAAC;AAGnC,OAAO,EACL,MAAM,EACN,UAAU,EACV,uBAAuB,GACxB,MAAM,2CAA2C,CAAC;AAUnD,OAAO,EAAE,sBAAsB,EAAE,MAAM,2CAA2C,CAAC;AAKnF,OAAO,EACL,qBAAqB,EACrB,KAAK,MAAM,EACX,KAAK,qBAAqB,EAC1B,KAAK,YAAY,EACjB,KAAK,SAAS,GACf,MAAM,4BAA4B,CAAC;AAMpC,OAAO,EACL,sBAAsB,EACtB,sBAAsB,EACtB,sBAAsB,EACtB,KAAK,cAAc,GACpB,MAAM,8CAA8C,CAAC;AAOtD,OAAO,EACL,yBAAyB,EACzB,2BAA2B,EAC3B,oBAAoB,EACpB,wBAAwB,EACxB,oBAAoB,EACpB,wBAAwB,EACxB,WAAW,EACX,4BAA4B,EAC5B,qBAAqB,EACrB,mBAAmB,EACnB,sBAAsB,EACtB,qBAAqB,EACrB,YAAY,GACb,MAAM,oBAAoB,CAAC;AAI5B,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAOzE,OAAO,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AACvD,OAAO,EACL,aAAa,EACb,cAAc,EACd,kBAAkB,EAClB,mBAAmB,EACnB,wBAAwB,EACxB,KAAK,SAAS,EACd,KAAK,gBAAgB,EACrB,KAAK,oBAAoB,EACzB,KAAK,mBAAmB,GACzB,MAAM,wBAAwB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* `@astram/guard` — the thin NestJS integration for the Shield framework
|
|
4
|
+
* (ADR-0023 §1, ADR-0003).
|
|
5
|
+
*
|
|
6
|
+
* This is the shippable, consumer-INSTALLED framework glue: the global
|
|
7
|
+
* deny-by-default enforcement guard (ADR-0002), its `@Public()`/`@Classified()`
|
|
8
|
+
* classification decorators, the ADR-0018 boot-pool assertion, and the ONE
|
|
9
|
+
* registration seam — {@link ShieldModule}`.forRoot()` / `.forRootAsync()`.
|
|
10
|
+
*
|
|
11
|
+
* A consumer app depends on this package and `@astram/core`, imports
|
|
12
|
+
* `ShieldModule.forRoot({...})` once, and builds features in its own editable
|
|
13
|
+
* `src/`. It never edits the framework; upgrades flow through `npm update`.
|
|
14
|
+
*
|
|
15
|
+
* Depends on `@astram/core` (workspace); PEER-depends on `@nestjs/common`,
|
|
16
|
+
* `@nestjs/core`, `reflect-metadata`, `rxjs` so the host owns one copy of each.
|
|
17
|
+
*/
|
|
18
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
19
|
+
exports.SCHEMA_SVC_POOL_HARD_CAP = exports.DEFAULT_POOL_BUDGET = exports.evaluatePoolBudget = exports.loadPoolBudget = exports.loadAppConfig = exports.APP_CONFIG = exports.assertPoolBudget = exports.BootSequence = exports.SHIELD_CLOCK = exports.SHIELD_REFRESH_HASHER = exports.SHIELD_TOKEN_GENERATOR = exports.systemClockProvider = exports.refreshHasherProvider = exports.cryptoTokenGeneratorProvider = exports.SystemClock = exports.Sha256RefreshTokenHasher = exports.CryptoTokenGenerator = exports.SHIELD_HOT_SESSION_STORE = exports.RedisHotSessionStore = exports.SHIELD_SESSION_RECORD_STORE = exports.MariaDbSessionRecordStore = exports.SHIELD_PASSWORD_HASHER = exports.argon2idHasherProvider = exports.Argon2idPasswordHasher = exports.stubDecisionAuthority = exports.GlobalEnforcementGuard = exports.CLASSIFICATION_METADATA = exports.Classified = exports.Public = exports.SHIELD_DECISION_AUTHORITY = exports.ShieldModule = void 0;
|
|
20
|
+
// The single registration seam.
|
|
21
|
+
var shield_module_js_1 = require("./module/shield.module.js");
|
|
22
|
+
Object.defineProperty(exports, "ShieldModule", { enumerable: true, get: function () { return shield_module_js_1.ShieldModule; } });
|
|
23
|
+
Object.defineProperty(exports, "SHIELD_DECISION_AUTHORITY", { enumerable: true, get: function () { return shield_module_js_1.SHIELD_DECISION_AUTHORITY; } });
|
|
24
|
+
// Route classification (the consumer authors these on its controllers).
|
|
25
|
+
var classification_decorator_js_1 = require("./enforcement/classification.decorator.js");
|
|
26
|
+
Object.defineProperty(exports, "Public", { enumerable: true, get: function () { return classification_decorator_js_1.Public; } });
|
|
27
|
+
Object.defineProperty(exports, "Classified", { enumerable: true, get: function () { return classification_decorator_js_1.Classified; } });
|
|
28
|
+
Object.defineProperty(exports, "CLASSIFICATION_METADATA", { enumerable: true, get: function () { return classification_decorator_js_1.CLASSIFICATION_METADATA; } });
|
|
29
|
+
// The global enforcement guard (framework-owned; exported so the enforcement
|
|
30
|
+
// point is inspectable/testable, not so consumers re-wire it).
|
|
31
|
+
//
|
|
32
|
+
// NOTE: `EnforcementModule` / `BootModule` / `ConfigModule` are DELIBERATELY NOT
|
|
33
|
+
// exported. `ShieldModule.forRoot()` is the ONE registration seam and composes
|
|
34
|
+
// them internally (EnforcementModule holds the SOLE `APP_GUARD` binding). Exposing
|
|
35
|
+
// them would let a consumer import a module that independently re-binds `APP_GUARD`
|
|
36
|
+
// — a second, divergent wiring path that contradicts ADR-0023 §4 ("one seam").
|
|
37
|
+
var global_enforcement_guard_js_1 = require("./enforcement/global-enforcement.guard.js");
|
|
38
|
+
Object.defineProperty(exports, "GlobalEnforcementGuard", { enumerable: true, get: function () { return global_enforcement_guard_js_1.GlobalEnforcementGuard; } });
|
|
39
|
+
// The Core integration seam (ADR-0003): the decision-authority contract this
|
|
40
|
+
// layer wires against, plus the fail-closed stub used until a real authority is
|
|
41
|
+
// supplied through `ShieldModule.forRoot`.
|
|
42
|
+
var core_seam_js_1 = require("./enforcement/core-seam.js");
|
|
43
|
+
Object.defineProperty(exports, "stubDecisionAuthority", { enumerable: true, get: function () { return core_seam_js_1.stubDecisionAuthority; } });
|
|
44
|
+
// The Authentication crypto adapter (ADR-0003): the concrete Argon2id
|
|
45
|
+
// `PasswordHasher` implementation lives HERE (real `argon2` dependency) and is
|
|
46
|
+
// injected into `@astram/core`'s `createAuthenticator({ hasher })` — Core stays
|
|
47
|
+
// zero-dep. The DI token + provider factory wire it into a Nest container.
|
|
48
|
+
var argon2id_password_hasher_js_1 = require("./authentication/argon2id-password-hasher.js");
|
|
49
|
+
Object.defineProperty(exports, "Argon2idPasswordHasher", { enumerable: true, get: function () { return argon2id_password_hasher_js_1.Argon2idPasswordHasher; } });
|
|
50
|
+
Object.defineProperty(exports, "argon2idHasherProvider", { enumerable: true, get: function () { return argon2id_password_hasher_js_1.argon2idHasherProvider; } });
|
|
51
|
+
Object.defineProperty(exports, "SHIELD_PASSWORD_HASHER", { enumerable: true, get: function () { return argon2id_password_hasher_js_1.SHIELD_PASSWORD_HASHER; } });
|
|
52
|
+
// The Session storage/crypto adapters (ADR-0003 / ADR-0013): the concrete durable
|
|
53
|
+
// (MariaDB) + hot (Redis) stores, the node:crypto token generator, the keyed HMAC
|
|
54
|
+
// refresh hasher, and the system clock — all implementing `@astram/core`'s Session
|
|
55
|
+
// PORTs and injected into `createSessionAuthority(...)`. Core stays zero-dep; the
|
|
56
|
+
// real `mariadb` / `ioredis` / `node:crypto` live here.
|
|
57
|
+
var index_js_1 = require("./session/index.js");
|
|
58
|
+
Object.defineProperty(exports, "MariaDbSessionRecordStore", { enumerable: true, get: function () { return index_js_1.MariaDbSessionRecordStore; } });
|
|
59
|
+
Object.defineProperty(exports, "SHIELD_SESSION_RECORD_STORE", { enumerable: true, get: function () { return index_js_1.SHIELD_SESSION_RECORD_STORE; } });
|
|
60
|
+
Object.defineProperty(exports, "RedisHotSessionStore", { enumerable: true, get: function () { return index_js_1.RedisHotSessionStore; } });
|
|
61
|
+
Object.defineProperty(exports, "SHIELD_HOT_SESSION_STORE", { enumerable: true, get: function () { return index_js_1.SHIELD_HOT_SESSION_STORE; } });
|
|
62
|
+
Object.defineProperty(exports, "CryptoTokenGenerator", { enumerable: true, get: function () { return index_js_1.CryptoTokenGenerator; } });
|
|
63
|
+
Object.defineProperty(exports, "Sha256RefreshTokenHasher", { enumerable: true, get: function () { return index_js_1.Sha256RefreshTokenHasher; } });
|
|
64
|
+
Object.defineProperty(exports, "SystemClock", { enumerable: true, get: function () { return index_js_1.SystemClock; } });
|
|
65
|
+
Object.defineProperty(exports, "cryptoTokenGeneratorProvider", { enumerable: true, get: function () { return index_js_1.cryptoTokenGeneratorProvider; } });
|
|
66
|
+
Object.defineProperty(exports, "refreshHasherProvider", { enumerable: true, get: function () { return index_js_1.refreshHasherProvider; } });
|
|
67
|
+
Object.defineProperty(exports, "systemClockProvider", { enumerable: true, get: function () { return index_js_1.systemClockProvider; } });
|
|
68
|
+
Object.defineProperty(exports, "SHIELD_TOKEN_GENERATOR", { enumerable: true, get: function () { return index_js_1.SHIELD_TOKEN_GENERATOR; } });
|
|
69
|
+
Object.defineProperty(exports, "SHIELD_REFRESH_HASHER", { enumerable: true, get: function () { return index_js_1.SHIELD_REFRESH_HASHER; } });
|
|
70
|
+
Object.defineProperty(exports, "SHIELD_CLOCK", { enumerable: true, get: function () { return index_js_1.SHIELD_CLOCK; } });
|
|
71
|
+
// Boot infrastructure (ADR-0018 connection-pool budget assertion). `BootModule`
|
|
72
|
+
// itself is NOT exported — it is composed internally by `ShieldModule.forRoot()`.
|
|
73
|
+
var boot_sequence_js_1 = require("./boot/boot-sequence.js");
|
|
74
|
+
Object.defineProperty(exports, "BootSequence", { enumerable: true, get: function () { return boot_sequence_js_1.BootSequence; } });
|
|
75
|
+
Object.defineProperty(exports, "assertPoolBudget", { enumerable: true, get: function () { return boot_sequence_js_1.assertPoolBudget; } });
|
|
76
|
+
// Application config surface (port / environment / ADR-0018 pool budget). The
|
|
77
|
+
// consumer skeleton reads `loadAppConfig()` for its HTTP port; the boot assertion
|
|
78
|
+
// validates the pool budget. The `APP_CONFIG` DI token is exported; `ConfigModule`
|
|
79
|
+
// (its env-only provider) is NOT — `ShieldModule` provides `APP_CONFIG` itself so
|
|
80
|
+
// the one seam can honor caller-supplied config.
|
|
81
|
+
var config_module_js_1 = require("./config/config.module.js");
|
|
82
|
+
Object.defineProperty(exports, "APP_CONFIG", { enumerable: true, get: function () { return config_module_js_1.APP_CONFIG; } });
|
|
83
|
+
var app_config_js_1 = require("./config/app-config.js");
|
|
84
|
+
Object.defineProperty(exports, "loadAppConfig", { enumerable: true, get: function () { return app_config_js_1.loadAppConfig; } });
|
|
85
|
+
Object.defineProperty(exports, "loadPoolBudget", { enumerable: true, get: function () { return app_config_js_1.loadPoolBudget; } });
|
|
86
|
+
Object.defineProperty(exports, "evaluatePoolBudget", { enumerable: true, get: function () { return app_config_js_1.evaluatePoolBudget; } });
|
|
87
|
+
Object.defineProperty(exports, "DEFAULT_POOL_BUDGET", { enumerable: true, get: function () { return app_config_js_1.DEFAULT_POOL_BUDGET; } });
|
|
88
|
+
Object.defineProperty(exports, "SCHEMA_SVC_POOL_HARD_CAP", { enumerable: true, get: function () { return app_config_js_1.SCHEMA_SVC_POOL_HARD_CAP; } });
|