UNPKG

@iflow-mcp/ansvar-systems-german-law-mcp

Version:

German legal research MCP server with statutes, case law, and preparatory works from gesetze-im-internet.de

70 lines (69 loc) • 2.72 kB
#!/usr/bin/env tsx // scripts/drift-detect.ts — Upstream drift detection per MCP Infrastructure Blueprint §5.3 import { createHash } from 'node:crypto'; import { readFileSync } from 'node:fs'; import { join, dirname } from 'node:path'; import { fileURLToPath } from 'node:url'; const __dirname = dirname(fileURLToPath(import.meta.url)); function normalizeText(text) { return text.replace(/\s+/g, ' ').trim().toLowerCase(); } function sha256(text) { return createHash('sha256').update(normalizeText(text)).digest('hex'); } async function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } async function main() { const hashesPath = join(__dirname, '..', 'fixtures', 'golden-hashes.json'); const hashes = JSON.parse(readFileSync(hashesPath, 'utf-8')); let driftCount = 0; let errorCount = 0; let skippedCount = 0; console.log(`Drift detection: checking ${hashes.provisions.length} provisions...\n`); for (const entry of hashes.provisions) { if (entry.expected_sha256 === 'COMPUTE_ON_FIRST_RUN') { console.log(` SKIP ${entry.id}: ${entry.description} (hash not yet computed)`); skippedCount++; await sleep(1000); continue; } try { const response = await fetch(entry.upstream_url, { headers: { 'User-Agent': 'Ansvar-DriftDetect/1.0' }, signal: AbortSignal.timeout(15000), }); if (!response.ok) { console.log(` ERROR ${entry.id}: HTTP ${response.status} for ${entry.upstream_url}`); errorCount++; await sleep(1000); continue; } const text = await response.text(); const hash = sha256(text); if (hash !== entry.expected_sha256) { console.log(` DRIFT ${entry.id}: ${entry.description}`); console.log(` Expected: ${entry.expected_sha256}`); console.log(` Got: ${hash}`); driftCount++; } else { console.log(` OK ${entry.id}: ${entry.description}`); } } catch (err) { console.log(` ERROR ${entry.id}: ${err.message}`); errorCount++; } await sleep(1000); } console.log(`\nResults: ${hashes.provisions.length - driftCount - errorCount - skippedCount} OK, ${driftCount} drift, ${errorCount} errors, ${skippedCount} skipped`); if (driftCount > 0) process.exit(2); if (errorCount > 0) process.exit(1); } main().catch(err => { console.error('Fatal error:', err); process.exit(1); });