diff --git a/packages/twenty-sdk/src/cli/operations/publish.ts b/packages/twenty-sdk/src/cli/operations/publish.ts index d82d5aef4f..5140523b54 100644 --- a/packages/twenty-sdk/src/cli/operations/publish.ts +++ b/packages/twenty-sdk/src/cli/operations/publish.ts @@ -1,4 +1,4 @@ -import { execSync } from 'child_process'; +import { execFileSync } from 'child_process'; import { runSafe } from '@/cli/utilities/run-safe'; import { appBuild } from './build'; @@ -30,12 +30,28 @@ const innerAppPublish = async ( onProgress?.('Publishing to npm...'); - const tagArg = options.npmTag ? ` --tag ${options.npmTag}` : ''; + if (options.npmTag && !/^[a-zA-Z0-9][a-zA-Z0-9._-]*$/.test(options.npmTag)) { + return { + success: false, + error: { + code: APP_ERROR_CODES.PUBLISH_FAILED, + message: `Invalid npm tag: ${options.npmTag}`, + }, + }; + } + + const publishArgs = [ + 'publish', + ...(options.npmTag ? ['--tag', options.npmTag] : []), + ]; + + const isWindows = process.platform === 'win32'; try { - execSync(`npm publish${tagArg}`, { + execFileSync(isWindows ? 'npm.cmd' : 'npm', publishArgs, { cwd: buildResult.data.outputDir, stdio: 'inherit', + shell: isWindows, }); } catch { return { diff --git a/packages/twenty-sdk/src/cli/utilities/server/docker-container.ts b/packages/twenty-sdk/src/cli/utilities/server/docker-container.ts index 397fa1b5e2..e7b928edf7 100644 --- a/packages/twenty-sdk/src/cli/utilities/server/docker-container.ts +++ b/packages/twenty-sdk/src/cli/utilities/server/docker-container.ts @@ -1,4 +1,4 @@ -import { execSync } from 'node:child_process'; +import { execFileSync } from 'node:child_process'; export const CONTAINER_NAME = 'twenty-app-dev'; export const TEST_CONTAINER_NAME = 'twenty-app-dev-test'; @@ -8,8 +8,9 @@ export const DEFAULT_TEST_PORT = 2021; export const isContainerRunning = (containerName = CONTAINER_NAME): boolean => { try { - const result = execSync( - `docker inspect -f '{{.State.Running}}' ${containerName}`, + const result = execFileSync( + 'docker', + ['inspect', '-f', '{{.State.Running}}', containerName], { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'ignore'] }, ).trim(); @@ -24,8 +25,14 @@ export const getContainerPort = (containerName = CONTAINER_NAME): number => { containerName === TEST_CONTAINER_NAME ? DEFAULT_TEST_PORT : DEFAULT_PORT; try { - const result = execSync( - `docker inspect -f '{{range .Config.Env}}{{println .}}{{end}}' ${containerName}`, + const result = execFileSync( + 'docker', + [ + 'inspect', + '-f', + '{{range .Config.Env}}{{println .}}{{end}}', + containerName, + ], { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'ignore'] }, ); @@ -39,7 +46,7 @@ export const getContainerPort = (containerName = CONTAINER_NAME): number => { export const containerExists = (containerName = CONTAINER_NAME): boolean => { try { - execSync(`docker inspect ${containerName}`, { + execFileSync('docker', ['inspect', containerName], { stdio: ['pipe', 'pipe', 'ignore'], }); @@ -56,10 +63,14 @@ export const getContainerDigest = ( containerName = CONTAINER_NAME, ): string | null => { try { - return execSync(`docker inspect -f '{{.Image}}' ${containerName}`, { - encoding: 'utf-8', - stdio: ['pipe', 'pipe', 'ignore'], - }).trim(); + return execFileSync( + 'docker', + ['inspect', '-f', '{{.Image}}', containerName], + { + encoding: 'utf-8', + stdio: ['pipe', 'pipe', 'ignore'], + }, + ).trim(); } catch { return null; } @@ -67,7 +78,7 @@ export const getContainerDigest = ( export const getImageDigest = (image: string): string | null => { try { - return execSync(`docker inspect -f '{{.Id}}' ${image}`, { + return execFileSync('docker', ['inspect', '-f', '{{.Id}}', image], { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'ignore'], }).trim(); @@ -81,8 +92,14 @@ export const getContainerEnvVar = ( containerName = CONTAINER_NAME, ): string | null => { try { - const result = execSync( - `docker inspect -f '{{range .Config.Env}}{{println .}}{{end}}' ${containerName}`, + const result = execFileSync( + 'docker', + [ + 'inspect', + '-f', + '{{range .Config.Env}}{{println .}}{{end}}', + containerName, + ], { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'ignore'] }, ); @@ -96,7 +113,7 @@ export const getContainerEnvVar = ( export const checkDockerRunning = (): boolean => { try { - execSync('docker info', { stdio: 'ignore' }); + execFileSync('docker', ['info'], { stdio: 'ignore' }); return true; } catch {