@dofe/infra-workspace 0.1.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/dist/docker-volume.d.ts +8 -0
- package/dist/docker-volume.d.ts.map +1 -0
- package/dist/docker-volume.js +7 -0
- package/dist/docker-volume.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +20 -0
- package/dist/index.js.map +1 -0
- package/dist/path-policy.d.ts +12 -0
- package/dist/path-policy.d.ts.map +1 -0
- package/dist/path-policy.js +49 -0
- package/dist/path-policy.js.map +1 -0
- package/dist/workspace-root.d.ts +9 -0
- package/dist/workspace-root.d.ts.map +1 -0
- package/dist/workspace-root.js +32 -0
- package/dist/workspace-root.js.map +1 -0
- package/package.json +49 -0
- package/test/path-policy.smoke.mjs +73 -0
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export type DockerVolumeAccess = 'ro' | 'rw';
|
|
2
|
+
export interface DockerVolumeArgInput {
|
|
3
|
+
hostPath: string;
|
|
4
|
+
containerPath: string;
|
|
5
|
+
access?: DockerVolumeAccess;
|
|
6
|
+
}
|
|
7
|
+
export declare function buildDockerVolumeArg(input: DockerVolumeArgInput): string;
|
|
8
|
+
//# sourceMappingURL=docker-volume.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"docker-volume.d.ts","sourceRoot":"","sources":["../../../packages/workspace/src/docker-volume.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,kBAAkB,GAAG,IAAI,GAAG,IAAI,CAAC;AAE7C,MAAM,WAAW,oBAAoB;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,CAAC,EAAE,kBAAkB,CAAC;CAC7B;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,oBAAoB,GAAG,MAAM,CAExE"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.buildDockerVolumeArg = buildDockerVolumeArg;
|
|
4
|
+
function buildDockerVolumeArg(input) {
|
|
5
|
+
return `${input.hostPath}:${input.containerPath}:${input.access ?? 'rw'}`;
|
|
6
|
+
}
|
|
7
|
+
//# sourceMappingURL=docker-volume.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"docker-volume.js","sourceRoot":"","sources":["../../../packages/workspace/src/docker-volume.ts"],"names":[],"mappings":";;AAQA,oDAEC;AAFD,SAAgB,oBAAoB,CAAC,KAA2B;IAC9D,OAAO,GAAG,KAAK,CAAC,QAAQ,IAAI,KAAK,CAAC,aAAa,IAAI,KAAK,CAAC,MAAM,IAAI,IAAI,EAAE,CAAC;AAC5E,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../packages/workspace/src/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,kBAAkB,CAAC;AACjC,cAAc,iBAAiB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./path-policy"), exports);
|
|
18
|
+
__exportStar(require("./workspace-root"), exports);
|
|
19
|
+
__exportStar(require("./docker-volume"), exports);
|
|
20
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../packages/workspace/src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,gDAA8B;AAC9B,mDAAiC;AACjC,kDAAgC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export interface ResolveAllowedPathOptions {
|
|
2
|
+
input: string;
|
|
3
|
+
allowedRoots: readonly string[];
|
|
4
|
+
mustExist?: boolean;
|
|
5
|
+
directoryOnly?: boolean;
|
|
6
|
+
fieldName?: string;
|
|
7
|
+
}
|
|
8
|
+
export declare function isSameOrChildPath(root: string, target: string): boolean;
|
|
9
|
+
export declare function normalizeAllowedRoots(roots: readonly string[]): string[];
|
|
10
|
+
export declare function resolveAllowedTargetPath(options: ResolveAllowedPathOptions): Promise<string>;
|
|
11
|
+
export declare function interpolatePathTemplate(template: string, values: Record<string, string | number | boolean | null | undefined>): string;
|
|
12
|
+
//# sourceMappingURL=path-policy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"path-policy.d.ts","sourceRoot":"","sources":["../../../packages/workspace/src/path-policy.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,yBAAyB;IACxC,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,SAAS,MAAM,EAAE,CAAC;IAChC,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAQvE;AAED,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,EAAE,CAExE;AAED,wBAAsB,wBAAwB,CAC5C,OAAO,EAAE,yBAAyB,GACjC,OAAO,CAAC,MAAM,CAAC,CAuBjB;AAED,wBAAgB,uBAAuB,CACrC,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,CAAC,GACnE,MAAM,CAKR"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.isSameOrChildPath = isSameOrChildPath;
|
|
7
|
+
exports.normalizeAllowedRoots = normalizeAllowedRoots;
|
|
8
|
+
exports.resolveAllowedTargetPath = resolveAllowedTargetPath;
|
|
9
|
+
exports.interpolatePathTemplate = interpolatePathTemplate;
|
|
10
|
+
const path_1 = __importDefault(require("path"));
|
|
11
|
+
const promises_1 = require("fs/promises");
|
|
12
|
+
function isSameOrChildPath(root, target) {
|
|
13
|
+
const resolvedRoot = path_1.default.resolve(root);
|
|
14
|
+
const resolvedTarget = path_1.default.resolve(target);
|
|
15
|
+
const relative = path_1.default.relative(resolvedRoot, resolvedTarget);
|
|
16
|
+
return (relative === '' ||
|
|
17
|
+
(!relative.startsWith('..') && !path_1.default.isAbsolute(relative)));
|
|
18
|
+
}
|
|
19
|
+
function normalizeAllowedRoots(roots) {
|
|
20
|
+
return roots.map((root) => path_1.default.resolve(root));
|
|
21
|
+
}
|
|
22
|
+
async function resolveAllowedTargetPath(options) {
|
|
23
|
+
const fieldName = options.fieldName ?? 'path';
|
|
24
|
+
if (!path_1.default.isAbsolute(options.input)) {
|
|
25
|
+
throw new Error(`${fieldName} must be an absolute path`);
|
|
26
|
+
}
|
|
27
|
+
const target = path_1.default.resolve(options.input);
|
|
28
|
+
const allowedRoots = normalizeAllowedRoots(options.allowedRoots);
|
|
29
|
+
if (!allowedRoots.some((root) => isSameOrChildPath(root, target))) {
|
|
30
|
+
throw new Error(`${fieldName} is outside allowed roots: ${target}`);
|
|
31
|
+
}
|
|
32
|
+
if (options.mustExist || options.directoryOnly) {
|
|
33
|
+
const current = await (0, promises_1.stat)(target).catch(() => undefined);
|
|
34
|
+
if (!current) {
|
|
35
|
+
throw new Error(`${fieldName} does not exist: ${target}`);
|
|
36
|
+
}
|
|
37
|
+
if (options.directoryOnly && !current.isDirectory()) {
|
|
38
|
+
throw new Error(`${fieldName} is not a directory: ${target}`);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return target;
|
|
42
|
+
}
|
|
43
|
+
function interpolatePathTemplate(template, values) {
|
|
44
|
+
return template.replace(/\{([A-Za-z0-9_]+)\}/g, (match, key) => {
|
|
45
|
+
const value = values[key];
|
|
46
|
+
return value === undefined || value === null ? match : String(value);
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=path-policy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"path-policy.js","sourceRoot":"","sources":["../../../packages/workspace/src/path-policy.ts"],"names":[],"mappings":";;;;;AAWA,8CAQC;AAED,sDAEC;AAED,4DAyBC;AAED,0DAQC;AA5DD,gDAAwB;AACxB,0CAAmC;AAUnC,SAAgB,iBAAiB,CAAC,IAAY,EAAE,MAAc;IAC5D,MAAM,YAAY,GAAG,cAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IACxC,MAAM,cAAc,GAAG,cAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IAC5C,MAAM,QAAQ,GAAG,cAAI,CAAC,QAAQ,CAAC,YAAY,EAAE,cAAc,CAAC,CAAC;IAC7D,OAAO,CACL,QAAQ,KAAK,EAAE;QACf,CAAC,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,cAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,CAC3D,CAAC;AACJ,CAAC;AAED,SAAgB,qBAAqB,CAAC,KAAwB;IAC5D,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,cAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;AACjD,CAAC;AAEM,KAAK,UAAU,wBAAwB,CAC5C,OAAkC;IAElC,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,MAAM,CAAC;IAC9C,IAAI,CAAC,cAAI,CAAC,UAAU,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACpC,MAAM,IAAI,KAAK,CAAC,GAAG,SAAS,2BAA2B,CAAC,CAAC;IAC3D,CAAC;IAED,MAAM,MAAM,GAAG,cAAI,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IAC3C,MAAM,YAAY,GAAG,qBAAqB,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;IACjE,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,iBAAiB,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,EAAE,CAAC;QAClE,MAAM,IAAI,KAAK,CAAC,GAAG,SAAS,8BAA8B,MAAM,EAAE,CAAC,CAAC;IACtE,CAAC;IAED,IAAI,OAAO,CAAC,SAAS,IAAI,OAAO,CAAC,aAAa,EAAE,CAAC;QAC/C,MAAM,OAAO,GAAG,MAAM,IAAA,eAAI,EAAC,MAAM,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;QAC1D,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,MAAM,IAAI,KAAK,CAAC,GAAG,SAAS,oBAAoB,MAAM,EAAE,CAAC,CAAC;QAC5D,CAAC;QACD,IAAI,OAAO,CAAC,aAAa,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC;YACpD,MAAM,IAAI,KAAK,CAAC,GAAG,SAAS,wBAAwB,MAAM,EAAE,CAAC,CAAC;QAChE,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAgB,uBAAuB,CACrC,QAAgB,EAChB,MAAoE;IAEpE,OAAO,QAAQ,CAAC,OAAO,CAAC,sBAAsB,EAAE,CAAC,KAAK,EAAE,GAAW,EAAE,EAAE;QACrE,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;QAC1B,OAAO,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACvE,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export interface FindWorkspaceRootOptions {
|
|
2
|
+
startDir?: string;
|
|
3
|
+
envRoot?: string;
|
|
4
|
+
markerFiles?: readonly string[];
|
|
5
|
+
fallback?: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function findWorkspaceRoot(options?: FindWorkspaceRootOptions): string;
|
|
8
|
+
export declare function resolveConfiguredRoots(configured: string | undefined, fallbackRoot: string, delimiter?: ":" | ";"): string[];
|
|
9
|
+
//# sourceMappingURL=workspace-root.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workspace-root.d.ts","sourceRoot":"","sources":["../../../packages/workspace/src/workspace-root.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAChC,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,wBAAgB,iBAAiB,CAAC,OAAO,GAAE,wBAA6B,GAAG,MAAM,CAgBhF;AAED,wBAAgB,sBAAsB,CACpC,UAAU,EAAE,MAAM,GAAG,SAAS,EAC9B,YAAY,EAAE,MAAM,EACpB,SAAS,YAAiB,GACzB,MAAM,EAAE,CASV"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.findWorkspaceRoot = findWorkspaceRoot;
|
|
7
|
+
exports.resolveConfiguredRoots = resolveConfiguredRoots;
|
|
8
|
+
const fs_1 = require("fs");
|
|
9
|
+
const path_1 = __importDefault(require("path"));
|
|
10
|
+
function findWorkspaceRoot(options = {}) {
|
|
11
|
+
const fallback = path_1.default.resolve(options.fallback ?? process.cwd());
|
|
12
|
+
let current = path_1.default.resolve(options.envRoot || options.startDir || process.cwd());
|
|
13
|
+
const markerFiles = options.markerFiles ?? ['pnpm-workspace.yaml'];
|
|
14
|
+
for (;;) {
|
|
15
|
+
if (markerFiles.every((marker) => (0, fs_1.existsSync)(path_1.default.join(current, marker)))) {
|
|
16
|
+
return current;
|
|
17
|
+
}
|
|
18
|
+
const parent = path_1.default.dirname(current);
|
|
19
|
+
if (parent === current) {
|
|
20
|
+
return fallback;
|
|
21
|
+
}
|
|
22
|
+
current = parent;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
function resolveConfiguredRoots(configured, fallbackRoot, delimiter = path_1.default.delimiter) {
|
|
26
|
+
const roots = (configured ?? '')
|
|
27
|
+
.split(delimiter)
|
|
28
|
+
.map((item) => item.trim())
|
|
29
|
+
.filter(Boolean);
|
|
30
|
+
return (roots.length > 0 ? roots : [fallbackRoot]).map((root) => path_1.default.resolve(root));
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=workspace-root.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workspace-root.js","sourceRoot":"","sources":["../../../packages/workspace/src/workspace-root.ts"],"names":[],"mappings":";;;;;AAUA,8CAgBC;AAED,wDAaC;AAzCD,2BAAgC;AAChC,gDAAwB;AASxB,SAAgB,iBAAiB,CAAC,UAAoC,EAAE;IACtE,MAAM,QAAQ,GAAG,cAAI,CAAC,OAAO,CAAC,OAAO,CAAC,QAAQ,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;IACjE,IAAI,OAAO,GAAG,cAAI,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,IAAI,OAAO,CAAC,QAAQ,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;IACjF,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,IAAI,CAAC,qBAAqB,CAAC,CAAC;IAEnE,SAAS,CAAC;QACR,IAAI,WAAW,CAAC,KAAK,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,IAAA,eAAU,EAAC,cAAI,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;YAC1E,OAAO,OAAO,CAAC;QACjB,CAAC;QAED,MAAM,MAAM,GAAG,cAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QACrC,IAAI,MAAM,KAAK,OAAO,EAAE,CAAC;YACvB,OAAO,QAAQ,CAAC;QAClB,CAAC;QACD,OAAO,GAAG,MAAM,CAAC;IACnB,CAAC;AACH,CAAC;AAED,SAAgB,sBAAsB,CACpC,UAA8B,EAC9B,YAAoB,EACpB,SAAS,GAAG,cAAI,CAAC,SAAS;IAE1B,MAAM,KAAK,GAAG,CAAC,UAAU,IAAI,EAAE,CAAC;SAC7B,KAAK,CAAC,SAAS,CAAC;SAChB,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;SAC1B,MAAM,CAAC,OAAO,CAAC,CAAC;IAEnB,OAAO,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAC9D,cAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CACnB,CAAC;AACJ,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@dofe/infra-workspace",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Workspace and managed-path primitives for dofe.ai runtimes",
|
|
5
|
+
"engines": {
|
|
6
|
+
"node": ">=20.19.0"
|
|
7
|
+
},
|
|
8
|
+
"main": "dist/index.js",
|
|
9
|
+
"types": "dist/index.d.ts",
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"default": "./dist/index.js"
|
|
14
|
+
},
|
|
15
|
+
"./docker-volume": {
|
|
16
|
+
"types": "./dist/docker-volume.d.ts",
|
|
17
|
+
"default": "./dist/docker-volume.js"
|
|
18
|
+
},
|
|
19
|
+
"./path-policy": {
|
|
20
|
+
"types": "./dist/path-policy.d.ts",
|
|
21
|
+
"default": "./dist/path-policy.js"
|
|
22
|
+
},
|
|
23
|
+
"./workspace-root": {
|
|
24
|
+
"types": "./dist/workspace-root.d.ts",
|
|
25
|
+
"default": "./dist/workspace-root.js"
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
"publishConfig": {
|
|
29
|
+
"access": "public"
|
|
30
|
+
},
|
|
31
|
+
"files": [
|
|
32
|
+
"dist",
|
|
33
|
+
"test",
|
|
34
|
+
"package.json"
|
|
35
|
+
],
|
|
36
|
+
"license": "UNLICENSED",
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"@types/node": "^25.9.4",
|
|
39
|
+
"rimraf": "^6.1.2",
|
|
40
|
+
"typescript": "^6.0.3"
|
|
41
|
+
},
|
|
42
|
+
"scripts": {
|
|
43
|
+
"build": "tsc",
|
|
44
|
+
"typecheck": "tsc --noEmit",
|
|
45
|
+
"clean": "rimraf dist",
|
|
46
|
+
"test:smoke": "node --test test/*.smoke.mjs",
|
|
47
|
+
"postbuild": "node ../../scripts/generate-exports.mjs"
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import test from 'node:test';
|
|
3
|
+
import os from 'node:os';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import { mkdir, writeFile } from 'node:fs/promises';
|
|
6
|
+
import {
|
|
7
|
+
buildDockerVolumeArg,
|
|
8
|
+
findWorkspaceRoot,
|
|
9
|
+
interpolatePathTemplate,
|
|
10
|
+
isSameOrChildPath,
|
|
11
|
+
resolveAllowedTargetPath,
|
|
12
|
+
resolveConfiguredRoots,
|
|
13
|
+
} from '../dist/index.js';
|
|
14
|
+
|
|
15
|
+
test('isSameOrChildPath accepts exact paths and descendants only', () => {
|
|
16
|
+
const root = path.join(os.tmpdir(), 'infra-workspace-root');
|
|
17
|
+
|
|
18
|
+
assert.equal(isSameOrChildPath(root, root), true);
|
|
19
|
+
assert.equal(isSameOrChildPath(root, path.join(root, 'child')), true);
|
|
20
|
+
assert.equal(isSameOrChildPath(root, `${root}-sibling`), false);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
test('resolveAllowedTargetPath validates allowed absolute directories', async () => {
|
|
24
|
+
const root = path.join(os.tmpdir(), `infra-workspace-${Date.now()}`);
|
|
25
|
+
await mkdir(root, { recursive: true });
|
|
26
|
+
const child = path.join(root, 'repo');
|
|
27
|
+
await mkdir(child);
|
|
28
|
+
|
|
29
|
+
await assert.rejects(
|
|
30
|
+
() =>
|
|
31
|
+
resolveAllowedTargetPath({
|
|
32
|
+
input: 'relative/path',
|
|
33
|
+
allowedRoots: [root],
|
|
34
|
+
}),
|
|
35
|
+
/absolute path/,
|
|
36
|
+
);
|
|
37
|
+
assert.equal(
|
|
38
|
+
await resolveAllowedTargetPath({
|
|
39
|
+
input: child,
|
|
40
|
+
allowedRoots: [root],
|
|
41
|
+
directoryOnly: true,
|
|
42
|
+
}),
|
|
43
|
+
child,
|
|
44
|
+
);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
test('findWorkspaceRoot and configured roots support monorepo markers', async () => {
|
|
48
|
+
const root = path.join(os.tmpdir(), `infra-workspace-marker-${Date.now()}`);
|
|
49
|
+
const nested = path.join(root, 'apps', 'api');
|
|
50
|
+
await mkdir(nested, { recursive: true });
|
|
51
|
+
await writeFile(path.join(root, 'pnpm-workspace.yaml'), 'packages: []\n');
|
|
52
|
+
|
|
53
|
+
assert.equal(findWorkspaceRoot({ startDir: nested }), root);
|
|
54
|
+
assert.deepEqual(resolveConfiguredRoots('', root), [root]);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
test('path templates and Docker volume args are deterministic', () => {
|
|
58
|
+
assert.equal(
|
|
59
|
+
interpolatePathTemplate('/workspace/{scopeId}/{agentId}', {
|
|
60
|
+
scopeId: 'team-1',
|
|
61
|
+
agentId: 'bot-1',
|
|
62
|
+
}),
|
|
63
|
+
'/workspace/team-1/bot-1',
|
|
64
|
+
);
|
|
65
|
+
assert.equal(
|
|
66
|
+
buildDockerVolumeArg({
|
|
67
|
+
hostPath: '/workspace/agents/bot-1',
|
|
68
|
+
containerPath: '/app/workspace',
|
|
69
|
+
access: 'ro',
|
|
70
|
+
}),
|
|
71
|
+
'/workspace/agents/bot-1:/app/workspace:ro',
|
|
72
|
+
);
|
|
73
|
+
});
|