mirror of
https://github.com/bryanthaboi/gen1recomp.git
synced 2026-08-12 00:10:56 +02:00
12ff4dba2e
The overlay only wrapped the five loaders the boot path needed, leaving a silent-failure hole: any future state (or current code like Sound.lua's widenMono, which re-reads the pika-cry WAV via love.sound.newSoundData with the caller's bare path) could load a generated asset through an unwrapped API and silently degrade on hardware. NxAssetOverlay now wraps every read-side love function that accepts a filesystem path (filesystem.read/load/lines/newFileData/getInfo, graphics.newImage/newFont, image.newImageData, audio.newSource, sound.newSoundData, font.newFontData), so new states and mods fall inside the Blue/Yellow fallback with zero per-call-site work. Write-side functions stay stock, proven by identity assertions in the fallback suite. The static guard's forbidden-literal list covers the same APIs. Co-authored-by: Cursor <cursoragent@cursor.com>
70 lines
2.5 KiB
Lua
70 lines
2.5 KiB
Lua
-- Guard: core code must not call love loaders directly on literal
|
|
-- assets/generated paths. Centralized loading (Assets / the NX overlay)
|
|
-- is what keeps mod overrides and the Blue/Yellow NX fallback working; a
|
|
-- raw literal load silently bypasses both. This scans every src/*.lua and
|
|
-- fails on new violations so the class of bug cannot regress by accident.
|
|
-- Self-contained: luajit tests/engine/nx_generated_guard_test.lua
|
|
package.path = "./?.lua;./?/init.lua;" .. package.path
|
|
|
|
local T = require("tests.harness")
|
|
local check = T.check
|
|
|
|
local FORBIDDEN = {
|
|
'love%.graphics%.newImage%(%s*"assets/generated',
|
|
'love%.image%.newImageData%(%s*"assets/generated',
|
|
'love%.audio%.newSource%(%s*"assets/generated',
|
|
'love%.sound%.newSoundData%(%s*"assets/generated',
|
|
'love%.graphics%.newFont%(%s*"assets/generated',
|
|
'love%.font%.newFontData%(%s*"assets/generated',
|
|
'love%.filesystem%.read%(%s*"assets/generated',
|
|
'love%.filesystem%.load%(%s*"assets/generated',
|
|
'love%.filesystem%.lines%(%s*"assets/generated',
|
|
'love%.filesystem%.newFileData%(%s*"assets/generated',
|
|
'love%.filesystem%.getInfo%(%s*"assets/generated',
|
|
}
|
|
|
|
-- Files that legitimately reference generated literals but never load them
|
|
-- directly (writers, mount setup, the NX probe, mod source roots) are not
|
|
-- matched by the patterns above, so no allowlist is needed.
|
|
|
|
local function listLuaFiles(dir, out)
|
|
out = out or {}
|
|
local p = io.popen('find "' .. dir .. '" -name "*.lua" -type f')
|
|
if not p then return out end
|
|
for line in p:lines() do
|
|
out[#out + 1] = line
|
|
end
|
|
p:close()
|
|
return out
|
|
end
|
|
|
|
local violations = {}
|
|
for _, file in ipairs(listLuaFiles("src")) do
|
|
local f = io.open(file, "r")
|
|
if f then
|
|
local body = f:read("*a")
|
|
f:close()
|
|
for _, pat in ipairs(FORBIDDEN) do
|
|
if body:find(pat) then
|
|
violations[#violations + 1] = file .. " matches " .. pat
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
check(#violations == 0,
|
|
"no direct love loader call on literal assets/generated paths"
|
|
.. (#violations > 0 and (":\n " .. table.concat(violations, "\n ")) or ""))
|
|
|
|
-- The NX overlay module itself must exist and stay NX-gated at install time.
|
|
local f = io.open("main.lua", "r")
|
|
local mainSrc = f and f:read("*a") or ""
|
|
if f then f:close() end
|
|
check(mainSrc:find("NxAssetOverlay", 1, true) ~= nil,
|
|
"main.lua installs NxAssetOverlay")
|
|
check(mainSrc:find("isNX", 1, true) ~= nil
|
|
and mainSrc:find('require("src.core.NxAssetOverlay").install()', 1, true) ~= nil,
|
|
"the overlay install stays gated on Platform.isNX()")
|
|
|
|
T.finish()
|