configproof 0.3.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/LICENSE +21 -0
- package/README.md +217 -0
- package/dist/adapters/dotenv.d.ts +3 -0
- package/dist/adapters/dotenv.js +277 -0
- package/dist/adapters/dotenv.js.map +1 -0
- package/dist/adapters/native-env.d.ts +7 -0
- package/dist/adapters/native-env.js +196 -0
- package/dist/adapters/native-env.js.map +1 -0
- package/dist/adapters/registry.d.ts +7 -0
- package/dist/adapters/registry.js +30 -0
- package/dist/adapters/registry.js.map +1 -0
- package/dist/agent/server.d.ts +15 -0
- package/dist/agent/server.js +254 -0
- package/dist/agent/server.js.map +1 -0
- package/dist/analysis/diagnose.d.ts +64 -0
- package/dist/analysis/diagnose.js +142 -0
- package/dist/analysis/diagnose.js.map +1 -0
- package/dist/analysis/history.d.ts +52 -0
- package/dist/analysis/history.js +119 -0
- package/dist/analysis/history.js.map +1 -0
- package/dist/analysis/policy.d.ts +161 -0
- package/dist/analysis/policy.js +192 -0
- package/dist/analysis/policy.js.map +1 -0
- package/dist/analysis/provenance.d.ts +45 -0
- package/dist/analysis/provenance.js +144 -0
- package/dist/analysis/provenance.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +286 -0
- package/dist/cli.js.map +1 -0
- package/dist/core/analyze.d.ts +46 -0
- package/dist/core/analyze.js +168 -0
- package/dist/core/analyze.js.map +1 -0
- package/dist/core/collect.d.ts +5 -0
- package/dist/core/collect.js +147 -0
- package/dist/core/collect.js.map +1 -0
- package/dist/core/export.d.ts +53 -0
- package/dist/core/export.js +155 -0
- package/dist/core/export.js.map +1 -0
- package/dist/core/io.d.ts +13 -0
- package/dist/core/io.js +100 -0
- package/dist/core/io.js.map +1 -0
- package/dist/core/privacy.d.ts +25 -0
- package/dist/core/privacy.js +113 -0
- package/dist/core/privacy.js.map +1 -0
- package/dist/core/schema.d.ts +2149 -0
- package/dist/core/schema.js +181 -0
- package/dist/core/schema.js.map +1 -0
- package/dist/demo.d.ts +1 -0
- package/dist/demo.js +45 -0
- package/dist/demo.js.map +1 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.js +63 -0
- package/dist/index.js.map +1 -0
- package/dist/launcher.d.ts +27 -0
- package/dist/launcher.js +122 -0
- package/dist/launcher.js.map +1 -0
- package/dist/report/html.d.ts +5 -0
- package/dist/report/html.js +109 -0
- package/dist/report/html.js.map +1 -0
- package/dist/runtime/api.d.ts +44 -0
- package/dist/runtime/api.js +29 -0
- package/dist/runtime/api.js.map +1 -0
- package/dist/runtime/callsite.d.ts +3 -0
- package/dist/runtime/callsite.js +61 -0
- package/dist/runtime/callsite.js.map +1 -0
- package/dist/runtime/children.d.ts +8 -0
- package/dist/runtime/children.js +69 -0
- package/dist/runtime/children.js.map +1 -0
- package/dist/runtime/environment.d.ts +3 -0
- package/dist/runtime/environment.js +53 -0
- package/dist/runtime/environment.js.map +1 -0
- package/dist/runtime/preload.d.ts +1 -0
- package/dist/runtime/preload.js +117 -0
- package/dist/runtime/preload.js.map +1 -0
- package/dist/runtime/recorder.d.ts +59 -0
- package/dist/runtime/recorder.js +254 -0
- package/dist/runtime/recorder.js.map +1 -0
- package/dist/runtime/workers.d.ts +12 -0
- package/dist/runtime/workers.js +127 -0
- package/dist/runtime/workers.js.map +1 -0
- package/docs/ARCHITECTURE.md +54 -0
- package/docs/COMPATIBILITY.md +24 -0
- package/docs/PRIVACY.md +17 -0
- package/docs/VALIDATION.md +42 -0
- package/fixtures/bypass/app.cjs +6 -0
- package/fixtures/bypass/early.cjs +2 -0
- package/fixtures/child-process/child.cjs +2 -0
- package/fixtures/child-process/parent.cjs +5 -0
- package/fixtures/custom-target/app.cjs +4 -0
- package/fixtures/custom-target/sample.env +1 -0
- package/fixtures/esm/app.mjs +5 -0
- package/fixtures/exit-code/app.cjs +4 -0
- package/fixtures/failure-boundary/app.cjs +7 -0
- package/fixtures/load-order/app.cjs +9 -0
- package/fixtures/load-order/first.env +1 -0
- package/fixtures/load-order/second.env +1 -0
- package/fixtures/manifest.json +16 -0
- package/fixtures/native-env/app.cjs +6 -0
- package/fixtures/native-env/failure.cjs +4 -0
- package/fixtures/native-env/sample.env +1 -0
- package/fixtures/native-env/startup.cjs +2 -0
- package/fixtures/runtime-mutation/app.cjs +12 -0
- package/fixtures/source-map/input.ts +5 -0
- package/fixtures/source-map/tsconfig.json +7 -0
- package/fixtures/stale-inheritance/app.cjs +4 -0
- package/fixtures/stale-inheritance/sample.env +1 -0
- package/fixtures/v03-manifest.json +32 -0
- package/fixtures/worker/parent.cjs +3 -0
- package/fixtures/worker/worker.cjs +2 -0
- package/fixtures/worker-modes/parent.cjs +17 -0
- package/fixtures/worker-modes/worker.cjs +4 -0
- package/package.json +64 -0
- package/policies/configtrace-policy.yaml +23 -0
- package/policies/issue-share.yaml +12 -0
- package/policies/minimal.yaml +8 -0
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { WatchSet, PathScrubber } from '../core/privacy';
|
|
2
|
+
import { type AdapterManifest, type Observation, type Origin, type SafeValue, type Notice, type ProcessInfo } from '../core/schema';
|
|
3
|
+
import type { RuntimeConfig } from './api';
|
|
4
|
+
type ValueOperation = 'baseline' | 'read' | 'write' | 'delete' | 'candidate' | 'skip';
|
|
5
|
+
interface RecordOptions {
|
|
6
|
+
before?: string;
|
|
7
|
+
hasBefore?: boolean;
|
|
8
|
+
candidate?: string;
|
|
9
|
+
hasCandidate?: boolean;
|
|
10
|
+
origin?: Origin;
|
|
11
|
+
outcome?: Observation['outcome'];
|
|
12
|
+
site?: Observation['site'];
|
|
13
|
+
}
|
|
14
|
+
export declare class Recorder {
|
|
15
|
+
readonly config: RuntimeConfig;
|
|
16
|
+
readonly watch: WatchSet;
|
|
17
|
+
readonly paths: PathScrubber;
|
|
18
|
+
readonly process: ProcessInfo;
|
|
19
|
+
private readonly writer;
|
|
20
|
+
private readonly start;
|
|
21
|
+
private readonly states;
|
|
22
|
+
private readonly keys;
|
|
23
|
+
private readonly notices;
|
|
24
|
+
private readonly origins;
|
|
25
|
+
private seq;
|
|
26
|
+
private count;
|
|
27
|
+
private dropped;
|
|
28
|
+
private depth;
|
|
29
|
+
private stopped;
|
|
30
|
+
private adapterIds;
|
|
31
|
+
sharedEnvironment: boolean;
|
|
32
|
+
constructor(config: RuntimeConfig, instanceId: string, parentId?: string, worker?: {
|
|
33
|
+
threadId: number;
|
|
34
|
+
environmentMode: ProcessInfo['environmentMode'];
|
|
35
|
+
});
|
|
36
|
+
get suppressed(): boolean;
|
|
37
|
+
suppress<T>(action: () => T): T;
|
|
38
|
+
withOrigin<T>(origin: Origin | ((key: string) => Origin), action: () => T): T;
|
|
39
|
+
currentOrigin(key: string): Origin | undefined;
|
|
40
|
+
token(key: string, value: string | undefined): SafeValue;
|
|
41
|
+
site(): Observation['site'];
|
|
42
|
+
latestId(key: string): string | undefined;
|
|
43
|
+
notice(notice: Notice): void;
|
|
44
|
+
private emit;
|
|
45
|
+
/** Instrumentation failures are contained; the original operation has already run. */
|
|
46
|
+
observe(operation: ValueOperation, key: string, raw: string | undefined, options?: RecordOptions): Observation | undefined;
|
|
47
|
+
declareAdapter(manifest: AdapterManifest, installedVersion?: string): void;
|
|
48
|
+
loader(file: string | undefined, outcome: 'read-success' | 'read-failed' | 'declared', options?: {
|
|
49
|
+
kind?: 'dotenv' | 'native-env';
|
|
50
|
+
phase?: 'startup' | 'runtime';
|
|
51
|
+
method?: Observation['loaderMethod'];
|
|
52
|
+
confidence?: Origin['confidence'];
|
|
53
|
+
}): void;
|
|
54
|
+
child(childId: string, outcome: 'spawned' | 'spawn-failed'): void;
|
|
55
|
+
worker(childId: string, outcome: 'spawned' | 'spawn-failed', environmentMode: Observation['environmentMode']): void;
|
|
56
|
+
boundary(kind: 'manual' | 'uncaught-exception'): Observation | undefined;
|
|
57
|
+
finish(exitCode: number): void;
|
|
58
|
+
}
|
|
59
|
+
export {};
|
|
@@ -0,0 +1,254 @@
|
|
|
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.Recorder = void 0;
|
|
7
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
8
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
9
|
+
const privacy_1 = require("../core/privacy");
|
|
10
|
+
const schema_1 = require("../core/schema");
|
|
11
|
+
const callsite_1 = require("./callsite");
|
|
12
|
+
class StreamWriter {
|
|
13
|
+
maxBytes;
|
|
14
|
+
fd;
|
|
15
|
+
bytes = 0;
|
|
16
|
+
closed = false;
|
|
17
|
+
failed = false;
|
|
18
|
+
constructor(file, maxBytes) {
|
|
19
|
+
this.maxBytes = maxBytes;
|
|
20
|
+
this.fd = node_fs_1.default.openSync(file, 'wx', 0o600);
|
|
21
|
+
}
|
|
22
|
+
write(record, reserved = false) {
|
|
23
|
+
if (this.closed || this.failed)
|
|
24
|
+
return false;
|
|
25
|
+
try {
|
|
26
|
+
const data = Buffer.from(JSON.stringify(record) + '\n');
|
|
27
|
+
if (!reserved && this.bytes + data.length > this.maxBytes - 8192)
|
|
28
|
+
return false;
|
|
29
|
+
if (this.bytes + data.length > this.maxBytes)
|
|
30
|
+
return false;
|
|
31
|
+
let offset = 0;
|
|
32
|
+
while (offset < data.length) {
|
|
33
|
+
const n = node_fs_1.default.writeSync(this.fd, data, offset, data.length - offset);
|
|
34
|
+
if (n <= 0)
|
|
35
|
+
throw new Error('Recorder write failed');
|
|
36
|
+
offset += n;
|
|
37
|
+
}
|
|
38
|
+
this.bytes += data.length;
|
|
39
|
+
return true;
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
this.failed = true;
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
close() {
|
|
47
|
+
if (!this.closed) {
|
|
48
|
+
this.closed = true;
|
|
49
|
+
try {
|
|
50
|
+
node_fs_1.default.closeSync(this.fd);
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
this.failed = true;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
class Recorder {
|
|
59
|
+
config;
|
|
60
|
+
watch;
|
|
61
|
+
paths;
|
|
62
|
+
process;
|
|
63
|
+
writer;
|
|
64
|
+
start = process.hrtime.bigint();
|
|
65
|
+
states = new Map();
|
|
66
|
+
keys = new Set();
|
|
67
|
+
notices = new Set();
|
|
68
|
+
origins = [];
|
|
69
|
+
seq = 0;
|
|
70
|
+
count = 0;
|
|
71
|
+
dropped = 0;
|
|
72
|
+
depth = 0;
|
|
73
|
+
stopped = false;
|
|
74
|
+
adapterIds = new Set();
|
|
75
|
+
sharedEnvironment = false;
|
|
76
|
+
constructor(config, instanceId, parentId, worker) {
|
|
77
|
+
this.config = config;
|
|
78
|
+
this.watch = new privacy_1.WatchSet(config.watch, process.platform === 'win32' && !worker);
|
|
79
|
+
this.paths = new privacy_1.PathScrubber(config.root, config.comparison.secret);
|
|
80
|
+
this.process = {
|
|
81
|
+
id: instanceId, parentId, role: worker ? 'worker' : parentId ? 'child' : 'root',
|
|
82
|
+
threadId: worker?.threadId, environmentMode: worker?.environmentMode,
|
|
83
|
+
caseMode: this.watch.insensitive ? 'insensitive' : 'sensitive',
|
|
84
|
+
pid: process.pid, ppid: process.ppid, node: process.version, platform: process.platform,
|
|
85
|
+
entry: this.paths.scrub(process.argv[1] || '<eval>'), startedAt: new Date().toISOString(),
|
|
86
|
+
ended: false, exitCode: null, eventsDropped: 0,
|
|
87
|
+
};
|
|
88
|
+
this.sharedEnvironment = worker?.environmentMode === 'shared';
|
|
89
|
+
this.writer = new StreamWriter(node_path_1.default.join(config.directory, `${instanceId}.jsonl`), config.maxBytes);
|
|
90
|
+
this.writer.write({ type: 'start', process: this.process }, true);
|
|
91
|
+
}
|
|
92
|
+
get suppressed() { return this.depth > 0 || this.stopped; }
|
|
93
|
+
suppress(action) { this.depth++; try {
|
|
94
|
+
return action();
|
|
95
|
+
}
|
|
96
|
+
finally {
|
|
97
|
+
this.depth--;
|
|
98
|
+
} }
|
|
99
|
+
withOrigin(origin, action) {
|
|
100
|
+
this.origins.push(typeof origin === 'function' ? origin : () => origin);
|
|
101
|
+
try {
|
|
102
|
+
return action();
|
|
103
|
+
}
|
|
104
|
+
finally {
|
|
105
|
+
this.origins.pop();
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
currentOrigin(key) { return this.origins.at(-1)?.(key); }
|
|
109
|
+
token(key, value) {
|
|
110
|
+
return (0, privacy_1.fingerprint)(this.config.comparison, this.watch.canonical(key), value);
|
|
111
|
+
}
|
|
112
|
+
site() { return this.suppress(() => (0, callsite_1.captureSite)(this.paths, this.config.sourceMaps)); }
|
|
113
|
+
latestId(key) { return this.states.get(this.watch.canonical(key))?.eventId; }
|
|
114
|
+
notice(notice) {
|
|
115
|
+
if (notice === 'worker_shared_env')
|
|
116
|
+
this.sharedEnvironment = true;
|
|
117
|
+
if (this.notices.has(notice) || this.stopped)
|
|
118
|
+
return;
|
|
119
|
+
this.notices.add(notice);
|
|
120
|
+
this.suppress(() => this.writer.write({ type: 'notice', notice }, true));
|
|
121
|
+
}
|
|
122
|
+
emit(event) {
|
|
123
|
+
if (this.stopped)
|
|
124
|
+
return;
|
|
125
|
+
if (this.count >= this.config.maxEvents) {
|
|
126
|
+
this.dropped++;
|
|
127
|
+
this.notice('event_limit');
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
const seq = this.seq++;
|
|
131
|
+
const full = { ...event, id: `${this.process.id}:${seq}`, processId: this.process.id, seq, at: Number(process.hrtime.bigint() - this.start) / 1e6 };
|
|
132
|
+
if (!this.writer.write({ type: 'event', event: full })) {
|
|
133
|
+
this.dropped++;
|
|
134
|
+
this.notice(this.writer.failed ? 'recorder_failed' : 'byte_limit');
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
this.count++;
|
|
138
|
+
return full;
|
|
139
|
+
}
|
|
140
|
+
/** Instrumentation failures are contained; the original operation has already run. */
|
|
141
|
+
observe(operation, key, raw, options = {}) {
|
|
142
|
+
if (this.suppressed || !this.watch.matches(key))
|
|
143
|
+
return;
|
|
144
|
+
return this.suppress(() => {
|
|
145
|
+
try {
|
|
146
|
+
key = this.watch.canonical(key);
|
|
147
|
+
if (!this.keys.has(key) && this.keys.size >= 256) {
|
|
148
|
+
this.dropped++;
|
|
149
|
+
this.notice('key_limit');
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
this.keys.add(key);
|
|
153
|
+
const value = this.token(key, raw);
|
|
154
|
+
const previous = this.states.get(key);
|
|
155
|
+
let origin = options.origin ?? this.currentOrigin(key);
|
|
156
|
+
let causedBy;
|
|
157
|
+
if (operation === 'read') {
|
|
158
|
+
if (previous && (0, privacy_1.sameValue)(previous.value, value)) {
|
|
159
|
+
causedBy = previous.eventId;
|
|
160
|
+
origin = { ...previous.origin, confidence: 'inferred' };
|
|
161
|
+
}
|
|
162
|
+
else
|
|
163
|
+
origin = { kind: 'unknown', confidence: 'unknown' };
|
|
164
|
+
}
|
|
165
|
+
if (!origin)
|
|
166
|
+
origin = { kind: operation === 'baseline' ? 'startup' : 'runtime', confidence: 'observed' };
|
|
167
|
+
if (origin.file)
|
|
168
|
+
origin = { ...origin, file: this.paths.scrub(origin.file) };
|
|
169
|
+
const event = this.emit({
|
|
170
|
+
key, operation, value, origin, causedBy,
|
|
171
|
+
before: options.hasBefore ? this.token(key, options.before) : undefined,
|
|
172
|
+
candidate: options.hasCandidate ? this.token(key, options.candidate) : undefined,
|
|
173
|
+
outcome: options.outcome,
|
|
174
|
+
purpose: this.origins.length ? 'loader' : 'application',
|
|
175
|
+
site: operation === 'baseline' ? undefined : options.site ?? (0, callsite_1.captureSite)(this.paths, this.config.sourceMaps),
|
|
176
|
+
});
|
|
177
|
+
if (event && ['baseline', 'write', 'delete'].includes(operation))
|
|
178
|
+
this.states.set(key, { value, eventId: event.id, origin });
|
|
179
|
+
return event;
|
|
180
|
+
}
|
|
181
|
+
catch {
|
|
182
|
+
this.notice('recorder_failed');
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
declareAdapter(manifest, installedVersion) {
|
|
188
|
+
try {
|
|
189
|
+
const checked = schema_1.AdapterManifestSchema.parse(manifest);
|
|
190
|
+
if (this.adapterIds.has(checked.id) || this.adapterIds.size >= 8)
|
|
191
|
+
return;
|
|
192
|
+
this.adapterIds.add(checked.id);
|
|
193
|
+
const written = this.suppress(() => this.writer.write({ type: 'adapter', declaration: {
|
|
194
|
+
processId: this.process.id, manifest: checked,
|
|
195
|
+
installedVersion: installedVersion?.slice(0, 80), validation: 'unverified',
|
|
196
|
+
} }, true));
|
|
197
|
+
if (!written) {
|
|
198
|
+
this.dropped++;
|
|
199
|
+
this.notice(this.writer.failed ? 'recorder_failed' : 'byte_limit');
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
catch {
|
|
203
|
+
this.notice('adapter_failed');
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
loader(file, outcome, options = {}) {
|
|
207
|
+
try {
|
|
208
|
+
this.suppress(() => this.emit({ operation: 'load', origin: {
|
|
209
|
+
kind: options.kind || 'dotenv', confidence: options.confidence || (file ? 'observed' : 'unknown'),
|
|
210
|
+
file: file ? this.paths.scrub(file) : undefined,
|
|
211
|
+
}, outcome, purpose: 'loader', phase: options.phase, loaderMethod: options.method }));
|
|
212
|
+
}
|
|
213
|
+
catch {
|
|
214
|
+
this.notice('recorder_failed');
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
child(childId, outcome) {
|
|
218
|
+
try {
|
|
219
|
+
this.suppress(() => this.emit({ operation: 'child-spawn', childId, outcome, site: (0, callsite_1.captureSite)(this.paths, this.config.sourceMaps) }));
|
|
220
|
+
}
|
|
221
|
+
catch {
|
|
222
|
+
this.notice('recorder_failed');
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
worker(childId, outcome, environmentMode) {
|
|
226
|
+
try {
|
|
227
|
+
this.suppress(() => this.emit({ operation: 'worker-spawn', childId, outcome, environmentMode, site: (0, callsite_1.captureSite)(this.paths, this.config.sourceMaps) }));
|
|
228
|
+
}
|
|
229
|
+
catch {
|
|
230
|
+
this.notice('recorder_failed');
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
boundary(kind) {
|
|
234
|
+
try {
|
|
235
|
+
this.notice('failure_boundary_recorded');
|
|
236
|
+
return this.suppress(() => this.emit({ operation: 'boundary', boundaryKind: kind, site: (0, callsite_1.captureSite)(this.paths, this.config.sourceMaps) }));
|
|
237
|
+
}
|
|
238
|
+
catch {
|
|
239
|
+
this.notice('recorder_failed');
|
|
240
|
+
return undefined;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
finish(exitCode) {
|
|
244
|
+
if (this.stopped)
|
|
245
|
+
return;
|
|
246
|
+
this.suppress(() => {
|
|
247
|
+
this.writer.write({ type: 'end', exitCode, eventsDropped: this.dropped }, true);
|
|
248
|
+
this.writer.close();
|
|
249
|
+
});
|
|
250
|
+
this.stopped = true;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
exports.Recorder = Recorder;
|
|
254
|
+
//# sourceMappingURL=recorder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recorder.js","sourceRoot":"","sources":["../../src/runtime/recorder.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { Recorder } from './recorder';
|
|
2
|
+
export declare const WORKER_SESSION_KEY = "__configtrace_worker_session_v1";
|
|
3
|
+
export interface WorkerSession {
|
|
4
|
+
configPath: string;
|
|
5
|
+
id: string;
|
|
6
|
+
parentId: string;
|
|
7
|
+
depth: number;
|
|
8
|
+
environmentMode: 'copied' | 'explicit' | 'shared';
|
|
9
|
+
}
|
|
10
|
+
/** Consume the thread-local clone, without touching process.env (especially SHARE_ENV). */
|
|
11
|
+
export declare function takeWorkerSession(): WorkerSession | undefined;
|
|
12
|
+
export declare function installWorkers(recorder: Recorder, depth: number): () => void;
|
|
@@ -0,0 +1,127 @@
|
|
|
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.WORKER_SESSION_KEY = void 0;
|
|
7
|
+
exports.takeWorkerSession = takeWorkerSession;
|
|
8
|
+
exports.installWorkers = installWorkers;
|
|
9
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
10
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
11
|
+
const node_module_1 = require("node:module");
|
|
12
|
+
const workers = require("node:worker_threads");
|
|
13
|
+
const io_1 = require("../core/io");
|
|
14
|
+
exports.WORKER_SESSION_KEY = '__configtrace_worker_session_v1';
|
|
15
|
+
/** Consume the thread-local clone, without touching process.env (especially SHARE_ENV). */
|
|
16
|
+
function takeWorkerSession() {
|
|
17
|
+
const value = workers.getEnvironmentData(exports.WORKER_SESSION_KEY);
|
|
18
|
+
workers.setEnvironmentData(exports.WORKER_SESSION_KEY, undefined);
|
|
19
|
+
if (!value || typeof value !== 'object')
|
|
20
|
+
return undefined;
|
|
21
|
+
const v = value;
|
|
22
|
+
if (typeof v.configPath !== 'string' || typeof v.id !== 'string' || typeof v.parentId !== 'string'
|
|
23
|
+
|| !Number.isInteger(v.depth) || !['copied', 'explicit', 'shared'].includes(v.environmentMode || ''))
|
|
24
|
+
return undefined;
|
|
25
|
+
return v;
|
|
26
|
+
}
|
|
27
|
+
function claimSlot(recorder) {
|
|
28
|
+
// Exclusive files make the worker budget session-wide, including workers in children.
|
|
29
|
+
for (let slot = 0; slot < recorder.config.maxWorkers; slot++) {
|
|
30
|
+
let fd;
|
|
31
|
+
try {
|
|
32
|
+
fd = node_fs_1.default.openSync(node_path_1.default.join(recorder.config.directory, `worker-slot-${slot}`), 'wx', 0o600);
|
|
33
|
+
}
|
|
34
|
+
catch (error) {
|
|
35
|
+
if (error.code === 'EEXIST')
|
|
36
|
+
continue;
|
|
37
|
+
throw error;
|
|
38
|
+
}
|
|
39
|
+
node_fs_1.default.closeSync(fd);
|
|
40
|
+
return true;
|
|
41
|
+
}
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
function installWorkers(recorder, depth) {
|
|
45
|
+
if (!recorder.config.workers) {
|
|
46
|
+
recorder.notice('workers_disabled');
|
|
47
|
+
return () => { };
|
|
48
|
+
}
|
|
49
|
+
recorder.notice('workers_opt_in');
|
|
50
|
+
const module = workers;
|
|
51
|
+
const OriginalWorker = module.Worker;
|
|
52
|
+
const WrappedWorker = new Proxy(OriginalWorker, {
|
|
53
|
+
construct(target, args, newTarget) {
|
|
54
|
+
let prepared;
|
|
55
|
+
let session;
|
|
56
|
+
let previous = workers.getEnvironmentData(exports.WORKER_SESSION_KEY);
|
|
57
|
+
let mode = 'unknown';
|
|
58
|
+
try {
|
|
59
|
+
const options = args[1];
|
|
60
|
+
if (options !== undefined && (!options || typeof options !== 'object' || Object.getPrototypeOf(options) !== Object.prototype
|
|
61
|
+
|| Object.values(Object.getOwnPropertyDescriptors(options)).some(d => !('value' in d)))) {
|
|
62
|
+
recorder.notice('worker_shape_unsupported');
|
|
63
|
+
}
|
|
64
|
+
else if (depth >= recorder.config.maxDepth)
|
|
65
|
+
recorder.notice('worker_depth_limit');
|
|
66
|
+
else {
|
|
67
|
+
const opts = options || {};
|
|
68
|
+
const execArgv = opts.execArgv === undefined ? process.execArgv : opts.execArgv;
|
|
69
|
+
if (!Array.isArray(execArgv) || !execArgv.every((arg) => typeof arg === 'string'))
|
|
70
|
+
recorder.notice('worker_shape_unsupported');
|
|
71
|
+
else if (!recorder.suppress(() => claimSlot(recorder)))
|
|
72
|
+
recorder.notice('worker_count_limit');
|
|
73
|
+
else {
|
|
74
|
+
mode = opts.env === workers.SHARE_ENV ? 'shared' : opts.env === undefined ? 'copied' : 'explicit';
|
|
75
|
+
if (mode === 'shared')
|
|
76
|
+
recorder.notice('worker_shared_env');
|
|
77
|
+
session = { configPath: recorder.config.configPath, id: (0, io_1.uniqueId)('p'), parentId: recorder.process.id, depth: depth + 1, environmentMode: mode };
|
|
78
|
+
prepared = [args[0], { ...opts, execArgv: ['--require', recorder.config.preloadPath, ...execArgv] }];
|
|
79
|
+
// Environment data is cloned synchronously by Worker construction. No env/workerData rewrite.
|
|
80
|
+
previous = workers.getEnvironmentData(exports.WORKER_SESSION_KEY);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
prepared = undefined;
|
|
86
|
+
session = undefined;
|
|
87
|
+
recorder.notice('worker_shape_unsupported');
|
|
88
|
+
}
|
|
89
|
+
if (!prepared || !session)
|
|
90
|
+
return Reflect.construct(target, args, newTarget);
|
|
91
|
+
try {
|
|
92
|
+
workers.setEnvironmentData(exports.WORKER_SESSION_KEY, session);
|
|
93
|
+
}
|
|
94
|
+
catch {
|
|
95
|
+
recorder.notice('worker_shape_unsupported');
|
|
96
|
+
return Reflect.construct(target, args, newTarget);
|
|
97
|
+
}
|
|
98
|
+
try {
|
|
99
|
+
let instance;
|
|
100
|
+
try {
|
|
101
|
+
instance = recorder.suppress(() => Reflect.construct(target, prepared, newTarget));
|
|
102
|
+
}
|
|
103
|
+
catch (error) {
|
|
104
|
+
recorder.worker(session.id, 'spawn-failed', mode);
|
|
105
|
+
throw error;
|
|
106
|
+
}
|
|
107
|
+
recorder.worker(session.id, 'spawned', mode);
|
|
108
|
+
return instance;
|
|
109
|
+
}
|
|
110
|
+
finally {
|
|
111
|
+
try {
|
|
112
|
+
workers.setEnvironmentData(exports.WORKER_SESSION_KEY, previous);
|
|
113
|
+
}
|
|
114
|
+
catch {
|
|
115
|
+
recorder.notice('adapter_failed');
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
},
|
|
119
|
+
});
|
|
120
|
+
module.Worker = WrappedWorker;
|
|
121
|
+
(0, node_module_1.syncBuiltinESMExports)();
|
|
122
|
+
return () => { if (module.Worker === WrappedWorker) {
|
|
123
|
+
module.Worker = OriginalWorker;
|
|
124
|
+
(0, node_module_1.syncBuiltinESMExports)();
|
|
125
|
+
} };
|
|
126
|
+
}
|
|
127
|
+
//# sourceMappingURL=workers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workers.js","sourceRoot":"","sources":["../../src/runtime/workers.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# Architecture — v0.3
|
|
2
|
+
|
|
3
|
+
## Runtime path
|
|
4
|
+
|
|
5
|
+
```text
|
|
6
|
+
CLI direct Node launch
|
|
7
|
+
-> private temporary session + preload
|
|
8
|
+
-> selected process.env Proxy
|
|
9
|
+
-> dotenv / native env / trusted adapter observations
|
|
10
|
+
-> optional child and Worker preload propagation
|
|
11
|
+
-> in-memory keyed fingerprint boundary
|
|
12
|
+
-> bounded per-context JSONL streams + declarations/notices
|
|
13
|
+
-> collector validates contexts/order and records missing streams
|
|
14
|
+
-> configtrace/2 artifact
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
The launcher does not replace arbitrary shells. It passes through application output, exit codes, and signals where supported. The temporary session contains the comparison secret; it is restricted local state, not an exported artifact. Same-privilege application code is outside the isolation guarantee.
|
|
18
|
+
|
|
19
|
+
## Analysis path
|
|
20
|
+
|
|
21
|
+
```text
|
|
22
|
+
readTrace / strict schema
|
|
23
|
+
-> context selection and captured key evidence
|
|
24
|
+
-> provenance DAG
|
|
25
|
+
-> paired diff / deterministic diagnosis / contracts / ordered drift
|
|
26
|
+
-> terminal, JSON, offline HTML
|
|
27
|
+
-> token-free authorized MCP projection
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
The provenance engine distinguishes observed operations from derived/inferred relationships. Context-local order and confirmed parent-child creation are the only ordering links used; it does not merge process or Worker timestamps into a global causal sequence. Source files are origins; read-site nodes are sinks; these identities are intentionally distinct.
|
|
31
|
+
|
|
32
|
+
Diagnosis uses common call-site occurrence comparisons and bounded relevance intervals. A marker is explicit metadata without exception arguments. A nonzero exit does not create an invented first-failure boundary. Contracts evaluate captured evidence, with a separate inconclusive result. History compares adjacent entries in a chosen order, not unobserved deployment state.
|
|
33
|
+
|
|
34
|
+
## Worker boundary
|
|
35
|
+
|
|
36
|
+
The Worker constructor wrapper preserves `env` and `workerData`, injects preload arguments, and supplies context metadata through cloned environment data. Session-wide exclusive slot files bound instrumented creations; each Worker writes its own stream. Known children without streams are unconfirmed. Shared environments do not imply observed cross-thread writers.
|
|
37
|
+
|
|
38
|
+
## Persistence and formats
|
|
39
|
+
|
|
40
|
+
Core schemas and runtime capture remain in one npm package. Capture output uses configtrace/2; the reader retains configtrace/1 compatibility. Derived payloads have independent schema labels. Older binaries need not read new captures. Custom adapters must use the recorder for value-bearing observations and must not persist raw values independently.
|
|
41
|
+
|
|
42
|
+
Artifact parse/byte/event limits protect normal read paths; they are not an application sandbox or a complete denial-of-service guarantee. Most typed library APIs assume parsed Trace objects. Disk inputs must pass through readTrace. Evidence files are unsigned and unauthenticated.
|
|
43
|
+
|
|
44
|
+
## Module ownership
|
|
45
|
+
|
|
46
|
+
- `core/`: schema, privacy, I/O, collection, original explanations/diffs, export.
|
|
47
|
+
- `runtime/`: instrumentation, session/bootstrap, context capture, recorder lifecycle.
|
|
48
|
+
- `adapters/`: dotenv, native env, declared adapter catalog.
|
|
49
|
+
- `analysis/`: graph, diagnosis, contracts, history; no application execution.
|
|
50
|
+
- `agent/`: tools-only MCP snapshots and token-free projections.
|
|
51
|
+
- `report/`: offline HTML and local filtering.
|
|
52
|
+
- `cli.ts`: validated command dispatch; execution is confined to explicit run/demo commands.
|
|
53
|
+
|
|
54
|
+
See the README and requested-features document for scoped or unfinished behavior. No architecture claim is a test result.
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Compatibility targets — NOT validated
|
|
2
|
+
|
|
3
|
+
Every entry below is a source-level target. No platform, runtime, library, browser, or MCP client was exercised during this update. Existing v0.2 claims were not upgraded into test results.
|
|
4
|
+
|
|
5
|
+
| Area | Target | Status / limitation |
|
|
6
|
+
|---|---|---|
|
|
7
|
+
| Node | 22.14+ within 22.x, 24.x | Unrun; engines enforced by manifest only where the package manager honors them. |
|
|
8
|
+
| OS | Windows, Linux, macOS | Unrun; Windows Worker/main case behavior and filesystem permissions need special verification. |
|
|
9
|
+
| Application modules | Direct Node CJS and ESM | Unrun; early preloads/retained references/native access may bypass hooks. |
|
|
10
|
+
| TypeScript | Compiled JS with optional source maps | Unrun; no universal ts-node/tsx/framework loader claim. |
|
|
11
|
+
| dotenv | 16.x / 17.x targets; development dependency 17.2.3 | Unrun; eager load/private CJS interception may alter behavior. |
|
|
12
|
+
| Native env | process.loadEnvFile + util.parseEnv where available | Unrun; bounded extra file read yields inferred candidates. |
|
|
13
|
+
| Startup env files | --env-file, --env-file-if-exists declarations | Conservative hints only; parsing occurs before preload. |
|
|
14
|
+
| Workers | Plain-data options; copied/explicit/SHARE_ENV; direct constructor hook | Unrun, opt-in; no promise for early constructors, internal threads, custom loaders or accessor options. |
|
|
15
|
+
| Children | Async direct Node spawn/execFile/fork paths within bounds | Unrun; no sync/shell/detached/general process tracing. |
|
|
16
|
+
| HTML | Browser supporting inline SHA-256 CSP and local JS/DOM | Unrun; no browser or accessibility audit. |
|
|
17
|
+
| MCP | Tools-only stdio; 2025-11-25 / 2025-06-18 negotiation | Unrun; no HTTP transport and no verified named-client configuration. |
|
|
18
|
+
| Legacy artifact | configtrace/1, toolVersion 0.2.0 | Reader code accepts it; backward-read tests are unrun. |
|
|
19
|
+
| New artifact | configtrace/2, toolVersion 0.3.0 | New capture target, unrun. |
|
|
20
|
+
| node-config / convict / NestJS | No implementation | Planned catalog entries only. |
|
|
21
|
+
|
|
22
|
+
Native-addon access, original process.env references, pre-instrumentation history, replaced environment objects, early/nested lifecycle paths, build-time/browser substitution, and late exit-handler operations are not fully observed.
|
|
23
|
+
|
|
24
|
+
Record actual runtime, OS, dependency version, command, output, fixture expectation, result, and failure evidence before changing an entry to validated. Do not infer broad support from a single passing demo.
|
package/docs/PRIVACY.md
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Privacy boundary and disclosure model
|
|
2
|
+
|
|
3
|
+
Raw environment values are fingerprinted in the recorder before its event stream is serialized. HMAC inputs include the selected key identity. Explicitly paired runs share a private domain key; unrelated domains are not treated as comparable. New value metadata distinguishes empty from missing. This is intentional information disclosure, not a plaintext-value feature.
|
|
4
|
+
|
|
5
|
+
Temporary native-loader candidate maps and before/after snapshots hold raw strings briefly in memory. The extra bounded candidate read uses Node's parser. Maps are cleared after the call, but JavaScript strings are not securely erased and the process is not a secret-isolated sandbox. The temporary session configuration holds the comparison key, as required for descendant recorders.
|
|
6
|
+
|
|
7
|
+
Original artifacts retain fingerprints plus metadata such as key names, scrubbed paths, identities, timing, and sources. Local HTML replaces fingerprints with masked equality classes. DAG/diagnosis/verification/history payloads expose states and evidence rather than plaintext. MCP event projection also withholds fingerprints, comparison-domain identifiers, and secret keys. It authorizes snapshots explicitly and does not expose run/file-discovery/shell functions.
|
|
8
|
+
|
|
9
|
+
Export generates a fresh keyed transformation and optional key aliases, preserving intended paired relationships. Minimal metadata drops OS PIDs, parent OS PIDs, thread IDs, timestamps, and adapter declarations. Exported context relationships remain pseudonymous. Disabling comparisons removes present-value equality information; missing state can remain visible. Removing loaders/call sites reduces what later policy or analysis can conclude.
|
|
10
|
+
|
|
11
|
+
Sanitization does not certify that all arbitrary metadata is harmless. Paths, key names, source labels, application-chosen strings, event timing, relationships, and manifest text may identify users, infrastructure, or secrets. Review the actual exported files before sharing or authorizing an agent. A malicious producer can put sensitive content in metadata fields; the schema is not a secret detector.
|
|
12
|
+
|
|
13
|
+
Application stdout/stderr are inherited, not captured or sanitized. Uncaught exceptions may still be printed by Node/application handlers. ConfigTrace's marker does not persist exception messages, but does not suppress the application's output. Never treat terminal transcripts as equivalent to sanitized artifacts.
|
|
14
|
+
|
|
15
|
+
Windows permissions and race behavior require testing. Regular-file and size checks reject direct symlink inputs where implemented, but do not establish a sandbox against same-user races, malicious ancestors, or a cooperating application. Same-privilege code can inspect or tamper with recorder/session state. Artifacts are unsigned and not tamper-evident.
|
|
16
|
+
|
|
17
|
+
No canary tests, dependency audits, secret scans, runtime privacy validation, or penetration tests were executed for this source-only delivery. See VALIDATION.md before using real credentials.
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Validation guide
|
|
2
|
+
|
|
3
|
+
## First local checks
|
|
4
|
+
|
|
5
|
+
```sh
|
|
6
|
+
npm install --ignore-scripts
|
|
7
|
+
npm run typecheck
|
|
8
|
+
npm run build
|
|
9
|
+
npm test
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
These commands passed locally for the v0.3.0 release snapshot. Repeat them in a clean checkout and on each supported Node runtime before publishing. Resolve actual failures before marking anything complete. Use synthetic values and an isolated development directory.
|
|
13
|
+
|
|
14
|
+
## Extended acceptance checklist
|
|
15
|
+
|
|
16
|
+
- [ ] Compile the entire package and generated declarations on each supported Node/types target.
|
|
17
|
+
- [ ] Re-run preserved v0.2 tests: env operation semantics, dotenv source handling, custom targets, paired export, failed streams, children, source maps, stdout/exit preservation, metadata escaping.
|
|
18
|
+
- [ ] Read actual saved v0.2 artifacts and reject malformed v0.3 event/context references.
|
|
19
|
+
- [ ] Prove DAG acyclicity over fixtures, repeated source/read sites, parent/child/Worker edges, and malicious ancestry.
|
|
20
|
+
- [ ] Verify native runtime apply/skip/failure, option hints, missing files, optional files, Buffer/file-URL arguments, file races, parser-unavailable fallbacks, ESM imports, earlier references and disabling the adapter.
|
|
21
|
+
- [ ] Compare instrumented and uninstrumented Worker outputs across copied, explicit, SHARE_ENV, nested, eval, execArgv overrides, constructor failures, depth/count limits, termination, missing footers, Windows key case and concurrent mutation.
|
|
22
|
+
- [ ] Confirm no original environment or workerData rewriting, no added Worker error listener, and preserved application errors.
|
|
23
|
+
- [ ] Check policy 0/2/3 results for missing/empty/present, unread keys, post-first-read transient changes, inferred/unknown sources, forbidden loaders, transformed exports, pair mismatch and partial coverage.
|
|
24
|
+
- [ ] Check deterministic diagnosis ordering, shared/unrelated domains, missing sites, explicit/uncaught/no marker, post-boundary reads, and no fabricated causal verdict.
|
|
25
|
+
- [ ] Check history ordering, first divergence in supplied series, new read sites, source/loader/mutation changes, coverage regressions, absent timestamps, file permissions/symlinks and budgets.
|
|
26
|
+
- [ ] Open single/pair reports offline; inspect CSP, no requests, filtering, context selection, graph/timeline jumps, truncation notices, keyboard use and malicious metadata escaping.
|
|
27
|
+
- [ ] Exercise MCP initialization/notifications/ping, supported and unsupported versions, fixed tool list, schemas, unauthorized aliases, paging, oversize input/output, EOF, invalid JSON, and protocol-only stdout.
|
|
28
|
+
- [ ] Connect actual target coding clients. No client is considered verified until its specific configuration/handshake/tool calls are recorded.
|
|
29
|
+
- [ ] Seed synthetic secrets in every value/exception/input path; inspect all created artifacts, reports, exports, and protocol responses. Separately confirm application stdout remains unsanitized.
|
|
30
|
+
- [ ] Exercise malicious metadata and same-user tampering assumptions. Ensure documentation does not overclaim artifact authenticity.
|
|
31
|
+
- [ ] Measure overhead, event loss and storage growth on named fixtures; publish actual raw results, not estimates.
|
|
32
|
+
- [ ] Review dependency versions, security advisories, workflow action pins, runtime hooks and publication configuration.
|
|
33
|
+
|
|
34
|
+
## Test material
|
|
35
|
+
|
|
36
|
+
`tests/core.test.cjs` and `tests/integration.test.cjs` preserve the earlier acceptance sources. `tests/v03-analysis.test.cjs` covers new pure analysis/schema/report/agent behavior. `tests/v03-runtime.test.cjs` covers selected native loader/Worker/boundary paths. The automated suite passed locally, but these focused tests are not a substitute for the extended checks above.
|
|
37
|
+
|
|
38
|
+
Fixtures use synthetic values only. `fixtures/v03-manifest.json` lists the new cases. Verify the GitHub workflow independently for each release.
|
|
39
|
+
|
|
40
|
+
## Results record
|
|
41
|
+
|
|
42
|
+
When executing, record: date, OS, exact Node version, installed dependency lockfile, commit/source digest, command, actual result, artifacts, interpretation, and unresolved cases. Keep failures visible. Do not label a passing policy as proof of complete runtime provenance.
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
if (globalThis.__configtraceSavedOriginalEnv) {
|
|
2
|
+
globalThis.__configtraceSavedOriginalEnv.CONFIGTRACE_FIXTURE = 'synthetic-bypass';
|
|
3
|
+
void globalThis.__configtraceSavedOriginalEnv.CONFIGTRACE_FIXTURE;
|
|
4
|
+
}
|
|
5
|
+
void process.env.CONFIGTRACE_FIXTURE;
|
|
6
|
+
console.log('An original-reference bypass must not acquire a fictional write origin.');
|