@generazioneai/authz 0.0.1
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/codegen/authz-check.d.ts +3 -0
- package/dist/codegen/authz-check.d.ts.map +1 -0
- package/dist/codegen/authz-check.js +76 -0
- package/dist/codegen/authz-check.js.map +1 -0
- package/dist/codegen/check-rules.d.ts +73 -0
- package/dist/codegen/check-rules.d.ts.map +1 -0
- package/dist/codegen/check-rules.js +387 -0
- package/dist/codegen/check-rules.js.map +1 -0
- package/dist/codegen/effective-actions.d.ts +13 -0
- package/dist/codegen/effective-actions.d.ts.map +1 -0
- package/dist/codegen/effective-actions.js +44 -0
- package/dist/codegen/effective-actions.js.map +1 -0
- package/dist/codegen/generate-types.d.ts +8 -0
- package/dist/codegen/generate-types.d.ts.map +1 -0
- package/dist/codegen/generate-types.js +121 -0
- package/dist/codegen/generate-types.js.map +1 -0
- package/dist/codegen/index.d.ts +3 -0
- package/dist/codegen/index.d.ts.map +1 -0
- package/dist/codegen/index.js +74 -0
- package/dist/codegen/index.js.map +1 -0
- package/dist/codegen/manifest-io.d.ts +19 -0
- package/dist/codegen/manifest-io.d.ts.map +1 -0
- package/dist/codegen/manifest-io.js +59 -0
- package/dist/codegen/manifest-io.js.map +1 -0
- package/dist/context/als.d.ts +14 -0
- package/dist/context/als.d.ts.map +1 -0
- package/dist/context/als.js +30 -0
- package/dist/context/als.js.map +1 -0
- package/dist/context/authz-context.d.ts +54 -0
- package/dist/context/authz-context.d.ts.map +1 -0
- package/dist/context/authz-context.js +24 -0
- package/dist/context/authz-context.js.map +1 -0
- package/dist/define-resource.d.ts +150 -0
- package/dist/define-resource.d.ts.map +1 -0
- package/dist/define-resource.js +26 -0
- package/dist/define-resource.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +23 -0
- package/dist/index.js.map +1 -0
- package/dist/nats/canonical-hash.d.ts +5 -0
- package/dist/nats/canonical-hash.d.ts.map +1 -0
- package/dist/nats/canonical-hash.js +24 -0
- package/dist/nats/canonical-hash.js.map +1 -0
- package/dist/nats/index.d.ts +7 -0
- package/dist/nats/index.d.ts.map +1 -0
- package/dist/nats/index.js +27 -0
- package/dist/nats/index.js.map +1 -0
- package/dist/nats/internal-token.d.ts +56 -0
- package/dist/nats/internal-token.d.ts.map +1 -0
- package/dist/nats/internal-token.js +93 -0
- package/dist/nats/internal-token.js.map +1 -0
- package/dist/nats/internal-token.signer.d.ts +21 -0
- package/dist/nats/internal-token.signer.d.ts.map +1 -0
- package/dist/nats/internal-token.signer.js +48 -0
- package/dist/nats/internal-token.signer.js.map +1 -0
- package/dist/nats/jwks-client.d.ts +10 -0
- package/dist/nats/jwks-client.d.ts.map +1 -0
- package/dist/nats/jwks-client.js +14 -0
- package/dist/nats/jwks-client.js.map +1 -0
- package/dist/nats/key-loader.d.ts +24 -0
- package/dist/nats/key-loader.d.ts.map +1 -0
- package/dist/nats/key-loader.js +65 -0
- package/dist/nats/key-loader.js.map +1 -0
- package/dist/nats/replay-cache.d.ts +14 -0
- package/dist/nats/replay-cache.d.ts.map +1 -0
- package/dist/nats/replay-cache.js +23 -0
- package/dist/nats/replay-cache.js.map +1 -0
- package/dist/nest/authz-context.interceptor.d.ts +6 -0
- package/dist/nest/authz-context.interceptor.d.ts.map +1 -0
- package/dist/nest/authz-context.interceptor.js +47 -0
- package/dist/nest/authz-context.interceptor.js.map +1 -0
- package/dist/nest/authz-context.middleware.d.ts +15 -0
- package/dist/nest/authz-context.middleware.d.ts.map +1 -0
- package/dist/nest/authz-context.middleware.js +40 -0
- package/dist/nest/authz-context.middleware.js.map +1 -0
- package/dist/nest/index.d.ts +6 -0
- package/dist/nest/index.d.ts.map +1 -0
- package/dist/nest/index.js +25 -0
- package/dist/nest/index.js.map +1 -0
- package/dist/nest/internal-auth.interceptor.d.ts +29 -0
- package/dist/nest/internal-auth.interceptor.d.ts.map +1 -0
- package/dist/nest/internal-auth.interceptor.js +140 -0
- package/dist/nest/internal-auth.interceptor.js.map +1 -0
- package/dist/nest/nats-scoped-client.proxy.d.ts +23 -0
- package/dist/nest/nats-scoped-client.proxy.d.ts.map +1 -0
- package/dist/nest/nats-scoped-client.proxy.js +50 -0
- package/dist/nest/nats-scoped-client.proxy.js.map +1 -0
- package/dist/nest/skip-internal-auth.decorator.d.ts +4 -0
- package/dist/nest/skip-internal-auth.decorator.d.ts.map +1 -0
- package/dist/nest/skip-internal-auth.decorator.js +13 -0
- package/dist/nest/skip-internal-auth.decorator.js.map +1 -0
- package/dist/resource-registry.d.ts +31 -0
- package/dist/resource-registry.d.ts.map +1 -0
- package/dist/resource-registry.js +64 -0
- package/dist/resource-registry.js.map +1 -0
- package/dist/resource-registry.module.d.ts +25 -0
- package/dist/resource-registry.module.d.ts.map +1 -0
- package/dist/resource-registry.module.js +67 -0
- package/dist/resource-registry.module.js.map +1 -0
- package/dist/scope-substitute.d.ts +20 -0
- package/dist/scope-substitute.d.ts.map +1 -0
- package/dist/scope-substitute.js +58 -0
- package/dist/scope-substitute.js.map +1 -0
- package/package.json +94 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"authz-check.d.ts","sourceRoot":"","sources":["../../src/codegen/authz-check.ts"],"names":[],"mappings":";AA4DA,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,CAOlD"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
// Step 1 DEC-19 / DEC-S8.21: `authz:check` CLI — manifest ↔ schema coherence gate.
|
|
4
|
+
//
|
|
5
|
+
// Usage:
|
|
6
|
+
// authz:check [--manifests <a.json> <b.json>...] [--dmmf <dmmf.json>] [--opt-out <Model>...]
|
|
7
|
+
//
|
|
8
|
+
// Manifest-only checks always run. When `--dmmf` (a JSON dump of
|
|
9
|
+
// `Prisma.dmmf.datamodel`) is supplied, field-existence + 100% coverage checks
|
|
10
|
+
// run too — services wire this in their own `authz:check` script. Exit 1 if any
|
|
11
|
+
// error-level violation is found (warnings do not fail the gate).
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
exports.runCheckCli = runCheckCli;
|
|
14
|
+
const node_fs_1 = require("node:fs");
|
|
15
|
+
const node_path_1 = require("node:path");
|
|
16
|
+
const manifest_io_1 = require("./manifest-io");
|
|
17
|
+
const check_rules_1 = require("./check-rules");
|
|
18
|
+
function parseArgs(argv) {
|
|
19
|
+
const args = { manifests: [], optOut: [] };
|
|
20
|
+
for (let i = 0; i < argv.length; i++) {
|
|
21
|
+
const a = argv[i];
|
|
22
|
+
if (a === '--dmmf')
|
|
23
|
+
args.dmmf = (0, node_path_1.resolve)(argv[++i]);
|
|
24
|
+
else if (a === '--manifests') {
|
|
25
|
+
while (i + 1 < argv.length && !argv[i + 1].startsWith('--'))
|
|
26
|
+
args.manifests.push((0, node_path_1.resolve)(argv[++i]));
|
|
27
|
+
}
|
|
28
|
+
else if (a === '--opt-out') {
|
|
29
|
+
while (i + 1 < argv.length && !argv[i + 1].startsWith('--'))
|
|
30
|
+
args.optOut.push(argv[++i]);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return args;
|
|
34
|
+
}
|
|
35
|
+
function loadDmmf(path) {
|
|
36
|
+
if (!(0, node_fs_1.existsSync)(path))
|
|
37
|
+
throw new Error(`[authz:check] dmmf file not found: ${path}`);
|
|
38
|
+
const parsed = JSON.parse((0, node_fs_1.readFileSync)(path, 'utf8'));
|
|
39
|
+
// Accept either the full datamodel ({models:[...]}) or a bare {models} dump.
|
|
40
|
+
const models = parsed?.models ?? parsed?.datamodel?.models;
|
|
41
|
+
if (!Array.isArray(models))
|
|
42
|
+
throw new Error(`[authz:check] ${path} has no .models array`);
|
|
43
|
+
return { models };
|
|
44
|
+
}
|
|
45
|
+
function report(violations) {
|
|
46
|
+
if (!violations.length) {
|
|
47
|
+
console.log('[authz:check] OK — no violations.');
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
for (const v of violations) {
|
|
51
|
+
const tag = v.level === 'error' ? 'ERROR' : 'warn ';
|
|
52
|
+
const where = v.subject ? ` (${v.subject})` : '';
|
|
53
|
+
console.error(`[authz:check] ${tag} ${v.code}${where}: ${v.message}`);
|
|
54
|
+
}
|
|
55
|
+
const errs = violations.filter((v) => v.level === 'error').length;
|
|
56
|
+
const warns = violations.length - errs;
|
|
57
|
+
console.error(`[authz:check] ${errs} error(s), ${warns} warning(s).`);
|
|
58
|
+
}
|
|
59
|
+
function runCheckCli(argv) {
|
|
60
|
+
const args = parseArgs(argv);
|
|
61
|
+
const manifests = args.manifests.length ? (0, manifest_io_1.loadManifests)(args.manifests) : [];
|
|
62
|
+
const dmmf = args.dmmf ? loadDmmf(args.dmmf) : undefined;
|
|
63
|
+
const violations = (0, check_rules_1.runChecks)(manifests, { dmmf, optOut: args.optOut });
|
|
64
|
+
report(violations);
|
|
65
|
+
return (0, check_rules_1.hasErrors)(violations) ? 1 : 0;
|
|
66
|
+
}
|
|
67
|
+
if (require.main === module) {
|
|
68
|
+
try {
|
|
69
|
+
process.exit(runCheckCli(process.argv.slice(2)));
|
|
70
|
+
}
|
|
71
|
+
catch (e) {
|
|
72
|
+
console.error(`[authz:check] FATAL: ${e.message}`);
|
|
73
|
+
process.exit(2);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=authz-check.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"authz-check.js","sourceRoot":"","sources":["../../src/codegen/authz-check.ts"],"names":[],"mappings":";;AACA,mFAAmF;AACnF,EAAE;AACF,SAAS;AACT,+FAA+F;AAC/F,EAAE;AACF,iEAAiE;AACjE,+EAA+E;AAC/E,gFAAgF;AAChF,kEAAkE;;AAmDlE,kCAOC;AAxDD,qCAAmD;AACnD,yCAAoC;AACpC,+CAA8C;AAC9C,+CAAoF;AAQpF,SAAS,SAAS,CAAC,IAAc;IAC/B,MAAM,IAAI,GAAY,EAAE,SAAS,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;IACpD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,IAAI,CAAC,KAAK,QAAQ;YAAE,IAAI,CAAC,IAAI,GAAG,IAAA,mBAAO,EAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;aAC9C,IAAI,CAAC,KAAK,aAAa,EAAE,CAAC;YAC7B,OAAO,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC;gBAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAA,mBAAO,EAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QACvG,CAAC;aAAM,IAAI,CAAC,KAAK,WAAW,EAAE,CAAC;YAC7B,OAAO,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC;gBAAE,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QAC3F,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,QAAQ,CAAC,IAAY;IAC5B,IAAI,CAAC,IAAA,oBAAU,EAAC,IAAI,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,sCAAsC,IAAI,EAAE,CAAC,CAAC;IACrF,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAA,sBAAY,EAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;IACtD,6EAA6E;IAC7E,MAAM,MAAM,GAAG,MAAM,EAAE,MAAM,IAAI,MAAM,EAAE,SAAS,EAAE,MAAM,CAAC;IAC3D,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,iBAAiB,IAAI,uBAAuB,CAAC,CAAC;IAC1F,OAAO,EAAE,MAAM,EAAE,CAAC;AACpB,CAAC;AAED,SAAS,MAAM,CAAC,UAAuB;IACrC,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC;QACvB,OAAO,CAAC,GAAG,CAAC,mCAAmC,CAAC,CAAC;QACjD,OAAO;IACT,CAAC;IACD,KAAK,MAAM,CAAC,IAAI,UAAU,EAAE,CAAC;QAC3B,MAAM,GAAG,GAAG,CAAC,CAAC,KAAK,KAAK,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC;QACpD,MAAM,KAAK,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;QACjD,OAAO,CAAC,KAAK,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAAC,IAAI,GAAG,KAAK,KAAK,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;IACxE,CAAC;IACD,MAAM,IAAI,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,OAAO,CAAC,CAAC,MAAM,CAAC;IAClE,MAAM,KAAK,GAAG,UAAU,CAAC,MAAM,GAAG,IAAI,CAAC;IACvC,OAAO,CAAC,KAAK,CAAC,iBAAiB,IAAI,cAAc,KAAK,cAAc,CAAC,CAAC;AACxE,CAAC;AAED,SAAgB,WAAW,CAAC,IAAc;IACxC,MAAM,IAAI,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;IAC7B,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,IAAA,2BAAa,EAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAC7E,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IACzD,MAAM,UAAU,GAAG,IAAA,uBAAS,EAAC,SAAS,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;IACvE,MAAM,CAAC,UAAU,CAAC,CAAC;IACnB,OAAO,IAAA,uBAAS,EAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACvC,CAAC;AAED,IAAI,OAAO,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;IAC5B,IAAI,CAAC;QACH,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACnD,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,OAAO,CAAC,KAAK,CAAC,wBAAyB,CAAW,CAAC,OAAO,EAAE,CAAC,CAAC;QAC9D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import type { ResourceManifest } from '../define-resource';
|
|
2
|
+
export type ViolationLevel = 'error' | 'warn';
|
|
3
|
+
export interface Violation {
|
|
4
|
+
level: ViolationLevel;
|
|
5
|
+
code: string;
|
|
6
|
+
subject?: string;
|
|
7
|
+
message: string;
|
|
8
|
+
}
|
|
9
|
+
/** Canonical `$ctx` paths (must stay in sync with `CtxPath` in authz-context.ts). */
|
|
10
|
+
export declare const KNOWN_CTX_PATHS: readonly string[];
|
|
11
|
+
export interface DmmfField {
|
|
12
|
+
name: string;
|
|
13
|
+
kind?: string;
|
|
14
|
+
relationName?: string;
|
|
15
|
+
type?: string;
|
|
16
|
+
}
|
|
17
|
+
export interface DmmfModel {
|
|
18
|
+
name: string;
|
|
19
|
+
fields: DmmfField[];
|
|
20
|
+
}
|
|
21
|
+
export interface DmmfLike {
|
|
22
|
+
models: DmmfModel[];
|
|
23
|
+
}
|
|
24
|
+
export interface CheckOptions {
|
|
25
|
+
dmmf?: DmmfLike;
|
|
26
|
+
/** Models intentionally excluded from authz (DEC-3 opt-out, e.g. OidcEntity). */
|
|
27
|
+
optOut?: string[];
|
|
28
|
+
}
|
|
29
|
+
/** Collect every `$ctx` path referenced anywhere inside the scope templates. */
|
|
30
|
+
export declare function collectCtxPaths(template: unknown, acc?: string[]): string[];
|
|
31
|
+
/** DEC-14/15: actions must be built-in, lifecycle-derived, or non-empty custom. */
|
|
32
|
+
export declare function checkActions(m: ResourceManifest): Violation[];
|
|
33
|
+
/** DEC-23/EDGE-24: softDelete:false ⇒ no delete/softDelete/restore/findDeleted. */
|
|
34
|
+
export declare function checkSoftDelete(m: ResourceManifest): Violation[];
|
|
35
|
+
/** DEC-19: every `$ctx` path in scopes must be a known AuthzContext path. */
|
|
36
|
+
export declare function checkCtxPaths(m: ResourceManifest): Violation[];
|
|
37
|
+
/** DEC-28: lifecycle states/transitions internally consistent. */
|
|
38
|
+
export declare function checkLifecycle(m: ResourceManifest): Violation[];
|
|
39
|
+
/**
|
|
40
|
+
* A lifecycle transition's `requires: [SCOPE]` must have a matching scope declared
|
|
41
|
+
* in `scopes`. Otherwise the transition is either unauthorizable or silently falls
|
|
42
|
+
* back to another scope (e.g. an owner self-approving). Catches the class the
|
|
43
|
+
* adversarial review flagged on IndividualCompetence (requires TENANT, only OWN).
|
|
44
|
+
*/
|
|
45
|
+
export declare function checkLifecycleRequiresScopes(m: ResourceManifest): Violation[];
|
|
46
|
+
/** DEC-6..10: tenancy declaration shape is well-formed for its kind. */
|
|
47
|
+
export declare function checkTenancyShape(m: ResourceManifest): Violation[];
|
|
48
|
+
/**
|
|
49
|
+
* Every resource must declare at least one scope (else nothing is enforceable).
|
|
50
|
+
* A `global`-tenancy resource that exposes only OWN/TENANT (no GLOBAL) is a
|
|
51
|
+
* legitimate pattern — a table with no tenant column whose visibility is
|
|
52
|
+
* owner-based (e.g. EmployeeSurvey, JuridicalSurvey) — so it is NOT warned.
|
|
53
|
+
*/
|
|
54
|
+
export declare function checkScopesPresence(m: ResourceManifest): Violation[];
|
|
55
|
+
/** DEC-S8.5: external link should be a multiRef whose fields cover provider/customer. */
|
|
56
|
+
export declare function checkExternalConsistency(m: ResourceManifest): Violation[];
|
|
57
|
+
/**
|
|
58
|
+
* DEC-3: Subject is unique GLOBALLY (the codegen Subject union spans all services).
|
|
59
|
+
* prismaModel is unique only WITHIN a service — two services legitimately own a
|
|
60
|
+
* `client`/`user`/`individual` model in separate databases, so the model key is
|
|
61
|
+
* scoped by service. Within one service the per-service check still catches dups.
|
|
62
|
+
*/
|
|
63
|
+
export declare function checkUniqueness(manifests: ResourceManifest[]): Violation[];
|
|
64
|
+
/** DEC-25a / EDGE-S8.5: polymorphicMap targets must resolve to known subjects. */
|
|
65
|
+
export declare function checkPolymorphicTargets(manifests: ResourceManifest[]): Violation[];
|
|
66
|
+
/** DEC-19: model exists; tenancy/ownership fields exist; scope top-level fields exist. */
|
|
67
|
+
export declare function checkAgainstDmmf(m: ResourceManifest, dmmf: DmmfLike): Violation[];
|
|
68
|
+
/** DEC-3 / coverage gate: every datamodel model is covered or explicitly opted out. */
|
|
69
|
+
export declare function checkCoverage(manifests: ResourceManifest[], dmmf: DmmfLike, optOut?: string[]): Violation[];
|
|
70
|
+
/** Run every check (manifest-only always; DMMF-backed + coverage if `dmmf` given). */
|
|
71
|
+
export declare function runChecks(manifests: ResourceManifest[], opts?: CheckOptions): Violation[];
|
|
72
|
+
export declare function hasErrors(violations: Violation[]): boolean;
|
|
73
|
+
//# sourceMappingURL=check-rules.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check-rules.d.ts","sourceRoot":"","sources":["../../src/codegen/check-rules.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,gBAAgB,EAAe,MAAM,oBAAoB,CAAC;AAGxE,MAAM,MAAM,cAAc,GAAG,OAAO,GAAG,MAAM,CAAC;AAE9C,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,cAAc,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,qFAAqF;AACrF,eAAO,MAAM,eAAe,EAAE,SAAS,MAAM,EAa5C,CAAC;AAwBF,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AACD,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,SAAS,EAAE,CAAC;CACrB;AACD,MAAM,WAAW,QAAQ;IACvB,MAAM,EAAE,SAAS,EAAE,CAAC;CACrB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,CAAC,EAAE,QAAQ,CAAC;IAChB,iFAAiF;IACjF,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB;AA0BD,gFAAgF;AAChF,wBAAgB,eAAe,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,GAAE,MAAM,EAAO,GAAG,MAAM,EAAE,CAU/E;AAID,mFAAmF;AACnF,wBAAgB,YAAY,CAAC,CAAC,EAAE,gBAAgB,GAAG,SAAS,EAAE,CAqB7D;AAED,mFAAmF;AACnF,wBAAgB,eAAe,CAAC,CAAC,EAAE,gBAAgB,GAAG,SAAS,EAAE,CAWhE;AAED,6EAA6E;AAC7E,wBAAgB,aAAa,CAAC,CAAC,EAAE,gBAAgB,GAAG,SAAS,EAAE,CAgB9D;AAED,kEAAkE;AAClE,wBAAgB,cAAc,CAAC,CAAC,EAAE,gBAAgB,GAAG,SAAS,EAAE,CA0B/D;AAED;;;;;GAKG;AACH,wBAAgB,4BAA4B,CAAC,CAAC,EAAE,gBAAgB,GAAG,SAAS,EAAE,CAkB7E;AAED,wEAAwE;AACxE,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,gBAAgB,GAAG,SAAS,EAAE,CAmClE;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,CAAC,EAAE,gBAAgB,GAAG,SAAS,EAAE,CAMpE;AAED,yFAAyF;AACzF,wBAAgB,wBAAwB,CAAC,CAAC,EAAE,gBAAgB,GAAG,SAAS,EAAE,CAgBzE;AAID;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,gBAAgB,EAAE,GAAG,SAAS,EAAE,CAa1E;AAED,kFAAkF;AAClF,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,gBAAgB,EAAE,GAAG,SAAS,EAAE,CAkBlF;AAWD,0FAA0F;AAC1F,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,gBAAgB,EAAE,IAAI,EAAE,QAAQ,GAAG,SAAS,EAAE,CA+DjF;AAED,uFAAuF;AACvF,wBAAgB,aAAa,CAC3B,SAAS,EAAE,gBAAgB,EAAE,EAC7B,IAAI,EAAE,QAAQ,EACd,MAAM,GAAE,MAAM,EAAO,GACpB,SAAS,EAAE,CAeb;AAID,sFAAsF;AACtF,wBAAgB,SAAS,CACvB,SAAS,EAAE,gBAAgB,EAAE,EAC7B,IAAI,GAAE,YAAiB,GACtB,SAAS,EAAE,CAmBb;AAED,wBAAgB,SAAS,CAAC,UAAU,EAAE,SAAS,EAAE,GAAG,OAAO,CAE1D"}
|
|
@@ -0,0 +1,387 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Step 1 DEC-19: manifest ↔ Prisma schema coherence checks (`authz:check`).
|
|
3
|
+
//
|
|
4
|
+
// Two tiers of checks:
|
|
5
|
+
// - manifest-only (no schema needed): action/softDelete/lifecycle/tenancy/ctx
|
|
6
|
+
// shape, plus cross-manifest uniqueness + polymorphic target resolution.
|
|
7
|
+
// - DMMF-backed (optional `dmmf`): model exists, tenancy/ownership/scope fields
|
|
8
|
+
// exist, inheritFrom chain resolvable, 100% model coverage.
|
|
9
|
+
//
|
|
10
|
+
// The SDK exposes the rules as pure functions; each service runs a thin script
|
|
11
|
+
// that loads its own `Prisma.dmmf` + manifests and calls `runChecks`.
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
exports.KNOWN_CTX_PATHS = void 0;
|
|
14
|
+
exports.collectCtxPaths = collectCtxPaths;
|
|
15
|
+
exports.checkActions = checkActions;
|
|
16
|
+
exports.checkSoftDelete = checkSoftDelete;
|
|
17
|
+
exports.checkCtxPaths = checkCtxPaths;
|
|
18
|
+
exports.checkLifecycle = checkLifecycle;
|
|
19
|
+
exports.checkLifecycleRequiresScopes = checkLifecycleRequiresScopes;
|
|
20
|
+
exports.checkTenancyShape = checkTenancyShape;
|
|
21
|
+
exports.checkScopesPresence = checkScopesPresence;
|
|
22
|
+
exports.checkExternalConsistency = checkExternalConsistency;
|
|
23
|
+
exports.checkUniqueness = checkUniqueness;
|
|
24
|
+
exports.checkPolymorphicTargets = checkPolymorphicTargets;
|
|
25
|
+
exports.checkAgainstDmmf = checkAgainstDmmf;
|
|
26
|
+
exports.checkCoverage = checkCoverage;
|
|
27
|
+
exports.runChecks = runChecks;
|
|
28
|
+
exports.hasErrors = hasErrors;
|
|
29
|
+
const effective_actions_1 = require("./effective-actions");
|
|
30
|
+
/** Canonical `$ctx` paths (must stay in sync with `CtxPath` in authz-context.ts). */
|
|
31
|
+
exports.KNOWN_CTX_PATHS = [
|
|
32
|
+
'userId',
|
|
33
|
+
'individualId',
|
|
34
|
+
'tenantId',
|
|
35
|
+
'juridicalIndividualId',
|
|
36
|
+
'connected.studentsOfTeacher',
|
|
37
|
+
'connected.reportsOfManager',
|
|
38
|
+
'connected.pendingApprovalResourceIds',
|
|
39
|
+
'connected.customRelations',
|
|
40
|
+
'accreditedAs.provider.accreditationIds',
|
|
41
|
+
'accreditedAs.provider.customerJuridicalIds',
|
|
42
|
+
'accreditedAs.customer.accreditationIds',
|
|
43
|
+
'accreditedAs.customer.providerJuridicalIds',
|
|
44
|
+
];
|
|
45
|
+
const KNOWN_CTX_SET = new Set(exports.KNOWN_CTX_PATHS);
|
|
46
|
+
/** Prisma filter / logical operators to skip when treating object keys as fields. */
|
|
47
|
+
const PRISMA_OPERATORS = new Set([
|
|
48
|
+
'AND', 'OR', 'NOT',
|
|
49
|
+
'$ctx',
|
|
50
|
+
'equals', 'not', 'in', 'notIn',
|
|
51
|
+
'lt', 'lte', 'gt', 'gte',
|
|
52
|
+
'contains', 'startsWith', 'endsWith', 'mode', 'search',
|
|
53
|
+
'some', 'every', 'none', 'is', 'isNot',
|
|
54
|
+
'has', 'hasSome', 'hasEvery', 'isEmpty',
|
|
55
|
+
]);
|
|
56
|
+
const SOFT_DELETE_ACTIONS = new Set([
|
|
57
|
+
'delete',
|
|
58
|
+
'softDelete',
|
|
59
|
+
'restore',
|
|
60
|
+
'findDeleted',
|
|
61
|
+
]);
|
|
62
|
+
const lowerFirst = (s) => s.length ? s.charAt(0).toLowerCase() + s.slice(1) : s;
|
|
63
|
+
function findModel(dmmf, prismaModel) {
|
|
64
|
+
return dmmf.models.find((m) => m.name === prismaModel || lowerFirst(m.name) === prismaModel);
|
|
65
|
+
}
|
|
66
|
+
const err = (code, subject, message) => ({
|
|
67
|
+
level: 'error',
|
|
68
|
+
code,
|
|
69
|
+
subject,
|
|
70
|
+
message,
|
|
71
|
+
});
|
|
72
|
+
const warn = (code, subject, message) => ({
|
|
73
|
+
level: 'warn',
|
|
74
|
+
code,
|
|
75
|
+
subject,
|
|
76
|
+
message,
|
|
77
|
+
});
|
|
78
|
+
// ---- $ctx walking ------------------------------------------------------------
|
|
79
|
+
/** Collect every `$ctx` path referenced anywhere inside the scope templates. */
|
|
80
|
+
function collectCtxPaths(template, acc = []) {
|
|
81
|
+
if (template === null || typeof template !== 'object')
|
|
82
|
+
return acc;
|
|
83
|
+
if (Array.isArray(template)) {
|
|
84
|
+
for (const item of template)
|
|
85
|
+
collectCtxPaths(item, acc);
|
|
86
|
+
return acc;
|
|
87
|
+
}
|
|
88
|
+
const obj = template;
|
|
89
|
+
if (typeof obj.$ctx === 'string')
|
|
90
|
+
acc.push(obj.$ctx);
|
|
91
|
+
for (const value of Object.values(obj))
|
|
92
|
+
collectCtxPaths(value, acc);
|
|
93
|
+
return acc;
|
|
94
|
+
}
|
|
95
|
+
// ---- manifest-only checks ----------------------------------------------------
|
|
96
|
+
/** DEC-14/15: actions must be built-in, lifecycle-derived, or non-empty custom. */
|
|
97
|
+
function checkActions(m) {
|
|
98
|
+
const out = [];
|
|
99
|
+
const verbs = new Set((0, effective_actions_1.lifecycleVerbs)(m));
|
|
100
|
+
for (const a of m.actions) {
|
|
101
|
+
if (typeof a !== 'string' || a.length === 0) {
|
|
102
|
+
out.push(err('action-empty', m.subject, `empty/invalid action declared`));
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
// Lifecycle verbs should be surfaced in `actions` for clarity (DEC-15).
|
|
106
|
+
for (const verb of verbs) {
|
|
107
|
+
if (!m.actions.includes(verb)) {
|
|
108
|
+
out.push(warn('lifecycle-verb-missing-in-actions', m.subject, `lifecycle verb '${verb}' is not listed in actions[] (framework auto-adds it; list it for clarity)`));
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return out;
|
|
112
|
+
}
|
|
113
|
+
/** DEC-23/EDGE-24: softDelete:false ⇒ no delete/softDelete/restore/findDeleted. */
|
|
114
|
+
function checkSoftDelete(m) {
|
|
115
|
+
if (m.softDelete !== false)
|
|
116
|
+
return [];
|
|
117
|
+
return m.actions
|
|
118
|
+
.filter((a) => SOFT_DELETE_ACTIONS.has(a))
|
|
119
|
+
.map((a) => err('softdelete-action-conflict', m.subject, `softDelete:false but actions includes '${a}'`));
|
|
120
|
+
}
|
|
121
|
+
/** DEC-19: every `$ctx` path in scopes must be a known AuthzContext path. */
|
|
122
|
+
function checkCtxPaths(m) {
|
|
123
|
+
const out = [];
|
|
124
|
+
for (const [scope, template] of Object.entries(m.scopes ?? {})) {
|
|
125
|
+
for (const path of collectCtxPaths(template)) {
|
|
126
|
+
if (!KNOWN_CTX_SET.has(path)) {
|
|
127
|
+
out.push(err('unknown-ctx-path', m.subject, `scope ${scope} references unknown $ctx path '${path}' (known: ${exports.KNOWN_CTX_PATHS.join(', ')})`));
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return out;
|
|
132
|
+
}
|
|
133
|
+
/** DEC-28: lifecycle states/transitions internally consistent. */
|
|
134
|
+
function checkLifecycle(m) {
|
|
135
|
+
const lc = m.lifecycle;
|
|
136
|
+
if (!lc)
|
|
137
|
+
return [];
|
|
138
|
+
const out = [];
|
|
139
|
+
if (!lc.field)
|
|
140
|
+
out.push(err('lifecycle-no-field', m.subject, 'lifecycle.field is empty'));
|
|
141
|
+
const states = new Set(lc.states ?? []);
|
|
142
|
+
if (!states.has(lc.initial)) {
|
|
143
|
+
out.push(err('lifecycle-bad-initial', m.subject, `initial state '${lc.initial}' not in states[]`));
|
|
144
|
+
}
|
|
145
|
+
for (const [verb, t] of Object.entries(lc.transitions ?? {})) {
|
|
146
|
+
if (!states.has(t.to)) {
|
|
147
|
+
out.push(err('lifecycle-bad-to', m.subject, `transition '${verb}' targets unknown state '${t.to}'`));
|
|
148
|
+
}
|
|
149
|
+
for (const f of t.from ?? []) {
|
|
150
|
+
if (!states.has(f)) {
|
|
151
|
+
out.push(err('lifecycle-bad-from', m.subject, `transition '${verb}' from unknown state '${f}'`));
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
return out;
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* A lifecycle transition's `requires: [SCOPE]` must have a matching scope declared
|
|
159
|
+
* in `scopes`. Otherwise the transition is either unauthorizable or silently falls
|
|
160
|
+
* back to another scope (e.g. an owner self-approving). Catches the class the
|
|
161
|
+
* adversarial review flagged on IndividualCompetence (requires TENANT, only OWN).
|
|
162
|
+
*/
|
|
163
|
+
function checkLifecycleRequiresScopes(m) {
|
|
164
|
+
if (!m.lifecycle)
|
|
165
|
+
return [];
|
|
166
|
+
const scopeKeys = new Set(Object.keys(m.scopes ?? {}));
|
|
167
|
+
const out = [];
|
|
168
|
+
for (const [verb, t] of Object.entries(m.lifecycle.transitions ?? {})) {
|
|
169
|
+
for (const req of t.requires ?? []) {
|
|
170
|
+
if (!scopeKeys.has(req)) {
|
|
171
|
+
out.push(err('lifecycle-requires-missing-scope', m.subject, `transition '${verb}' requires scope '${req}' but no '${req}' scope is declared (declared: ${[...scopeKeys].join(', ') || 'none'})`));
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
return out;
|
|
176
|
+
}
|
|
177
|
+
/** DEC-6..10: tenancy declaration shape is well-formed for its kind. */
|
|
178
|
+
function checkTenancyShape(m) {
|
|
179
|
+
const out = [];
|
|
180
|
+
const t = m.tenancy;
|
|
181
|
+
if (!t || !('kind' in t)) {
|
|
182
|
+
out.push(err('tenancy-missing', m.subject, 'tenancy declaration missing'));
|
|
183
|
+
return out;
|
|
184
|
+
}
|
|
185
|
+
switch (t.kind) {
|
|
186
|
+
case 'single':
|
|
187
|
+
if (!t.field)
|
|
188
|
+
out.push(err('tenancy-single-no-field', m.subject, "tenancy.single requires 'field'"));
|
|
189
|
+
break;
|
|
190
|
+
case 'multiRef':
|
|
191
|
+
if (!Array.isArray(t.fields) || t.fields.length === 0)
|
|
192
|
+
out.push(err('tenancy-multiref-empty', m.subject, 'tenancy.multiRef requires non-empty fields[]'));
|
|
193
|
+
if (t.relation !== 'AND' && t.relation !== 'OR')
|
|
194
|
+
out.push(err('tenancy-multiref-relation', m.subject, "tenancy.multiRef.relation must be 'AND' or 'OR'"));
|
|
195
|
+
break;
|
|
196
|
+
case 'transitive':
|
|
197
|
+
if (!t.via || !t.through || !t.field)
|
|
198
|
+
out.push(err('tenancy-transitive-incomplete', m.subject, 'tenancy.transitive requires via/through/field'));
|
|
199
|
+
break;
|
|
200
|
+
case 'inheritFrom':
|
|
201
|
+
if (!t.relation)
|
|
202
|
+
out.push(err('tenancy-inheritfrom-no-relation', m.subject, "tenancy.inheritFrom requires 'relation'"));
|
|
203
|
+
break;
|
|
204
|
+
case 'global':
|
|
205
|
+
break;
|
|
206
|
+
default:
|
|
207
|
+
out.push(err('tenancy-unknown-kind', m.subject, `unknown tenancy kind '${t.kind}'`));
|
|
208
|
+
}
|
|
209
|
+
if (m.nested) {
|
|
210
|
+
if (!m.nested.parent)
|
|
211
|
+
out.push(err('nested-no-parent', m.subject, 'nested.parent is empty'));
|
|
212
|
+
if (!m.nested.via)
|
|
213
|
+
out.push(err('nested-no-via', m.subject, 'nested.via is empty'));
|
|
214
|
+
}
|
|
215
|
+
return out;
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Every resource must declare at least one scope (else nothing is enforceable).
|
|
219
|
+
* A `global`-tenancy resource that exposes only OWN/TENANT (no GLOBAL) is a
|
|
220
|
+
* legitimate pattern — a table with no tenant column whose visibility is
|
|
221
|
+
* owner-based (e.g. EmployeeSurvey, JuridicalSurvey) — so it is NOT warned.
|
|
222
|
+
*/
|
|
223
|
+
function checkScopesPresence(m) {
|
|
224
|
+
const scopeKeys = Object.keys(m.scopes ?? {});
|
|
225
|
+
if (scopeKeys.length === 0) {
|
|
226
|
+
return [warn('no-scopes', m.subject, 'resource declares no scopes (nothing enforceable)')];
|
|
227
|
+
}
|
|
228
|
+
return [];
|
|
229
|
+
}
|
|
230
|
+
/** DEC-S8.5: external link should be a multiRef whose fields cover provider/customer. */
|
|
231
|
+
function checkExternalConsistency(m) {
|
|
232
|
+
if (!m.external)
|
|
233
|
+
return [];
|
|
234
|
+
const out = [];
|
|
235
|
+
const t = m.tenancy;
|
|
236
|
+
if (t?.kind !== 'multiRef') {
|
|
237
|
+
out.push(warn('external-not-multiref', m.subject, 'external link declared but tenancy is not multiRef'));
|
|
238
|
+
return out;
|
|
239
|
+
}
|
|
240
|
+
for (const f of [m.external.providerField, m.external.customerField]) {
|
|
241
|
+
if (!t.fields.includes(f)) {
|
|
242
|
+
out.push(warn('external-field-not-in-tenancy', m.subject, `external field '${f}' not among tenancy.fields`));
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
return out;
|
|
246
|
+
}
|
|
247
|
+
// ---- cross-manifest checks ---------------------------------------------------
|
|
248
|
+
/**
|
|
249
|
+
* DEC-3: Subject is unique GLOBALLY (the codegen Subject union spans all services).
|
|
250
|
+
* prismaModel is unique only WITHIN a service — two services legitimately own a
|
|
251
|
+
* `client`/`user`/`individual` model in separate databases, so the model key is
|
|
252
|
+
* scoped by service. Within one service the per-service check still catches dups.
|
|
253
|
+
*/
|
|
254
|
+
function checkUniqueness(manifests) {
|
|
255
|
+
const out = [];
|
|
256
|
+
const subjects = new Map();
|
|
257
|
+
const models = new Map(); // keyed `service:prismaModel`
|
|
258
|
+
for (const m of manifests) {
|
|
259
|
+
subjects.set(m.subject, (subjects.get(m.subject) ?? 0) + 1);
|
|
260
|
+
const key = `${m.service}:${m.prismaModel}`;
|
|
261
|
+
models.set(key, (models.get(key) ?? 0) + 1);
|
|
262
|
+
}
|
|
263
|
+
for (const [s, n] of subjects)
|
|
264
|
+
if (n > 1)
|
|
265
|
+
out.push(err('duplicate-subject', s, `subject '${s}' declared ${n}×`));
|
|
266
|
+
for (const [key, n] of models)
|
|
267
|
+
if (n > 1)
|
|
268
|
+
out.push({ level: 'error', code: 'duplicate-model', message: `prismaModel '${key}' declared ${n}×` });
|
|
269
|
+
return out;
|
|
270
|
+
}
|
|
271
|
+
/** DEC-25a / EDGE-S8.5: polymorphicMap targets must resolve to known subjects. */
|
|
272
|
+
function checkPolymorphicTargets(manifests) {
|
|
273
|
+
const subjects = new Set(manifests.map((m) => m.subject));
|
|
274
|
+
const out = [];
|
|
275
|
+
for (const m of manifests) {
|
|
276
|
+
if (!m.polymorphicMap)
|
|
277
|
+
continue;
|
|
278
|
+
for (const [enumVal, target] of Object.entries(m.polymorphicMap)) {
|
|
279
|
+
if (!subjects.has(target)) {
|
|
280
|
+
out.push(warn('polymorphic-target-unknown', m.subject, `polymorphicMap['${enumVal}'] -> '${target}' is not a known subject (out-of-scope target?)`));
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
return out;
|
|
285
|
+
}
|
|
286
|
+
// ---- DMMF-backed checks ------------------------------------------------------
|
|
287
|
+
function fieldNames(model) {
|
|
288
|
+
return new Set(model.fields.map((f) => f.name));
|
|
289
|
+
}
|
|
290
|
+
function relationNames(model) {
|
|
291
|
+
return new Set(model.fields.filter((f) => f.kind === 'object' || f.relationName).map((f) => f.name));
|
|
292
|
+
}
|
|
293
|
+
/** DEC-19: model exists; tenancy/ownership fields exist; scope top-level fields exist. */
|
|
294
|
+
function checkAgainstDmmf(m, dmmf) {
|
|
295
|
+
const out = [];
|
|
296
|
+
const model = findModel(dmmf, m.prismaModel);
|
|
297
|
+
if (!model) {
|
|
298
|
+
out.push(err('model-not-found', m.subject, `prismaModel '${m.prismaModel}' not in datamodel`));
|
|
299
|
+
return out; // can't validate fields without the model
|
|
300
|
+
}
|
|
301
|
+
const fields = fieldNames(model);
|
|
302
|
+
const relations = relationNames(model);
|
|
303
|
+
// DEC-23: a model with default (active) soft-delete must actually have the
|
|
304
|
+
// soft-delete column, else the framework injects `deletedAt: null` into a
|
|
305
|
+
// non-existent field and every query throws at runtime (Step 3 extension).
|
|
306
|
+
if (m.softDelete !== false) {
|
|
307
|
+
const sdField = (m.softDelete && m.softDelete.field) || 'deletedAt';
|
|
308
|
+
if (!fields.has(sdField)) {
|
|
309
|
+
out.push(err('softdelete-field-missing', m.subject, `soft-delete is active but model has no '${sdField}' column — set softDelete:false (and drop delete/softDelete/restore/findDeleted from actions)`));
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
const t = m.tenancy;
|
|
313
|
+
if (t?.kind === 'single' && t.field && !fields.has(t.field)) {
|
|
314
|
+
out.push(err('tenancy-field-missing', m.subject, `tenancy field '${t.field}' not on model`));
|
|
315
|
+
}
|
|
316
|
+
if (t?.kind === 'multiRef') {
|
|
317
|
+
for (const f of t.fields ?? []) {
|
|
318
|
+
if (!fields.has(f))
|
|
319
|
+
out.push(err('tenancy-field-missing', m.subject, `multiRef field '${f}' not on model`));
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
if (t?.kind === 'transitive' && t.via && !relations.has(t.via)) {
|
|
323
|
+
out.push(err('tenancy-via-missing', m.subject, `transitive via relation '${t.via}' not on model`));
|
|
324
|
+
}
|
|
325
|
+
if (t?.kind === 'inheritFrom' && t.relation) {
|
|
326
|
+
const firstHop = t.relation.split('.')[0];
|
|
327
|
+
if (!relations.has(firstHop)) {
|
|
328
|
+
out.push(err('inheritfrom-relation-missing', m.subject, `inheritFrom relation '${firstHop}' not on model`));
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
for (const o of m.ownership ?? []) {
|
|
332
|
+
if (!fields.has(o.field)) {
|
|
333
|
+
out.push(err('ownership-field-missing', m.subject, `ownership field '${o.field}' not on model`));
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
// Top-level scope keys (excluding operators) must be a field or relation.
|
|
337
|
+
for (const [scope, template] of Object.entries(m.scopes ?? {})) {
|
|
338
|
+
if (!template || typeof template !== 'object')
|
|
339
|
+
continue;
|
|
340
|
+
for (const key of Object.keys(template)) {
|
|
341
|
+
if (PRISMA_OPERATORS.has(key))
|
|
342
|
+
continue;
|
|
343
|
+
if (!fields.has(key) && !relations.has(key)) {
|
|
344
|
+
out.push(err('scope-field-missing', m.subject, `scope ${scope} references unknown field/relation '${key}'`));
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
return out;
|
|
349
|
+
}
|
|
350
|
+
/** DEC-3 / coverage gate: every datamodel model is covered or explicitly opted out. */
|
|
351
|
+
function checkCoverage(manifests, dmmf, optOut = []) {
|
|
352
|
+
const covered = new Set(manifests.map((m) => m.prismaModel));
|
|
353
|
+
const optOutSet = new Set(optOut);
|
|
354
|
+
const out = [];
|
|
355
|
+
for (const model of dmmf.models) {
|
|
356
|
+
const camel = lowerFirst(model.name);
|
|
357
|
+
if (covered.has(camel) || covered.has(model.name))
|
|
358
|
+
continue;
|
|
359
|
+
if (optOutSet.has(camel) || optOutSet.has(model.name))
|
|
360
|
+
continue;
|
|
361
|
+
out.push({
|
|
362
|
+
level: 'error',
|
|
363
|
+
code: 'model-uncovered',
|
|
364
|
+
message: `model '${model.name}' has no manifest and is not in the opt-out list`,
|
|
365
|
+
});
|
|
366
|
+
}
|
|
367
|
+
return out;
|
|
368
|
+
}
|
|
369
|
+
// ---- orchestrator ------------------------------------------------------------
|
|
370
|
+
/** Run every check (manifest-only always; DMMF-backed + coverage if `dmmf` given). */
|
|
371
|
+
function runChecks(manifests, opts = {}) {
|
|
372
|
+
const out = [];
|
|
373
|
+
for (const m of manifests) {
|
|
374
|
+
out.push(...checkActions(m), ...checkSoftDelete(m), ...checkCtxPaths(m), ...checkLifecycle(m), ...checkLifecycleRequiresScopes(m), ...checkTenancyShape(m), ...checkScopesPresence(m), ...checkExternalConsistency(m));
|
|
375
|
+
if (opts.dmmf)
|
|
376
|
+
out.push(...checkAgainstDmmf(m, opts.dmmf));
|
|
377
|
+
}
|
|
378
|
+
out.push(...checkUniqueness(manifests));
|
|
379
|
+
out.push(...checkPolymorphicTargets(manifests));
|
|
380
|
+
if (opts.dmmf)
|
|
381
|
+
out.push(...checkCoverage(manifests, opts.dmmf, opts.optOut));
|
|
382
|
+
return out;
|
|
383
|
+
}
|
|
384
|
+
function hasErrors(violations) {
|
|
385
|
+
return violations.some((v) => v.level === 'error');
|
|
386
|
+
}
|
|
387
|
+
//# sourceMappingURL=check-rules.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check-rules.js","sourceRoot":"","sources":["../../src/codegen/check-rules.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { ResourceManifest } from '../define-resource';
|
|
2
|
+
/** Step 1 DEC-14: built-in CRUD + soft-delete + wildcard actions. */
|
|
3
|
+
export declare const BUILTIN_ACTIONS: readonly ["create", "read", "update", "delete", "softDelete", "restore", "findDeleted", "manage"];
|
|
4
|
+
export type BuiltinAction = (typeof BUILTIN_ACTIONS)[number];
|
|
5
|
+
export declare function isBuiltinAction(action: string): boolean;
|
|
6
|
+
/** Lifecycle transition verbs declared by the manifest (DEC-15). */
|
|
7
|
+
export declare function lifecycleVerbs(m: ResourceManifest): string[];
|
|
8
|
+
/**
|
|
9
|
+
* Declared actions ∪ lifecycle verbs, de-duplicated and sorted for deterministic
|
|
10
|
+
* codegen output (drift detection relies on stable ordering).
|
|
11
|
+
*/
|
|
12
|
+
export declare function effectiveActions(m: ResourceManifest): string[];
|
|
13
|
+
//# sourceMappingURL=effective-actions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"effective-actions.d.ts","sourceRoot":"","sources":["../../src/codegen/effective-actions.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAE3D,qEAAqE;AACrE,eAAO,MAAM,eAAe,mGASlB,CAAC;AAEX,MAAM,MAAM,aAAa,GAAG,CAAC,OAAO,eAAe,CAAC,CAAC,MAAM,CAAC,CAAC;AAI7D,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAEvD;AAED,oEAAoE;AACpE,wBAAgB,cAAc,CAAC,CAAC,EAAE,gBAAgB,GAAG,MAAM,EAAE,CAG5D;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,gBAAgB,GAAG,MAAM,EAAE,CAI9D"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Step 1 DEC-14/15: effective action set for a manifest.
|
|
3
|
+
//
|
|
4
|
+
// The effective actions a Subject supports = the declared `actions` UNION the
|
|
5
|
+
// keys of `lifecycle.transitions` (DEC-15: the framework auto-adds lifecycle
|
|
6
|
+
// verbs like `submit`/`approve`/`reject`). Used by codegen (`ActionFor<S>`)
|
|
7
|
+
// and by the coherence check.
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.BUILTIN_ACTIONS = void 0;
|
|
10
|
+
exports.isBuiltinAction = isBuiltinAction;
|
|
11
|
+
exports.lifecycleVerbs = lifecycleVerbs;
|
|
12
|
+
exports.effectiveActions = effectiveActions;
|
|
13
|
+
/** Step 1 DEC-14: built-in CRUD + soft-delete + wildcard actions. */
|
|
14
|
+
exports.BUILTIN_ACTIONS = [
|
|
15
|
+
'create',
|
|
16
|
+
'read',
|
|
17
|
+
'update',
|
|
18
|
+
'delete',
|
|
19
|
+
'softDelete',
|
|
20
|
+
'restore',
|
|
21
|
+
'findDeleted',
|
|
22
|
+
'manage',
|
|
23
|
+
];
|
|
24
|
+
const BUILTIN_SET = new Set(exports.BUILTIN_ACTIONS);
|
|
25
|
+
function isBuiltinAction(action) {
|
|
26
|
+
return BUILTIN_SET.has(action);
|
|
27
|
+
}
|
|
28
|
+
/** Lifecycle transition verbs declared by the manifest (DEC-15). */
|
|
29
|
+
function lifecycleVerbs(m) {
|
|
30
|
+
if (!m.lifecycle)
|
|
31
|
+
return [];
|
|
32
|
+
return Object.keys(m.lifecycle.transitions);
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Declared actions ∪ lifecycle verbs, de-duplicated and sorted for deterministic
|
|
36
|
+
* codegen output (drift detection relies on stable ordering).
|
|
37
|
+
*/
|
|
38
|
+
function effectiveActions(m) {
|
|
39
|
+
const set = new Set(m.actions);
|
|
40
|
+
for (const verb of lifecycleVerbs(m))
|
|
41
|
+
set.add(verb);
|
|
42
|
+
return Array.from(set).sort();
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=effective-actions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"effective-actions.js","sourceRoot":"","sources":["../../src/codegen/effective-actions.ts"],"names":[],"mappings":";AAAA,yDAAyD;AACzD,EAAE;AACF,8EAA8E;AAC9E,6EAA6E;AAC7E,4EAA4E;AAC5E,8BAA8B;;;AAoB9B,0CAEC;AAGD,wCAGC;AAMD,4CAIC;AAlCD,qEAAqE;AACxD,QAAA,eAAe,GAAG;IAC7B,QAAQ;IACR,MAAM;IACN,QAAQ;IACR,QAAQ;IACR,YAAY;IACZ,SAAS;IACT,aAAa;IACb,QAAQ;CACA,CAAC;AAIX,MAAM,WAAW,GAAwB,IAAI,GAAG,CAAC,uBAAe,CAAC,CAAC;AAElE,SAAgB,eAAe,CAAC,MAAc;IAC5C,OAAO,WAAW,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;AACjC,CAAC;AAED,oEAAoE;AACpE,SAAgB,cAAc,CAAC,CAAmB;IAChD,IAAI,CAAC,CAAC,CAAC,SAAS;QAAE,OAAO,EAAE,CAAC;IAC5B,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;AAC9C,CAAC;AAED;;;GAGG;AACH,SAAgB,gBAAgB,CAAC,CAAmB;IAClD,MAAM,GAAG,GAAG,IAAI,GAAG,CAAS,CAAC,CAAC,OAAO,CAAC,CAAC;IACvC,KAAK,MAAM,IAAI,IAAI,cAAc,CAAC,CAAC,CAAC;QAAE,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACpD,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;AAChC,CAAC"}
|