diff --git a/packages/cli/src/config/extensions/github.ts b/packages/cli/src/config/extensions/github.ts index 79f2385c41..d1598c84a4 100644 --- a/packages/cli/src/config/extensions/github.ts +++ b/packages/cli/src/config/extensions/github.ts @@ -15,9 +15,8 @@ import * as os from 'node:os'; import * as https from 'node:https'; import * as fs from 'node:fs'; import * as path from 'node:path'; -import { execSync } from 'node:child_process'; +import { spawnSync } from 'node:child_process'; import { EXTENSIONS_CONFIG_FILENAME, loadExtension } from '../extension.js'; -import { quote } from 'shell-quote'; function getGitHubToken(): string | undefined { return process.env['GITHUB_TOKEN']; @@ -71,7 +70,7 @@ export async function cloneFromGit( await git.checkout('FETCH_HEAD'); } catch (error) { throw new Error( - `Failed to clone Git repository from ${installMetadata.source}`, + `Failed to clone Git repository from ${installMetadata.source} ${getErrorMessage(error)}`, { cause: error, }, @@ -418,13 +417,23 @@ async function downloadFile(url: string, dest: string): Promise { } function extractFile(file: string, dest: string) { - const safeFile = quote([file]); - const safeDest = quote([dest]); + let args: string[]; if (file.endsWith('.tar.gz')) { - execSync(`tar -xzf ${safeFile} -C ${safeDest}`); + args = ['-xzf', file, '-C', dest]; } else if (file.endsWith('.zip')) { - execSync(`unzip ${safeFile} -d ${safeDest}`); + args = ['-xf', file, '-C', dest]; } else { throw new Error(`Unsupported file extension for extraction: ${file}`); } + + const result = spawnSync('tar', args, { stdio: 'pipe' }); + + if (result.status !== 0) { + if (result.error) { + throw new Error(`Failed to spawn 'tar': ${result.error.message}`); + } + throw new Error( + `'tar' command failed with exit code ${result.status}: ${result.stderr.toString()}`, + ); + } }