mirror of
https://github.com/AgentSeal/codeburn.git
synced 2026-05-19 07:43:09 +00:00
Fix command injection in yield via execFileSync
Replace execSync with execFileSync and argument arrays so shell metacharacters in git branch names cannot be interpreted as commands. Add SAFE_REF_PATTERN validation as defense in depth for branch names from git symbolic-ref. Addresses #214.
This commit is contained in:
parent
15334fac67
commit
6fb05c6813
1 changed files with 12 additions and 11 deletions
23
src/yield.ts
23
src/yield.ts
|
|
@ -1,4 +1,4 @@
|
|||
import { execSync } from 'child_process'
|
||||
import { execFileSync } from 'child_process'
|
||||
import { parseAllSessions } from './parser.js'
|
||||
import type { DateRange, SessionSummary } from './types.js'
|
||||
|
||||
|
|
@ -20,27 +20,28 @@ export type YieldSummary = {
|
|||
details: SessionYield[]
|
||||
}
|
||||
|
||||
function runGit(cmd: string, cwd: string): string | null {
|
||||
const SAFE_REF_PATTERN = /^[A-Za-z0-9._/\-]+$/
|
||||
|
||||
function runGit(args: string[], cwd: string): string | null {
|
||||
try {
|
||||
return execSync(cmd, { cwd, encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] }).trim()
|
||||
return execFileSync('git', args, { cwd, encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] }).trim()
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
function isGitRepo(dir: string): boolean {
|
||||
return runGit('git rev-parse --is-inside-work-tree', dir) === 'true'
|
||||
return runGit(['rev-parse', '--is-inside-work-tree'], dir) === 'true'
|
||||
}
|
||||
|
||||
function getMainBranch(cwd: string): string {
|
||||
// Try to get default branch from remote
|
||||
const result = runGit('git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null', cwd)
|
||||
const result = runGit(['symbolic-ref', 'refs/remotes/origin/HEAD'], cwd)
|
||||
if (result) {
|
||||
return result.replace('refs/remotes/origin/', '')
|
||||
const branch = result.replace('refs/remotes/origin/', '')
|
||||
if (SAFE_REF_PATTERN.test(branch)) return branch
|
||||
}
|
||||
|
||||
// Fallback: check common names
|
||||
const branches = runGit('git branch -a', cwd) ?? ''
|
||||
const branches = runGit(['branch', '-a'], cwd) ?? ''
|
||||
if (branches.includes('main')) return 'main'
|
||||
if (branches.includes('master')) return 'master'
|
||||
return 'main'
|
||||
|
|
@ -58,14 +59,14 @@ function getCommitsInRange(cwd: string, since: Date, until: Date, mainBranch: st
|
|||
const untilStr = until.toISOString()
|
||||
|
||||
const log = runGit(
|
||||
`git log --all --since="${sinceStr}" --until="${untilStr}" --format="%H|%aI|%s"`,
|
||||
['log', '--all', `--since=${sinceStr}`, `--until=${untilStr}`, '--format=%H|%aI|%s'],
|
||||
cwd
|
||||
)
|
||||
|
||||
if (!log) return []
|
||||
|
||||
const mainCommits = new Set(
|
||||
(runGit(`git log ${mainBranch} --format="%H"`, cwd) ?? '').split('\n').filter(Boolean)
|
||||
(runGit(['log', mainBranch, '--format=%H'], cwd) ?? '').split('\n').filter(Boolean)
|
||||
)
|
||||
|
||||
return log.split('\n').filter(Boolean).map(line => {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue