Skip to content

Commit 8ee388b

Browse files
fix: EPERM error during SSO token refresh (aws#5335)
* fix: eperm error during SSO token refresh Problem: During token refresh we were seeing unexpected EPERM errors in the `aws_refreshCredentials` metric. Solution: A node filesystem rename() call can fail due to a racecondition on Windows. Looking in to the VS Code Filesystem implementation they account for this: https://github.com/microsoft/vscode/blob/09d5f4efc5089ce2fc5c8f6aeb51d728d7f4e758/src/vs/base/node/pfs.ts#L496 So we just need to use this rename instead. Additional info here from graceful-fs which inspired the VSCode implementation: https://github.com/isaacs/node-graceful-fs/blob/234379906b7d2f4c9cfeb412d2516f42b0fb4953/polyfills.js#L87 Signed-off-by: Nikolas Komonen <[email protected]> * changelog items Signed-off-by: Nikolas Komonen <[email protected]> --------- Signed-off-by: Nikolas Komonen <[email protected]>
1 parent d58f5fe commit 8ee388b

File tree

5 files changed

+55
-2
lines changed

5 files changed

+55
-2
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"type": "Bug Fix",
3+
"description": "Unexpected SSO expiration on Windows due to EPERM"
4+
}

packages/core/src/shared/fs/fs.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,18 @@ export class FileSystem {
202202
return vfs.writeFile(uri, content).then(undefined, errHandler)
203203
}
204204

205+
async rename(oldPath: vscode.Uri | string, newPath: vscode.Uri | string) {
206+
const oldUri = this.#toUri(oldPath)
207+
const newUri = this.#toUri(newPath)
208+
const errHandler = createPermissionsErrorHandler(this.isWeb, oldUri, 'rw*')
209+
210+
if (isCloud9()) {
211+
return nodefs.rename(oldUri.fsPath, newUri.fsPath).catch(errHandler)
212+
}
213+
214+
return vfs.rename(oldUri, newUri, { overwrite: true }).then(undefined, errHandler)
215+
}
216+
205217
/**
206218
* The stat of the file, throws if the file does not exist or on any other error.
207219
*/

packages/core/src/shared/utilities/cacheUtils.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import * as vscode from 'vscode'
77
import { dirname } from 'path'
88
import { ToolkitError, isFileNotFoundError } from '../errors'
99
import fs from '../../shared/fs/fs'
10-
import { promises as fsPromises } from 'fs'
1110
import crypto from 'crypto'
1211
import { isWeb } from '../extensionGlobals'
1312

@@ -136,7 +135,7 @@ export function createDiskCache<T, K>(
136135
// write, though there can still be race conditions with which version remains after overwrites.
137136
const tempFile = `${target}.tmp-${crypto.randomBytes(4).toString('hex')}`
138137
await fs.writeFile(tempFile, JSON.stringify(data), { mode: 0o600 })
139-
await fsPromises.rename(tempFile, target)
138+
await fs.rename(tempFile, target)
140139
}
141140
} catch (error) {
142141
throw ToolkitError.chain(error, `Failed to save "${target}"`, {

packages/core/src/test/shared/fs/fs.test.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,40 @@ describe('FileSystem', function () {
331331
})
332332
})
333333

334+
describe('rename()', async () => {
335+
it('renames a file', async () => {
336+
const oldPath = await makeFile('oldFile.txt', 'hello world')
337+
const newPath = path.join(path.dirname(oldPath), 'newFile.txt')
338+
339+
await fs.rename(oldPath, newPath)
340+
341+
assert.strictEqual(await fs.readFileAsString(newPath), 'hello world')
342+
assert(!existsSync(oldPath))
343+
})
344+
345+
it('renames a folder', async () => {
346+
const oldPath = mkTestDir('test')
347+
await fs.writeFile(path.join(oldPath, 'file.txt'), 'test text')
348+
const newPath = path.join(path.dirname(oldPath), 'newName')
349+
350+
await fs.rename(oldPath, newPath)
351+
352+
assert(existsSync(newPath))
353+
assert.deepStrictEqual(await fs.readFileAsString(path.join(newPath, 'file.txt')), 'test text')
354+
assert(!existsSync(oldPath))
355+
})
356+
357+
it('overwrites if destination exists', async () => {
358+
const oldPath = await makeFile('oldFile.txt', 'hello world')
359+
const newPath = await makeFile('newFile.txt', 'some content')
360+
361+
await fs.rename(oldPath, newPath)
362+
363+
assert.strictEqual(await fs.readFileAsString(newPath), 'hello world')
364+
assert(!existsSync(oldPath))
365+
})
366+
})
367+
334368
describe('getUserHomeDir()', function () {
335369
let fakeHome: string
336370
let saveEnv: EnvironmentVariables = {}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"type": "Bug Fix",
3+
"description": "Unexpected SSO expiration on Windows due to EPERM"
4+
}

0 commit comments

Comments
 (0)