mirror of
https://github.com/stablyai/orca.git
synced 2026-10-01 08:01:56 +00:00
fix(windows): log the port-scan fall-through on the relay diagnostic stream
Checked where this code actually runs before trusting the log. `console.warn` did reach a file, but relayLogLine is the right call and the reasoning is worth recording. `scanWindowsListeningPorts` runs only in the detached relay daemon: relay.ts returns early for --connect and --orca-cli, so PortScanHandler is reached only through runRelayDaemon, and both launchers start it detached with a log file (POSIX `> relay.log 2>&1`, Windows `1>relay.log 2>relay.err.log` via Win32_Process.Create). installRelayLogRotation then wraps both streams into relay.log, which is the file the documented diagnostics tail reads. Verified by installing the real rotation over a temp path and reading the file back. So the line surfaced -- but untimestamped, in a log whose format exists so reconnect flaps can be correlated with the events around them (#7773). relayLogLine is that format and the relay idiom in 41 other places, and "since when has this host been stuck on PowerShell" is most of what this line is for. The test spies on process.stderr to pin the stream and the ISO stamp rather than just asserting something was called, since a fall-through logged somewhere unread is the failure being guarded against. Also fixes a comment that ended its own block early: `relay-*/relay.log` in a doc comment contains `*/`.
This commit is contained in:
@@ -14,7 +14,10 @@ import {
|
||||
__setWindowsProcessTreeLoaderForTests,
|
||||
resetWindowsProcessTableForTests
|
||||
} from '../main/windows/windows-process-table'
|
||||
import { scanWindowsListeningPorts } from './windows-port-scan'
|
||||
import {
|
||||
resetWindowsPortScanDiagnosticsForTests,
|
||||
scanWindowsListeningPorts
|
||||
} from './windows-port-scan'
|
||||
|
||||
type Spec = {
|
||||
program: string
|
||||
@@ -85,6 +88,7 @@ function specs(): Spec[] {
|
||||
describe('scanWindowsListeningPorts', () => {
|
||||
beforeEach(() => {
|
||||
runProcessMock.mockReset()
|
||||
resetWindowsPortScanDiagnosticsForTests()
|
||||
resetWindowsProcessTableForTests()
|
||||
__setWindowsProcessTreeLoaderForTests(
|
||||
nativeTable([
|
||||
@@ -310,6 +314,33 @@ describe('scanWindowsListeningPorts', () => {
|
||||
expect(getAllProcesses).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
// The relay daemon's stderr is what installRelayLogRotation routes into
|
||||
// relay.log, so a fall-through logged anywhere else is a fall-through nobody
|
||||
// can diagnose. Pin the stream, not just the fact that something was called.
|
||||
it('reports leaving the native path on the relay diagnostic stream, once', async () => {
|
||||
const lines: string[] = []
|
||||
const stderr = vi
|
||||
.spyOn(process.stderr, 'write')
|
||||
.mockImplementation((chunk: string | Uint8Array) => {
|
||||
lines.push(String(chunk))
|
||||
return true
|
||||
})
|
||||
try {
|
||||
runProcessMock.mockResolvedValue(ok(''))
|
||||
await scanWindowsListeningPorts()
|
||||
await scanWindowsListeningPorts()
|
||||
} finally {
|
||||
stderr.mockRestore()
|
||||
}
|
||||
|
||||
const reported = lines.filter((line) => line.includes('[ports] netstat unusable'))
|
||||
expect(reported).toHaveLength(1)
|
||||
expect(reported[0]).toContain('no listening row parsed')
|
||||
// relayLogLine's ISO stamp: an unplaceable line cannot be read against the
|
||||
// reconnect flaps around it.
|
||||
expect(reported[0]).toMatch(/^\d{4}-\d{2}-\d{2}T[\d:.]+Z /)
|
||||
})
|
||||
|
||||
it('treats a netstat timeout as unanswered and falls through', async () => {
|
||||
runProcessMock
|
||||
.mockResolvedValueOnce({
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
import { getProcessOutputFields } from '../shared/process-output-field-scanner'
|
||||
import type { DetectedPort } from './port-scan-handler'
|
||||
import { buildRelayCommandEnv } from './relay-command-env'
|
||||
import { relayLogLine } from './relay-diagnostic-log'
|
||||
|
||||
const SYSTEM_PORTS_TO_EXCLUDE = new Set([22])
|
||||
const MAX_DETECTED_PORTS = 50
|
||||
@@ -91,13 +92,24 @@ let reportedNetstatUnusable = false
|
||||
* Both fall-throughs are permanent when they are wrong — the host stays on the
|
||||
* PowerShell payload, or on nothing, for the life of the relay — and the scan
|
||||
* repeats every 12-30s, so this logs one line rather than a stream.
|
||||
*
|
||||
* Through relayLogLine, not console.warn: this only ever runs in the detached
|
||||
* daemon, whose stderr installRelayLogRotation routes into the relay.log that
|
||||
* the remote-diagnostics tail reads. An untimestamped line in that file cannot
|
||||
* be placed against the reconnect flaps around it (#7773), and "since when" is
|
||||
* most of what this line is for.
|
||||
*/
|
||||
function reportWindowsNetstatUnusable(reason: string): void {
|
||||
if (reportedNetstatUnusable) {
|
||||
return
|
||||
}
|
||||
reportedNetstatUnusable = true
|
||||
console.warn(`[ports] netstat unusable on this host (${reason}); falling back to PowerShell`)
|
||||
relayLogLine(`[ports] netstat unusable on this host (${reason}); falling back to PowerShell`)
|
||||
}
|
||||
|
||||
/** Test-only: re-arm the one-shot so each case can observe its own line. */
|
||||
export function resetWindowsPortScanDiagnosticsForTests(): void {
|
||||
reportedNetstatUnusable = false
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user