fix: security hardening and code quality

- SQL query mode uses read-only SQLite connection with PRAGMA query_only=ON
- Lua sandbox removes dofile/loadfile/load after OpenBase to block file access
- Plugin manager sorts by priority once at load time; GetPlugins is a plain copy
- Proxy appends [body truncated] marker when body hits size limit
- App startup exits with os.Exit(1) on DB open failure
- tickCmd uses tea.Tick instead of time.Sleep in a goroutine
- ErrMsg with non-nil error shows notification then quits
- DB stores path for use by read-only query connection
- WAL journal mode + NORMAL synchronous set in migrate()
- config.go uses errors.Is(err, os.ErrNotExist)
- main.go uses os.UserHomeDir() and removes racy port pre-check
- findings renderer is cached and rebuilt only on width change

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Hadi
2026-05-19 13:38:10 +02:00
parent 41c0e489cf
commit 172a77e13b
11 changed files with 88 additions and 37 deletions
+4 -1
View File
@@ -16,7 +16,6 @@ func newLuaState(mgr *Manager, p *Plugin) *lua.LState {
name string
fn lua.LGFunction
}{
{lua.LoadLibName, lua.OpenPackage},
{lua.BaseLibName, lua.OpenBase},
{lua.TabLibName, lua.OpenTable},
{lua.StringLibName, lua.OpenString},
@@ -27,6 +26,10 @@ func newLuaState(mgr *Manager, p *Plugin) *lua.LState {
L.Push(lua.LString(lib.name))
L.Call(1, 0)
}
// Remove filesystem-access functions to prevent plugins from reading/executing arbitrary files.
for _, name := range []string{"dofile", "loadfile", "load"} {
L.SetGlobal(name, lua.LNil)
}
registerUtilities(L, mgr, p)
return L
}
+3 -1
View File
@@ -81,6 +81,9 @@ func (m *Manager) LoadFromDir(dir string) error {
m.plugins = append(m.plugins, p)
m.mu.Unlock()
}
m.mu.Lock()
sort.Slice(m.plugins, func(i, j int) bool { return m.plugins[i].Priority > m.plugins[j].Priority })
m.mu.Unlock()
return nil
}
@@ -157,7 +160,6 @@ func (m *Manager) GetPlugins() []*Plugin {
defer m.mu.RUnlock()
out := make([]*Plugin, len(m.plugins))
copy(out, m.plugins)
sort.Slice(out, func(i, j int) bool { return out[i].Priority > out[j].Priority })
return out
}