Skip to content

Commit 914bbd4

Browse files
authored
Merge pull request #16 from OnoSendae/fix/relase-workflow
fix: ajuste no workflow para dist no npm
2 parents 7c755ca + 35e523e commit 914bbd4

File tree

5 files changed

+232
-3
lines changed

5 files changed

+232
-3
lines changed

apps/cli/src/commands/install.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { AdapterRegistry, AgentDetector, type VibePackage, type TargetPaths } fr
1010
import { ConflictDetector } from '../stash/conflict-detector.js';
1111
import { ConflictResolver } from '../stash/conflict-resolver.js';
1212
import { StashManager } from '../stash/stash-manager.js';
13+
import { isCriticalSystemDirectory } from '../utils/safe-paths.js';
1314

1415
interface GlobalManifest {
1516
version: string;
@@ -158,6 +159,14 @@ export async function installCommand(
158159
source: string,
159160
options: { conflict?: string; agent?: string; dryRun?: boolean } = {}
160161
): Promise<void> {
162+
const projectRoot = path.resolve(process.cwd());
163+
164+
if (isCriticalSystemDirectory(projectRoot)) {
165+
console.error(chalk.red(`❌ Cannot install in critical system directory: ${projectRoot}`));
166+
console.error(chalk.yellow('Please run from a safe project directory.'));
167+
throw new Error(`Installation blocked: critical system directory`);
168+
}
169+
161170
const spinner = ora('Installing vibe...').start();
162171

163172
try {
@@ -197,7 +206,6 @@ export async function installCommand(
197206

198207
spinner.text = 'Detecting agents...';
199208

200-
const projectRoot = process.cwd();
201209
const adapters = AdapterRegistry.getAllAdapters();
202210
const detector = new AgentDetector(adapters);
203211
let detectedAgents = await detector.detectAll();

apps/cli/src/commands/update.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { getVibesHome, getVibePackageDir } from '../utils/symlink-manager.js';
99
import { ConflictDetector } from '../stash/conflict-detector.js';
1010
import { ConflictResolver } from '../stash/conflict-resolver.js';
1111
import { StashManager } from '../stash/stash-manager.js';
12+
import { isCriticalSystemDirectory } from '../utils/safe-paths.js';
1213

1314
interface GlobalManifest {
1415
version: string;
@@ -63,6 +64,14 @@ export async function updateCommand(
6364
dryRun?: boolean;
6465
} = {}
6566
): Promise<void> {
67+
const projectRoot = path.resolve(process.cwd());
68+
69+
if (isCriticalSystemDirectory(projectRoot)) {
70+
console.error(chalk.red(`❌ Cannot update in critical system directory: ${projectRoot}`));
71+
console.error(chalk.yellow('Please run from a safe project directory.'));
72+
throw new Error(`Update blocked: critical system directory`);
73+
}
74+
6675
const spinner = ora('Updating vibe...').start();
6776

6877
try {
@@ -92,7 +101,6 @@ export async function updateCommand(
92101
vibeManifest = result.manifest;
93102
}
94103

95-
const projectRoot = process.cwd();
96104
const vibeDir = getVibePackageDir(vibeManifest.name, vibeManifest.version);
97105

98106
if (!vibeManifest.symlinks) {

apps/cli/src/stash/conflict-detector.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { existsSync, statSync } from 'node:fs';
22
import path from 'node:path';
3+
import crypto from 'node:crypto';
34
import { HashCalculator } from './hash-calculator.js';
45

56
export interface Conflict {
@@ -68,7 +69,9 @@ export class ConflictDetector {
6869
if (stats.isDirectory()) {
6970
const hashes = await this.hashCalculator.calculateDirectory(filePath);
7071
const allHashes = Array.from(hashes.values()).join('');
71-
return this.hashCalculator.calculateFile(Buffer.from(allHashes) as any) || allHashes.substring(0, 64);
72+
const hash = crypto.createHash('sha256');
73+
hash.update(allHashes);
74+
return hash.digest('hex');
7275
}
7376

7477
return this.hashCalculator.calculateFile(filePath);
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
import { describe, it, expect, afterEach } from 'vitest';
2+
import { getCriticalSystemPaths, isCriticalSystemDirectory, isUserHomeDirectory } from '../safe-paths.js';
3+
import os from 'node:os';
4+
import path from 'node:path';
5+
6+
describe('safe-paths', () => {
7+
const originalPlatform = process.platform;
8+
9+
afterEach(() => {
10+
Object.defineProperty(process, 'platform', {
11+
value: originalPlatform
12+
});
13+
});
14+
15+
describe('getCriticalSystemPaths', () => {
16+
it('returns Windows paths on win32', () => {
17+
Object.defineProperty(process, 'platform', {
18+
value: 'win32'
19+
});
20+
21+
const paths = getCriticalSystemPaths();
22+
23+
expect(paths).toContain('C:\\');
24+
expect(paths.some(p => p.includes('Windows'))).toBe(true);
25+
expect(paths.some(p => p.includes('Program Files'))).toBe(true);
26+
});
27+
28+
it('returns macOS paths on darwin', () => {
29+
Object.defineProperty(process, 'platform', {
30+
value: 'darwin'
31+
});
32+
33+
const paths = getCriticalSystemPaths();
34+
35+
expect(paths).toContain('/');
36+
expect(paths).toContain('/System');
37+
expect(paths).toContain('/Library');
38+
expect(paths).toContain('/Applications');
39+
});
40+
41+
it('returns Linux paths on linux', () => {
42+
Object.defineProperty(process, 'platform', {
43+
value: 'linux'
44+
});
45+
46+
const paths = getCriticalSystemPaths();
47+
48+
expect(paths).toContain('/');
49+
expect(paths).toContain('/usr');
50+
expect(paths).toContain('/etc');
51+
expect(paths).toContain('/var');
52+
});
53+
});
54+
55+
describe('isCriticalSystemDirectory', () => {
56+
it('detects root directory as critical', () => {
57+
const isRootCritical = isCriticalSystemDirectory('/');
58+
expect(isRootCritical).toBe(true);
59+
});
60+
61+
it('detects subdirectories of critical paths', () => {
62+
if (process.platform === 'darwin' || process.platform === 'linux') {
63+
expect(isCriticalSystemDirectory('/usr/local')).toBe(true);
64+
expect(isCriticalSystemDirectory('/etc/config')).toBe(true);
65+
}
66+
});
67+
68+
it('allows safe project directories', () => {
69+
const homeDir = os.homedir();
70+
const projectDir = path.join(homeDir, 'projects', 'my-app');
71+
72+
expect(isCriticalSystemDirectory(projectDir)).toBe(false);
73+
});
74+
75+
it('normalizes paths correctly', () => {
76+
if (process.platform === 'darwin' || process.platform === 'linux') {
77+
expect(isCriticalSystemDirectory('/usr/../usr')).toBe(true);
78+
}
79+
});
80+
});
81+
82+
describe('isUserHomeDirectory', () => {
83+
it('detects user home directory', () => {
84+
const homeDir = os.homedir();
85+
expect(isUserHomeDirectory(homeDir)).toBe(true);
86+
});
87+
88+
it('allows subdirectories of home', () => {
89+
const homeDir = os.homedir();
90+
const subDir = path.join(homeDir, 'projects');
91+
92+
expect(isUserHomeDirectory(subDir)).toBe(false);
93+
});
94+
});
95+
96+
describe('cross-platform compatibility', () => {
97+
it('handles paths with different separators', () => {
98+
const userDir = path.join(os.homedir(), 'projects', 'app');
99+
100+
const result = isCriticalSystemDirectory(userDir);
101+
102+
expect(typeof result).toBe('boolean');
103+
});
104+
105+
it('resolves relative paths', () => {
106+
const relativePath = './some/project';
107+
const resolvedCheck = isCriticalSystemDirectory(relativePath);
108+
109+
expect(typeof resolvedCheck).toBe('boolean');
110+
});
111+
});
112+
});
113+

apps/cli/src/utils/safe-paths.ts

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
import path from 'node:path';
2+
import os from 'node:os';
3+
4+
export function getCriticalSystemPaths(): string[] {
5+
const platform = process.platform;
6+
7+
if (platform === 'win32') {
8+
const systemRoot = process.env.SystemRoot || 'C:\\Windows';
9+
const programFiles = process.env['ProgramFiles'] || 'C:\\Program Files';
10+
const programFilesX86 = process.env['ProgramFiles(x86)'] || 'C:\\Program Files (x86)';
11+
const drives = ['C:\\', 'D:\\', 'E:\\'];
12+
13+
return [
14+
...drives,
15+
systemRoot,
16+
path.join(systemRoot, 'System32'),
17+
programFiles,
18+
programFilesX86,
19+
'C:\\Windows',
20+
'C:\\Program Files',
21+
'C:\\Program Files (x86)'
22+
];
23+
}
24+
25+
if (platform === 'darwin') {
26+
return [
27+
'/',
28+
'/usr',
29+
'/etc',
30+
'/var',
31+
'/System',
32+
'/Library',
33+
'/bin',
34+
'/sbin',
35+
'/opt',
36+
'/private/etc',
37+
'/private/var',
38+
'/private/tmp',
39+
'/Applications'
40+
];
41+
}
42+
43+
return [
44+
'/',
45+
'/usr',
46+
'/etc',
47+
'/var',
48+
'/bin',
49+
'/sbin',
50+
'/opt',
51+
'/boot',
52+
'/lib',
53+
'/lib64',
54+
'/sys',
55+
'/proc',
56+
'/dev',
57+
'/root'
58+
];
59+
}
60+
61+
export function isCriticalSystemDirectory(targetPath: string): boolean {
62+
const resolved = path.resolve(targetPath);
63+
const criticalPaths = getCriticalSystemPaths();
64+
65+
return criticalPaths.some(critical => {
66+
const resolvedCritical = path.resolve(critical);
67+
68+
if (resolved === resolvedCritical) {
69+
return true;
70+
}
71+
72+
const normalizedResolved = resolved + path.sep;
73+
const normalizedCritical = resolvedCritical + path.sep;
74+
75+
return normalizedResolved.startsWith(normalizedCritical);
76+
});
77+
}
78+
79+
export function isUserHomeDirectory(targetPath: string): boolean {
80+
const resolved = path.resolve(targetPath);
81+
const homeDir = os.homedir();
82+
83+
return resolved === homeDir;
84+
}
85+
86+
export function getSafeInstallMessage(targetPath: string): string {
87+
if (isUserHomeDirectory(targetPath)) {
88+
return 'Installing in home directory is not recommended. Please run from a project directory.';
89+
}
90+
91+
if (isCriticalSystemDirectory(targetPath)) {
92+
return 'Cannot install in critical system directory. Please run from a safe project directory.';
93+
}
94+
95+
return '';
96+
}
97+

0 commit comments

Comments
 (0)