/**
 * 运行安全包 — 证据 hash chain、命令副作用分级、供应链治理、迁移回滚契约。
 * advisory: 不 hard block（除 destructive 命令需人工确认）。
 */
import crypto from "node:crypto";
import { debug } from "../core/logger.js";
/**
 * 构建证据链 — 每个步骤产出带 hash 的证据块，与前一个块链式连接。
 */
export function buildEvidenceChain(steps) {
    const chain = [];
    let prevHash = null;
    for (const s of steps) {
        const timestamp = s.timestamp ?? new Date().toISOString();
        const dataHash = crypto
            .createHash("sha256")
            .update(s.payload)
            .digest("hex")
            .slice(0, 16);
        const chainInput = `${s.step}:${timestamp}:${dataHash}:${prevHash ?? "genesis"}`;
        const chainHash = crypto
            .createHash("sha256")
            .update(chainInput)
            .digest("hex")
            .slice(0, 16);
        const block = {
            step: s.step,
            timestamp,
            data_hash: dataHash,
            prev_hash: prevHash,
            chain_hash: chainHash,
            payload: s.payload,
        };
        chain.push(block);
        prevHash = chainHash;
    }
    return chain;
}
/**
 * 验证证据链完整性 — 检查每个块的 chain_hash 是否与重算结果一致。
 */
export function verifyEvidenceChain(chain) {
    if (chain.length > 0)
        debug("运行安全", "验证证据链，块数:", chain.length);
    if (chain.length === 0) {
        return { valid: true, broken_at: null, advisory: "证据链为空，无需校验" };
    }
    for (let i = 0; i < chain.length; i++) {
        const block = chain[i];
        const expectedPrev = i === 0 ? null : chain[i - 1].chain_hash;
        if (block.prev_hash !== expectedPrev) {
            return {
                valid: false,
                broken_at: i,
                advisory: `证据链在第 ${i} 步断裂: prev_hash 不匹配，请检查步骤顺序是否被篡改`,
            };
        }
        // 从 payload 重算 data_hash 以检测篡改
        const expectedDataHash = crypto
            .createHash("sha256")
            .update(block.payload)
            .digest("hex")
            .slice(0, 16);
        if (block.data_hash !== expectedDataHash) {
            return {
                valid: false,
                broken_at: i,
                advisory: `证据链在第 ${i} 步断裂: data_hash 不匹配（payload 被篡改），请恢复原始执行记录`,
            };
        }
        const chainInput = `${block.step}:${block.timestamp}:${block.data_hash}:${block.prev_hash ?? "genesis"}`;
        const expectedHash = crypto
            .createHash("sha256")
            .update(chainInput)
            .digest("hex")
            .slice(0, 16);
        if (block.chain_hash !== expectedHash) {
            return {
                valid: false,
                broken_at: i,
                advisory: `证据链在第 ${i} 步断裂: chain_hash 不匹配，请重新执行并生成完整证据链`,
            };
        }
    }
    return {
        valid: true,
        broken_at: null,
        advisory: `证据链完整: ${chain.length} 个步骤已验证通过`,
    };
}
const DESTRUCTIVE_PATTERNS = [
    { pattern: /\brm\s+(-[rf]+\s+|--no-preserve-root)/, example: "rm -rf" },
    { pattern: /\bgit\s+(push\s+--force|reset\s+--hard|clean\s+-fd)/, example: "git push --force" },
    { pattern: /\bdd\s+if=/, example: "dd" },
    { pattern: /\b(format|mkfs)\b/, example: "format" },
    { pattern: /\bdrop\s+(table|database|schema)\b/i, example: "DROP TABLE" },
    { pattern: /\bTRUNCATE\b/i, example: "TRUNCATE" },
    { pattern: /\bDELETE\s+FROM\b/i, example: "DELETE FROM" },
    { pattern: /\b(npm\s+publish|yarn\s+publish|pnpm\s+publish)\b/, example: "npm publish" },
];
const MUTATING_PATTERNS = [
    { pattern: /\bgit\s+(add|commit|push|merge|rebase|checkout)\b/, example: "git commit" },
    { pattern: /\b(npm\s+install|yarn\s+add|pnpm\s+add)\b/, example: "npm install" },
    { pattern: /\bmv\s+/, example: "mv" },
    { pattern: /\bcp\s+/, example: "cp" },
    { pattern: /\bmkdir\s+/, example: "mkdir" },
    { pattern: /\bdocker\s+(run|build|push|rmi|rm)\b/, example: "docker run" },
    { pattern: /\b(INSERT|UPDATE|ALTER|CREATE)\b/i, example: "INSERT" },
];
/**
 * 分类命令的副作用级别。
 */
