Files
orca/src/main/ssh/ssh-config-loader-regression.test.ts
T
NeilandOrca 46646d7ff1 chore(lint): upgrade oxlint to 1.71 + enable 7 new rules (autofixed backlog) (#6841)
* chore(lint): upgrade oxlint to 1.71 and enable 7 new rules

Upgrade oxlint 1.67.0 -> 1.71.0 (1.72 was blocked by the repo's 3-day
minimum-release-age supply-chain guard; nothing here needs it). The
bump is a no-op on the existing config.

Enable 3 error rules (backlog autofixed to zero in this commit) and
4 warn rules (surface signal without gating CI):

error (autofixed, behavior-preserving):
- unicorn/prefer-node-protocol        (~1531 sites: bare builtin -> node:)
- typescript/no-import-type-side-effects (~36: all-inline-type -> import type)
- unicorn/no-array-reverse            (19: copy-then-reverse -> toReversed)

warn (real signal, current fires are test-only/correct):
- unicorn/no-array-fill-with-reference-type  (aliasing footgun guard)
- typescript/no-unsafe-function-type         (bans bare Function type)
- unicorn/prefer-array-flat-map              (map().flat() -> flatMap())
- unicorn/prefer-regexp-test                 (.match() in bool ctx -> .test())

mobile/.oxlintrc.json extends root, so it inherits all 7; the autofix
ran from root and covered mobile/ too.

Verification (all green): oxlint 0 errors (root+mobile+aux configs),
oxfmt clean, typecheck (node+cli+web), vitest 22795 passed / 0 failed,
builds (electron-vite + web + cli) succeed. node: rewrites confirmed to
skip embedded SSH/CLI string payloads (AST-only); all toReversed sites
verified to operate on fresh copies or write-once locals.

* chore(lint): bump mobile oxlint to 1.71 so inherited rules parse

mobile/ is a standalone pnpm project pinning its own oxlint@1.67, which
lacks unicorn/no-array-fill-with-reference-type (needs >=1.70). Since
mobile/.oxlintrc.json extends the root config, mobile CI's 'cd mobile &&
oxlint' failed to parse the new rule. Bump mobile to match root (1.71).

Verified in mobile/: oxlint 0 errors, oxfmt --check clean, tsc --noEmit
pass, vitest 978 passed / 0 failed.

Co-authored-by: Orca <help@stably.ai>

---------

Co-authored-by: Orca <help@stably.ai>
2026-06-29 22:38:29 -07:00

280 lines
10 KiB
TypeScript

import type * as FsModule from 'node:fs'
import type * as OsModule from 'node:os'
import { win32 } from 'node:path'
import { afterEach, describe, expect, it, vi } from 'vitest'
afterEach(() => {
vi.restoreAllMocks()
vi.resetModules()
vi.doUnmock('fs')
vi.doUnmock('os')
})
function normalizeWin(value: string): string {
return win32.normalize(value.replaceAll('/', '\\'))
}
function platformSshHome(): string {
return process.platform === 'win32' ? 'C:\\Users\\testuser' : '/home/testuser'
}
function platformSshPath(home: string, relativePath: string): string {
return process.platform === 'win32'
? normalizeWin(`${home}/${relativePath}`)
: `${home}/${relativePath}`
}
async function mockOs(
home: string,
username = 'testuser',
uid = 1001,
hostname = 'host.example.com'
) {
vi.doMock('os', async () => {
const actual = await vi.importActual<typeof OsModule>('os')
return {
...actual,
homedir: () => home,
hostname: () => hostname,
userInfo: () => ({ username, uid })
}
})
}
async function loadUserSshConfig() {
const mod = await import('./ssh-config-parser')
return mod.loadUserSshConfig()
}
describe('loadUserSshConfig regressions', () => {
it('supports Windows-style home paths and include separators', async () => {
const files = new Map<string, string>([
[
normalizeWin('C:/Users/Test User/.ssh/config'),
'Include .\\conf.d\\*.conf "C:\\Users\\Test User\\quoted configs\\team.conf" forward/slash.conf'
],
[
normalizeWin('C:/Users/Test User/.ssh/conf.d/zeta.conf'),
'Host zeta\n HostName zeta.example.com\n'
],
[
normalizeWin('C:/Users/Test User/.ssh/conf.d/alpha.conf'),
'Host alpha\n HostName alpha.example.com\n'
],
[
normalizeWin('C:/Users/Test User/quoted configs/team.conf'),
'Host team\n HostName team.example.com\n'
],
[
normalizeWin('C:/Users/Test User/.ssh/forward/slash.conf'),
'Host forward\n HostName forward.example.com\n'
]
])
await mockOs('C:\\Users\\Test User', 'TestUser', -1, 'winbox.example.com')
vi.doMock('fs', async () => {
const actual = await vi.importActual<typeof FsModule>('fs')
return {
...actual,
existsSync: (filePath: string) => files.has(normalizeWin(filePath)),
globSync: (pattern: string) =>
normalizeWin(pattern) === normalizeWin('C:/Users/Test User/.ssh/conf.d/*.conf')
? [
normalizeWin('C:/Users/Test User/.ssh/conf.d/alpha.conf'),
normalizeWin('C:/Users/Test User/.ssh/conf.d/zeta.conf')
]
: [],
readFileSync: (filePath: string) => {
const content = files.get(normalizeWin(filePath))
if (content === undefined) {
throw new Error(`ENOENT: ${filePath}`)
}
return content
},
realpathSync: Object.assign((filePath: string) => normalizeWin(filePath), {
native: (filePath: string) => normalizeWin(filePath)
}),
statSync: (filePath: string) => {
const content = files.get(normalizeWin(filePath))
if (content === undefined) {
throw new Error(`ENOENT: ${filePath}`)
}
return { isFile: () => true, size: content.length }
}
}
})
const hosts = await loadUserSshConfig()
expect(hosts.map((host) => host.host)).toEqual(['alpha', 'zeta', 'team', 'forward'])
})
it('preserves quoted Windows include paths with native backslashes and spaces', async () => {
const files = new Map<string, string>([
[
normalizeWin('C:/Users/Test User/.ssh/config'),
'Include "C:\\Users\\Test User\\quoted configs\\team.conf"'
],
[
normalizeWin('C:/Users/Test User/quoted configs/team.conf'),
'Host team\n HostName team.example.com\n'
]
])
await mockOs('C:\\Users\\Test User', 'TestUser', -1, 'winbox.example.com')
vi.doMock('fs', async () => {
const actual = await vi.importActual<typeof FsModule>('fs')
return {
...actual,
existsSync: (filePath: string) => files.has(normalizeWin(filePath)),
readFileSync: (filePath: string) => {
const content = files.get(normalizeWin(filePath))
if (content === undefined) {
throw new Error(`ENOENT: ${filePath}`)
}
return content
},
realpathSync: Object.assign((filePath: string) => normalizeWin(filePath), {
native: (filePath: string) => normalizeWin(filePath)
}),
statSync: (filePath: string) => {
const content = files.get(normalizeWin(filePath))
if (content === undefined) {
throw new Error(`ENOENT: ${filePath}`)
}
return { isFile: () => true, size: content.length }
}
}
})
expect(await loadUserSshConfig()).toEqual([{ host: 'team', hostname: 'team.example.com' }])
})
it('skips non-regular include targets without reading them', async () => {
const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {})
const home = platformSshHome()
const configPath = platformSshPath(home, '.ssh/config')
const unsafePath = platformSshPath(home, '.ssh/unsafe.conf')
const safePath = platformSshPath(home, '.ssh/safe.conf')
const unsafeReadSpy = vi.fn()
await mockOs(home)
vi.doMock('fs', async () => {
const actual = await vi.importActual<typeof FsModule>('fs')
return {
...actual,
existsSync: (filePath: string) =>
filePath === configPath || filePath === unsafePath || filePath === safePath,
readFileSync: (filePath: string) => {
if (filePath === unsafePath) {
unsafeReadSpy()
throw new Error(`unexpected read: ${filePath}`)
}
if (filePath === configPath) {
return 'Include unsafe.conf safe.conf\n'
}
if (filePath === safePath) {
return 'Host safe\n HostName safe.example.com\n'
}
throw new Error(`ENOENT: ${filePath}`)
},
realpathSync: Object.assign((filePath: string) => filePath, {
native: (filePath: string) => filePath
}),
statSync: (filePath: string) => ({ isFile: () => filePath !== unsafePath, size: 64 })
}
})
expect(await loadUserSshConfig()).toEqual([{ host: 'safe', hostname: 'safe.example.com' }])
expect(unsafeReadSpy).not.toHaveBeenCalled()
expect(warnSpy).toHaveBeenCalledWith(expect.stringContaining('Skipping SSH config include'))
})
it('caps overly broad include globs and skips the remainder', async () => {
const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {})
const home = platformSshHome()
const configPath = platformSshPath(home, '.ssh/config')
const includePaths = Array.from({ length: 2000 }, (_, index) => {
return platformSshPath(home, `.ssh/conf.d/${String(index).padStart(4, '0')}.conf`)
})
const readPaths = new Set<string>()
await mockOs(home)
vi.doMock('fs', async () => {
const actual = await vi.importActual<typeof FsModule>('fs')
return {
...actual,
existsSync: (filePath: string) =>
filePath === configPath || includePaths.includes(filePath),
globSync: () => [...includePaths].toReversed(),
readFileSync: (filePath: string) => {
if (filePath === configPath) {
return 'Include conf.d/*.conf\n'
}
if (includePaths.includes(filePath)) {
readPaths.add(filePath)
const alias = filePath.match(/(\d+)\.conf$/)?.[1] ?? 'unknown'
return `Host host-${alias}\n HostName ${alias}.example.com\n`
}
throw new Error(`ENOENT: ${filePath}`)
},
realpathSync: Object.assign((filePath: string) => filePath, {
native: (filePath: string) => filePath
}),
statSync: (filePath: string) => ({
isFile: () => filePath === configPath || includePaths.includes(filePath),
size: 64
})
}
})
const hosts = await loadUserSshConfig()
expect(hosts.length).toBeGreaterThan(0)
expect(hosts.length).toBeLessThan(includePaths.length)
expect(readPaths.has(includePaths.at(-1)!)).toBe(false)
expect(warnSpy).toHaveBeenCalledWith(expect.stringContaining('matched'))
})
it('skips oversized include files without reading them', async () => {
const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {})
const home = platformSshHome()
const configPath = platformSshPath(home, '.ssh/config')
const oversizedPath = platformSshPath(home, '.ssh/oversized.conf')
const safePath = platformSshPath(home, '.ssh/safe.conf')
const oversizedReadSpy = vi.fn()
await mockOs(home)
vi.doMock('fs', async () => {
const actual = await vi.importActual<typeof FsModule>('fs')
return {
...actual,
existsSync: (filePath: string) =>
filePath === configPath || filePath === oversizedPath || filePath === safePath,
readFileSync: (filePath: string) => {
if (filePath === oversizedPath) {
oversizedReadSpy()
throw new Error(`unexpected read: ${filePath}`)
}
if (filePath === configPath) {
return 'Include oversized.conf safe.conf\n'
}
if (filePath === safePath) {
return 'Host safe\n HostName safe.example.com\n'
}
throw new Error(`ENOENT: ${filePath}`)
},
realpathSync: Object.assign((filePath: string) => filePath, {
native: (filePath: string) => filePath
}),
statSync: (filePath: string) => ({
isFile: () => true,
size: filePath === oversizedPath ? 2 * 1024 * 1024 : 64
})
}
})
expect(await loadUserSshConfig()).toEqual([{ host: 'safe', hostname: 'safe.example.com' }])
expect(oversizedReadSpy).not.toHaveBeenCalled()
expect(warnSpy).toHaveBeenCalledWith(expect.stringContaining('exceeds'))
})
})