From fa871e912749431c9561fdda00633ebebfdc2ba1 Mon Sep 17 00:00:00 2001 From: leyoonafr Date: Mon, 27 Jul 2026 00:25:28 +0800 Subject: [PATCH] fix(loop): allow exact restore Git probes --- .../scripts/lib/github-identity.mjs | 15 ++++++++ .../tests/github-identity-routing.test.mjs | 38 ++++++++++++++++++- 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/loops/issue-dev-loop/scripts/lib/github-identity.mjs b/loops/issue-dev-loop/scripts/lib/github-identity.mjs index e3178ceb..f814c1b3 100644 --- a/loops/issue-dev-loop/scripts/lib/github-identity.mjs +++ b/loops/issue-dev-loop/scripts/lib/github-identity.mjs @@ -295,6 +295,21 @@ function authorizedPushBranches(authorization) { export function assertGitCommandPolicy(role, args, { authorization = null } = {}) { const subcommand = gitSubcommand(args) + const restoreCleanlinessProbe = + role === 'automation' && + (sameArguments(args, ['ls-files', '-v', '-z']) || + sameArguments(args, [ + '-c', + 'core.fileMode=true', + 'diff', + '--quiet', + '--no-ext-diff', + '--no-textconv', + 'HEAD', + '--', + ])) + if (restoreCleanlinessProbe) return + if (subcommand.name === 'push') { if (role === 'reviewer') throw new Error('reviewer identity cannot run git push') const claimBranch = authorization?.issue?.branch diff --git a/loops/issue-dev-loop/tests/github-identity-routing.test.mjs b/loops/issue-dev-loop/tests/github-identity-routing.test.mjs index bc2158d2..b2705551 100644 --- a/loops/issue-dev-loop/tests/github-identity-routing.test.mjs +++ b/loops/issue-dev-loop/tests/github-identity-routing.test.mjs @@ -32,7 +32,10 @@ import { canonicalFinalizationRecord, finalizationRecordDigest, } from '../scripts/lib/finalization-proof.mjs' -import { resolveExecutable } from '../scripts/lib/github-identity.mjs' +import { + assertGitCommandPolicy, + resolveExecutable, +} from '../scripts/lib/github-identity.mjs' const execFileAsync = promisify(execFile) const testDirectory = path.dirname(fileURLToPath(import.meta.url)) @@ -2324,6 +2327,39 @@ test('authenticated remote Git accepts only exact origin and authorized ref shap } }) +test('automation allows only the exact restore cleanliness Git probes', () => { + for (const args of [ + ['ls-files', '-v', '-z'], + [ + '-c', + 'core.fileMode=true', + 'diff', + '--quiet', + '--no-ext-diff', + '--no-textconv', + 'HEAD', + '--', + ], + ]) { + assert.doesNotThrow(() => assertGitCommandPolicy('automation', args)) + assert.throws( + () => assertGitCommandPolicy('reviewer', args), + /outside the authenticated reviewer command tree/, + ) + } + for (const args of [ + ['ls-files', '-v'], + ['ls-files', '-v', '-z', '--others'], + ['-c', 'core.fileMode=false', 'diff', '--quiet', 'HEAD', '--'], + ['-c', 'core.fileMode=true', 'diff', 'HEAD', '--'], + ]) { + assert.throws( + () => assertGitCommandPolicy('automation', args), + /outside the authenticated automation command tree/, + ) + } +}) + test('authenticated real Git ignores local execution hooks and configured diff helpers', async () => { const fixture = await createFixture({ realGit: true }) const realGit = await resolveExecutable('git', process.env)