Skip to content

Commit 8ac1e78

Browse files
committed
improve error message on failure to write/rename
1 parent b61468b commit 8ac1e78

File tree

2 files changed

+70
-5
lines changed

2 files changed

+70
-5
lines changed

src/sshConfig.test.ts

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -607,3 +607,52 @@ Host coder-vscode.dev.coder.com--*
607607
)
608608
expect(mockFileSystem.rename).toBeCalledWith(expect.stringMatching(sshTempFilePathExpr), sshFilePath)
609609
})
610+
611+
it("fails if we are unable to write the temporary file", async () => {
612+
const existentSSHConfig = `Host beforeconfig
613+
HostName before.config.tld
614+
User before`
615+
616+
const sshConfig = new SSHConfig(sshFilePath, mockFileSystem)
617+
mockFileSystem.readFile.mockResolvedValueOnce(existentSSHConfig)
618+
mockFileSystem.stat.mockResolvedValueOnce({ mode: 0o600 })
619+
mockFileSystem.writeFile.mockRejectedValueOnce(new Error("EACCES"))
620+
621+
await sshConfig.load()
622+
623+
expect(mockFileSystem.readFile).toBeCalledWith(sshFilePath, expect.anything())
624+
await expect(
625+
sshConfig.update("dev.coder.com", {
626+
Host: "coder-vscode.dev.coder.com--*",
627+
ProxyCommand: "some-command-here",
628+
ConnectTimeout: "0",
629+
StrictHostKeyChecking: "no",
630+
UserKnownHostsFile: "/dev/null",
631+
LogLevel: "ERROR",
632+
}),
633+
).rejects.toThrow(/Failed to write temporary SSH config file.*EACCES/)
634+
})
635+
636+
it("fails if we are unable to rename the temporary file", async () => {
637+
const existentSSHConfig = `Host beforeconfig
638+
HostName before.config.tld
639+
User before`
640+
641+
const sshConfig = new SSHConfig(sshFilePath, mockFileSystem)
642+
mockFileSystem.readFile.mockResolvedValueOnce(existentSSHConfig)
643+
mockFileSystem.stat.mockResolvedValueOnce({ mode: 0o600 })
644+
mockFileSystem.writeFile.mockResolvedValueOnce("")
645+
mockFileSystem.rename.mockRejectedValueOnce(new Error("EACCES"))
646+
647+
await sshConfig.load()
648+
await expect(
649+
sshConfig.update("dev.coder.com", {
650+
Host: "coder-vscode.dev.coder.com--*",
651+
ProxyCommand: "some-command-here",
652+
ConnectTimeout: "0",
653+
StrictHostKeyChecking: "no",
654+
UserKnownHostsFile: "/dev/null",
655+
LogLevel: "ERROR",
656+
}),
657+
).rejects.toThrow(/Failed to rename temporary SSH config file.*EACCES/)
658+
})

src/sshConfig.ts

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -242,11 +242,27 @@ export class SSHConfig {
242242
const fileName = path.basename(this.filePath)
243243
const dirName = path.dirname(this.filePath)
244244
const tempFilePath = `${dirName}/.${fileName}.vscode-coder-tmp.${randSuffix}`
245-
await this.fileSystem.writeFile(tempFilePath, this.getRaw(), {
246-
mode: existingMode,
247-
encoding: "utf-8",
248-
})
249-
await this.fileSystem.rename(tempFilePath, this.filePath)
245+
try {
246+
await this.fileSystem.writeFile(tempFilePath, this.getRaw(), {
247+
mode: existingMode,
248+
encoding: "utf-8",
249+
})
250+
} catch (err) {
251+
throw new Error(
252+
`Failed to write temporary SSH config file at ${tempFilePath}: ${err instanceof Error ? err.message : String(err)}. ` +
253+
`Please check your disk space, permissions, and that the directory exists.`,
254+
)
255+
}
256+
257+
try {
258+
await this.fileSystem.rename(tempFilePath, this.filePath)
259+
} catch (err) {
260+
throw new Error(
261+
`Failed to rename temporary SSH config file at ${tempFilePath} to ${this.filePath}: ${
262+
err instanceof Error ? err.message : String(err)
263+
}. Please check your disk space, permissions, and that the directory exists.`,
264+
)
265+
}
250266
}
251267

252268
public getRaw() {

0 commit comments

Comments
 (0)