fix(local): resolve guest cwd against the shell's fsBase before validating (#11625)

Co-authored-by: Andrea Bergamasco <a.bergamasco@keesystem.com>
Co-authored-by: Eugene <inbox@null.page>
This commit is contained in:
Andrea Bergamasco
2026-09-11 22:24:29 +02:00
committed by GitHub
co-authored by Andrea Bergamasco Eugene
parent 034a76a853
commit 508dccc0b9
6 changed files with 45 additions and 5 deletions
+11 -3
View File
@@ -49,6 +49,13 @@ export class WSLShellProvider extends ShellProvider {
return []
}
// Windows path backing the distro's rootfs, so a POSIX cwd from the guest can be resolved.
// Flags bit 3 marks a WSL2 distro (files served over \\wsl$); WSL1 lives under BasePath.
const fsBaseForDistro = (key: any): string | undefined =>
(key.Flags?.value || 0) & 8
? `\\\\wsl$\\${key.DistributionName.value}`
: key.BasePath ? key.BasePath.value + '\\rootfs' : undefined
const bashPath = `${process.env.windir}\\system32\\bash.exe`
const wslPath = `${process.env.windir}\\system32\\wsl.exe`
@@ -59,6 +66,7 @@ export class WSLShellProvider extends ShellProvider {
if (lxss?.DefaultDistribution) {
const defaultDistKey = wnr.getRegistryKey(wnr.HK.CU, lxssPath + '\\' + String(lxss.DefaultDistribution.value))
if (defaultDistKey?.DistributionName) {
const name = defaultDistKey.DistributionName.value
const shell: Shell = {
id: 'wsl',
name: 'WSL / Default distro',
@@ -68,8 +76,9 @@ export class WSLShellProvider extends ShellProvider {
COLORTERM: 'truecolor',
},
shellType: 'unix',
fsBase: fsBaseForDistro(defaultDistKey),
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
icon: wslIconMap[defaultDistKey.DistributionName.value] ?? wslIconMap.Linux,
icon: wslIconMap[name] ?? wslIconMap.Linux,
}
shells.push(shell)
}
@@ -97,9 +106,8 @@ export class WSLShellProvider extends ShellProvider {
if (!childKey.DistributionName || !childKey.BasePath) {
continue
}
const wslVersion = (childKey.Flags?.value || 0) & 8 ? 2 : 1
const name = childKey.DistributionName.value
const fsBase = wslVersion === 2 ? `\\\\wsl$\\${name}` : childKey.BasePath.value as string + '\\rootfs'
const fsBase = fsBaseForDistro(childKey)
const slug = slugify(name, { remove: /[:.]/g })
const shell: Shell = {
id: `wsl-${slug}`,
+6
View File
@@ -46,6 +46,12 @@ export interface SessionOptions {
shellType: ShellType | null
pauseAfterExit: boolean
runAsAdministrator: boolean
/**
* Base path to which cwd is relative, e.g. `\\wsl$\Ubuntu` for WSL shells.
* Used to translate a POSIX cwd reported by the guest shell into a real Windows path.
*/
fsBase: string | null
}
export interface LocalProfile extends BaseTerminalProfile {
+2
View File
@@ -25,6 +25,7 @@ export class LocalProfilesService extends ProfileProvider<LocalProfile> {
shellType: null,
pauseAfterExit: false,
runAsAdministrator: false,
fsBase: null,
},
}
@@ -84,6 +85,7 @@ export class LocalProfilesService extends ProfileProvider<LocalProfile> {
env: shell.env,
cwd: shell.cwd ?? null,
shellType: shell.shellType ?? null,
fsBase: shell.fsBase ?? null,
}
}
+2 -1
View File
@@ -2,6 +2,7 @@ import { Injectable } from '@angular/core'
import { Logger, LogService, ConfigService, ProfilesService, PartialProfile } from 'tabby-core'
import { TerminalTabComponent } from '../components/terminalTab.component'
import { LocalProfile } from '../api'
import { resolveGuestCWD } from '../wslPath'
import { isDirectorySync } from '../util'
@Injectable({ providedIn: 'root' })
@@ -37,7 +38,7 @@ export class TerminalService {
const fullProfile = this.profilesService.getConfigProxyForProfile(profile)
cwd = cwd ?? fullProfile.options.cwd
cwd = resolveGuestCWD(cwd ?? fullProfile.options.cwd, fullProfile.options.fsBase)
if (cwd && !isDirectorySync(cwd)) {
console.warn('Ignoring invalid CWD:', cwd)
+2 -1
View File
@@ -4,6 +4,7 @@ import { HostAppService, ConfigService, WIN_BUILD_CONPTY_SUPPORTED, isWindowsBui
import { BaseSession } from 'tabby-terminal'
import { SessionOptions, ChildProcess, PTYInterface, PTYProxy } from './api'
import { getEnvironment, substituteEnv } from './environment'
import { resolveGuestCWD } from './wslPath'
import { isDirectory, isDirectorySync } from './util'
const windowsDirectoryRegex = /([a-zA-Z]:[^\:\[\]\?\"\<\>\|]+)/mi
@@ -87,7 +88,7 @@ export class Session extends BaseSession {
}
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
let cwd = options.cwd || process.env.HOME
let cwd = resolveGuestCWD(options.cwd, options.fsBase) || process.env.HOME
if (!isDirectorySync(cwd)) {
console.warn('Ignoring invalid CWD:', cwd)
+22
View File
@@ -0,0 +1,22 @@
import { strictEqual } from 'assert'
/** Rewrite a POSIX guest cwd (e.g. WSL) to a Windows path via fsBase; unchanged otherwise. */
export function resolveGuestCWD (cwd: string | null | undefined, fsBase: string | null | undefined): string | null | undefined {
if (cwd?.startsWith('/') && fsBase) {
return fsBase + cwd.replace(/\//g, '\\')
}
return cwd
}
function selfCheck (): void {
strictEqual(resolveGuestCWD('/home/x', '\\\\wsl$\\Ubuntu'), '\\\\wsl$\\Ubuntu\\home\\x')
strictEqual(resolveGuestCWD('C:\\Users\\x', '\\\\wsl$\\Ubuntu'), 'C:\\Users\\x')
strictEqual(resolveGuestCWD('/home/x', null), '/home/x')
strictEqual(resolveGuestCWD(null, '\\\\wsl$\\Ubuntu'), null)
strictEqual(resolveGuestCWD(undefined, null), undefined)
}
// run: npx ts-node -O '{"module":"commonjs"}' tabby-local/src/wslPath.ts
if (String(process.argv[1]).includes('wslPath')) {
selfCheck()
}