export function classifyCommand(command) {
    for (const dp of DESTRUCTIVE_PATTERNS) {
        if (dp.pattern.test(command)) {
            debug("运行安全", "检测到破坏性命令:", command);
            return {
                command,
                risk: "destructive",
                advisory: `检测到破坏性命令: ${dp.example} — 需要人工确认后方可执行`,
                requires_human_confirm: true,
            };
        }
    }
    for (const mp of MUTATING_PATTERNS) {
        if (mp.pattern.test(command)) {
            return {
                command,
                risk: "mutating",
                advisory: `变更类命令: ${mp.example}`,
                requires_human_confirm: false,
            };
        }
    }
    return {
        command,
        risk: "read_only",
        advisory: "只读命令",
        requires_human_confirm: false,
    };
}
/**
 * 检查迁移契约 — 确保 schema 变更有回滚路径。
 */
export function checkMigrationContract(migration) {
    const forwardClassified = classifyCommand(migration.forward_command);
    const rollbackClassified = classifyCommand(migration.rollback_command);
    if (!migration.rollback_command || migration.rollback_command.trim().length === 0) {
        return {
            migration_id: migration.migration_id,
            has_rollback: false,
            rollback_valid: false,
            advisory: `迁移 "${migration.migration_id}" 缺少回滚命令 — 如果迁移失败需要手动恢复，建议补充 rollback_command`,
        };
    }
    // 回滚命令应是正向操作的反向操作
    const rollbackValid = migration.rollback_command.length > 0;
    return {
        migration_id: migration.migration_id,
        has_rollback: true,
        rollback_valid: rollbackValid,
        advisory: `迁移 "${migration.migration_id}": 正向风险=${forwardClassified.risk}, 回滚风险=${rollbackClassified.risk}`,
    };
}
const LOCKFILE_NAMES = [
    "package-lock.json",
    "pnpm-lock.yaml",
    "yarn.lock",
    "go.sum",
    "Cargo.lock",
];
/**
 * 检查供应链安全 — 验证依赖有 lockfile 和完整性 hash。
 * 此为轻量级检查，不读取实际文件内容。
 */
export function checkSupplyChain(rootDirFiles, dependencies) {
    const hasLockfile = LOCKFILE_NAMES.some((lf) => rootDirFiles.includes(lf));
    debug("运行安全", "检查供应链安全，依赖数:", dependencies.length, "lockfile:", hasLockfile);
    const checks = dependencies.map((dep) => ({
        package_name: dep.name,
        version: dep.version,
        has_lockfile: hasLockfile,
        has_integrity_hash: hasLockfile, // lockfile 意味着存在完整性哈希
        advisory: hasLockfile
            ? "已通过 lockfile 锁定，含完整性哈希"
            : `${dep.name}@${dep.version} 未锁定 — 存在供应链风险，建议添加 lockfile`,
    }));
    const locked = checks.filter((c) => c.has_lockfile).length;
    const unlocked = checks.length - locked;
    return {
        total_dependencies: dependencies.length,
        locked_dependencies: locked,
        unlocked_dependencies: unlocked,
        checks,
        advisory: unlocked > 0
            ? `${unlocked}/${dependencies.length} 个依赖未锁定 — 建议添加 lockfile 以保障供应链安全`
            : `全部 ${dependencies.length} 个依赖已锁定`,
    };
}
//# sourceMappingURL=runtime_safety.js.map