refactor(dynamic): introduce SQL profile for migration hardening with SQLite egress restrictions, extend framework SQL handling logic, and update test coverage across harnesses

This commit is contained in:
elipeter 2026-05-26 23:12:35 -05:00
parent 6ee2bdda36
commit 9bf085ee48
11 changed files with 365 additions and 23 deletions

View file

@ -1208,9 +1208,28 @@ function _nyxLooksLikeSql(sql) {{
const upper = String(sql).toUpperCase();
return ['SELECT', 'INSERT', 'UPDATE', 'DELETE', 'CREATE', 'ALTER', 'DROP'].some((k) => upper.includes(k));
}}
function _nyxTryExecuteSqlite(sql) {{
const endpoint = process.env.NYX_SQL_ENDPOINT;
if (!endpoint) return 'none';
try {{
const {{ DatabaseSync }} = require('node:sqlite');
const db = new DatabaseSync(endpoint);
try {{
db.exec(String(sql));
return 'node:sqlite';
}} catch (e) {{
return 'node:sqlite-error:' + (e && e.constructor ? e.constructor.name : 'Error');
}} finally {{
try {{ db.close(); }} catch (e) {{}}
}}
}} catch (e) {{
return 'none';
}}
}}
function _nyxMigrationSqlRecord(sql, driver) {{
if (!_nyxLooksLikeSql(sql)) return;
__nyx_stub_sql_record(String(sql), {{ driver: driver, source: 'migration' }});
const sqliteDriver = _nyxTryExecuteSqlite(sql);
__nyx_stub_sql_record(String(sql), {{ driver: driver, source: 'migration', sqlite_driver: sqliteDriver }});
}}
// QueryInterface shim for sequelize-style up/down(queryInterface, Sequelize).
const _qi = {{
@ -1231,11 +1250,15 @@ global.__nyx_prisma = _prisma;
(async () => {{
try {{
let _result;
// Try the sequelize shape first (queryInterface, Sequelize).
// Sequelize migrations conventionally take (queryInterface, Sequelize).
// Single-arg migrations are Prisma/raw shapes and should receive payload.
try {{
_result = await Promise.resolve(_h(_qi, {{}}));
if (_h.length >= 2) {{
_result = await Promise.resolve(_h(_qi, {{}}));
}} else {{
_result = await Promise.resolve(_h(payload));
}}
}} catch (e1) {{
// Prisma / raw migration shape — pass payload.
try {{
_result = await Promise.resolve(_h(payload));
}} catch (e2) {{

View file

@ -3174,7 +3174,30 @@ function __nyx_migration_sqlish($value): bool {{
function __nyx_record_migration_result($value, string $driver): void {{
if ($value === null || !__nyx_migration_sqlish($value)) return;
__nyx_stub_sql_record((string)$value, ['driver' => $driver, 'source' => 'migration']);
$sqliteDriver = __nyx_try_execute_migration_sqlite($value);
__nyx_stub_sql_record((string)$value, [
'driver' => $driver,
'source' => 'migration',
'sqlite_driver' => $sqliteDriver,
]);
}}
function __nyx_try_execute_migration_sqlite($value): string {{
$endpoint = getenv('NYX_SQL_ENDPOINT');
if ($endpoint === false || $endpoint === '' || !class_exists('SQLite3')) return 'none';
try {{
$db = new SQLite3($endpoint);
try {{
$db->exec((string)$value);
return 'SQLite3';
}} catch (Throwable $e) {{
return 'SQLite3-error:' . get_class($e);
}} finally {{
@$db->close();
}}
}} catch (Throwable $e) {{
return 'SQLite3-error:' . get_class($e);
}}
}}
if (class_exists({handler:?})) {{

View file

@ -907,7 +907,32 @@ end
def __nyx_record_migration_result(value, driver)
return if value.nil?
return unless __nyx_migration_sqlish?(value)
__nyx_stub_sql_record(value, driver: driver, source: 'migration')
sqlite_driver = __nyx_try_execute_migration_sqlite(value)
__nyx_stub_sql_record(value, driver: driver, source: 'migration', sqlite_driver: sqlite_driver)
end
def __nyx_try_execute_migration_sqlite(value)
endpoint = ENV['NYX_SQL_ENDPOINT']
return 'none' if endpoint.nil? || endpoint.empty?
begin
require 'sqlite3'
db = SQLite3::Database.new(endpoint)
begin
db.execute_batch(value.to_s)
'sqlite3'
rescue StandardError => e
'sqlite3-error:' + e.class.name
ensure
begin
db.close if db
rescue StandardError
end
end
rescue LoadError
'none'
rescue StandardError => e
'sqlite3-error:' + e.class.name
end
end
# ActiveRecord migrations expose `up` / `down` / `change` on a subclass.