@pellux/goodvibes-sdk 0.18.20 → 0.18.21
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/_internal/platform/core/deterministic-replay.d.ts +2 -1
- package/dist/_internal/platform/core/deterministic-replay.d.ts.map +1 -1
- package/dist/_internal/platform/core/deterministic-replay.js +11 -5
- package/dist/_internal/platform/core/replay-command-handler.js +1 -1
- package/package.json +1 -1
|
@@ -83,7 +83,7 @@ export interface ReplayEngineSnapshot {
|
|
|
83
83
|
* engine.step(5); // advance five events
|
|
84
84
|
* engine.seek(10); // jump to rev 10
|
|
85
85
|
* const report = engine.diff(); // compare current to recorded
|
|
86
|
-
* engine.export('
|
|
86
|
+
* engine.export('replay.json'); // write report inside the project root
|
|
87
87
|
* ```
|
|
88
88
|
*/
|
|
89
89
|
export declare class DeterministicReplayEngine {
|
|
@@ -102,6 +102,7 @@ export declare class DeterministicReplayEngine {
|
|
|
102
102
|
private _turnSummaries;
|
|
103
103
|
private readonly _subscribers;
|
|
104
104
|
constructor(projectRoot: string);
|
|
105
|
+
private _isInsideRoot;
|
|
105
106
|
/**
|
|
106
107
|
* Load a run for replay.
|
|
107
108
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deterministic-replay.d.ts","sourceRoot":"","sources":["../../../../src/_internal/platform/core/deterministic-replay.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"deterministic-replay.d.ts","sourceRoot":"","sources":["../../../../src/_internal/platform/core/deterministic-replay.ts"],"names":[],"mappings":"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"}
|
|
@@ -11,7 +11,8 @@
|
|
|
11
11
|
* initial snapshot. This isolation ensures replay never affects live state.
|
|
12
12
|
*/
|
|
13
13
|
import { writeFile } from 'node:fs/promises';
|
|
14
|
-
import {
|
|
14
|
+
import { tmpdir } from 'node:os';
|
|
15
|
+
import { normalize, relative, resolve } from 'node:path';
|
|
15
16
|
import { logger } from '../utils/logger.js';
|
|
16
17
|
import { summarizeError } from '../utils/error-display.js';
|
|
17
18
|
// ── DeterministicReplayEngine ──────────────────────────────────────────────
|
|
@@ -26,7 +27,7 @@ import { summarizeError } from '../utils/error-display.js';
|
|
|
26
27
|
* engine.step(5); // advance five events
|
|
27
28
|
* engine.seek(10); // jump to rev 10
|
|
28
29
|
* const report = engine.diff(); // compare current to recorded
|
|
29
|
-
* engine.export('
|
|
30
|
+
* engine.export('replay.json'); // write report inside the project root
|
|
30
31
|
* ```
|
|
31
32
|
*/
|
|
32
33
|
export class DeterministicReplayEngine {
|
|
@@ -49,6 +50,10 @@ export class DeterministicReplayEngine {
|
|
|
49
50
|
constructor(projectRoot) {
|
|
50
51
|
this._projectRoot = resolve(projectRoot);
|
|
51
52
|
}
|
|
53
|
+
_isInsideRoot(root, candidate) {
|
|
54
|
+
const rel = relative(root, candidate);
|
|
55
|
+
return rel === '' || (!rel.startsWith('..') && !rel.startsWith('/'));
|
|
56
|
+
}
|
|
52
57
|
// ── Public API ─────────────────────────────────────────────────────────
|
|
53
58
|
/**
|
|
54
59
|
* Load a run for replay.
|
|
@@ -253,10 +258,11 @@ export class DeterministicReplayEngine {
|
|
|
253
258
|
logger.warn('[DeterministicReplayEngine] export called with no run loaded');
|
|
254
259
|
return;
|
|
255
260
|
}
|
|
256
|
-
|
|
261
|
+
const tempRoot = resolve(tmpdir());
|
|
262
|
+
// Path traversal guard — confine exports to the project directory or the active temp root.
|
|
257
263
|
const resolved = resolve(this._projectRoot, normalize(filePath));
|
|
258
|
-
if (!
|
|
259
|
-
throw new Error(`Export path must be within project directory or
|
|
264
|
+
if (!this._isInsideRoot(this._projectRoot, resolved) && !this._isInsideRoot(tempRoot, resolved)) {
|
|
265
|
+
throw new Error(`Export path must be within project directory or the active temp root. Got: ${resolved}`);
|
|
260
266
|
}
|
|
261
267
|
const report = {
|
|
262
268
|
runId: this._runId,
|
|
@@ -189,7 +189,7 @@ export function handleReplayCommand(deps, subcommand, args, ledger) {
|
|
|
189
189
|
if (!filePath) {
|
|
190
190
|
return {
|
|
191
191
|
ok: false,
|
|
192
|
-
output: 'Usage: /replay export <path>\n\nExample: /replay export
|
|
192
|
+
output: 'Usage: /replay export <path>\n\nExample: /replay export replay-report.json',
|
|
193
193
|
};
|
|
194
194
|
}
|
|
195
195
|
// engine.export() is async and validates the path before writing.
|
package/package.json
CHANGED