@astram/guide 0.2.1 → 0.2.3
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/CAPABILITIES.md +11 -12
- package/FRAMEWORK_RULES.md +8 -0
- package/package.json +1 -1
package/CAPABILITIES.md
CHANGED
|
@@ -20,13 +20,9 @@ below is wired by the two `forRoot` calls in your `app.module.ts`; you write no
|
|
|
20
20
|
import { ShieldModule } from '@astram/guard';
|
|
21
21
|
import {
|
|
22
22
|
IdentityFeatureModule, identityAuthActionKeys, identityControlPlaneKeys,
|
|
23
|
-
buildIdentityRecordAuthorization,
|
|
24
23
|
} from '@astram/identity';
|
|
25
|
-
// Raw-pool factory: composition root only (app.module.ts), never exported from it.
|
|
26
|
-
import { createIdentityAuthzPool } from '@astram/identity/internal';
|
|
27
24
|
|
|
28
25
|
const rootIds = ['<platform-admin user uuid>']; // from config, never from a request
|
|
29
|
-
const authzPool = createIdentityAuthzPool();
|
|
30
26
|
|
|
31
27
|
imports: [
|
|
32
28
|
ShieldModule.forRoot({
|
|
@@ -35,14 +31,15 @@ imports: [
|
|
|
35
31
|
rootIds,
|
|
36
32
|
identityActionKeys: identityAuthActionKeys,
|
|
37
33
|
identityControlPlaneKeys,
|
|
38
|
-
recordAuthorization:
|
|
34
|
+
// no recordAuthorization: IdentityFeatureModule provides it
|
|
39
35
|
}),
|
|
40
36
|
IdentityFeatureModule.forRoot({ rootIds, extraObjects: [/* YourType */] }),
|
|
41
37
|
],
|
|
42
38
|
```
|
|
43
39
|
|
|
44
40
|
- **`ShieldModule.forRoot(options?)`** (`@astram/guard`; `forRootAsync` for DI-computed options).
|
|
45
|
-
Options: `auth?`, `recordAuthorization?` (or a pre-built `decisionAuthority
|
|
41
|
+
Options: `auth?`, `recordAuthorization?` (or a pre-built `decisionAuthority?`; only for an app
|
|
42
|
+
WITHOUT `IdentityFeatureModule`, never both),
|
|
46
43
|
`emailSender?: EmailSender | 'disabled'`, `rootIds?`, `identityActionKeys?`,
|
|
47
44
|
`identityControlPlaneKeys?`, `config?`, and optional overrides `credentialResolver?`,
|
|
48
45
|
`profileResolver?`, `credentialWriter?`, `resetTokenStore?`, `recoveryCodeStore?`,
|
|
@@ -50,11 +47,12 @@ imports: [
|
|
|
50
47
|
`sessionFactsProjector?`, `scopeSubtreeResolver?`, `membershipChecker?`. With `auth: true` every
|
|
51
48
|
override has a MariaDB/Redis default; leave them out unless you have a reason.
|
|
52
49
|
- **`IdentityFeatureModule.forRoot({ rootIds?, extraObjects? })`** (`@astram/identity`). Pass the
|
|
53
|
-
SAME `rootIds` as `ShieldModule
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
50
|
+
SAME `rootIds` as `ShieldModule`. `extraObjects` (your own registered object types) are given
|
|
51
|
+
HERE ONLY: the module builds the record authorization from them and `ShieldModule` decides with
|
|
52
|
+
it. Passing `recordAuthorization`/`decisionAuthority` to `ShieldModule` as well fails the boot.
|
|
53
|
+
Without `rootIds` it logs a boot warning.
|
|
54
|
+
- `ShieldModule.forRoot()` with no options and no identity module = enforcement only (no DB, no
|
|
55
|
+
Redis, boots without `.env`); it binds a stub that denies every `@Classified` route.
|
|
58
56
|
|
|
59
57
|
## Enforcement (`@astram/guard`)
|
|
60
58
|
- **Global deny-by-default guard** — every route is denied unless `@Public()` or
|
|
@@ -142,7 +140,8 @@ imports: [
|
|
|
142
140
|
`readScope` declares the subtree wall; `create: 'unscoped'` opts a type out of the create wall.
|
|
143
141
|
- **Physical wall** — the raw DB pool is sealed in the engine. The scaffold's
|
|
144
142
|
`server/eslint.config.mjs` fails lint on driver imports, raw pools, `.query()` and the
|
|
145
|
-
framework's internal DB exports anywhere in `src/**` except `app.module.ts` and `main.ts
|
|
143
|
+
framework's internal DB exports anywhere in `src/**` except `app.module.ts` and `main.ts`, and on
|
|
144
|
+
uuid-named route/body inputs read without `UuidPipe` / `uuidField` (`@astram/guard`). A lint
|
|
146
145
|
rule is a backstop, not a sandbox: do not go around it.
|
|
147
146
|
- **Gap signal** — an unsupported field type or operation throws `CapabilityNotSupportedError`
|
|
148
147
|
(a Rule-4 STOP). Field types this version: `string`, `number`, `boolean`, `uuid`, `timestamp`,
|
package/FRAMEWORK_RULES.md
CHANGED
|
@@ -71,6 +71,14 @@ app refuses to boot with one — a forgotten declaration locks the door instead
|
|
|
71
71
|
silently exposing it. Never make a route public to "make it work"; classify it
|
|
72
72
|
correctly.
|
|
73
73
|
|
|
74
|
+
**Validate uuid inputs at the edge.** Every uuid route param uses `UuidPipe`
|
|
75
|
+
(`@Param('uuid', UuidPipe)`) and every uuid body or query field goes through
|
|
76
|
+
`uuidField` / `optionalUuidField` / `uuidArrayField` (all from `@astram/guard`). They
|
|
77
|
+
answer 400 for anything that is not a strict uuid and hand you the canonical lower-case
|
|
78
|
+
form. The database matches uuids ignoring case, trailing spaces and character width, so
|
|
79
|
+
a raw `"<id> "` reaches the row while your exact checks in code miss it. The lint wall
|
|
80
|
+
flags uuid-named inputs (`id`, `uuid`, `…Id(s)`, `…Uuid(s)`) read without them.
|
|
81
|
+
|
|
74
82
|
## 4. When the framework can't do it: STOP and FLAG the gap — do NOT work around it
|
|
75
83
|
|
|
76
84
|
This is the most important rule. When a feature needs a capability the framework does
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@astram/guide",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.3",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "Astram framework — the AI/dev GUIDE layer (ADR-0025). Ships the framework's hard rules + capabilities manifest as installed, upgrade-refreshed docs. A consumer app's CLAUDE.md references FRAMEWORK_RULES.md from this package; `npm update` replaces it wholesale so new rules arrive cleanly, while the app's own .astram/guide/ layer is never touched. This is the framework-owned FLOOR: an app rule may tighten it, never weaken it.",
|
|
6
6
|
"type": "commonjs",
|