@trillboards/edge-sdk 0.2.21 → 0.2.25

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.
Files changed (65) hide show
  1. package/deploy/macos/scripts/setup-litertlm.sh +30 -0
  2. package/deploy/windows/build-windows.ps1 +1 -0
  3. package/deploy/windows/e2e/test-enterprise-trust-store.ps1 +341 -0
  4. package/deploy/windows/enroll-connector.ps1 +169 -0
  5. package/deploy/windows/installer.nsi +102 -6
  6. package/deploy/windows/run-connector.ps1 +30 -0
  7. package/deploy/windows/setup-litertlm.ps1 +49 -1
  8. package/dist/AudienceAnalyzeClient.d.ts +32 -1
  9. package/dist/AudienceAnalyzeClient.d.ts.map +1 -1
  10. package/dist/AudienceAnalyzeClient.js +34 -5
  11. package/dist/AudienceAnalyzeClient.js.map +1 -1
  12. package/dist/CloudSensingManager.d.ts +30 -0
  13. package/dist/CloudSensingManager.d.ts.map +1 -1
  14. package/dist/CloudSensingManager.js +61 -1
  15. package/dist/CloudSensingManager.js.map +1 -1
  16. package/dist/ConnectorCameraClient.d.ts +79 -0
  17. package/dist/ConnectorCameraClient.d.ts.map +1 -0
  18. package/dist/ConnectorCameraClient.js +114 -0
  19. package/dist/ConnectorCameraClient.js.map +1 -0
  20. package/dist/EdgeAgent.js +1 -1
  21. package/dist/EnrollClient.d.ts +81 -0
  22. package/dist/EnrollClient.d.ts.map +1 -0
  23. package/dist/EnrollClient.js +97 -0
  24. package/dist/EnrollClient.js.map +1 -0
  25. package/dist/cli.d.ts +49 -0
  26. package/dist/cli.d.ts.map +1 -1
  27. package/dist/cli.js +392 -0
  28. package/dist/cli.js.map +1 -1
  29. package/dist/config.d.ts +15 -0
  30. package/dist/config.d.ts.map +1 -1
  31. package/dist/config.js +4 -0
  32. package/dist/config.js.map +1 -1
  33. package/dist/diagnose.d.ts +37 -4
  34. package/dist/diagnose.d.ts.map +1 -1
  35. package/dist/diagnose.js +155 -6
  36. package/dist/diagnose.js.map +1 -1
  37. package/dist/enterpriseNetwork.d.ts +130 -0
  38. package/dist/enterpriseNetwork.d.ts.map +1 -0
  39. package/dist/enterpriseNetwork.js +568 -0
  40. package/dist/enterpriseNetwork.js.map +1 -0
  41. package/dist/enterpriseProxy.d.ts +73 -0
  42. package/dist/enterpriseProxy.d.ts.map +1 -0
  43. package/dist/enterpriseProxy.js +406 -0
  44. package/dist/enterpriseProxy.js.map +1 -0
  45. package/dist/enterpriseTrust.d.ts +188 -0
  46. package/dist/enterpriseTrust.d.ts.map +1 -0
  47. package/dist/enterpriseTrust.js +615 -0
  48. package/dist/enterpriseTrust.js.map +1 -0
  49. package/dist/index.d.ts +10 -0
  50. package/dist/index.d.ts.map +1 -1
  51. package/dist/index.js +29 -1
  52. package/dist/index.js.map +1 -1
  53. package/dist/localNetworkAccess.d.ts +166 -0
  54. package/dist/localNetworkAccess.d.ts.map +1 -0
  55. package/dist/localNetworkAccess.js +490 -0
  56. package/dist/localNetworkAccess.js.map +1 -0
  57. package/dist/sensingRunMode.d.ts +36 -0
  58. package/dist/sensingRunMode.d.ts.map +1 -1
  59. package/dist/sensingRunMode.js +63 -1
  60. package/dist/sensingRunMode.js.map +1 -1
  61. package/dist/transportFailure.d.ts +118 -0
  62. package/dist/transportFailure.d.ts.map +1 -0
  63. package/dist/transportFailure.js +267 -0
  64. package/dist/transportFailure.js.map +1 -0
  65. package/package.json +1 -1
