mirror of
https://github.com/abhigyanpatwari/GitNexus.git
synced 2026-10-29 06:32:28 +00:00
fix: ensure exec usage does not allow poisoning
Previous usage was vulnerable to "poisoned" tags which could enduce commands to be run when a `detectChanges` command was hit. This was primarily fixed in `local-backend.ts` however I changes the `execSync` usages where any injection was potentially able to be performed (e.g. staleness). Skipped touching wiki and generator as those use static input, though these should potentially be changed over in the future.
This commit is contained in:
parent
dc66bb83ef
commit
bb7ade91ab
4 changed files with 31 additions and 24 deletions
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
import path from 'path';
|
||||
import readline from 'readline';
|
||||
import { execSync } from 'child_process';
|
||||
import { execSync, execFileSync } from 'child_process';
|
||||
import cliProgress from 'cli-progress';
|
||||
import { getGitRoot, isGitRepo } from '../storage/git.js';
|
||||
import { getStoragePaths, loadMeta, loadCLIConfig, saveCLIConfig } from '../storage/repo-manager.js';
|
||||
|
|
@ -343,10 +343,11 @@ function hasGhCLI(): boolean {
|
|||
|
||||
function publishGist(htmlPath: string): { url: string; rawUrl: string } | null {
|
||||
try {
|
||||
const output = execSync(
|
||||
`gh gist create "${htmlPath}" --desc "Repository Wiki — generated by GitNexus" --public`,
|
||||
{ encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] },
|
||||
).trim();
|
||||
const output = execFileSync('gh', [
|
||||
'gist', 'create', htmlPath,
|
||||
'--desc', 'Repository Wiki — generated by GitNexus',
|
||||
'--public',
|
||||
], { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] }).trim();
|
||||
|
||||
// gh gist create prints the gist URL as the last line
|
||||
const lines = output.split('\n');
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
|
||||
import fs from 'fs/promises';
|
||||
import path from 'path';
|
||||
import { execSync } from 'child_process';
|
||||
import { execSync, execFileSync } from 'child_process';
|
||||
|
||||
import {
|
||||
initWikiDb,
|
||||
|
|
@ -712,8 +712,8 @@ export class WikiGenerator {
|
|||
|
||||
private getChangedFiles(fromCommit: string, toCommit: string): string[] {
|
||||
try {
|
||||
const output = execSync(
|
||||
`git diff ${fromCommit}..${toCommit} --name-only`,
|
||||
const output = execFileSync(
|
||||
'git', ['diff', `${fromCommit}..${toCommit}`, '--name-only'],
|
||||
{ cwd: this.repoPath },
|
||||
).toString().trim();
|
||||
return output ? output.split('\n').filter(Boolean) : [];
|
||||
|
|
|
|||
|
|
@ -988,30 +988,30 @@ export class LocalBackend {
|
|||
await this.ensureInitialized(repo.id);
|
||||
|
||||
const scope = params.scope || 'unstaged';
|
||||
const { execSync } = await import('child_process');
|
||||
|
||||
// Build git diff command based on scope
|
||||
let diffCmd: string;
|
||||
const { execFileSync } = await import('child_process');
|
||||
|
||||
// Build git diff args based on scope (using execFileSync to avoid shell injection)
|
||||
let diffArgs: string[];
|
||||
switch (scope) {
|
||||
case 'staged':
|
||||
diffCmd = 'git diff --staged --name-only';
|
||||
diffArgs = ['diff', '--staged', '--name-only'];
|
||||
break;
|
||||
case 'all':
|
||||
diffCmd = 'git diff HEAD --name-only';
|
||||
diffArgs = ['diff', 'HEAD', '--name-only'];
|
||||
break;
|
||||
case 'compare':
|
||||
if (!params.base_ref) return { error: 'base_ref is required for "compare" scope' };
|
||||
diffCmd = `git diff ${params.base_ref} --name-only`;
|
||||
diffArgs = ['diff', params.base_ref, '--name-only'];
|
||||
break;
|
||||
case 'unstaged':
|
||||
default:
|
||||
diffCmd = 'git diff --name-only';
|
||||
diffArgs = ['diff', '--name-only'];
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
let changedFiles: string[];
|
||||
try {
|
||||
const output = execSync(diffCmd, { cwd: repo.repoPath, encoding: 'utf-8' });
|
||||
const output = execFileSync('git', diffArgs, { cwd: repo.repoPath, encoding: 'utf-8' });
|
||||
changedFiles = output.trim().split('\n').filter(f => f.length > 0);
|
||||
} catch (err: any) {
|
||||
return { error: `Git diff failed: ${err.message}` };
|
||||
|
|
@ -1185,9 +1185,15 @@ export class LocalBackend {
|
|||
|
||||
// Simple text search across the repo for the old name (in files not already covered by graph)
|
||||
try {
|
||||
const { execSync } = await import('child_process');
|
||||
const rgCmd = `rg -l --type-add "code:*.{ts,tsx,js,jsx,py,go,rs,java}" -t code "\\b${oldName}\\b" .`;
|
||||
const output = execSync(rgCmd, { cwd: repo.repoPath, encoding: 'utf-8', timeout: 5000 });
|
||||
const { execFileSync } = await import('child_process');
|
||||
const rgArgs = [
|
||||
'-l',
|
||||
'--type-add', 'code:*.{ts,tsx,js,jsx,py,go,rs,java}',
|
||||
'-t', 'code',
|
||||
`\\b${oldName}\\b`,
|
||||
'.',
|
||||
];
|
||||
const output = execFileSync('rg', rgArgs, { cwd: repo.repoPath, encoding: 'utf-8', timeout: 5000 });
|
||||
const files = output.trim().split('\n').filter(f => f.length > 0);
|
||||
|
||||
for (const file of files) {
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
* Returns a hint for the LLM to call analyze if stale.
|
||||
*/
|
||||
|
||||
import { execSync } from 'child_process';
|
||||
import { execFileSync } from 'child_process';
|
||||
import path from 'path';
|
||||
|
||||
export interface StalenessInfo {
|
||||
|
|
@ -20,8 +20,8 @@ export interface StalenessInfo {
|
|||
export function checkStaleness(repoPath: string, lastCommit: string): StalenessInfo {
|
||||
try {
|
||||
// Get count of commits between lastCommit and HEAD
|
||||
const result = execSync(
|
||||
`git rev-list --count ${lastCommit}..HEAD`,
|
||||
const result = execFileSync(
|
||||
'git', ['rev-list', '--count', `${lastCommit}..HEAD`],
|
||||
{ cwd: repoPath, encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] }
|
||||
).trim();
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue