mirror of
https://github.com/affaan-m/everything-claude-code.git
synced 2026-05-01 06:23:28 +08:00
fix: show correct gateguard hook recovery id
This commit is contained in:
committed by
Affaan Mustafa
parent
7c5452f4fa
commit
bb40978e31
@@ -38,6 +38,8 @@ const READ_HEARTBEAT_MS = 60 * 1000;
|
||||
const MAX_CHECKED_ENTRIES = 500;
|
||||
const MAX_SESSION_KEYS = 50;
|
||||
const ROUTINE_BASH_SESSION_KEY = '__bash_session__';
|
||||
const EDIT_WRITE_HOOK_ID = 'pre:edit-write:gateguard-fact-force';
|
||||
const BASH_HOOK_ID = 'pre:bash:gateguard-fact-force';
|
||||
const ECC_DISABLE_VALUES = new Set(['0', 'false', 'off', 'disabled', 'disable']);
|
||||
|
||||
const DESTRUCTIVE_BASH = /\b(rm\s+-rf|git\s+reset\s+--hard|git\s+checkout\s+--|git\s+clean\s+-f|drop\s+table|delete\s+from|truncate|git\s+push\s+--force(?!-with-lease)|git\s+commit\s+--amend|dd\s+if=)\b/i;
|
||||
@@ -365,11 +367,12 @@ function routineBashMsg() {
|
||||
].join('\n');
|
||||
}
|
||||
|
||||
function withRecoveryHint(message) {
|
||||
function withRecoveryHint(message, hookIds = [EDIT_WRITE_HOOK_ID]) {
|
||||
const disableTargets = hookIds.map(hookId => `\`${hookId}\``).join(' or ');
|
||||
return [
|
||||
message,
|
||||
'',
|
||||
'Recovery: if GateGuard is blocking setup or repair work, run this session with `ECC_GATEGUARD=off` or add `pre:edit-write:gateguard-fact-force` to `ECC_DISABLED_HOOKS`.'
|
||||
`Recovery: if GateGuard is blocking setup or repair work, run this session with \`ECC_GATEGUARD=off\` or add ${disableTargets} to \`ECC_DISABLED_HOOKS\`.`
|
||||
].join('\n');
|
||||
}
|
||||
|
||||
@@ -377,12 +380,13 @@ function withRecoveryHint(message) {
|
||||
|
||||
function denyResult(reason, options = {}) {
|
||||
const includeRecoveryHint = options.includeRecoveryHint !== false;
|
||||
const hookIds = Array.isArray(options.hookIds) && options.hookIds.length > 0 ? options.hookIds : [EDIT_WRITE_HOOK_ID];
|
||||
return {
|
||||
stdout: JSON.stringify({
|
||||
hookSpecificOutput: {
|
||||
hookEventName: 'PreToolUse',
|
||||
permissionDecision: 'deny',
|
||||
permissionDecisionReason: includeRecoveryHint ? withRecoveryHint(reason) : reason
|
||||
permissionDecisionReason: includeRecoveryHint ? withRecoveryHint(reason, hookIds) : reason
|
||||
}
|
||||
}),
|
||||
exitCode: 0
|
||||
@@ -471,7 +475,7 @@ function run(rawInput) {
|
||||
if (!markChecked(ROUTINE_BASH_SESSION_KEY)) {
|
||||
return allowWithStateWarning();
|
||||
}
|
||||
return denyResult(routineBashMsg());
|
||||
return denyResult(routineBashMsg(), { hookIds: [BASH_HOOK_ID] });
|
||||
}
|
||||
|
||||
return rawInput; // allow
|
||||
|
||||
@@ -471,7 +471,25 @@ function runTests() {
|
||||
'denial reason should mention the existing hook-id disable control');
|
||||
})) passed++; else failed++;
|
||||
|
||||
// --- Test 14: destructive Bash denials do not advertise the recovery escape hatch ---
|
||||
// --- Test 14: routine Bash denial messages show the Bash hook escape hatch ---
|
||||
clearState();
|
||||
if (test('routine Bash denials include Bash hook disable id', () => {
|
||||
const input = {
|
||||
tool_name: 'Bash',
|
||||
tool_input: { command: 'npm test' }
|
||||
};
|
||||
const result = runBashHook(input);
|
||||
const output = parseOutput(result.stdout);
|
||||
const reason = output.hookSpecificOutput.permissionDecisionReason;
|
||||
|
||||
assert.strictEqual(output.hookSpecificOutput.permissionDecision, 'deny');
|
||||
assert.ok(reason.includes('pre:bash:gateguard-fact-force'),
|
||||
'routine Bash denial should show the Bash hook ID');
|
||||
assert.ok(!reason.includes('pre:edit-write:gateguard-fact-force'),
|
||||
'routine Bash denial should not show the Edit/Write hook ID as the targeted disable');
|
||||
})) passed++; else failed++;
|
||||
|
||||
// --- Test 15: destructive Bash denials do not advertise the recovery escape hatch ---
|
||||
clearState();
|
||||
if (test('destructive Bash denials omit recovery escape hatch', () => {
|
||||
const input = {
|
||||
@@ -487,7 +505,7 @@ function runTests() {
|
||||
'destructive gate should not advertise disabling GateGuard');
|
||||
})) passed++; else failed++;
|
||||
|
||||
// --- Test 15: MultiEdit gates first unchecked file ---
|
||||
// --- Test 16: MultiEdit gates first unchecked file ---
|
||||
clearState();
|
||||
if (test('denies first MultiEdit with unchecked file', () => {
|
||||
const input = {
|
||||
|
||||
Reference in New Issue
Block a user