@@ -0,0 +1,568 @@
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 __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.EnterpriseHttpsAgent = void 0;
37
+ exports.resolveProxyCached = resolveProxyCached;
38
+ exports.resetEnterpriseNetworkCaches = resetEnterpriseNetworkCaches;
39
+ exports.refreshTrustAnchorsAfterFailure = refreshTrustAnchorsAfterFailure;
40
+ exports.connectThroughProxy = connectThroughProxy;
41
+ exports.createEnterpriseAgent = createEnterpriseAgent;
42
+ exports.getEnterpriseAgent = getEnterpriseAgent;
43
+ exports.describeNetworkPosture = describeNetworkPosture;
44
+ exports.installEnterpriseNetworking = installEnterpriseNetworking;
45
+ exports.uninstallEnterpriseNetworking = uninstallEnterpriseNetworking;
46
+ exports.diagnoseTransportError = diagnoseTransportError;
47
+ exports.applyHttpProxy = applyHttpProxy;
48
+ const https = __importStar(require("https"));
49
+ const net = __importStar(require("net"));
50
+ const tls = __importStar(require("tls"));
51
+ const enterpriseTrust_1 = require("./enterpriseTrust");
52
+ const enterpriseProxy_1 = require("./enterpriseProxy");
53
+ const transportFailure_1 = require("./transportFailure");
54
+ /**
55
+ * enterpriseNetwork — one agent that carries the machine's trust and the
56
+ * machine's proxy, installed once, used by everything.
57
+ *
58
+ * The connector had THREE TLS stacks and only one of them (the installer's
59
+ * Schannel calls) could see an enterprise root. This closes the Node one. The
60
+ * uv one is closed in `deploy/windows/setup-litertlm.ps1` and
61
+ * `deploy/macos/scripts/setup-litertlm.sh` by exporting `UV_SYSTEM_CERTS` /
62
+ * `UV_NATIVE_TLS` and the resolved proxy into uv's environment — uv has its own
63
+ * platform-verifier and does NOT auto-discover a Windows proxy, so both halves
64
+ * have to be handed to it explicitly.
65
+ *
66
+ * `installEnterpriseNetworking()` replaces `https.globalAgent`. That is a
67
+ * deliberate process-wide install and not a shortcut: eight modules across
68
+ * three packages construct `node:https` requests directly (`AudienceAnalyzeClient`,
69
+ * `cli`, `autoSense`, `diagnose`, `mcp-server`, `LiteRtVlmProvider`,
70
+ * `edge-core/ModelManager`, `edge-federated/FederatedModelClient`), several of
71
+ * them with the bare `https.get(url, cb)` form that takes no options at all.
72
+ * Threading an agent through every one of them would have left whichever site
73
+ * was missed failing exactly as before, silently — and the model OTA
74
+ * (`ModelManager`) is in a different package, so it could not have been reached
75
+ * any other way. One install covers every https call the process makes.
76
+ *
77
+ * Loopback is never proxied (see `findBypassRule`), so the local litert-lm
78
+ * server on `127.0.0.1:9379` is untouched.
79
+ */
80
+ /**
81
+ * How long a per-host proxy decision is reused.
82
+ *
83
+ * Long, and deliberately: on Windows and macOS a resolution costs a SYNCHRONOUS
84
+ * subprocess (`reg.exe`/`netsh.exe`, `scutil`) taken inside `createConnection`,
85
+ * which blocks the event loop — and on a 32-camera connector the event loop is
86
+ * the capture scheduler for every other feed. The answer is a per-machine
87
+ * constant that changes on the timescale of an IT ticket, `installEnterpriseNetworking`
88
+ * warms it for the API host at startup, and every feed shares that one host, so
89
+ * the steady-state cost is one resolution per interval for the whole process.
90
+ * Matches `TRUST_CACHE_TTL_MS` so the two do not drift.
91
+ */
92
+ const PROXY_CACHE_TTL_MS = 30 * 60 * 1000;
93
+ /** Minimum spacing between forced trust-store re-reads after a trust failure. */
94
+ const TRUST_REFRESH_MIN_INTERVAL_MS = 60 * 1000;
95
+ const proxyCache = new Map();
96
+ /**
97
+ * Cached `resolveProxyForUrl`. The cache exists because resolving costs a
98
+ * subprocess on Windows and macOS and the answer is a per-machine constant that
99
+ * changes on the timescale of an IT ticket, not a request.
100
+ *
101
+ * The cache is keyed on the TARGET only, so it is valid exactly while the
102
+ * environment is a process-wide constant — which it is in production and is
103
+ * NOT when a caller injects one. An injected `env`/`platform`/`exec` therefore
104
+ * bypasses the cache in both directions: it neither reads a decision taken
105
+ * under a different environment nor publishes its own for someone else to
106
+ * read. Without that, two agents built with different proxies in the same
107
+ * process silently share the first one's answer.
108
+ */
109
+ function resolveProxyCached(targetUrl, opts = {}) {
110
+ const injected = Boolean(opts.env || opts.platform || opts.exec);
111
+ if (injected)
112
+ return (0, enterpriseProxy_1.resolveProxyForUrl)(targetUrl, opts);
113
+ let key;
114
+ try {
115
+ const url = new URL(targetUrl);
116
+ key = `${url.protocol}//${url.host}`;
117
+ }
118
+ catch {
119
+ key = targetUrl;
120
+ }
121
+ const now = Date.now();
122
+ const hit = proxyCache.get(key);
123
+ if (hit && now - hit.atMs < PROXY_CACHE_TTL_MS)
124
+ return hit.resolution;
125
+ const resolution = (0, enterpriseProxy_1.resolveProxyForUrl)(targetUrl, opts);
126
+ proxyCache.set(key, { resolution, atMs: now });
127
+ return resolution;
128
+ }
129
+ /** Drop every cached network decision. Used by tests and by `diagnose`. */
130
+ function resetEnterpriseNetworkCaches() {
131
+ proxyCache.clear();
132
+ (0, enterpriseTrust_1.invalidateTrustAnchorCache)();
133
+ lastTrustRefreshAtMs = 0;
134
+ }
135
+ let lastTrustRefreshAtMs = 0;
136
+ /**
137
+ * Re-read the trust store after a certificate failure, at most once a minute.
138
+ *
139
+ * The point of the whole runtime-resolution design: an operator on the phone
140
+ * with IT gets the root installed, and the connector picks it up on the next
141
+ * cadence tick instead of needing a restart nobody is present to perform.
142
+ * Returns whether a re-read was actually armed, so the caller can say so.
143
+ */
144
+ function refreshTrustAnchorsAfterFailure(now = Date.now()) {
145
+ if (now - lastTrustRefreshAtMs < TRUST_REFRESH_MIN_INTERVAL_MS)
146
+ return false;
147
+ lastTrustRefreshAtMs = now;
148
+ (0, enterpriseTrust_1.invalidateTrustAnchorCache)();
149
+ // DROPPING THE CACHE IS NOT ENOUGH, and this is the half that makes the whole
150
+ // runtime-resolution design real rather than merely described.
151
+ //
152
+ // The agent's `ca` was baked into its options when it was constructed. An
153
+ // invalidated cache only changes what the NEXT `resolveTrustAnchors()` call
154
+ // returns — and on the request path nothing calls it again, because the agent
155
+ // is a process-wide singleton. So the newly-installed root would have been
156
+ // read, correctly, into a value nobody consults, and the connector would have
157
+ // gone on refusing until a restart: exactly the behaviour the install-time
158
+ // export was rejected for. The agent has to be rebuilt.
159
+ //
160
+ // The old agent's pooled sockets are dropped with it. That is correct here:
161
+ // every one of them is either idle or already failing verification, and a
162
+ // keep-alive socket established under the OLD trust decision must not carry
163
+ // the next request anyway.
164
+ if (installedAgent) {
165
+ const previous = installedAgent;
166
+ installedAgent = createEnterpriseAgent((0, enterpriseTrust_1.resolveTrustAnchors)(), {});
167
+ setGlobalHttpsAgent(installedAgent);
168
+ previous.destroy();
169
+ }
170
+ return true;
171
+ }
172
+ /**
173
+ * An `https.Agent` that decides, per connection, whether to tunnel.
174
+ *
175
+ * Per-connection and not per-agent because `NO_PROXY` is a per-host rule: one
176
+ * process talks to `api.trillboards.com` (proxied) and `127.0.0.1:9379` (never
177
+ * proxied), and a single agent has to get both right.
178
+ */
179
+ class EnterpriseHttpsAgent extends https.Agent {
180
+ constructor(options, netOptions = {}) {
181
+ super(options);
182
+ this.netOptions = netOptions;
183
+ }
184
+ createConnection(options, cb) {
185
+ const opts = options;
186
+ const host = String(opts.host ?? opts.servername ?? '');
187
+ const port = Number(opts.port ?? 443);
188
+ const targetUrl = `https://${host}:${port}`;
189
+ let decision;
190
+ try {
191
+ decision = resolveProxyCached(targetUrl, this.netOptions);
192
+ }
193
+ catch {
194
+ decision = { proxyUrl: null, source: 'none', warnings: [] };
195
+ }
196
+ if (!decision.proxyUrl) {
197
+ // Stock path, untouched — including TLS session resumption, which the
198
+ // base class does bookkeeping for and a hand-rolled tls.connect loses.
199
+ return https.Agent.prototype.createConnection.call(this, options, cb);
200
+ }
201
+ connectThroughProxy({
202
+ target: { host, port, servername: String(opts.servername ?? host) },
203
+ proxyUrl: decision.proxyUrl,
204
+ proxySource: decision.source,
205
+ tlsOptions: tunnelTlsOptions({ ...this.options, ...opts }),
206
+ callback: (err, socket) => {
207
+ // `createSocket` only invokes the callback when we return nothing, so a
208
+ // missing callback here would be a Node contract change, not a case to
209
+ // handle silently.
210
+ cb(err, socket);
211
+ },
212
+ });
213
+ return undefined;
214
+ }
215
+ }
216
+ exports.EnterpriseHttpsAgent = EnterpriseHttpsAgent;
217
+ /**
218
+ * The TLS options that survive into the tunnel.
219
+ *
220
+ * A CONNECT tunnel hands `tls.connect` an already-open socket, so every
221
+ * connection-addressing key on the agent's merged options is at best ignored
222
+ * and at worst wrong there — `path` in particular would be read as a Unix
223
+ * socket path. Keeping an explicit allowlist means a future agent option cannot
224
+ * silently change tunnel behaviour, and it keeps the set of things that could
225
+ * possibly weaken verification down to the ones named here.
226
+ */
227
+ function tunnelTlsOptions(merged) {
228
+ const allowed = [
229
+ 'ca',
230
+ 'cert',
231
+ 'key',
232
+ 'passphrase',
233
+ 'pfx',
234
+ 'ciphers',
235
+ 'minVersion',
236
+ 'maxVersion',
237
+ 'ALPNProtocols',
238
+ 'secureProtocol',
239
+ 'secureOptions',
240
+ 'sessionTimeout',
241
+ 'checkServerIdentity',
242
+ ];
243
+ const out = {};
244
+ for (const key of allowed) {
245
+ if (merged[key] !== undefined)
246
+ out[key] = merged[key];
247
+ }
248
+ return out;
249
+ }
250
+ /**
251
+ * Wall-clock budget for TCP-connect + the `CONNECT` reply.
252
+ *
253
+ * Load-bearing, not defensive. A request's `timeout:` is applied by
254
+ * `http.ClientRequest` only once a socket has been ASSIGNED to it, so nothing
255
+ * bounds the window this function owns: a proxy address that blackholes packets
256
+ * (a decommissioned appliance, a firewall dropping rather than refusing) would
257
+ * hang inside `createConnection` until the OS TCP timeout — about 75 s on Linux,
258
+ * far past the client's own 30 s budget — and a tick that never settles takes
259
+ * that feed down until the process restarts. That is the exact shape of the
260
+ * already-documented `defaultHttpPoster` hang in
261
+ * docs/runbooks/cctv-connector-runtime-edge-cases.md §6.6, and it must not be
262
+ * reintroduced by the fix for a different problem.
263
+ */
264
+ const PROXY_CONNECT_TIMEOUT_MS = 20000;
265
+ /**
266
+ * Open a CONNECT tunnel and start TLS inside it.
267
+ *
268
+ * Hand-rolled because the SDK ships with no third-party HTTP dependency at all
269
+ * (`package.json` has jpeg-js/jsqr/pngjs and nothing network-facing) and is
270
+ * bundled into a self-contained tree; adding `proxy-agent` would pull a
271
+ * dependency graph into a signed customer artifact for ~90 lines of protocol.
272
+ *
273
+ * `rejectUnauthorized` is never touched here. The tunnel changes WHO carries
274
+ * the bytes; it does not change who we are willing to believe at the other end.
275
+ */
276
+ function connectThroughProxy(args) {
277
+ const { target, proxyUrl, proxySource, tlsOptions, callback } = args;
278
+ const connectTimeoutMs = args.connectTimeoutMs ?? PROXY_CONNECT_TIMEOUT_MS;
279
+ const ctx = {
280
+ url: `https://${target.host}:${target.port}`,
281
+ proxyUrl,
282
+ proxySource,
283
+ };
284
+ let proxy;
285
+ try {
286
+ proxy = new URL(proxyUrl);
287
+ }
288
+ catch {
289
+ callback((0, transportFailure_1.classifyTransportError)(new Error(`unparseable proxy URL: ${(0, enterpriseProxy_1.redactProxyUrl)(proxyUrl)}`), ctx));
290
+ return;
291
+ }
292
+ if (/^socks/i.test(proxy.protocol)) {
293
+ callback(new transportFailure_1.TransportFailure({
294
+ failureClass: 'proxy_rejected',
295
+ code: 'PROXY_SOCKS_UNSUPPORTED',
296
+ url: ctx.url,
297
+ proxyUrl,
298
+ summary: `This machine is configured to use a SOCKS proxy (${(0, enterpriseProxy_1.redactProxyUrl)(proxyUrl)}), which the connector cannot use.`,
299
+ action: 'Ask IT for an HTTP CONNECT proxy for this machine and set HTTPS_PROXY to it, or ' +
300
+ 'exempt api.trillboards.com from the SOCKS policy.',
301
+ }));
302
+ return;
303
+ }
304
+ const proxyPort = Number(proxy.port) || (proxy.protocol === 'https:' ? 443 : 80);
305
+ const authority = `${target.host}:${target.port}`;
306
+ const lines = [`CONNECT ${authority} HTTP/1.1`, `Host: ${authority}`];
307
+ if (proxy.username) {
308
+ const credentials = Buffer.from(`${decodeURIComponent(proxy.username)}:${decodeURIComponent(proxy.password || '')}`, 'utf-8').toString('base64');
309
+ lines.push(`Proxy-Authorization: Basic ${credentials}`);
310
+ }
311
+ lines.push('Proxy-Connection: keep-alive', '', '');
312
+ // The proxy hop itself may be TLS (an "HTTPS proxy"); when it is, it is
313
+ // verified with the same CA bundle. A proxy we cannot verify is still a
314
+ // certificate failure and still reported as one.
315
+ const outer = proxy.protocol === 'https:'
316
+ ? tls.connect({
317
+ host: proxy.hostname,
318
+ port: proxyPort,
319
+ servername: proxy.hostname,
320
+ ca: tlsOptions.ca,
321
+ })
322
+ : net.connect({ host: proxy.hostname, port: proxyPort });
323
+ let settled = false;
324
+ // `unref()` so a pending tunnel can never be the only thing holding the
325
+ // process open — the connector is a long-running background service and a
326
+ // stray handle at shutdown is indistinguishable from a wedge.
327
+ const deadline = setTimeout(() => {
328
+ fail(Object.assign(new Error(`the proxy did not answer CONNECT within ${connectTimeoutMs} ms ` +
329
+ '(it accepted the connection, or the packets are being dropped)'), { code: 'ETIMEDOUT' }));
330
+ }, connectTimeoutMs);
331
+ if (typeof deadline.unref === 'function')
332
+ deadline.unref();
333
+ const fail = (err) => {
334
+ if (settled)
335
+ return;
336
+ settled = true;
337
+ clearTimeout(deadline);
338
+ outer.destroy();
339
+ callback(err instanceof transportFailure_1.TransportFailure ? err : (0, transportFailure_1.classifyTransportError)(err, ctx));
340
+ };
341
+ // Named so they can be removed individually once the tunnel is up. A blanket
342
+ // removeAllListeners() there would also take whatever `net`/`tls` has attached.
343
+ const onEarlyClose = () => {
344
+ if (settled)
345
+ return;
346
+ fail(Object.assign(new Error('the proxy closed the connection before answering CONNECT'), {
347
+ code: 'ECONNRESET',
348
+ }));
349
+ };
350
+ outer.once('error', fail);
351
+ outer.once('close', onEarlyClose);
352
+ const onReady = () => {
353
+ outer.write(lines.join('\r\n'));
354
+ };
355
+ if (proxy.protocol === 'https:')
356
+ outer.once('secureConnect', onReady);
357
+ else
358
+ outer.once('connect', onReady);
359
+ let head = Buffer.alloc(0);
360
+ const onData = (chunk) => {
361
+ head = Buffer.concat([head, chunk]);
362
+ const end = head.indexOf('\r\n\r\n');
363
+ if (end === -1) {
364
+ // A proxy that answers with an unbounded body instead of a status line
365
+ // must not be able to grow this buffer without limit.
366
+ if (head.length > 64 * 1024) {
367
+ fail(new Error('the proxy sent an oversized reply to CONNECT'));
368
+ }
369
+ return;
370
+ }
371
+ outer.removeListener('data', onData);
372
+ const statusLine = head.slice(0, head.indexOf('\r\n')).toString('latin1');
373
+ const match = statusLine.match(/^HTTP\/1\.[01] (\d{3})\s*(.*)$/);
374
+ const status = match ? Number(match[1]) : 0;
375
+ if (!match || status < 200 || status > 299) {
376
+ settled = true;
377
+ clearTimeout(deadline);
378
+ outer.destroy();
379
+ callback((0, transportFailure_1.proxyRejection)(status, match ? match[2] : statusLine.slice(0, 80), ctx));
380
+ return;
381
+ }
382
+ const residue = head.slice(end + 4);
383
+ if (residue.length > 0) {
384
+ // The server must wait for our ClientHello. Bytes here mean it is not
385
+ // speaking the tunnel protocol, and feeding them to TLS would produce an
386
+ // unreadable handshake error instead of this sentence.
387
+ fail(new Error('the proxy sent data before the tunnel was established'));
388
+ return;
389
+ }
390
+ settled = true;
391
+ clearTimeout(deadline);
392
+ outer.removeListener('error', fail);
393
+ outer.removeListener('close', onEarlyClose);
394
+ const secured = tls.connect({
395
+ ...tlsOptions,
396
+ socket: outer,
397
+ servername: target.servername || target.host,
398
+ // Explicitly restated, not inherited by accident: this is the line the
399
+ // whole change would be worthless without. A handshake failure inside the
400
+ // tunnel surfaces on the request and is classified there, by
401
+ // `diagnoseTransportError`, which re-reads the same cached proxy decision
402
+ // and so still says "via the proxy X".
403
+ rejectUnauthorized: true,
404
+ });
405
+ // The raw socket keeps its own error channel after the wrap, and an `error`
406
+ // with no listener is a process-level throw — on a connector that runs 24/7
407
+ // in a background process, that is an outage. Forward it into the TLS socket
408
+ // so it reaches the request and gets classified like any other failure.
409
+ outer.on('error', (err) => secured.destroy(err));
410
+ callback(null, secured);
411
+ };
412
+ outer.on('data', onData);
413
+ }
414
+ // ---------------------------------------------------------------------------
415
+ // Install + posture
416
+ // ---------------------------------------------------------------------------
417
+ let installedAgent = null;
418
+ /**
419
+ * Build (without installing) the agent for a set of resolved anchors.
420
+ * Exposed so a test can hold one without touching process globals.
421
+ */
422
+ function createEnterpriseAgent(anchors, netOptions = {}, base = {}) {
423
+ const ca = (0, enterpriseTrust_1.buildCaBundle)(anchors);
424
+ return new EnterpriseHttpsAgent({
425
+ // Inherit whatever Node's own defaults currently are (keepAlive,
426
+ // scheduling, timeout) instead of restating them and drifting from them.
427
+ ...currentGlobalHttpsAgent().options,
428
+ ...base,
429
+ ...(ca ? { ca } : {}),
430
+ }, netOptions);
431
+ }
432
+ /**
433
+ * The process-wide agent. Built on first use and reused forever after — an
434
+ * agent owns a socket pool, so returning a fresh one per call would defeat
435
+ * keep-alive and leak a pool per request.
436
+ */
437
+ function getEnterpriseAgent(netOptions = {}) {
438
+ if (!installedAgent) {
439
+ installedAgent = createEnterpriseAgent((0, enterpriseTrust_1.resolveTrustAnchors)(netOptions), netOptions);
440
+ }
441
+ return installedAgent;
442
+ }
443
+ /** What the connector resolved, for a startup line and for `diagnose`. */
444
+ function describeNetworkPosture(apiBaseUrl, netOptions = {}) {
445
+ const trust = (0, enterpriseTrust_1.resolveTrustAnchors)(netOptions);
446
+ const proxy = resolveProxyCached(apiBaseUrl, netOptions);
447
+ const lines = [(0, enterpriseTrust_1.describeTrustAnchors)(trust), (0, enterpriseProxy_1.describeProxy)(proxy)];
448
+ for (const warning of [...trust.warnings, ...proxy.warnings])
449
+ lines.push(`note: ${warning}`);
450
+ return { trust, proxy, lines };
451
+ }
452
+ /**
453
+ * Install the enterprise agent as `https.globalAgent` and report what it found.
454
+ *
455
+ * Idempotent. Returns the posture so the caller can print it — printing is the
456
+ * caller's job because the CLI, the supervisor and `diagnose` each have their
457
+ * own output channel.
458
+ */
459
+ function installEnterpriseNetworking(apiBaseUrl, netOptions = {}) {
460
+ const posture = describeNetworkPosture(apiBaseUrl, netOptions);
461
+ if (!installedAgent) {
462
+ installedAgent = createEnterpriseAgent(posture.trust, netOptions);
463
+ }
464
+ setGlobalHttpsAgent(installedAgent);
465
+ return posture;
466
+ }
467
+ /** Undo the install. Tests only — production installs once and never removes it. */
468
+ function uninstallEnterpriseNetworking(original) {
469
+ installedAgent = null;
470
+ if (original)
471
+ setGlobalHttpsAgent(original);
472
+ }
473
+ /**
474
+ * `https.globalAgent` is typed readonly by @types/node but is a plain writable
475
+ * property on the real module object at runtime (verified on the bundled Node
476
+ * 22). Replacing it is the only way to reach the `https.get(url, cb)` call sites
477
+ * that take no options at all.
478
+ *
479
+ * THE `require` IS LOAD-BEARING, do not "tidy" it into the `import * as https`
480
+ * binding above. `import * as` compiles to TypeScript's `__importStar` namespace
481
+ * wrapper, whose properties are GETTERS — assigning through it throws
482
+ * `Cannot set property globalAgent of #<Object> which has only a getter`. That
483
+ * throw is caught by the CLI's installer, which logs a warning and carries on,
484
+ * so the whole process-wide install silently became a no-op in the COMPILED
485
+ * build while every test kept passing (the tests build their agent directly).
486
+ * It was found by running `dist/cli.js diagnose` and reading the first line.
487
+ */
488
+ function setGlobalHttpsAgent(agent) {
489
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
490
+ const httpsModule = require('https');
491
+ httpsModule.globalAgent = agent;
492
+ }
493
+ /** The live `https.globalAgent`, read through the same real module object. */
494
+ function currentGlobalHttpsAgent() {
495
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
496
+ return require('https').globalAgent;
497
+ }
498
+ /**
499
+ * The one place a caught transport error becomes a diagnosis.
500
+ *
501
+ * Also arms a trust-store re-read when the failure was a trust failure, so the
502
+ * recovery path described in `enterpriseTrust` actually fires.
503
+ */
504
+ function diagnoseTransportError(err, targetUrl) {
505
+ const proxy = (() => {
506
+ try {
507
+ return resolveProxyCached(targetUrl);
508
+ }
509
+ catch {
510
+ return { proxyUrl: null, source: 'none', warnings: [] };
511
+ }
512
+ })();
513
+ const failure = (0, transportFailure_1.classifyTransportError)(err, {
514
+ url: targetUrl,
515
+ proxyUrl: proxy.proxyUrl,
516
+ proxySource: proxy.source,
517
+ autoConfigUrl: proxy.autoConfigUrl,
518
+ });
519
+ if ((0, transportFailure_1.isTrustFailure)(failure.failureClass))
520
+ refreshTrustAnchorsAfterFailure();
521
+ return failure;
522
+ }
523
+ /**
524
+ * Rewrite request options so a PLAIN-HTTP target goes through the proxy.
525
+ *
526
+ * http through a forward proxy is absolute-form, not a tunnel: connect to the
527
+ * proxy and put the whole URL in the request line. Returns the options
528
+ * unchanged when no proxy applies. `https` never comes through here — it goes
529
+ * through the agent above.
530
+ */
531
+ function applyHttpProxy(url, options, netOptions = {}) {
532
+ let parsed;
533
+ try {
534
+ parsed = new URL(url);
535
+ }
536
+ catch {
537
+ return { options, proxyUrl: null };
538
+ }
539
+ if (parsed.protocol !== 'http:')
540
+ return { options, proxyUrl: null };
541
+ const decision = resolveProxyCached(url, netOptions);
542
+ if (!decision.proxyUrl)
543
+ return { options, proxyUrl: null };
544
+ let proxy;
545
+ try {
546
+ proxy = new URL(decision.proxyUrl);
547
+ }
548
+ catch {
549
+ return { options, proxyUrl: null };
550
+ }
551
+ const headers = { ...options.headers };
552
+ if (proxy.username) {
553
+ headers['Proxy-Authorization'] = `Basic ${Buffer.from(`${decodeURIComponent(proxy.username)}:${decodeURIComponent(proxy.password || '')}`, 'utf-8').toString('base64')}`;
554
+ }
555
+ return {
556
+ options: {
557
+ ...options,
558
+ protocol: 'http:',
559
+ host: proxy.hostname,
560
+ hostname: proxy.hostname,
561
+ port: Number(proxy.port) || 80,
562
+ path: parsed.toString(),
563
+ headers,
564
+ },
565
+ proxyUrl: decision.proxyUrl,
566
+ };
567
+ }
568
+ //# sourceMappingURL=enterpriseNetwork.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"enterpriseNetwork.js","sourceRoot":"","sources":["../src/enterpriseNetwork.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,73 @@
1
+ import { type SpawnSyncReturns } from 'child_process';
2
+ export type ProxySource = 'env' | 'wininet' | 'winhttp' | 'macos-scutil' | 'none';
3
+ export interface ProxyResolution {
4
+ /** Absolute proxy URL (`http://host:port`), or null for a direct connection. */
5
+ proxyUrl: string | null;
6
+ /** Where the answer came from. `none` means no configuration was found. */
7
+ source: ProxySource;
8
+ /** The bypass rule that matched, when the target is excluded from the proxy. */
9
+ bypassedBy?: string;
10
+ /**
11
+ * A PAC / auto-config URL the platform names and this build cannot evaluate.
12
+ * Present ⇒ the machine HAS a proxy policy we could not follow, which is a
13
+ * very different statement from "no proxy", and the failure text says so.
14
+ */
15
+ autoConfigUrl?: string;
16
+ /** Non-fatal problems reading a source. */
17
+ warnings: string[];
18
+ }
19
+ export interface ProxyReadOptions {
20
+ platform?: NodeJS.Platform;
21
+ env?: NodeJS.ProcessEnv;
22
+ exec?: (cmd: string, args: string[]) => SpawnSyncReturns<string>;
23
+ }
24
+ /**
25
+ * Normalise whatever the platform gave us into an absolute proxy URL.
26
+ *
27
+ * WinINET stores `proxy:8080`, or a scheme-keyed list
28
+ * `http=p1:80;https=p2:8080`; `scutil` gives host and port separately; the
29
+ * environment usually has a full URL but is frequently set to a bare host:port.
30
+ * Returns null for anything that cannot be made into a URL, so a malformed
31
+ * setting degrades to DIRECT rather than to a crash on the request path.
32
+ */
33
+ export declare function normalizeProxyUrl(raw: string | undefined | null): string | null;
34
+ /** Pick the `https=` (or `http=`) entry out of a WinINET scheme-keyed list. */
35
+ export declare function pickWinInetProxy(proxyServer: string, targetProtocol: string): string | null;
36
+ /**
37
+ * Does a bypass list exempt this host?
38
+ *
39
+ * Accepts both the POSIX `NO_PROXY` vocabulary and the Windows `ProxyOverride`
40
+ * vocabulary, because the same function serves both:
41
+ * `*` — everything
42
+ * `<local>` — Windows: any hostname with no dot in it
43
+ * `.corp.local` — that suffix
44
+ * `corp.local` — that host and its subdomains
45
+ * `*.corp.local` — same, wildcard spelling
46
+ * `10.0.0.7` — that literal address
47
+ * `host:8080` — that host, only on that port
48
+ *
49
+ * Returns the matching entry (so the caller can SAY which rule applied) or null.
50
+ */
51
+ export declare function findBypassRule(host: string, port: number | undefined, bypassList: string | undefined | null): string | null;
52
+ /** Parse `reg.exe query` output into a name -> value map. */
53
+ export declare function parseRegQuery(stdout: string): Record<string, string>;
54
+ /** Parse `netsh winhttp show proxy` output. */
55
+ export declare function parseNetshWinhttp(stdout: string): {
56
+ server: string | null;
57
+ bypass: string | null;
58
+ };
59
+ /** Parse `scutil --proxy` output into a flat map (arrays are joined with `,`). */
60
+ export declare function parseScutilProxy(stdout: string): Record<string, string>;
61
+ /**
62
+ * The whole decision for one target URL: which proxy (if any), or why not.
63
+ *
64
+ * Pure with respect to its options, so the platform branches are all testable
65
+ * off their native platform — which is the only way the Windows path gets any
66
+ * coverage at all from a Linux CI lane.
67
+ */
68
+ export declare function resolveProxyForUrl(targetUrl: string, opts?: ProxyReadOptions): ProxyResolution;
69
+ /** One operator-facing line describing the proxy decision. */
70
+ export declare function describeProxy(resolution: ProxyResolution): string;
71
+ /** Strip proxy credentials before anything is logged. */
72
+ export declare function redactProxyUrl(proxyUrl: string): string;
73
+ //# sourceMappingURL=enterpriseProxy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"enterpriseProxy.d.ts","sourceRoot":"","sources":["../src/enterpriseProxy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,KAAK,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAwCjE,MAAM,MAAM,WAAW,GAAG,KAAK,GAAG,SAAS,GAAG,SAAS,GAAG,cAAc,GAAG,MAAM,CAAC;AAElF,MAAM,WAAW,eAAe;IAC9B,gFAAgF;IAChF,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,2EAA2E;IAC3E,MAAM,EAAE,WAAW,CAAC;IACpB,gFAAgF;IAChF,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;OAIG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,2CAA2C;IAC3C,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC;IAC3B,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,gBAAgB,CAAC,MAAM,CAAC,CAAC;CAClE;AAWD;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,GAAG,MAAM,GAAG,IAAI,CAgB/E;AAgBD,+EAA+E;AAC/E,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAgB3F;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,cAAc,CAC5B,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,GAAG,SAAS,EACxB,UAAU,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,GACpC,MAAM,GAAG,IAAI,CA4Cf;AAmBD,6DAA6D;AAC7D,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CASpE;AAED,+CAA+C;AAC/C,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG;IAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAMlG;AAED,kFAAkF;AAClF,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAwBvE;AA8ED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,GAAE,gBAAqB,GAAG,eAAe,CAqDlG;AAED,8DAA8D;AAC9D,wBAAgB,aAAa,CAAC,UAAU,EAAE,eAAe,GAAG,MAAM,CAejE;AAED,yDAAyD;AACzD,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAWvD"}