| @@ -65,6 +65,7 @@ function makeHandle(input: { · 64 unmodified lines |
| 65 | readonly isRunning?: () => boolean; | 65 | readonly isRunning?: () => boolean; |
| 66 | readonly isRunningEffect?: ChildProcessSpawner.ChildProcessHandle["isRunning"]; | 66 | readonly isRunningEffect?: ChildProcessSpawner.ChildProcessHandle["isRunning"]; |
| 67 | readonly exitCode?: Effect.Effect<ChildProcessSpawner.ExitCode>; | 67 | readonly exitCode?: Effect.Effect<ChildProcessSpawner.ExitCode>; |
| | 68 | readonly output?: string; |
| 68 | }) { | 69 | }) { |
| 69 | return ChildProcessSpawner.makeHandle({ | 70 | return ChildProcessSpawner.makeHandle({ |
| 70 | pid: ChildProcessSpawner.ProcessId(input.pid), | 71 | pid: ChildProcessSpawner.ProcessId(input.pid), |
| @@ -78,7 +79,10 @@ function makeHandle(input: { · 7 unmodified lines |
| 78 | stdin: Sink.drain, | 79 | stdin: Sink.drain, |
| 79 | stdout: Stream.empty, | 80 | stdout: Stream.empty, |
| 80 | stderr: Stream.empty, | 81 | stderr: Stream.empty, |
| 81 | all: Stream.empty, | 82 | all: |
| | 83 | input.output === undefined |
| | 84 | ? Stream.empty |
| | 85 | : Stream.make(new TextEncoder().encode(input.output)), |
| 82 | getInputFd: () => Sink.drain, | 86 | getInputFd: () => Sink.drain, |
| 83 | getOutputFd: () => Stream.empty, | 87 | getOutputFd: () => Stream.empty, |
| 84 | }); | 88 | }); |
| @@ -262,6 +266,64 @@ describe("CloudManagedEndpointRuntime", () => { · 177 unmodified lines |
| 262 | }).pipe(Effect.provide(Logger.layer([logger], { mergeWithExisting: false }))); | 266 | }).pipe(Effect.provide(Logger.layer([logger], { mergeWithExisting: false }))); |
| 263 | }); | 267 | }); |
| 264 | | 268 | |
| | 269 | it.effect("does not copy relay client output into log annotations", () => { |
| | 270 | const connectorToken = "connector-token-sentinel"; |
| | 271 | const signedUrl = "https://user:password@example.com/private?token=secret#fragment"; |
| | 272 | const output = `ERR failed request ${signedUrl} ${connectorToken}`; |
| | 273 | const logMessages: unknown[] = []; |
| | 274 | let resolveObserved!: () => void; |
| | 275 | const observed = new Promise<void>((resolve) => { |
| | 276 | resolveObserved = resolve; |
| | 277 | }); |
| | 278 | const logger = Logger.make(({ message }) => { |
| | 279 | logMessages.push(message); |
| | 280 | if (Array.isArray(message) && message[0] === "Relay client reported a transport warning") { |
| | 281 | resolveObserved(); |
| | 282 | } |
| | 283 | }); |
| | 284 | const spawner = ChildProcessSpawner.make(() => |
| | 285 | Effect.gen(function* () { |
| | 286 | const handle = makeHandle({ |
| | 287 | pid: 350, |
| | 288 | output, |
| | 289 | onKill: () => undefined, |
| | 290 | }); |
| | 291 | yield* Effect.addFinalizer(() => handle.kill().pipe(Effect.ignore)); |
| | 292 | return handle; |
| | 293 | }), |
| | 294 | ); |
| | 295 | |
| | 296 | return Effect.gen(function* () { |
| | 297 | const runtime = yield* buildCloudManagedEndpointRuntime(spawner); |
| | 298 | yield* runtime.applyConfig({ |
| | 299 | providerKind: "cloudflare_tunnel", |
| | 300 | connectorToken, |
| | 301 | tunnelId: "tunnel-1", |
| | 302 | }); |
| | 303 | yield* Effect.promise(() => observed); |
| | 304 | |
| | 305 | const warning = logMessages.find( |
| | 306 | (message) => |
| | 307 | Array.isArray(message) && message[0] === "Relay client reported a transport warning", |
| | 308 | ); |
| | 309 | expect(warning).toBeDefined(); |
| | 310 | if (!Array.isArray(warning)) return; |
| | 311 | expect(warning[1]).toMatchObject({ |
| | 312 | pid: 350, |
| | 313 | tunnelId: "tunnel-1", |
| | 314 | outputLength: output.length, |
| | 315 | }); |
| | 316 | expect(warning[1]).not.toHaveProperty("output"); |
| | 317 | const diagnosticText = Object.values(warning[1] as Record<string, unknown>) |
| | 318 | .map(String) |
| | 319 | .join("\n"); |
| | 320 | expect(diagnosticText).not.toContain(connectorToken); |
| | 321 | expect(diagnosticText).not.toContain(signedUrl); |
| | 322 | expect(diagnosticText).not.toContain("user:password"); |
| | 323 | expect(diagnosticText).not.toContain("token=secret"); |
| | 324 | }).pipe(Effect.provide(Logger.layer([logger], { mergeWithExisting: false }))); |
| | 325 | }); |
| | 326 | |
| 265 | it.effect("supervises the active connector and restarts it after process exit", () => | 327 | it.effect("supervises the active connector and restarts it after process exit", () => |
| 266 | Effect.gen(function* () { | 328 | Effect.gen(function* () { |
| 267 | const spawned: Array<number> = []; | 329 | const spawned: Array<number> = []; |