@astram/guard
v0.4.1
Published
Astram framework — the enforcement guard + real-world adapters (the 'hands'). One global deny-by-default gate every request passes through (ADR-0002), classification decorators, boot-pool assertion (ADR-0018), the forRoot() registration seam, and the DB/R
Readme
@astram/guard — the enforcement gate + NestJS adapters
The enforcement gate + thin NestJS integration for the Astram framework — the
shippable glue a consumer app installs (it runs on / integrates with NestJS). Per
ADR-0023
this is framework code, owned + locked, not consumer-editable: it lives in the
consumer's node_modules, and upgrades flow through npm update. It depends on
@astram/core (the framework-agnostic kernel) and PEER-depends on the
host's NestJS runtime.
What's in here
| Piece | File | Purpose |
| ------------------------- | --------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
| ShieldModule | src/module/shield.module.ts | The one registration seam — forRoot() / forRootAsync(). Consumers import it once; the framework owns composition. |
| Global enforcement guard | src/enforcement/global-enforcement.guard.ts | The deny-by-default APP_GUARD (ADR-0002) every route traverses. |
| Classification decorators | src/enforcement/classification.decorator.ts | @Public() / @Classified() — the consumer authors these on controllers. |
| Core seam | src/enforcement/core-seam.ts | Type-only import of @astram/core's DecisionAuthority (ADR-0003) + the fail-closed stub. |
| Boot-pool assertion | src/boot/boot-sequence.ts | ADR-0018 connection-pool budget check at boot (fail-closed). |
| App config | src/config/app-config.ts | Port / environment / ADR-0018 pool budget (env loader, pure). |
The registration seam (ADR-0023 §4)
A consumer app wires Astram with a single import in its root module — it never edits the framework:
import { Module } from '@nestjs/common';
import { ShieldModule } from '@astram/guard';
@Module({
imports: [
ShieldModule.forRoot(), // fail-closed stub authority; env-loaded config
// ShieldModule.forRoot({ decisionAuthority, config }) to supply the real Core authority
],
controllers: [/* the consumer's feature controllers */],
})
export class AppModule {}forRoot() binds:
GlobalEnforcementGuardasAPP_GUARD→ the global, structurally-unavoidable, deny-by-default enforcement point (ADR-0002).@Public()is the only opt-out; an unclassified route is denied (403).- The resolved
AppConfig(underAPP_CONFIG) + theBootSequencehook, which runs the ADR-0018 pool-budget assertion at boot (aborts on violation). - The Core decision authority (under
SHIELD_DECISION_AUTHORITY) — the real@astram/coreauthority when supplied viaforRoot({ decisionAuthority }), else the fail-closed stub (deny-by-default), so a mis-wiring cannot open a door.
forRootAsync({ useFactory, inject, imports }) is the DI-computed variant (a stub
in this layer): the factory resolves the same options at startup; the guard/boot
wiring is identical.
Peer dependencies (ADR-0023 §2)
@astram/guard peer-depends on the host runtime so the consumer owns exactly
one copy (a single reflect-metadata singleton / DI injector):
@nestjs/common ^11 · @nestjs/core ^11 · reflect-metadata ^0.2 · rxjs ^7These are also devDependencies here so the package compiles + tests locally.
@astram/core is a real (workspace) dependency.
Commands
pnpm --filter @astram/guard build # tsc -p tsconfig.build.json (emits dist + .d.ts)
pnpm --filter @astram/guard lint # eslint
pnpm --filter @astram/guard test # vitest run (guard unit + boot-pool + forRoot e2e)Notes
- CommonJS locally (
"type": "commonjs") for the NestJS decorator +reflect-metadataDI model. The repo root and@astram/corestay ESM/NodeNext; the override is scoped to this package (seetsconfig.json). - The core seam imports the REAL
@astram/corebarrel (type-only) — Core'sexportsmap exposes only".", so subpath imports fail Node resolution. This package's tsconfig clears the basepathsso@astram/coreresolves through the node_modules workspace symlink to Core's builtdist.
