fix: allow additional read-only git introspection commands (#2268)

This commit is contained in:
leoeletronics 2026-06-16 02:59:23 -03:00 committed by GitHub
parent a6ac0273e2
commit d90d921137
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 87 additions and 2 deletions

View File

@ -853,7 +853,10 @@ function isReadOnlyGitIntrospection(command) {
}
if (subcommand === 'diff') {
return args.length <= 1 && args.every(arg => ['--name-only', '--name-status'].includes(arg));
const allowedDiffArgs = new Set(['--name-only', '--name-status', '--cached', '--staged', '--stat']);
// git diff without arguments is read-only introspection
if (args.length === 0) return true;
return args.length <= 2 && args.every(arg => allowedDiffArgs.has(arg));
}
if (subcommand === 'log') {
@ -861,7 +864,25 @@ function isReadOnlyGitIntrospection(command) {
}
if (subcommand === 'show') {
return args.length === 1 && !args[0].startsWith('--') && /^[a-zA-Z0-9._:/ -]+$/.test(args[0]);
// Permite: git show <ref>, git show --stat, git show --name-only,
// git show <ref> --stat, git show <ref> --name-only
if (args.length === 0) return false;
if (args.length === 1) {
const arg = args[0];
if (arg === '--stat' || arg === '--name-only') return true;
// ref
return !arg.startsWith('--') && /^[a-zA-Z0-9._:/ -]+$/.test(arg);
}
if (args.length === 2) {
const [first, second] = args;
// ref + flag
if (!first.startsWith('--') && /^[a-zA-Z0-9._:/ -]+$/.test(first) &&
(second === '--stat' || second === '--name-only')) {
return true;
}
return false;
}
return false;
}
if (subcommand === 'branch') {

View File

@ -1788,6 +1788,70 @@ function runTests() {
'destructive gate is exempt from dampening');
})) passed++; else failed++;
// --- Novos comandos Git read-only ---
console.log('\n Novos comandos Git read-only:');
clearState();
if (test('allows git diff --cached', () => {
expectAllow('git diff --cached', 'git diff --cached');
})) passed++; else failed++;
clearState();
if (test('allows git diff --staged', () => {
expectAllow('git diff --staged', 'git diff --staged');
})) passed++; else failed++;
clearState();
if (test('allows git diff --stat', () => {
expectAllow('git diff --stat', 'git diff --stat');
})) passed++; else failed++;
clearState();
if (test('allows git diff --name-only --cached', () => {
expectAllow('git diff --name-only --cached', 'git diff --name-only --cached');
})) passed++; else failed++;
clearState();
if (test('allows git show --stat', () => {
expectAllow('git show --stat', 'git show --stat');
})) passed++; else failed++;
clearState();
if (test('allows git show --name-only', () => {
expectAllow('git show --name-only', 'git show --name-only');
})) passed++; else failed++;
clearState();
if (test('allows git show HEAD --stat', () => {
expectAllow('git show HEAD --stat', 'git show HEAD --stat');
})) passed++; else failed++;
clearState();
if (test('allows git show HEAD --name-only', () => {
expectAllow('git show HEAD --name-only', 'git show HEAD --name-only');
})) passed++; else failed++;
// Garantir que comandos destrutivos continuam negados
clearState();
if (test('still denies git reset --hard', () => {
expectDestructiveDeny('git reset --hard', 'git reset --hard');
})) passed++; else failed++;
clearState();
if (test('still denies git checkout -f', () => {
expectDestructiveDeny('git checkout -f main', 'git checkout -f');
})) passed++; else failed++;
clearState();
if (test('still denies git clean -fd', () => {
expectDestructiveDeny('git clean -fd', 'git clean -fd');
})) passed++; else failed++;
clearState();
if (test('still denies git push --force', () => {
expectDestructiveDeny('git push --force origin main', 'git push --force');
})) passed++; else failed++;
// Cleanup only the temp directory created by this test file.
try {
if (fs.existsSync(stateDir)) {