Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit5277656

Browse files
committed
fix: SSHConfig: atomically write ssh config
1 parenteda19a2 commit5277656

File tree

2 files changed

+36
-10
lines changed

2 files changed

+36
-10
lines changed

‎src/sshConfig.test.ts

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ const mockFileSystem = {
88
readFile:vi.fn(),
99
mkdir:vi.fn(),
1010
writeFile:vi.fn(),
11+
rename:vi.fn(),
1112
}
1213

1314
afterEach(()=>{
@@ -38,7 +39,12 @@ Host coder-vscode--*
3839
# --- END CODER VSCODE ---`
3940

4041
expect(mockFileSystem.readFile).toBeCalledWith(sshFilePath,expect.anything())
41-
expect(mockFileSystem.writeFile).toBeCalledWith(sshFilePath,expectedOutput,expect.anything())
42+
expect(mockFileSystem.writeFile).toBeCalledWith(
43+
expect.stringContaining(sshFilePath),
44+
expectedOutput,
45+
expect.anything(),
46+
)
47+
expect(mockFileSystem.rename).toBeCalledWith(expect.stringContaining(sshFilePath+"."),sshFilePath)
4248
})
4349

4450
it("creates a new file and adds the config",async()=>{
@@ -65,7 +71,12 @@ Host coder-vscode.dev.coder.com--*
6571
# --- END CODER VSCODE dev.coder.com ---`
6672

6773
expect(mockFileSystem.readFile).toBeCalledWith(sshFilePath,expect.anything())
68-
expect(mockFileSystem.writeFile).toBeCalledWith(sshFilePath,expectedOutput,expect.anything())
74+
expect(mockFileSystem.writeFile).toBeCalledWith(
75+
expect.stringContaining(sshFilePath),
76+
expectedOutput,
77+
expect.anything(),
78+
)
79+
expect(mockFileSystem.rename).toBeCalledWith(expect.stringContaining(sshFilePath+"."),sshFilePath)
6980
})
7081

