Skip to content

Commit 1668dbd

Browse files
authored
fix(cli): ENOENT during asset publishing (#25869)
There was still a TOCTOU error in the file asset publishing, which could lead to `ENOENT: no such file or directory` when assets were being published in parallel. The whole `if (fileExists) { delete; }` logic was actually not necessary, as `fs.rename` will atomically overwrite existing files already, so we can just call it directly. Closes #25293. ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
1 parent 60699f4 commit 1668dbd

File tree

1 file changed

+6
-17
lines changed

1 file changed

+6
-17
lines changed

packages/cdk-assets/lib/private/archive.ts

Lines changed: 6 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -58,17 +58,18 @@ function writeZipFile(directory: string, outputFile: string): Promise<void> {
5858
}
5959

6060
/**
61-
* Rename the file to the target location, taking into account that we may see EPERM on Windows
62-
* while an Antivirus scanner still has the file open, so retry a couple of times.
61+
* Rename the file to the target location, taking into account:
62+
*
63+
* - That we may see EPERM on Windows while an Antivirus scanner still has the
64+
* file open, so retry a couple of times.
65+
* - This same function may be called in parallel and be interrupted at any point.
6366
*/
6467
async function moveIntoPlace(source: string, target: string, logger: Logger) {
6568
let delay = 100;
6669
let attempts = 5;
6770
while (true) {
6871
try {
69-
if (await pathExists(target)) {
70-
await fs.unlink(target);
71-
}
72+
// 'rename' is guaranteed to overwrite an existing target, as long as it is a file (not a directory)
7273
await fs.rename(source, target);
7374
return;
7475
} catch (e: any) {
@@ -86,18 +87,6 @@ function sleep(ms: number) {
8687
return new Promise(ok => setTimeout(ok, ms));
8788
}
8889

89-
async function pathExists(x: string) {
90-
try {
91-
await fs.stat(x);
92-
return true;
93-
} catch (e: any) {
94-
if (e.code === 'ENOENT') {
95-
return false;
96-
}
97-
throw e;
98-
}
99-
}
100-
10190
function randomString() {
10291
return Math.random().toString(36).replace(/[^a-z0-9]+/g, '');
10392
}

0 commit comments

Comments
 (0)