#!/usr/bin/env node const fs = require('fs'); const path = require('path'); const openHubRoot = process.env.OPENHUB_RESEARCH_ROOT || '/mnt/Data1T/Mnote_data/openhub/OpenHub'; const backendRoot = path.join(openHubRoot, 'smart-query-backend'); const disableEnv = 'MNOTE_OPENHUB_DISABLE_GIT_SNAPSHOT_RESTORE'; const legacyDisableEnv = 'OPENHUB_DISABLE_GIT_SNAPSHOT_RESTORE'; function read(relativePath) { return fs.readFileSync(path.join(backendRoot, relativePath), 'utf8'); } function assertCheck(name, passed) { if (!passed) failures.push(name); } function includesAll(source, needles) { return needles.every((needle) => source.includes(needle)); } const failures = []; const gitSnapshot = read('app/services/git_snapshot.py'); const stream = read('app/services/stream.py'); const taskExecutor = read('app/services/task_executor.py'); const session = read('app/api/session.py'); assertCheck( 'git_snapshot exposes MNote disable env and legacy equivalent', includesAll(gitSnapshot, [disableEnv, legacyDisableEnv, 'def is_snapshot_restore_disabled']) ); assertCheck( 'git_snapshot low-level git write command guard covers destructive/write commands', includesAll(gitSnapshot, [ '_GIT_WRITE_COMMANDS', '"init"', '"config"', '"add"', '"commit"', '"checkout"', '"restore"', '"reset"', '"revert"', 'is_snapshot_restore_disabled() and _is_git_write(args)', ]) ); assertCheck( 'git_snapshot high-level write APIs short-circuit when disabled', includesAll(gitSnapshot, [ 'def init_git_repo', 'def create_snapshot', 'def create_restore_snapshot', 'def restore_all', 'def restore_single_file', 'disabled by {GIT_SNAPSHOT_RESTORE_DISABLE_ENV}', ]) ); assertCheck( 'stream automatic snapshot path is guarded before init/create_snapshot', stream.includes('not git_snap.is_snapshot_restore_disabled()') && stream.includes('git_snap.init_git_repo') && stream.includes('git_snap.create_snapshot') && stream.includes('Git snapshot skipped: disabled by MNOTE_OPENHUB_DISABLE_GIT_SNAPSHOT_RESTORE') ); assertCheck( 'task_executor automatic snapshot path is guarded before init/create_snapshot', taskExecutor.includes('not git_snapshot.is_snapshot_restore_disabled()') && taskExecutor.includes('git_snapshot.init_git_repo') && taskExecutor.includes('git_snapshot.create_snapshot') && taskExecutor.includes('Git snapshot skipped: disabled by MNOTE_OPENHUB_DISABLE_GIT_SNAPSHOT_RESTORE') ); const restoreRouteGuardCount = ( session.match(/git_snapshot\.is_snapshot_restore_disabled\(\)/g) || [] ).length; assertCheck( 'session restore routes reject when disabled', restoreRouteGuardCount >= 2 && session.includes('Git snapshot/restore 写链已由 MNote 禁用') && session.includes('git_snapshot.restore_all') && session.includes('git_snapshot.restore_single_file') && session.includes('git_snapshot.create_restore_snapshot') ); if (failures.length) { console.error('OpenHub git snapshot/restore guard static smoke failed:'); for (const failure of failures) console.error(`- ${failure}`); process.exit(1); } console.log('OpenHub git snapshot/restore guard static smoke passed.');