@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
JavaScript
// 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);
});