From 91c6b8377d17ac30148d94ebc783c97132bdb3a6 Mon Sep 17 00:00:00 2001 From: Cleber Hensel Date: Fri, 24 Oct 2025 13:07:54 -0300 Subject: [PATCH 1/3] fix: ajuste no workflow para dist no npm --- apps/cli/src/commands/install.ts | 18 +++++++++++++++++- apps/cli/src/commands/update.ts | 18 +++++++++++++++++- apps/cli/src/stash/conflict-detector.ts | 5 ++++- 3 files changed, 38 insertions(+), 3 deletions(-) diff --git a/apps/cli/src/commands/install.ts b/apps/cli/src/commands/install.ts index 64eea48..586a808 100644 --- a/apps/cli/src/commands/install.ts +++ b/apps/cli/src/commands/install.ts @@ -158,6 +158,23 @@ export async function installCommand( source: string, options: { conflict?: string; agent?: string; dryRun?: boolean } = {} ): Promise { + const projectRoot = path.resolve(process.cwd()); + const criticalPaths = [ + '/', '/usr', '/etc', '/var', '/System', '/Library', '/bin', '/sbin', '/opt', '/boot', + '/private/etc', '/private/var', '/private/tmp' + ]; + + const isCriticalDir = criticalPaths.some(critical => { + const resolvedCritical = path.resolve(critical); + return projectRoot === resolvedCritical || projectRoot.startsWith(resolvedCritical + path.sep); + }); + + if (isCriticalDir) { + console.error(chalk.red(`❌ Cannot install in critical system directory: ${projectRoot}`)); + console.error(chalk.yellow('Please run from a safe project directory.')); + throw new Error(`Installation blocked: critical system directory`); + } + const spinner = ora('Installing vibe...').start(); try { @@ -197,7 +214,6 @@ export async function installCommand( spinner.text = 'Detecting agents...'; - const projectRoot = process.cwd(); const adapters = AdapterRegistry.getAllAdapters(); const detector = new AgentDetector(adapters); let detectedAgents = await detector.detectAll(); diff --git a/apps/cli/src/commands/update.ts b/apps/cli/src/commands/update.ts index db560a7..1fbc6a3 100644 --- a/apps/cli/src/commands/update.ts +++ b/apps/cli/src/commands/update.ts @@ -63,6 +63,23 @@ export async function updateCommand( dryRun?: boolean; } = {} ): Promise { + const projectRoot = path.resolve(process.cwd()); + const criticalPaths = [ + '/', '/usr', '/etc', '/var', '/System', '/Library', '/bin', '/sbin', '/opt', '/boot', + '/private/etc', '/private/var', '/private/tmp' + ]; + + const isCriticalDir = criticalPaths.some(critical => { + const resolvedCritical = path.resolve(critical); + return projectRoot === resolvedCritical || projectRoot.startsWith(resolvedCritical + path.sep); + }); + + if (isCriticalDir) { + console.error(chalk.red(`❌ Cannot update in critical system directory: ${projectRoot}`)); + console.error(chalk.yellow('Please run from a safe project directory.')); + throw new Error(`Update blocked: critical system directory`); + } + const spinner = ora('Updating vibe...').start(); try { @@ -92,7 +109,6 @@ export async function updateCommand( vibeManifest = result.manifest; } - const projectRoot = process.cwd(); const vibeDir = getVibePackageDir(vibeManifest.name, vibeManifest.version); if (!vibeManifest.symlinks) { diff --git a/apps/cli/src/stash/conflict-detector.ts b/apps/cli/src/stash/conflict-detector.ts index e3ec4b2..82e6720 100644 --- a/apps/cli/src/stash/conflict-detector.ts +++ b/apps/cli/src/stash/conflict-detector.ts @@ -1,5 +1,6 @@ import { existsSync, statSync } from 'node:fs'; import path from 'node:path'; +import crypto from 'node:crypto'; import { HashCalculator } from './hash-calculator.js'; export interface Conflict { @@ -68,7 +69,9 @@ export class ConflictDetector { if (stats.isDirectory()) { const hashes = await this.hashCalculator.calculateDirectory(filePath); const allHashes = Array.from(hashes.values()).join(''); - return this.hashCalculator.calculateFile(Buffer.from(allHashes) as any) || allHashes.substring(0, 64); + const hash = crypto.createHash('sha256'); + hash.update(allHashes); + return hash.digest('hex'); } return this.hashCalculator.calculateFile(filePath); From 342154aac0bc79616f1c7c33fbc67696fe76b46e Mon Sep 17 00:00:00 2001 From: Cleber Hensel Date: Fri, 24 Oct 2025 13:27:12 -0300 Subject: [PATCH 2/3] =?UTF-8?q?feat:=20ajuste=20na=20instala=C3=A7=C3=A3o?= =?UTF-8?q?=20para=20win?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/cli/src/commands/install.ts | 12 +- apps/cli/src/commands/update.ts | 12 +- .../src/utils/__tests__/safe-paths.test.ts | 113 ++++++++++++++++++ apps/cli/src/utils/safe-paths.ts | 97 +++++++++++++++ 4 files changed, 214 insertions(+), 20 deletions(-) create mode 100644 apps/cli/src/utils/__tests__/safe-paths.test.ts create mode 100644 apps/cli/src/utils/safe-paths.ts diff --git a/apps/cli/src/commands/install.ts b/apps/cli/src/commands/install.ts index 586a808..18f4748 100644 --- a/apps/cli/src/commands/install.ts +++ b/apps/cli/src/commands/install.ts @@ -10,6 +10,7 @@ import { AdapterRegistry, AgentDetector, type VibePackage, type TargetPaths } fr import { ConflictDetector } from '../stash/conflict-detector.js'; import { ConflictResolver } from '../stash/conflict-resolver.js'; import { StashManager } from '../stash/stash-manager.js'; +import { isCriticalSystemDirectory } from '../utils/safe-paths.js'; interface GlobalManifest { version: string; @@ -159,17 +160,8 @@ export async function installCommand( options: { conflict?: string; agent?: string; dryRun?: boolean } = {} ): Promise { const projectRoot = path.resolve(process.cwd()); - const criticalPaths = [ - '/', '/usr', '/etc', '/var', '/System', '/Library', '/bin', '/sbin', '/opt', '/boot', - '/private/etc', '/private/var', '/private/tmp' - ]; - const isCriticalDir = criticalPaths.some(critical => { - const resolvedCritical = path.resolve(critical); - return projectRoot === resolvedCritical || projectRoot.startsWith(resolvedCritical + path.sep); - }); - - if (isCriticalDir) { + if (isCriticalSystemDirectory(projectRoot)) { console.error(chalk.red(`❌ Cannot install in critical system directory: ${projectRoot}`)); console.error(chalk.yellow('Please run from a safe project directory.')); throw new Error(`Installation blocked: critical system directory`); diff --git a/apps/cli/src/commands/update.ts b/apps/cli/src/commands/update.ts index 1fbc6a3..e79e740 100644 --- a/apps/cli/src/commands/update.ts +++ b/apps/cli/src/commands/update.ts @@ -9,6 +9,7 @@ import { getVibesHome, getVibePackageDir } from '../utils/symlink-manager.js'; import { ConflictDetector } from '../stash/conflict-detector.js'; import { ConflictResolver } from '../stash/conflict-resolver.js'; import { StashManager } from '../stash/stash-manager.js'; +import { isCriticalSystemDirectory } from '../utils/safe-paths.js'; interface GlobalManifest { version: string; @@ -64,17 +65,8 @@ export async function updateCommand( } = {} ): Promise { const projectRoot = path.resolve(process.cwd()); - const criticalPaths = [ - '/', '/usr', '/etc', '/var', '/System', '/Library', '/bin', '/sbin', '/opt', '/boot', - '/private/etc', '/private/var', '/private/tmp' - ]; - const isCriticalDir = criticalPaths.some(critical => { - const resolvedCritical = path.resolve(critical); - return projectRoot === resolvedCritical || projectRoot.startsWith(resolvedCritical + path.sep); - }); - - if (isCriticalDir) { + if (isCriticalSystemDirectory(projectRoot)) { console.error(chalk.red(`❌ Cannot update in critical system directory: ${projectRoot}`)); console.error(chalk.yellow('Please run from a safe project directory.')); throw new Error(`Update blocked: critical system directory`); diff --git a/apps/cli/src/utils/__tests__/safe-paths.test.ts b/apps/cli/src/utils/__tests__/safe-paths.test.ts new file mode 100644 index 0000000..4227e64 --- /dev/null +++ b/apps/cli/src/utils/__tests__/safe-paths.test.ts @@ -0,0 +1,113 @@ +import { describe, it, expect, beforeEach, afterEach } from 'vitest'; +import { getCriticalSystemPaths, isCriticalSystemDirectory, isUserHomeDirectory } from '../safe-paths.js'; +import os from 'node:os'; +import path from 'node:path'; + +describe('safe-paths', () => { + const originalPlatform = process.platform; + + afterEach(() => { + Object.defineProperty(process, 'platform', { + value: originalPlatform + }); + }); + + describe('getCriticalSystemPaths', () => { + it('returns Windows paths on win32', () => { + Object.defineProperty(process, 'platform', { + value: 'win32' + }); + + const paths = getCriticalSystemPaths(); + + expect(paths).toContain('C:\\'); + expect(paths.some(p => p.includes('Windows'))).toBe(true); + expect(paths.some(p => p.includes('Program Files'))).toBe(true); + }); + + it('returns macOS paths on darwin', () => { + Object.defineProperty(process, 'platform', { + value: 'darwin' + }); + + const paths = getCriticalSystemPaths(); + + expect(paths).toContain('/'); + expect(paths).toContain('/System'); + expect(paths).toContain('/Library'); + expect(paths).toContain('/Applications'); + }); + + it('returns Linux paths on linux', () => { + Object.defineProperty(process, 'platform', { + value: 'linux' + }); + + const paths = getCriticalSystemPaths(); + + expect(paths).toContain('/'); + expect(paths).toContain('/usr'); + expect(paths).toContain('/etc'); + expect(paths).toContain('/var'); + }); + }); + + describe('isCriticalSystemDirectory', () => { + it('detects root directory as critical', () => { + const isRootCritical = isCriticalSystemDirectory('/'); + expect(isRootCritical).toBe(true); + }); + + it('detects subdirectories of critical paths', () => { + if (process.platform === 'darwin' || process.platform === 'linux') { + expect(isCriticalSystemDirectory('/usr/local')).toBe(true); + expect(isCriticalSystemDirectory('/etc/config')).toBe(true); + } + }); + + it('allows safe project directories', () => { + const homeDir = os.homedir(); + const projectDir = path.join(homeDir, 'projects', 'my-app'); + + expect(isCriticalSystemDirectory(projectDir)).toBe(false); + }); + + it('normalizes paths correctly', () => { + if (process.platform === 'darwin' || process.platform === 'linux') { + expect(isCriticalSystemDirectory('/usr/../usr')).toBe(true); + } + }); + }); + + describe('isUserHomeDirectory', () => { + it('detects user home directory', () => { + const homeDir = os.homedir(); + expect(isUserHomeDirectory(homeDir)).toBe(true); + }); + + it('allows subdirectories of home', () => { + const homeDir = os.homedir(); + const subDir = path.join(homeDir, 'projects'); + + expect(isUserHomeDirectory(subDir)).toBe(false); + }); + }); + + describe('cross-platform compatibility', () => { + it('handles paths with different separators', () => { + const userDir = path.join(os.homedir(), 'projects', 'app'); + + const result = isCriticalSystemDirectory(userDir); + + expect(typeof result).toBe('boolean'); + }); + + it('resolves relative paths', () => { + const relativePath = './some/project'; + const resolvedCheck = isCriticalSystemDirectory(relativePath); + + expect(typeof resolvedCheck).toBe('boolean'); + }); + }); +}); + diff --git a/apps/cli/src/utils/safe-paths.ts b/apps/cli/src/utils/safe-paths.ts new file mode 100644 index 0000000..f021bf0 --- /dev/null +++ b/apps/cli/src/utils/safe-paths.ts @@ -0,0 +1,97 @@ +import path from 'node:path'; +import os from 'node:os'; + +export function getCriticalSystemPaths(): string[] { + const platform = process.platform; + + if (platform === 'win32') { + const systemRoot = process.env.SystemRoot || 'C:\\Windows'; + const programFiles = process.env['ProgramFiles'] || 'C:\\Program Files'; + const programFilesX86 = process.env['ProgramFiles(x86)'] || 'C:\\Program Files (x86)'; + const drives = ['C:\\', 'D:\\', 'E:\\']; + + return [ + ...drives, + systemRoot, + path.join(systemRoot, 'System32'), + programFiles, + programFilesX86, + 'C:\\Windows', + 'C:\\Program Files', + 'C:\\Program Files (x86)' + ]; + } + + if (platform === 'darwin') { + return [ + '/', + '/usr', + '/etc', + '/var', + '/System', + '/Library', + '/bin', + '/sbin', + '/opt', + '/private/etc', + '/private/var', + '/private/tmp', + '/Applications' + ]; + } + + return [ + '/', + '/usr', + '/etc', + '/var', + '/bin', + '/sbin', + '/opt', + '/boot', + '/lib', + '/lib64', + '/sys', + '/proc', + '/dev', + '/root' + ]; +} + +export function isCriticalSystemDirectory(targetPath: string): boolean { + const resolved = path.resolve(targetPath); + const criticalPaths = getCriticalSystemPaths(); + + return criticalPaths.some(critical => { + const resolvedCritical = path.resolve(critical); + + if (resolved === resolvedCritical) { + return true; + } + + const normalizedResolved = resolved + path.sep; + const normalizedCritical = resolvedCritical + path.sep; + + return normalizedResolved.startsWith(normalizedCritical); + }); +} + +export function isUserHomeDirectory(targetPath: string): boolean { + const resolved = path.resolve(targetPath); + const homeDir = os.homedir(); + + return resolved === homeDir; +} + +export function getSafeInstallMessage(targetPath: string): string { + if (isUserHomeDirectory(targetPath)) { + return 'Installing in home directory is not recommended. Please run from a project directory.'; + } + + if (isCriticalSystemDirectory(targetPath)) { + return 'Cannot install in critical system directory. Please run from a safe project directory.'; + } + + return ''; +} + From 35e523e5eed6632a088ff0e02c9b2afa72f696d2 Mon Sep 17 00:00:00 2001 From: Cleber Hensel Date: Fri, 24 Oct 2025 13:31:23 -0300 Subject: [PATCH 3/3] fix(cli): add cross-platform support for critical system directory protection - Create safe-paths utility with platform-specific critical path detection - Support Windows (C:\, C:\Windows, C:\Program Files, etc) - Support macOS (/, /System, /Library, /Applications, etc) - Support Linux (/, /usr, /etc, /var, /root, etc) - Refactor install and update commands to use new utility - Add comprehensive test suite (11 tests covering all platforms) Fixes: POSIX path handling that failed on Windows --- apps/cli/src/utils/__tests__/safe-paths.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/cli/src/utils/__tests__/safe-paths.test.ts b/apps/cli/src/utils/__tests__/safe-paths.test.ts index 4227e64..f4ebdd7 100644 --- a/apps/cli/src/utils/__tests__/safe-paths.test.ts +++ b/apps/cli/src/utils/__tests__/safe-paths.test.ts @@ -1,4 +1,4 @@ -import { describe, it, expect, beforeEach, afterEach } from 'vitest'; +import { describe, it, expect, afterEach } from 'vitest'; import { getCriticalSystemPaths, isCriticalSystemDirectory, isUserHomeDirectory } from '../safe-paths.js'; import os from 'node:os'; import path from 'node:path';