mirror of
https://github.com/abhigyanpatwari/GitNexus.git
synced 2026-10-09 03:17:54 +00:00
fix(watch): normalize SSH repo identity paths
This commit is contained in:
parent
3b590acc79
commit
e1d8c65f8c
7 changed files with 60 additions and 7 deletions
|
|
@ -5,6 +5,7 @@ import path from 'node:path';
|
|||
import { fileURLToPath, pathToFileURL } from 'node:url';
|
||||
import type { AnalyzeOptions, AnalyzeResult } from '../run-analyze.js';
|
||||
import type { WorkerMessage } from '../../server/analyze-worker.js';
|
||||
import { autoHeapCapMb } from '../ingestion/utils/effective-ram.js';
|
||||
|
||||
const _require = createRequire(import.meta.url);
|
||||
const TERMINATION_GRACE_MS = 10_000;
|
||||
|
|
@ -58,9 +59,14 @@ export function createAutoSyncAnalysisRunner(
|
|||
reject(new Error(`Auto-sync analyze worker is missing: ${workerPath}`));
|
||||
return;
|
||||
}
|
||||
const workerHeapMb = Math.min(8192, autoHeapCapMb());
|
||||
const execArgv = isDev
|
||||
? ['--import', pathToFileURL(_require.resolve('tsx/esm')).href, '--max-old-space-size=8192']
|
||||
: ['--max-old-space-size=8192'];
|
||||
? [
|
||||
'--import',
|
||||
pathToFileURL(_require.resolve('tsx/esm')).href,
|
||||
`--max-old-space-size=${workerHeapMb}`,
|
||||
]
|
||||
: [`--max-old-space-size=${workerHeapMb}`];
|
||||
const child = deps.forkWorker(workerPath, execArgv);
|
||||
child.stdout?.resume();
|
||||
child.stderr?.resume();
|
||||
|
|
|
|||
|
|
@ -246,7 +246,11 @@ export function parseAutoSyncConfig(content: string, configPath: string): AutoSy
|
|||
}
|
||||
|
||||
export function validateAutoSyncRemoteUrl(remoteUrl: string): void {
|
||||
const match = /^git@([^:\s/]+):([^\s]+)$/.exec(remoteUrl.trim());
|
||||
const trimmed = remoteUrl.trim();
|
||||
if (trimmed.includes('?') || trimmed.includes('#')) {
|
||||
throw new Error('must not include query strings or fragments');
|
||||
}
|
||||
const match = /^git@([^:\s/]+):([^\s]+)$/.exec(trimmed);
|
||||
if (!match) {
|
||||
throw new Error(
|
||||
'must use an SSH URL on github.com, gitlab.com, or gitee.com',
|
||||
|
|
|
|||
|
|
@ -117,6 +117,10 @@ export function validateGitUrl(url: string): void {
|
|||
throw new Error('Only https:// and http:// git URLs are allowed');
|
||||
}
|
||||
|
||||
if (parsed.search || parsed.hash) {
|
||||
throw new Error('Git URLs must not include query strings or fragments');
|
||||
}
|
||||
|
||||
const host = parsed.hostname.toLowerCase();
|
||||
|
||||
// Block known dangerous hostnames (cloud metadata services)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,11 @@
|
|||
import { EventEmitter } from 'node:events';
|
||||
import { describe, expect, it, vi } from 'vitest';
|
||||
|
||||
const { autoHeapCapMbMock } = vi.hoisted(() => ({ autoHeapCapMbMock: vi.fn(() => 512) }));
|
||||
vi.mock('../../src/core/ingestion/utils/effective-ram.js', () => ({
|
||||
autoHeapCapMb: autoHeapCapMbMock,
|
||||
}));
|
||||
|
||||
import { createAutoSyncAnalysisRunner } from '../../src/core/auto-sync/analysis-worker-launch.js';
|
||||
|
||||
describe('auto-sync analysis worker', () => {
|
||||
|
|
@ -10,9 +16,14 @@ describe('auto-sync analysis worker', () => {
|
|||
stdout: { resume: vi.fn() },
|
||||
stderr: { resume: vi.fn() },
|
||||
});
|
||||
const run = createAutoSyncAnalysisRunner({ forkWorker: vi.fn(() => child as any) });
|
||||
const forkWorker = vi.fn(() => child as any);
|
||||
const run = createAutoSyncAnalysisRunner({ forkWorker });
|
||||
|
||||
const result = run('/tmp/repo', { branch: 'main' }, 50);
|
||||
expect(forkWorker).toHaveBeenCalledWith(
|
||||
expect.any(String),
|
||||
expect.arrayContaining(['--max-old-space-size=512']),
|
||||
);
|
||||
child.emit('message', { type: 'progress', phase: 'parsing', progress: 20 });
|
||||
child.emit('message', { type: 'complete', result: { stats: { files: 3 } } });
|
||||
child.emit('exit', 0, null);
|
||||
|
|
|
|||
|
|
@ -452,6 +452,12 @@ describe('auto-sync', () => {
|
|||
expect(() => validateAutoSyncRemoteUrl('git@example.com:owner/repo.git')).toThrow(
|
||||
'host must be',
|
||||
);
|
||||
expect(() => validateAutoSyncRemoteUrl('git@github.com:owner/repo.git?ref=main')).toThrow(
|
||||
'must not include query strings or fragments',
|
||||
);
|
||||
expect(() => validateAutoSyncRemoteUrl('git@github.com:owner/repo.git#main')).toThrow(
|
||||
'must not include query strings or fragments',
|
||||
);
|
||||
});
|
||||
|
||||
it('parses repo git timeout durations', () => {
|
||||
|
|
|
|||
|
|
@ -84,11 +84,24 @@ describe('file lock', () => {
|
|||
await nextRelease();
|
||||
});
|
||||
|
||||
it('fails closed for a legacy or invalid lock without owner metadata', async () => {
|
||||
it('fails closed for legacy or invalid lock contents without owner metadata', async () => {
|
||||
const lockPath = await tempLockPath();
|
||||
await fs.mkdir(lockPath, { recursive: true });
|
||||
const invalidContents = ['legacy lock', '{not json', JSON.stringify({ pid: 123 })];
|
||||
await fs.mkdir(path.dirname(lockPath), { recursive: true });
|
||||
|
||||
await expect(acquireFileLock(lockPath)).rejects.toBeInstanceOf(FileLockBusyError);
|
||||
for (const content of invalidContents) {
|
||||
await fs.writeFile(lockPath, content, 'utf-8');
|
||||
await expect(
|
||||
acquireFileLock(lockPath, { pid: 456, processStartTime: 'next-start' }),
|
||||
).rejects.toBeInstanceOf(FileLockBusyError);
|
||||
await expect(fs.readFile(lockPath, 'utf-8')).resolves.toBe(content);
|
||||
await fs.rm(lockPath);
|
||||
}
|
||||
|
||||
await fs.mkdir(lockPath, { recursive: true });
|
||||
await expect(
|
||||
acquireFileLock(lockPath, { pid: 456, processStartTime: 'next-start' }),
|
||||
).rejects.toBeInstanceOf(FileLockBusyError);
|
||||
await expect(fs.access(lockPath)).resolves.toBeUndefined();
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -197,6 +197,15 @@ describe('git-clone', () => {
|
|||
expect(() => validateGitUrl('http://gitlab.com/user/repo.git')).not.toThrow();
|
||||
});
|
||||
|
||||
it('rejects query strings and fragments instead of reinterpreting clone remotes', () => {
|
||||
expect(() => validateGitUrl('https://github.com/user/repo.git?ref=main')).toThrow(
|
||||
'must not include query strings or fragments',
|
||||
);
|
||||
expect(() => validateGitUrl('https://github.com/user/repo.git#main')).toThrow(
|
||||
'must not include query strings or fragments',
|
||||
);
|
||||
});
|
||||
|
||||
it('blocks SSH protocol', () => {
|
||||
expect(() => validateGitUrl('ssh://git@github.com/user/repo.git')).toThrow(
|
||||
'Only https:// and http://',
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue