@herdctl/core 2.1.0 → 3.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/config/__tests__/agent.test.js +67 -48
- package/dist/config/__tests__/agent.test.js.map +1 -1
- package/dist/config/__tests__/loader.test.js +22 -26
- package/dist/config/__tests__/loader.test.js.map +1 -1
- package/dist/config/__tests__/merge.test.js +32 -77
- package/dist/config/__tests__/merge.test.js.map +1 -1
- package/dist/config/__tests__/parser.test.js +30 -48
- package/dist/config/__tests__/parser.test.js.map +1 -1
- package/dist/config/__tests__/schema.test.js +8 -36
- package/dist/config/__tests__/schema.test.js.map +1 -1
- package/dist/config/index.d.ts +2 -2
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/index.js +1 -1
- package/dist/config/index.js.map +1 -1
- package/dist/config/merge.d.ts +8 -14
- package/dist/config/merge.d.ts.map +1 -1
- package/dist/config/merge.js +11 -6
- package/dist/config/merge.js.map +1 -1
- package/dist/config/schema.d.ts +91 -271
- package/dist/config/schema.d.ts.map +1 -1
- package/dist/config/schema.js +13 -13
- package/dist/config/schema.js.map +1 -1
- package/dist/runner/__tests__/sdk-adapter.test.js +25 -159
- package/dist/runner/__tests__/sdk-adapter.test.js.map +1 -1
- package/dist/runner/runtime/cli-runtime.d.ts.map +1 -1
- package/dist/runner/runtime/cli-runtime.js +6 -28
- package/dist/runner/runtime/cli-runtime.js.map +1 -1
- package/dist/runner/runtime/container-manager.d.ts.map +1 -1
- package/dist/runner/runtime/container-manager.js +9 -1
- package/dist/runner/runtime/container-manager.js.map +1 -1
- package/dist/runner/sdk-adapter.d.ts.map +1 -1
- package/dist/runner/sdk-adapter.js +7 -21
- package/dist/runner/sdk-adapter.js.map +1 -1
- package/dist/state/job-metadata.d.ts.map +1 -1
- package/dist/state/job-metadata.js +6 -1
- package/dist/state/job-metadata.js.map +1 -1
- package/dist/state/session.d.ts.map +1 -1
- package/dist/state/session.js +6 -2
- package/dist/state/session.js.map +1 -1
- package/dist/state/utils/__tests__/path-safety.test.d.ts +2 -0
- package/dist/state/utils/__tests__/path-safety.test.d.ts.map +1 -0
- package/dist/state/utils/__tests__/path-safety.test.js +182 -0
- package/dist/state/utils/__tests__/path-safety.test.js.map +1 -0
- package/dist/state/utils/index.d.ts +1 -0
- package/dist/state/utils/index.d.ts.map +1 -1
- package/dist/state/utils/index.js +1 -0
- package/dist/state/utils/index.js.map +1 -1
- package/dist/state/utils/path-safety.d.ts +51 -0
- package/dist/state/utils/path-safety.d.ts.map +1 -0
- package/dist/state/utils/path-safety.js +75 -0
- package/dist/state/utils/path-safety.js.map +1 -0
- package/package.json +2 -2
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Path safety utilities for state file operations
|
|
3
|
+
*
|
|
4
|
+
* Provides defense-in-depth protection against path traversal attacks
|
|
5
|
+
* when constructing file paths from user-controlled identifiers.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Error thrown when a path traversal attempt is detected
|
|
9
|
+
*/
|
|
10
|
+
export declare class PathTraversalError extends Error {
|
|
11
|
+
readonly baseDir: string;
|
|
12
|
+
readonly identifier: string;
|
|
13
|
+
readonly resultPath: string;
|
|
14
|
+
constructor(baseDir: string, identifier: string, resultPath: string);
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Pattern for valid identifiers (agent names, etc.)
|
|
18
|
+
* Must start with alphanumeric, can contain alphanumeric, underscore, hyphen
|
|
19
|
+
*/
|
|
20
|
+
export declare const SAFE_IDENTIFIER_PATTERN: RegExp;
|
|
21
|
+
/**
|
|
22
|
+
* Validate that an identifier is safe for use in file paths
|
|
23
|
+
*
|
|
24
|
+
* @param identifier - The identifier to validate (agent name, etc.)
|
|
25
|
+
* @returns true if valid, false if not
|
|
26
|
+
*/
|
|
27
|
+
export declare function isValidIdentifier(identifier: string): boolean;
|
|
28
|
+
/**
|
|
29
|
+
* Build a safe file path within a base directory
|
|
30
|
+
*
|
|
31
|
+
* This function provides defense-in-depth by:
|
|
32
|
+
* 1. Checking the identifier against a safe pattern
|
|
33
|
+
* 2. Resolving the final path and verifying it stays within the base directory
|
|
34
|
+
*
|
|
35
|
+
* @param baseDir - The base directory that the file must stay within
|
|
36
|
+
* @param identifier - The user-provided identifier (agent name, etc.)
|
|
37
|
+
* @param extension - File extension including the dot (e.g., ".json", ".yaml")
|
|
38
|
+
* @returns The safe, resolved file path
|
|
39
|
+
* @throws PathTraversalError if the path would escape the base directory
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* ```typescript
|
|
43
|
+
* const filePath = buildSafeFilePath("/home/user/.herdctl/sessions", "my-agent", ".json");
|
|
44
|
+
* // Returns: "/home/user/.herdctl/sessions/my-agent.json"
|
|
45
|
+
*
|
|
46
|
+
* // This would throw PathTraversalError:
|
|
47
|
+
* buildSafeFilePath("/home/user/.herdctl/sessions", "../../../etc/passwd", ".json");
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
export declare function buildSafeFilePath(baseDir: string, identifier: string, extension: string): string;
|
|
51
|
+
//# sourceMappingURL=path-safety.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"path-safety.d.ts","sourceRoot":"","sources":["../../../src/state/utils/path-safety.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH;;GAEG;AACH,qBAAa,kBAAmB,SAAQ,KAAK;IAC3C,SAAgB,OAAO,EAAE,MAAM,CAAC;IAChC,SAAgB,UAAU,EAAE,MAAM,CAAC;IACnC,SAAgB,UAAU,EAAE,MAAM,CAAC;gBAEvB,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM;CASpE;AAED;;;GAGG;AACH,eAAO,MAAM,uBAAuB,QAAgC,CAAC;AAErE;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAE7D;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,GAChB,MAAM,CAuBR"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Path safety utilities for state file operations
|
|
3
|
+
*
|
|
4
|
+
* Provides defense-in-depth protection against path traversal attacks
|
|
5
|
+
* when constructing file paths from user-controlled identifiers.
|
|
6
|
+
*/
|
|
7
|
+
import { resolve, join } from "node:path";
|
|
8
|
+
/**
|
|
9
|
+
* Error thrown when a path traversal attempt is detected
|
|
10
|
+
*/
|
|
11
|
+
export class PathTraversalError extends Error {
|
|
12
|
+
baseDir;
|
|
13
|
+
identifier;
|
|
14
|
+
resultPath;
|
|
15
|
+
constructor(baseDir, identifier, resultPath) {
|
|
16
|
+
super(`Path traversal detected: identifier "${identifier}" would resolve to "${resultPath}" which is outside base directory "${baseDir}"`);
|
|
17
|
+
this.name = "PathTraversalError";
|
|
18
|
+
this.baseDir = baseDir;
|
|
19
|
+
this.identifier = identifier;
|
|
20
|
+
this.resultPath = resultPath;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Pattern for valid identifiers (agent names, etc.)
|
|
25
|
+
* Must start with alphanumeric, can contain alphanumeric, underscore, hyphen
|
|
26
|
+
*/
|
|
27
|
+
export const SAFE_IDENTIFIER_PATTERN = /^[a-zA-Z0-9][a-zA-Z0-9_-]*$/;
|
|
28
|
+
/**
|
|
29
|
+
* Validate that an identifier is safe for use in file paths
|
|
30
|
+
*
|
|
31
|
+
* @param identifier - The identifier to validate (agent name, etc.)
|
|
32
|
+
* @returns true if valid, false if not
|
|
33
|
+
*/
|
|
34
|
+
export function isValidIdentifier(identifier) {
|
|
35
|
+
return SAFE_IDENTIFIER_PATTERN.test(identifier);
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Build a safe file path within a base directory
|
|
39
|
+
*
|
|
40
|
+
* This function provides defense-in-depth by:
|
|
41
|
+
* 1. Checking the identifier against a safe pattern
|
|
42
|
+
* 2. Resolving the final path and verifying it stays within the base directory
|
|
43
|
+
*
|
|
44
|
+
* @param baseDir - The base directory that the file must stay within
|
|
45
|
+
* @param identifier - The user-provided identifier (agent name, etc.)
|
|
46
|
+
* @param extension - File extension including the dot (e.g., ".json", ".yaml")
|
|
47
|
+
* @returns The safe, resolved file path
|
|
48
|
+
* @throws PathTraversalError if the path would escape the base directory
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* ```typescript
|
|
52
|
+
* const filePath = buildSafeFilePath("/home/user/.herdctl/sessions", "my-agent", ".json");
|
|
53
|
+
* // Returns: "/home/user/.herdctl/sessions/my-agent.json"
|
|
54
|
+
*
|
|
55
|
+
* // This would throw PathTraversalError:
|
|
56
|
+
* buildSafeFilePath("/home/user/.herdctl/sessions", "../../../etc/passwd", ".json");
|
|
57
|
+
* ```
|
|
58
|
+
*/
|
|
59
|
+
export function buildSafeFilePath(baseDir, identifier, extension) {
|
|
60
|
+
// First line of defense: validate identifier format
|
|
61
|
+
if (!isValidIdentifier(identifier)) {
|
|
62
|
+
throw new PathTraversalError(baseDir, identifier, `(invalid identifier: must match ${SAFE_IDENTIFIER_PATTERN})`);
|
|
63
|
+
}
|
|
64
|
+
// Construct the file path
|
|
65
|
+
const fileName = `${identifier}${extension}`;
|
|
66
|
+
const filePath = join(baseDir, fileName);
|
|
67
|
+
// Second line of defense: verify the resolved path stays within baseDir
|
|
68
|
+
const resolvedBase = resolve(baseDir);
|
|
69
|
+
const resolvedPath = resolve(filePath);
|
|
70
|
+
if (!resolvedPath.startsWith(resolvedBase + "/") && resolvedPath !== resolvedBase) {
|
|
71
|
+
throw new PathTraversalError(baseDir, identifier, resolvedPath);
|
|
72
|
+
}
|
|
73
|
+
return filePath;
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=path-safety.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"path-safety.js","sourceRoot":"","sources":["../../../src/state/utils/path-safety.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAE1C;;GAEG;AACH,MAAM,OAAO,kBAAmB,SAAQ,KAAK;IAC3B,OAAO,CAAS;IAChB,UAAU,CAAS;IACnB,UAAU,CAAS;IAEnC,YAAY,OAAe,EAAE,UAAkB,EAAE,UAAkB;QACjE,KAAK,CACH,wCAAwC,UAAU,uBAAuB,UAAU,sCAAsC,OAAO,GAAG,CACpI,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,oBAAoB,CAAC;QACjC,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;QAC7B,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;IAC/B,CAAC;CACF;AAED;;;GAGG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG,6BAA6B,CAAC;AAErE;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB,CAAC,UAAkB;IAClD,OAAO,uBAAuB,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;AAClD,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,UAAU,iBAAiB,CAC/B,OAAe,EACf,UAAkB,EAClB,SAAiB;IAEjB,oDAAoD;IACpD,IAAI,CAAC,iBAAiB,CAAC,UAAU,CAAC,EAAE,CAAC;QACnC,MAAM,IAAI,kBAAkB,CAC1B,OAAO,EACP,UAAU,EACV,mCAAmC,uBAAuB,GAAG,CAC9D,CAAC;IACJ,CAAC;IAED,0BAA0B;IAC1B,MAAM,QAAQ,GAAG,GAAG,UAAU,GAAG,SAAS,EAAE,CAAC;IAC7C,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IAEzC,wEAAwE;IACxE,MAAM,YAAY,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACtC,MAAM,YAAY,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IAEvC,IAAI,CAAC,YAAY,CAAC,UAAU,CAAC,YAAY,GAAG,GAAG,CAAC,IAAI,YAAY,KAAK,YAAY,EAAE,CAAC;QAClF,MAAM,IAAI,kBAAkB,CAAC,OAAO,EAAE,UAAU,EAAE,YAAY,CAAC,CAAC;IAClE,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@herdctl/core",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.1",
|
|
4
4
|
"description": "Core library for herdctl fleet management",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"zod": "^3.22.0"
|
|
21
21
|
},
|
|
22
22
|
"peerDependencies": {
|
|
23
|
-
"@herdctl/discord": "0.1.
|
|
23
|
+
"@herdctl/discord": "0.1.9"
|
|
24
24
|
},
|
|
25
25
|
"peerDependenciesMeta": {
|
|
26
26
|
"@herdctl/discord": {
|