grafeo-ogm 1.12.0 → 1.14.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/CHANGELOG.md +73 -0
- package/README.md +10 -1
- package/dist/cjs/cli/commands/db-push.d.ts.map +1 -1
- package/dist/cjs/cli/commands/db-push.js +6 -3
- package/dist/cjs/cli/commands/db-push.js.map +1 -1
- package/dist/cjs/cli/display.d.ts +15 -0
- package/dist/cjs/cli/display.d.ts.map +1 -0
- package/dist/cjs/cli/display.js +21 -0
- package/dist/cjs/cli/display.js.map +1 -0
- package/dist/cjs/compilers/mutation.compiler.d.ts +54 -1
- package/dist/cjs/compilers/mutation.compiler.d.ts.map +1 -1
- package/dist/cjs/compilers/mutation.compiler.js +134 -32
- package/dist/cjs/compilers/mutation.compiler.js.map +1 -1
- package/dist/cjs/compilers/where.compiler.d.ts.map +1 -1
- package/dist/cjs/compilers/where.compiler.js +7 -0
- package/dist/cjs/compilers/where.compiler.js.map +1 -1
- package/dist/cjs/interface-model.d.ts.map +1 -1
- package/dist/cjs/interface-model.js +9 -1
- package/dist/cjs/interface-model.js.map +1 -1
- package/dist/cjs/model.d.ts.map +1 -1
- package/dist/cjs/model.js +12 -3
- package/dist/cjs/model.js.map +1 -1
- package/dist/cjs/ogm.d.ts.map +1 -1
- package/dist/cjs/ogm.js +6 -1
- package/dist/cjs/ogm.js.map +1 -1
- package/dist/cjs/subgraph/subgraph-operations.d.ts +2 -1
- package/dist/cjs/subgraph/subgraph-operations.d.ts.map +1 -1
- package/dist/cjs/subgraph/subgraph-operations.js +20 -4
- package/dist/cjs/subgraph/subgraph-operations.js.map +1 -1
- package/dist/cjs/subgraph/types.d.ts +8 -0
- package/dist/cjs/subgraph/types.d.ts.map +1 -1
- package/dist/cjs/utils/validation.d.ts +7 -0
- package/dist/cjs/utils/validation.d.ts.map +1 -1
- package/dist/cjs/utils/validation.js +421 -0
- package/dist/cjs/utils/validation.js.map +1 -1
- package/dist/esm/cli/commands/db-push.d.ts.map +1 -1
- package/dist/esm/cli/commands/db-push.js +6 -3
- package/dist/esm/cli/commands/db-push.js.map +1 -1
- package/dist/esm/cli/display.d.ts +15 -0
- package/dist/esm/cli/display.d.ts.map +1 -0
- package/dist/esm/cli/display.js +18 -0
- package/dist/esm/cli/display.js.map +1 -0
- package/dist/esm/compilers/mutation.compiler.d.ts +54 -1
- package/dist/esm/compilers/mutation.compiler.d.ts.map +1 -1
- package/dist/esm/compilers/mutation.compiler.js +134 -32
- package/dist/esm/compilers/mutation.compiler.js.map +1 -1
- package/dist/esm/compilers/where.compiler.d.ts.map +1 -1
- package/dist/esm/compilers/where.compiler.js +8 -1
- package/dist/esm/compilers/where.compiler.js.map +1 -1
- package/dist/esm/interface-model.d.ts.map +1 -1
- package/dist/esm/interface-model.js +9 -1
- package/dist/esm/interface-model.js.map +1 -1
- package/dist/esm/model.d.ts.map +1 -1
- package/dist/esm/model.js +12 -3
- package/dist/esm/model.js.map +1 -1
- package/dist/esm/ogm.d.ts.map +1 -1
- package/dist/esm/ogm.js +6 -1
- package/dist/esm/ogm.js.map +1 -1
- package/dist/esm/subgraph/subgraph-operations.d.ts +2 -1
- package/dist/esm/subgraph/subgraph-operations.d.ts.map +1 -1
- package/dist/esm/subgraph/subgraph-operations.js +20 -4
- package/dist/esm/subgraph/subgraph-operations.js.map +1 -1
- package/dist/esm/subgraph/types.d.ts +8 -0
- package/dist/esm/subgraph/types.d.ts.map +1 -1
- package/dist/esm/utils/validation.d.ts +7 -0
- package/dist/esm/utils/validation.d.ts.map +1 -1
- package/dist/esm/utils/validation.js +420 -0
- package/dist/esm/utils/validation.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,78 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.14.0 (2026-07-24) — 🛡️ Security release: NLS enforcement on interface reads & relationship writes, and a `_MATCHES` ReDoS guard
|
|
4
|
+
|
|
5
|
+
> **Three security fixes.** Two are object-level authorization gaps: grafeo's node-level-security (NLS) policies were threaded correctly through the concrete-model read and write paths, but two paths silently skipped the **target type's** policy — nested relationship projections on **interface** reads, and **connect/disconnect** relationship writes — so a caller whose own access was correctly scoped could still read, or link/unlink, related nodes their policy forbids. The third hardens the `_MATCHES` filter operator against server-side ReDoS. If you use `policies` with interface models or nested `connect`/`disconnect`, or expose `_MATCHES` to untrusted input, upgrade.
|
|
6
|
+
|
|
7
|
+
### 🛡️ Interface reads now apply the target type's `read` policy to nested projections
|
|
8
|
+
|
|
9
|
+
`InterfaceModel.find` (and its `findFirst` / `findUnique` / `*OrThrow` siblings, which all route through it) applied the interface's source-side policy and the WHERE-side traversal policy — but compiled the **RETURN projection** without the read `policyContext` that `Model.find` passes. Every nested relationship pattern comprehension was therefore emitted with **no target-type policy**, so an interface query could project fields of related, policy-protected node types (e.g. another tenant's `author { email }`) that the target type's `read` policy is meant to filter out. The leak was silent and spanned every row the interface query returned.
|
|
10
|
+
|
|
11
|
+
The fix threads the resolved read `policyContext` into the interface selection compile, exactly as the concrete-model path already does, so every nested projection AND-stitches the target type's read policy — including union and connection branches. **When no policy layer is configured the emitted Cypher is byte-identical** to before; the guard engages only when a policy actually resolves for the projected type.
|
|
12
|
+
|
|
13
|
+
### 🛡️ Nested `connect` / `disconnect` now enforce the target type's `read` policy
|
|
14
|
+
|
|
15
|
+
`MutationCompiler` was policy-unaware: the target `MATCH` emitted for a nested `connect` (MERGE) or `disconnect` selected the target node by the caller's `where` alone, with no policy. A caller operating under a bound `withContext(ctx)` — whose *source* node was correctly policy-filtered — could therefore link or unlink relationships to arbitrary target nodes their policy should forbid (cross-tenant / cross-owner relationship writes):
|
|
16
|
+
|
|
17
|
+
```typescript
|
|
18
|
+
// `Book` has a read policy scoped to the owner. Previously this linked a
|
|
19
|
+
// foreign Book anyway — the target MATCH carried no Book policy. Now it
|
|
20
|
+
// AND-stitches the Book read policy, so an unreadable target fails to
|
|
21
|
+
// match and the MERGE is a no-op.
|
|
22
|
+
ogm.withContext({ uid }).model('User').update({
|
|
23
|
+
where: { id: myId },
|
|
24
|
+
connect: { ownedBooks: { where: { id: someBookId } } },
|
|
25
|
+
});
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
The fix threads the resolved policy context into `MutationCompiler` and AND-stitches the target type's `read` policy into every connect/disconnect target `MATCH` — all seven sites (single / array / `UNWIND` connect, specific disconnect, nested-in-update connect and disconnect, union targets), reached from both `update` and `updateMany`. `read` is the correct gate: row-level target visibility is expressed as the `read` policy, while `create`/`update` restrictives are WITH-CHECK predicates over a mutation-input bag that a referenced existing node has none of. **No-policy, bypass (`unsafe.bypassPolicies`), and no-target-policy paths stay byte-identical**; `create` and `upsert` (which never emits a relationship `MATCH`) are untouched. Policy predicates use the mutation's shared, monotonic parameter counter, so they never collide with the caller's `connect`/`disconnect` `where` params.
|
|
29
|
+
|
|
30
|
+
### 🛡️ `_MATCHES` is now guarded against catastrophic-backtracking regexes (ReDoS)
|
|
31
|
+
|
|
32
|
+
The `_MATCHES` filter operator forwards its value into a Neo4j `=~` predicate, which the server evaluates with Java's **backtracking** regex engine. An attacker able to influence a `where` filter could supply a catastrophic pattern (e.g. `(a+)+$`, `([a-z]+)+$`, `(a?)+$`) and pin shared Neo4j CPU — a server-side ReDoS ([CWE-1333](https://cwe.mitre.org/data/definitions/1333.html)). Parameterization stops injection but not this: the payload *is* the regex.
|
|
33
|
+
|
|
34
|
+
Every `_MATCHES` value is now validated at compile time by a **sound-by-construction** guard. Rather than blocklisting known-bad shapes (always incomplete), it accepts a pattern **only when it can prove the pattern is linear**, and refuses everything it cannot model — alternation, quantified groups, lookaround, backreferences, unsupported escapes. The check is single-pass and bounded, so it cannot itself become a DoS vector, and Java-flavor divergences are modeled soundly (`\v` is the vertical-whitespace class; `\0`/octal escapes are refused; only inline flags that don't change the analysis — `i`/`m`/`s`/`d` — are honored, so `(?x)` COMMENTS mode and `(?u)`/`(?U)` Unicode widening are refused).
|
|
35
|
+
|
|
36
|
+
- **Precision cost (intended, fail-closed).** Some linear-but-unprovable patterns are refused — notably **all alternation** (`(cat|dog)`) and **contains-style** `.*x.*` shapes. Reach for the dedicated, always-safe operators (`_CONTAINS` / `_STARTS_WITH` / `_ENDS_WITH` / `_IN`), simplify the pattern, or disable `_MATCHES` entirely via `features.filters.String.MATCHES` if you must run arbitrary regexes and accept the risk. The refusal error names these options.
|
|
37
|
+
- **Common patterns keep working** — anchors, character classes, single wildcards (`^foo.*bar$`, `[A-Za-z0-9_]+`, `\d{3}-\d{4}`), fenced quantifiers (`[a-z]+@[a-z]+\.[a-z]+`), and inline-flag prefixes (`(?i)…`).
|
|
38
|
+
|
|
39
|
+
### Tests
|
|
40
|
+
|
|
41
|
+
Interface-read policy: two specs asserting the nested projection now carries the target `read` predicate for interface reads, and that the no-policy path stays byte-identical. Connect/disconnect policy: six specs covering connect and disconnect target MATCHes carrying the target `read` policy, the update-op-not-stitched case, byte-identical no-policy/bypass Cypher, and non-colliding parameter numbering. ReDoS guard: a 100+-case battery covering every known catastrophic family (nested quantifiers, nullable/overlapping alternation under repeat, custom-class and nested-group bases, unrolled adjacent optionals), fail-closed refusal of unmodeled constructs, acceptance of provably-linear patterns, and the three Java-flavor soundness regressions found and closed during adversarial review (`(?x)`, `\v`, `\0`). Full suite green (1629); lint and format clean.
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## 1.13.0 (2026-07-14) — ✨ `$cloneSubgraph` returns `nodesByLabel`
|
|
46
|
+
|
|
47
|
+
> **First community-requested feature** ([#1](https://github.com/neomodular/grafeo-ogm/issues/1)). After deep-cloning a content subgraph, a caller often needs to post-process only the nodes of a **specific label** (re-normalize, re-stamp, re-index). Until now `nodeMapping` held every cloned id across all labels, forcing a broad-`IN`-plus-label-filter dance on the caller. The clone already visits every node with its labels in hand — so now it just tells you.
|
|
48
|
+
|
|
49
|
+
### ✨ `nodesByLabel: Map<label, newId[]>` on the clone result
|
|
50
|
+
|
|
51
|
+
- **Additive and backwards-compatible** — `clonedRootId` and `nodeMapping` are unchanged; existing callers are unaffected.
|
|
52
|
+
- **Zero extra round-trips** — `labels(output)` is folded into the existing Step-1 `RETURN` of the APOC clone query.
|
|
53
|
+
- **Multi-label nodes appear under each of their labels**, so `nodesByLabel.get('DoseValue')` is exactly the set you post-process.
|
|
54
|
+
- **Consistent by construction** — `nodesByLabel` is built in the same pass as the final `nodeMapping`, so a node dropped during UUID re-assignment is absent from *both* maps: every id in `nodesByLabel` is also a `nodeMapping` value.
|
|
55
|
+
|
|
56
|
+
```typescript
|
|
57
|
+
const result = await ogm.$cloneSubgraph(rootId, config, tx);
|
|
58
|
+
const doseValueIds = result.nodesByLabel.get('DoseValue') ?? [];
|
|
59
|
+
// target exactly one label — no over-broad IN list
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### 🛡️ CLI display hardening — `db push` sanitizes live-DB names
|
|
63
|
+
|
|
64
|
+
Names introspected from the live database that fail identifier validation are correctly routed to `unmanaged` and never executed as Cypher — but they were printed **raw**. Neo4j allows arbitrary characters in backtick-quoted identifiers, so a hostile constraint/index name could smuggle ANSI/C0 escape sequences into the developer's terminal (title changes, output spoofing). All live-DB names rendered by `db push` (unmanaged, orphan listings, drop confirmations) now pass through a `safeDisplay()` helper that replaces C0/C1 control characters with a visible `�` placeholder. Cypher execution was never affected — this closes the display path.
|
|
65
|
+
|
|
66
|
+
### 📝 Docs
|
|
67
|
+
|
|
68
|
+
- Fixed the `cloneSubgraph` README snippet: the result field is `nodeMapping`, not the stale `idMapping`, and the config examples now include the required `maxLevel`.
|
|
69
|
+
|
|
70
|
+
### Tests
|
|
71
|
+
|
|
72
|
+
Four new subgraph specs (label grouping, root-label → `clonedRootId` linkage, multi-label fan-out, UUID-failure consistency across both maps) plus a CLI spec proving a hostile constraint name lands in `unmanaged`, prints sanitized, and never reaches a `DROP`. Full suite green (1514); lint, format, and type-check clean.
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
3
76
|
## 1.12.0 (2026-07-01) — 🛡️ `OR: []` now matches nothing (Prisma semantics)
|
|
4
77
|
|
|
5
78
|
> **Safety fix, and the one deliberate compat break with `@neo4j/graphql-ogm`.** An empty logical `OR` array used to vanish from the compiled WHERE clause, so `deleteMany({ where: { OR: [] } })` compiled **byte-identical to no `where` at all**: `MATCH (n:Label) DETACH DELETE n` — a full-label wipe. The realistic trigger is a dynamically built filter (`OR: ids.map((id) => ({ id }))`) receiving an empty list. The deprecated `@neo4j/graphql-ogm` (verified against its final release, 5.11.4) has the same behavior, so grafeo was bug-for-bug compatible. We now diverge on purpose.
|
package/README.md
CHANGED
|
@@ -943,13 +943,21 @@ const cloneResult = await cloneSubgraph(
|
|
|
943
943
|
{
|
|
944
944
|
ownedLabels: ['Book', 'Chapter', 'Section'],
|
|
945
945
|
ownedRelationships: ['HAS_CHAPTER', 'HAS_SECTION'],
|
|
946
|
+
maxLevel: 5,
|
|
946
947
|
referenceRelationships: [
|
|
947
948
|
{ fromLabel: 'Book', relationshipType: 'WRITTEN_BY', direction: 'OUT' },
|
|
948
949
|
],
|
|
949
950
|
},
|
|
950
951
|
transaction,
|
|
951
952
|
);
|
|
952
|
-
// cloneResult: {
|
|
953
|
+
// cloneResult: {
|
|
954
|
+
// clonedRootId,
|
|
955
|
+
// nodeMapping: Map<originalId, newId>,
|
|
956
|
+
// nodesByLabel: Map<label, newId[]>, // v1.13.0+ — multi-label nodes appear under each label
|
|
957
|
+
// }
|
|
958
|
+
|
|
959
|
+
// v1.13.0+ — post-process only the nodes of one label, no broad-IN filtering:
|
|
960
|
+
const chapterIds = cloneResult.nodesByLabel.get('Chapter') ?? [];
|
|
953
961
|
|
|
954
962
|
// Delete a subgraph
|
|
955
963
|
const deleteResult = await deleteSubgraph(
|
|
@@ -957,6 +965,7 @@ const deleteResult = await deleteSubgraph(
|
|
|
957
965
|
{
|
|
958
966
|
ownedLabels: ['Book', 'Chapter'],
|
|
959
967
|
ownedRelationships: ['HAS_CHAPTER'],
|
|
968
|
+
maxLevel: 5,
|
|
960
969
|
referenceRelationships: [],
|
|
961
970
|
},
|
|
962
971
|
transaction,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"db-push.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/db-push.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"db-push.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/db-push.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,UAAU,CAAC;AAkJtC,wBAAsB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,CAgE1E"}
|
|
@@ -38,6 +38,7 @@ const fs = __importStar(require("node:fs"));
|
|
|
38
38
|
const node_util_1 = require("node:util");
|
|
39
39
|
const parser_1 = require("../../schema/parser");
|
|
40
40
|
const config_1 = require("../config");
|
|
41
|
+
const display_1 = require("../display");
|
|
41
42
|
const driver_1 = require("../driver");
|
|
42
43
|
const errors_1 = require("../errors");
|
|
43
44
|
const introspect_1 = require("../introspect");
|
|
@@ -98,10 +99,12 @@ function renderPlan(plan, io, willDrop) {
|
|
|
98
99
|
else {
|
|
99
100
|
io.out(`Orphans — ${plan.orphans.length} kept (use --force-drop to remove):`);
|
|
100
101
|
for (const orphan of plan.orphans)
|
|
101
|
-
io.out(` - ${orphan.name}`);
|
|
102
|
+
io.out(` - ${(0, display_1.safeDisplay)(orphan.name)}`);
|
|
102
103
|
}
|
|
104
|
+
// v1.13.0 — unmanaged names come from live introspection and are exactly
|
|
105
|
+
// the ones that FAILED identifier validation: sanitize before printing.
|
|
103
106
|
if (plan.unmanaged.length > 0)
|
|
104
|
-
io.out(`Unmanaged — ${plan.unmanaged.length} ignored: ${plan.unmanaged.join(', ')}`);
|
|
107
|
+
io.out(`Unmanaged — ${plan.unmanaged.length} ignored: ${plan.unmanaged.map(display_1.safeDisplay).join(', ')}`);
|
|
105
108
|
}
|
|
106
109
|
async function resolveDropConsent(plan, io, yes) {
|
|
107
110
|
if (yes)
|
|
@@ -135,7 +138,7 @@ async function applyDrops(driver, database, plan, io) {
|
|
|
135
138
|
try {
|
|
136
139
|
for (const orphan of plan.orphans) {
|
|
137
140
|
await session.run(orphan.dropCypher);
|
|
138
|
-
io.out(`✓ dropped ${orphan.name}`);
|
|
141
|
+
io.out(`✓ dropped ${(0, display_1.safeDisplay)(orphan.name)}`);
|
|
139
142
|
}
|
|
140
143
|
}
|
|
141
144
|
finally {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"db-push.js","sourceRoot":"","sources":["../../../../src/cli/commands/db-push.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"db-push.js","sourceRoot":"","sources":["../../../../src/cli/commands/db-push.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Display hygiene for strings sourced from LIVE database introspection.
|
|
3
|
+
*
|
|
4
|
+
* v1.13.0 — names failing `isSafeIdentifier` are correctly routed to
|
|
5
|
+
* `unmanaged` and never executed as Cypher, but they were printed raw. A
|
|
6
|
+
* hostile constraint/index name (Neo4j allows arbitrary characters in
|
|
7
|
+
* backtick-quoted identifiers) could smuggle ANSI/C0 escapes into the
|
|
8
|
+
* developer's terminal — title changes, output spoofing/hiding. The
|
|
9
|
+
* identifier validation that blocks Cypher injection does not cover the
|
|
10
|
+
* display path, so any live-DB string reaching `io.out`/`io.err` must pass
|
|
11
|
+
* through here first.
|
|
12
|
+
*/
|
|
13
|
+
/** Replaces C0/C1 control characters with a visible placeholder (U+FFFD). */
|
|
14
|
+
export declare function safeDisplay(value: string): string;
|
|
15
|
+
//# sourceMappingURL=display.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"display.d.ts","sourceRoot":"","sources":["../../../src/cli/display.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAIH,6EAA6E;AAC7E,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEjD"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Display hygiene for strings sourced from LIVE database introspection.
|
|
4
|
+
*
|
|
5
|
+
* v1.13.0 — names failing `isSafeIdentifier` are correctly routed to
|
|
6
|
+
* `unmanaged` and never executed as Cypher, but they were printed raw. A
|
|
7
|
+
* hostile constraint/index name (Neo4j allows arbitrary characters in
|
|
8
|
+
* backtick-quoted identifiers) could smuggle ANSI/C0 escapes into the
|
|
9
|
+
* developer's terminal — title changes, output spoofing/hiding. The
|
|
10
|
+
* identifier validation that blocks Cypher injection does not cover the
|
|
11
|
+
* display path, so any live-DB string reaching `io.out`/`io.err` must pass
|
|
12
|
+
* through here first.
|
|
13
|
+
*/
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.safeDisplay = safeDisplay;
|
|
16
|
+
const CONTROL_CHARS = new RegExp('[\\u0000-\\u001F\\u007F-\\u009F]', 'g');
|
|
17
|
+
/** Replaces C0/C1 control characters with a visible placeholder (U+FFFD). */
|
|
18
|
+
function safeDisplay(value) {
|
|
19
|
+
return value.replace(CONTROL_CHARS, '�');
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=display.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"display.js","sourceRoot":"","sources":["../../../src/cli/display.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;GAWG;;AAKH,kCAEC;AALD,MAAM,aAAa,GAAG,IAAI,MAAM,CAAC,kCAAkC,EAAE,GAAG,CAAC,CAAC;AAE1E,6EAA6E;AAC7E,SAAgB,WAAW,CAAC,KAAa;IACvC,OAAO,KAAK,CAAC,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC,CAAC;AAC3C,CAAC"}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import type { OGMLogger } from '../execution/executor';
|
|
2
|
+
import type { PolicyContextBundle } from '../policy/types';
|
|
2
3
|
import { NodeDefinition, SchemaMetadata } from '../schema/types';
|
|
4
|
+
import { WhereCompiler } from './where.compiler';
|
|
3
5
|
export interface MutationResult {
|
|
4
6
|
cypher: string;
|
|
5
7
|
params: Record<string, unknown>;
|
|
@@ -15,9 +17,44 @@ export declare class MutationCompiler {
|
|
|
15
17
|
*/
|
|
16
18
|
private labelCache;
|
|
17
19
|
private logger?;
|
|
20
|
+
/**
|
|
21
|
+
* WhereCompiler used ONLY to compile a relationship TARGET type's
|
|
22
|
+
* `read` policy predicate for connect/disconnect target MATCHes,
|
|
23
|
+
* mirroring the read paths (`WhereCompiler`/`SelectionCompiler`).
|
|
24
|
+
* Injected by the OGM so it shares the user's compiler options;
|
|
25
|
+
* lazily constructed with default options otherwise.
|
|
26
|
+
*/
|
|
27
|
+
private policyWhereCompiler?;
|
|
18
28
|
constructor(schema: SchemaMetadata, options?: {
|
|
19
29
|
logger?: OGMLogger;
|
|
30
|
+
whereCompiler?: WhereCompiler;
|
|
20
31
|
});
|
|
32
|
+
/**
|
|
33
|
+
* Resolve and compile the TARGET type's `read` policy predicate for a
|
|
34
|
+
* connect/disconnect target MATCH, mirroring the read path
|
|
35
|
+
* (`WhereCompiler.buildTargetBundle` + `WhereCompiler.compile`). You
|
|
36
|
+
* must be allowed to SEE a node to link/unlink it, so linking to an
|
|
37
|
+
* unreadable node is the IDOR this closes; the codebase models the
|
|
38
|
+
* row-level write gate for `update`/`delete` targets as `read`
|
|
39
|
+
* ReadRestrictive policies (see policy/types.ts), so `read` is both
|
|
40
|
+
* necessary and the semantically correct operation here.
|
|
41
|
+
*
|
|
42
|
+
* Returns `null` — leaving the emitted Cypher BYTE-IDENTICAL — when:
|
|
43
|
+
* - no policy context is threaded (no policy bound / bypass active), OR
|
|
44
|
+
* - no `paramCounter` is available to allocate policy params, OR
|
|
45
|
+
* - the target type has no policy applicable to `read`, OR
|
|
46
|
+
* - the resolved policy is `overridden` (compiles to nothing).
|
|
47
|
+
*
|
|
48
|
+
* When a target policy resolves, the compiled predicate is returned and
|
|
49
|
+
* its bound params are merged into `params`. Policy params use the
|
|
50
|
+
* shared `paramCounter` (`param<N>`), continuing the sequence started by
|
|
51
|
+
* the top-level WHERE, so they can never collide with the
|
|
52
|
+
* connect/disconnect `where` params (prefix-named, e.g.
|
|
53
|
+
* `connect_<field>_<prop>`) or the selection's params (allocated later
|
|
54
|
+
* from the same counter).
|
|
55
|
+
*/
|
|
56
|
+
private buildTargetPolicyPredicate;
|
|
57
|
+
private getPolicyWhereCompiler;
|
|
21
58
|
/**
|
|
22
59
|
* Surface a logical operator that contributed zero effective conditions.
|
|
23
60
|
* Mirrors WhereCompiler.warnEmptyLogical — fires only on the anomalous
|
|
@@ -39,7 +76,23 @@ export declare class MutationCompiler {
|
|
|
39
76
|
cypher: string;
|
|
40
77
|
params: Record<string, unknown>;
|
|
41
78
|
preludes?: string[];
|
|
42
|
-
}, labels?: string[], returnMode?: 'node' | 'count'
|
|
79
|
+
}, labels?: string[], returnMode?: 'node' | 'count',
|
|
80
|
+
/**
|
|
81
|
+
* The caller's resolved policy bundle for this mutation (the SOURCE
|
|
82
|
+
* type's `update` bundle). Its `resolveForType` is used to resolve
|
|
83
|
+
* each connect/disconnect TARGET type's `read` policy. `undefined`
|
|
84
|
+
* when no policy is bound or a bypass is active — in which case the
|
|
85
|
+
* emitted Cypher is byte-identical to before this enforcement.
|
|
86
|
+
*/
|
|
87
|
+
policyContext?: PolicyContextBundle,
|
|
88
|
+
/**
|
|
89
|
+
* Shared `param<N>` counter, continued from the top-level WHERE
|
|
90
|
+
* compile so target-policy params never collide with connect/
|
|
91
|
+
* disconnect `where` params or the selection's params.
|
|
92
|
+
*/
|
|
93
|
+
paramCounter?: {
|
|
94
|
+
count: number;
|
|
95
|
+
}): MutationResult;
|
|
43
96
|
/**
|
|
44
97
|
* Generate DELETE Cypher with optional cascade.
|
|
45
98
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mutation.compiler.d.ts","sourceRoot":"","sources":["../../../src/compilers/mutation.compiler.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EACL,cAAc,EAEd,cAAc,EACf,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"mutation.compiler.d.ts","sourceRoot":"","sources":["../../../src/compilers/mutation.compiler.ts"],"names":[],"mappings":"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"}
|