mirror of
https://github.com/garrytan/gbrain.git
synced 2026-07-27 22:15:33 +00:00
fix(gbrain): disable hooks for scaffolding commit to avoid harden push race
Takeover of #2545. The harden flow installs the durability post-commit hook, then commitScaffolding commits + pushes; the hook fires on that commit and background-pushes (pull --rebase -> index.lock), racing the foreground push. #2545 added --no-verify, but that only skips pre-commit/commit-msg hooks — post-commit still runs (empirically verified). Fix: run the scaffolding commit with -c core.hooksPath=/dev/null so no hooks fire, and correct the hook template's misleading 'Bypass: git commit --no-verify' comment. Co-authored-by: peterostrander2 <peterostrander2@users.noreply.github.com> Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
peterostrander2
Claude Fable 5
parent
0612b0daa8
commit
2f2dfd3410
@@ -156,7 +156,8 @@ function renderPostCommitHook(): string {
|
||||
${HOOK_BANNER}
|
||||
# LOCAL + untracked — NEVER commit this file. Best-effort background auto-push so
|
||||
# agent writes don't sit local-only. The real guarantee is ${HELPER_REL}.
|
||||
# Bypass: git commit --no-verify.
|
||||
# Bypass: git -c core.hooksPath=/dev/null commit … (--no-verify only skips
|
||||
# pre-commit/commit-msg hooks; post-commit hooks still run under it).
|
||||
set -euo pipefail
|
||||
|
||||
_branch="$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo HEAD)"
|
||||
@@ -729,7 +730,10 @@ function commitScaffolding(repoPath: string, branch: string, redact: (s: string)
|
||||
stdio: ['ignore', 'pipe', 'ignore'], timeout: 10_000, env: { ...process.env, ...GIT_ENV },
|
||||
}).toString().trim();
|
||||
if (!staged) return { status: 'ok', detail: 'scaffolding already committed' };
|
||||
execFileSync('git', ['-C', repoPath, 'commit', '-m', 'chore(gbrain): install brain durability scaffolding'], {
|
||||
// #2545: commit with hooks disabled so the just-installed post-commit hook
|
||||
// doesn't background-push (pull --rebase → index.lock) while we push below.
|
||||
// NOTE: --no-verify would NOT do this — it skips pre-commit/commit-msg only.
|
||||
execFileSync('git', ['-C', repoPath, '-c', 'core.hooksPath=/dev/null', 'commit', '-m', 'chore(gbrain): install brain durability scaffolding'], {
|
||||
stdio: 'ignore', timeout: 30_000, env: { ...process.env, ...GIT_ENV },
|
||||
});
|
||||
execFileSync('git', ['-C', repoPath, ...['-c', 'http.followRedirects=false'], 'push', 'origin', `HEAD:${branch}`], {
|
||||
|
||||
@@ -163,6 +163,21 @@ describe('hardenBrainRepo', () => {
|
||||
expect(r.steps.find(s => s.step === 'commit')).toBeUndefined();
|
||||
});
|
||||
|
||||
test('#2545 — scaffolding commit does not fire the post-commit hook (no push race)', async () => {
|
||||
await harden();
|
||||
// The gbrain hook's brain_push always writes to $GBRAIN_HOME/brain-push.log
|
||||
// (ok / rejected / lock-timeout — every path logs). If the scaffolding
|
||||
// commit fired the hook, the detached push races commitScaffolding's own
|
||||
// push (pull --rebase → index.lock) and this log appears within ms.
|
||||
await new Promise(r => setTimeout(r, 1500));
|
||||
expect(existsSync(join(process.env.GBRAIN_HOME!, 'brain-push.log'))).toBe(false);
|
||||
// And the hook no longer documents a bypass that doesn't work: --no-verify
|
||||
// skips pre-commit/commit-msg only, never post-commit.
|
||||
const hook = readFileSync(join(work, '.git', 'hooks', 'post-commit'), 'utf-8');
|
||||
expect(hook).not.toContain('Bypass: git commit --no-verify');
|
||||
expect(hook).toContain('core.hooksPath=/dev/null');
|
||||
});
|
||||
|
||||
test('dry-run makes no commit and writes no files', async () => {
|
||||
const before = commitCount(work);
|
||||
await harden({ dryRun: true });
|
||||
|
||||
Reference in New Issue
Block a user