← Files Aivana Database EngineerARCHIVED FILE
runtime/riskEngine.js
4.81 KB · Oct 2, 2026 · 00:34 UTC
const { getPolicy } = require("./config");
const HIGH_COST_PATTERNS = [
/\b(drop|truncate|delete\s+from)\b/i,
/\balter\s+table\b/i,
/\bcreate\s+(or\s+replace\s+)?(function|procedure|trigger|view|index|schema)\b/i,
];
const MEDIUM_COST_PATTERNS = [
/\bupdate\s+.*\bset\b/i,
/\binsert\s+into\b/i,
/\bmerge\s+into\b/i,
/\bcreate\s+table\b/i,
];
const READ_PATTERNS = [
/\bselect\b/i,
/\bexplain\b/i,
/\bshow\b/i,
/\bwith\s+\w+\s+as\b/i,
];
const TRANSACTION_PATTERNS = [
/\b(begin|commit|rollback|savepoint)\b/i,
/\btransaction\b/i,
/\block\s+\w+\b/i,
];
const INJECTION_PATTERNS = [
/'.*?(or|and)\s+1\s*=\s*1/i,
/;\s*(drop|alter|delete|insert|update|create|truncate)\b/i,
/union\s+select/i,
/--\s*?/,
/\/\*/,
];
const CRITICAL_PATTERNS = [
/\bdrop\s+database\b/i,
/\balter\s+system\b/i,
/\bshutdown\b/i,
/\bpg_terminate_backend\b/i,
];
function parseSqlWithSqlParser(sql) {
try {
const parserLib = require("node-sql-parser");
const parser = new (parserLib.Parser)();
return parser.astify(sql, { database: "postgresql" });
} catch (_error) {
return null;
}
}
function astRiskSignals(ast) {
if (!ast) {
return [];
}
if (Array.isArray(ast)) {
return ast.flatMap((entry) => astRiskSignals(entry));
}
const signals = [];
const type = String(ast?.type || "").toUpperCase();
if (type.includes("DELETE") || type.includes("UPDATE") || type.includes("INSERT")) {
signals.push("mutation_ast_node_detected");
}
if (type.includes("CREATE") || type.includes("ALTER") || type.includes("DROP")) {
signals.push("ddl_ast_node_detected");
}
if (type.includes("SELECT") && /union|join/i.test(JSON.stringify(ast).toLowerCase())) {
signals.push("ast_union_or_join_detected");
}
return signals;
}
function normalize(sql) {
return String(sql || "").trim().replace(/\s+/g, " ");
}
function stripComments(sql) {
return sql
.replace(/--.*$/gm, " ")
.replace(/\/\*[\s\S]*?\*\//g, " ")
.trim();
}
function hasNoWhereClause(sql) {
return /\bdelete\s+.*from\b/i.test(sql) && !/\bwhere\b/i.test(sql);
}
function countSqlTokens(sql) {
return normalize(sql).split(" ").filter(Boolean).length;
}
function estimateImpact(sql) {
const tokens = countSqlTokens(sql);
if (tokens > 120) {
return "high";
}
if (tokens > 60) {
return "medium";
}
return "low";
}
function classify(sql) {
const policy = getPolicy();
const sanitized = stripComments(normalize(sql)).toLowerCase();
const tokens = countSqlTokens(sanitized);
const riskSignals = [];
const ast = parseSqlWithSqlParser(sql);
const astSignals = astRiskSignals(ast);
riskSignals.push(...astSignals);
let level = "LOW";
if (CRITICAL_PATTERNS.some((re) => re.test(sanitized))) {
level = "CRITICAL";
riskSignals.push("critical_control_plane_operation_detected");
} else if (HIGH_COST_PATTERNS.some((re) => re.test(sanitized))) {
level = "HIGH";
riskSignals.push("high_risk_mutating_or_schema_operation");
} else if (MEDIUM_COST_PATTERNS.some((re) => re.test(sanitized))) {
level = "MEDIUM";
riskSignals.push("mutating_or_schema_write_operation");
} else if (READ_PATTERNS.some((re) => re.test(sanitized))) {
level = "LOW";
riskSignals.push("read_only_query");
}
if (hasNoWhereClause(sanitized)) {
level = "HIGH";
riskSignals.push("unsafe_bulk_delete_without_where");
}
if (INJECTION_PATTERNS.some((re) => re.test(sanitized))) {
level = "CRITICAL";
riskSignals.push("possible_sql_injection_pattern");
}
if (TRANSACTION_PATTERNS.some((re) => re.test(sanitized))) {
riskSignals.push("transaction_or_lock_context_detected");
if (level === "LOW") {
level = "MEDIUM";
}
}
if (astSignals.includes("ddl_ast_node_detected")) {
riskSignals.push("ddl_ast_structural_change");
}
if (astSignals.includes("mutation_ast_node_detected")) {
riskSignals.push("mutation_ast_structural_change");
}
if (estimateImpact(sanitized) === "high" && level !== "HIGH" && level !== "CRITICAL") {
level = "MEDIUM";
riskSignals.push("high_complexity_query");
}
if (tokens > 250) {
riskSignals.push("very_large_query_text");
if (policy && policy.risk[level]) {
const current = policy.risk[level];
if (current.action === "AUTO_EXECUTE") {
level = "MEDIUM";
}
}
}
const enforcement = policy.risk[level] || policy.risk.LOW;
return {
riskLevel: level,
riskSignals,
impact: estimateImpact(sanitized),
requiresHumanApproval: enforcement.requiresApproval,
suggestedAction: enforcement.action,
maxExecutionWindowMs: enforcement.maxExecutionWindowMs,
estimatedComplexity: estimateImpact(sanitized),
sqlFingerprint: Buffer.from(sanitized).toString("base64").slice(0, 24),
astParsed: Boolean(ast),
safetyFlags: riskSignals,
};
}
module.exports = {
classify,
};
SHA-256: 1f1e38e5697559880cd2a4bb588fc7909e1797b32d95ad9e4809a20e351e2ef7