7182
it("adds a new coder config in an existent SSH configuration",async()=>{
@@ -100,10 +111,11 @@ Host coder-vscode.dev.coder.com--*
100111
UserKnownHostsFile /dev/null
101112
# --- END CODER VSCODE dev.coder.com ---`
102113

103-
expect(mockFileSystem.writeFile).toBeCalledWith(sshFilePath,expectedOutput,{
114+
expect(mockFileSystem.writeFile).toBeCalledWith(expect.stringContaining(sshFilePath),expectedOutput,{
104115
encoding:"utf-8",
105116
mode:384,
106117
})
118+
expect(mockFileSystem.rename).toBeCalledWith(expect.stringContaining(sshFilePath+"."),sshFilePath)
107119
})
108120

109121
it("updates an existent coder config",async()=>{
@@ -164,10 +176,11 @@ Host coder-vscode.dev-updated.coder.com--*
164176
Host *
165177
SetEnv TEST=1`
166178

167-
expect(mockFileSystem.writeFile).toBeCalledWith(sshFilePath,expectedOutput,{
179+
expect(mockFileSystem.writeFile).toBeCalledWith(expect.stringContaining(sshFilePath),expectedOutput,{
168180
encoding:"utf-8",
169181
mode:384,
170182
})
183+
expect(mockFileSystem.rename).toBeCalledWith(expect.stringContaining(sshFilePath+"."),sshFilePath)
171184
})
172185

173186
it("does not remove deployment-unaware SSH config and adds the new one",async()=>{
@@ -209,10 +222,11 @@ Host coder-vscode.dev.coder.com--*
209222
UserKnownHostsFile /dev/null
210223
# --- END CODER VSCODE dev.coder.com ---`
211224

212-
expect(mockFileSystem.writeFile).toBeCalledWith(sshFilePath,expectedOutput,{
225+
expect(mockFileSystem.writeFile).toBeCalledWith(expect.stringContaining(sshFilePath),expectedOutput,{
213226
encoding:"utf-8",
214227
mode:384,
215228
})
229+
expect(mockFileSystem.rename).toBeCalledWith(expect.stringContaining(sshFilePath+"."),sshFilePath)
216230
})
217231

218232
it("it does not remove a user-added block that only matches the host of an old coder SSH config",async()=>{
@@ -243,10 +257,11 @@ Host coder-vscode.dev.coder.com--*
243257
UserKnownHostsFile /dev/null
244258
# --- END CODER VSCODE dev.coder.com ---`
245259

246-
expect(mockFileSystem.writeFile).toBeCalledWith(sshFilePath,expectedOutput,{
260+
expect(mockFileSystem.writeFile).toBeCalledWith(expect.stringContaining(sshFilePath),expectedOutput,{
247261
encoding:"utf-8",
248262
mode:384,
249263
})
264+
expect(mockFileSystem.rename).toBeCalledWith(expect.stringContaining(sshFilePath+"."),sshFilePath)
250265
})
251266

252267
it("throws an error if there is a mismatched start and end block count",async()=>{
@@ -426,10 +441,11 @@ Host afterconfig
426441
LogLevel:"ERROR",
427442
})
428443

429-
expect(mockFileSystem.writeFile).toBeCalledWith(sshFilePath,expectedOutput,{
444+
expect(mockFileSystem.writeFile).toBeCalledWith(expect.stringContaining(sshFilePath),expectedOutput,{
430445
encoding:"utf-8",
431446
mode:384,
432447
})
448+
expect(mockFileSystem.rename).toBeCalledWith(expect.stringContaining(sshFilePath+"."),sshFilePath)
433449
})
434450

435451
it("override values",async()=>{
@@ -470,5 +486,10 @@ Host coder-vscode.dev.coder.com--*
470486
# --- END CODER VSCODE dev.coder.com ---`
471487

472488
expect(mockFileSystem.readFile).toBeCalledWith(sshFilePath,expect.anything())
473-
expect(mockFileSystem.writeFile).toBeCalledWith(sshFilePath,expectedOutput,expect.anything())
489+
expect(mockFileSystem.writeFile).toBeCalledWith(
490+
expect.stringContaining(sshFilePath),
491+
expectedOutput,
492+
expect.anything(),
493+
)
494+
expect(mockFileSystem.rename).toBeCalledWith(expect.stringContaining(sshFilePath+"."),sshFilePath)
474495
})

‎src/sshConfig.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import{mkdir,readFile,writeFile}from"fs/promises"
1+
import{mkdir,readFile,writeFile,rename}from"fs/promises"
22
importpathfrom"path"
33
import{countSubstring}from"./util"
44

@@ -23,12 +23,14 @@ export interface FileSystem {
2323
readFile:typeofreadFile
2424
mkdir:typeofmkdir
2525
writeFile:typeofwriteFile
26+
rename:typeofrename
2627
}
2728

2829
constdefaultFileSystem:FileSystem={
2930
readFile,
3031
mkdir,
3132
writeFile,
33+
rename,
3234
}
3335

3436
// mergeSSHConfigValues will take a given ssh config and merge it with the overrides
@@ -223,10 +225,13 @@ export class SSHConfig {
223225
mode:0o700,// only owner has rwx permission, not group or everyone.
224226
recursive:true,
225227
})
226-
returnthis.fileSystem.writeFile(this.filePath,this.getRaw(),{
228+
constrandSuffix=Math.random().toString(36).substring(8)
229+
consttempFilePath=`${this.filePath}.${randSuffix}`
230+
awaitthis.fileSystem.writeFile(tempFilePath,this.getRaw(),{
227231
mode:0o600,// owner rw
228232
encoding:"utf-8",
229233
})
234+
awaitthis.fileSystem.rename(tempFilePath,this.filePath)
230235
}
231236

232237
publicgetRaw(){

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp