@gobing-ai/ts-rule-engine 0.4.6 → 0.4.8
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.
|
@@ -23,6 +23,16 @@ export interface LoadExtensionsOptions {
|
|
|
23
23
|
logger?: Pick<Logger, 'warn'>;
|
|
24
24
|
/** Optional module loader seam for tests or embedders with custom import policy. */
|
|
25
25
|
moduleLoader?: (absPath: string) => Promise<Record<string, unknown>>;
|
|
26
|
+
/**
|
|
27
|
+
* Optional canonical-path resolver for symlink-safe confinement (ADR-022).
|
|
28
|
+
* Forwarded to the shared loader. Defaults to the node filesystem's
|
|
29
|
+
* canonicalizer whenever the default (real dynamic-import) `moduleLoader` is
|
|
30
|
+
* in effect, so a symlink inside the declaring directory cannot escape it.
|
|
31
|
+
* Pass `realPath: undefined` explicitly to opt out (e.g. pnpm/Nix symlinked
|
|
32
|
+
* layouts), or supply a custom resolver. When a custom `moduleLoader` is
|
|
33
|
+
* given, confinement policy is caller-owned and no default applies.
|
|
34
|
+
*/
|
|
35
|
+
realPath?: (absPath: string) => string;
|
|
26
36
|
}
|
|
27
37
|
/**
|
|
28
38
|
* Collect extension refs declared by a preset's or rule file's `extensions` block.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extensions.d.ts","sourceRoot":"","sources":["../../src/config/extensions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"extensions.d.ts","sourceRoot":"","sources":["../../src/config/extensions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAclD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC/D,2DAA2D;AAC3D,MAAM,MAAM,aAAa,GAAG,WAAW,GAAG,YAAY,GAAG,QAAQ,GAAG,YAAY,CAAC;AAEjF,yEAAyE;AACzE,MAAM,WAAW,YAAY;IACzB,qDAAqD;IACrD,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;IAC7B,6CAA6C;IAC7C,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,yEAAyE;IACzE,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC/B;AAED,oDAAoD;AACpD,MAAM,WAAW,qBAAqB;IAClC;;;;OAIG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,sEAAsE;IACtE,MAAM,CAAC,EAAE,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B,oFAAoF;IACpF,YAAY,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IACrE;;;;;;;;OAQG;IACH,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,CAAC;CAC1C;AAUD;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAC7B,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,OAAO,CAAC,MAAM,CAAC,aAAa,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC,CAAC,GAAG,SAAS,GAC7E,YAAY,EAAE,CAShB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,sBAAsB,CACxC,IAAI,EAAE,cAAc,EACpB,IAAI,EAAE,SAAS,YAAY,EAAE,EAC7B,OAAO,GAAE,qBAA0B,GACpC,OAAO,CAAC,IAAI,CAAC,CAiEf"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { basenamePath, dirnamePath, fileUrlToPath, normalizeSeparators, resolvePath } from '@gobing-ai/ts-runtime';
|
|
1
|
+
import { basenamePath, createNodeFileSystem, dirnamePath, fileUrlToPath, normalizeSeparators, resolvePath, } from '@gobing-ai/ts-runtime';
|
|
2
2
|
import { loadExtensionModules } from '@gobing-ai/ts-runtime/extension';
|
|
3
3
|
/** Host registries that can receive extension capabilities (all four kinds). */
|
|
4
4
|
const HOST_REGISTRY_BY_KIND = {
|
|
@@ -72,10 +72,17 @@ export async function loadExtensionsIntoHost(host, refs, options = {}) {
|
|
|
72
72
|
};
|
|
73
73
|
});
|
|
74
74
|
const moduleLoader = options.moduleLoader ?? defaultModuleLoader;
|
|
75
|
+
// Real import policy gets real confinement by default (ADR-022 addendum): a
|
|
76
|
+
// caller relying on the default dynamic-import loader that has not set
|
|
77
|
+
// `realPath` — even explicitly to undefined — gets node canonicalization, so a
|
|
78
|
+
// symlink inside the declaring directory cannot escape it. A custom
|
|
79
|
+
// moduleLoader owns its confinement policy; no default applies there.
|
|
80
|
+
const realPath = 'realPath' in options ? options.realPath : options.moduleLoader === undefined ? defaultRealPath() : undefined;
|
|
75
81
|
const sharedOptions = {
|
|
76
82
|
allowExtensions: options.allowExtensions,
|
|
77
83
|
logger: options.logger,
|
|
78
84
|
moduleLoader,
|
|
85
|
+
realPath,
|
|
79
86
|
};
|
|
80
87
|
await loadExtensionModules(sharedRefs, sharedOptions, async (sharedRef, extension) => {
|
|
81
88
|
const name = extension.name;
|
|
@@ -93,3 +100,7 @@ export async function loadExtensionsIntoHost(host, refs, options = {}) {
|
|
|
93
100
|
async function defaultModuleLoader(absPath) {
|
|
94
101
|
return (await import(absPath));
|
|
95
102
|
}
|
|
103
|
+
function defaultRealPath() {
|
|
104
|
+
const fs = createNodeFileSystem();
|
|
105
|
+
return (absPath) => (fs.realPath ? fs.realPath(absPath) : absPath);
|
|
106
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gobing-ai/ts-rule-engine",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.8",
|
|
4
4
|
"description": "@gobing-ai/ts-rule-engine — Constraint rule schemas, loading, evaluation, and result formatting.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"typescript",
|
|
@@ -49,10 +49,10 @@
|
|
|
49
49
|
"release": "echo 'Manual publish is disabled. Releases go through GitHub Actions via Trusted Publishing — push a tag: git tag @gobing-ai/ts-rule-engine-v<version> && git push --tags' && exit 1"
|
|
50
50
|
},
|
|
51
51
|
"dependencies": {
|
|
52
|
-
"@gobing-ai/ts-ai-runner": "^0.4.
|
|
53
|
-
"@gobing-ai/ts-infra": "^0.4.
|
|
54
|
-
"@gobing-ai/ts-runtime": "^0.4.
|
|
55
|
-
"@gobing-ai/ts-db": "^0.4.
|
|
52
|
+
"@gobing-ai/ts-ai-runner": "^0.4.8",
|
|
53
|
+
"@gobing-ai/ts-infra": "^0.4.8",
|
|
54
|
+
"@gobing-ai/ts-runtime": "^0.4.8",
|
|
55
|
+
"@gobing-ai/ts-db": "^0.4.8",
|
|
56
56
|
"yaml": "^2.7.0",
|
|
57
57
|
"zod": "^4.1.0"
|
|
58
58
|
},
|
package/src/config/extensions.ts
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
import type { Logger } from '@gobing-ai/ts-infra';
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
basenamePath,
|
|
4
|
+
createNodeFileSystem,
|
|
5
|
+
dirnamePath,
|
|
6
|
+
fileUrlToPath,
|
|
7
|
+
normalizeSeparators,
|
|
8
|
+
resolvePath,
|
|
9
|
+
} from '@gobing-ai/ts-runtime';
|
|
3
10
|
import type {
|
|
4
11
|
ExtensionRef as SharedExtensionRef,
|
|
5
12
|
LoadExtensionsOptions as SharedLoadExtensionsOptions,
|
|
@@ -31,6 +38,16 @@ export interface LoadExtensionsOptions {
|
|
|
31
38
|
logger?: Pick<Logger, 'warn'>;
|
|
32
39
|
/** Optional module loader seam for tests or embedders with custom import policy. */
|
|
33
40
|
moduleLoader?: (absPath: string) => Promise<Record<string, unknown>>;
|
|
41
|
+
/**
|
|
42
|
+
* Optional canonical-path resolver for symlink-safe confinement (ADR-022).
|
|
43
|
+
* Forwarded to the shared loader. Defaults to the node filesystem's
|
|
44
|
+
* canonicalizer whenever the default (real dynamic-import) `moduleLoader` is
|
|
45
|
+
* in effect, so a symlink inside the declaring directory cannot escape it.
|
|
46
|
+
* Pass `realPath: undefined` explicitly to opt out (e.g. pnpm/Nix symlinked
|
|
47
|
+
* layouts), or supply a custom resolver. When a custom `moduleLoader` is
|
|
48
|
+
* given, confinement policy is caller-owned and no default applies.
|
|
49
|
+
*/
|
|
50
|
+
realPath?: (absPath: string) => string;
|
|
34
51
|
}
|
|
35
52
|
|
|
36
53
|
/** Host registries that can receive extension capabilities (all four kinds). */
|
|
@@ -119,10 +136,18 @@ export async function loadExtensionsIntoHost(
|
|
|
119
136
|
});
|
|
120
137
|
|
|
121
138
|
const moduleLoader = options.moduleLoader ?? defaultModuleLoader;
|
|
139
|
+
// Real import policy gets real confinement by default (ADR-022 addendum): a
|
|
140
|
+
// caller relying on the default dynamic-import loader that has not set
|
|
141
|
+
// `realPath` — even explicitly to undefined — gets node canonicalization, so a
|
|
142
|
+
// symlink inside the declaring directory cannot escape it. A custom
|
|
143
|
+
// moduleLoader owns its confinement policy; no default applies there.
|
|
144
|
+
const realPath =
|
|
145
|
+
'realPath' in options ? options.realPath : options.moduleLoader === undefined ? defaultRealPath() : undefined;
|
|
122
146
|
const sharedOptions: SharedLoadExtensionsOptions = {
|
|
123
147
|
allowExtensions: options.allowExtensions,
|
|
124
148
|
logger: options.logger,
|
|
125
149
|
moduleLoader,
|
|
150
|
+
realPath,
|
|
126
151
|
};
|
|
127
152
|
|
|
128
153
|
await loadExtensionModules<ExtensionKind>(sharedRefs, sharedOptions, async (sharedRef, extension) => {
|
|
@@ -145,3 +170,8 @@ export async function loadExtensionsIntoHost(
|
|
|
145
170
|
async function defaultModuleLoader(absPath: string): Promise<Record<string, unknown>> {
|
|
146
171
|
return (await import(absPath)) as Record<string, unknown>;
|
|
147
172
|
}
|
|
173
|
+
|
|
174
|
+
function defaultRealPath(): (absPath: string) => string {
|
|
175
|
+
const fs = createNodeFileSystem();
|
|
176
|
+
return (absPath) => (fs.realPath ? fs.realPath(absPath) : absPath);
|
|
177
|
+
}
|