From 69d5d0ffec2bee1c0e01444e4b267bd7a70e99f5 Mon Sep 17 00:00:00 2001 From: Hadi <112569860+anotherhadi@users.noreply.github.com> Date: Tue, 19 May 2026 20:00:04 +0200 Subject: [PATCH] Add shell exec to plugins Signed-off-by: Hadi <112569860+anotherhadi@users.noreply.github.com> --- docs/plugins.md | 10 ++++++++++ internal/plugins/lua.go | 28 ++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/docs/plugins.md b/docs/plugins.md index 2b485d3..27849db 100644 --- a/docs/plugins.md +++ b/docs/plugins.md @@ -110,6 +110,16 @@ end -- Quit the app (useful for startup checks that fail) quit("reason message") + +-- Run a shell command, optionally piping a string to its stdin. +-- Returns: output string, error string (nil on success). +-- The command runs via "sh -c" with a 30-second timeout. +local out, err = shell_pipe("trufflehog filesystem --no-update --json /dev/stdin", body) +if err then + log("command failed: " .. err) +else + log("output: " .. out) +end ``` ### Finding deduplication diff --git a/internal/plugins/lua.go b/internal/plugins/lua.go index 69c6c3c..bb6de9a 100644 --- a/internal/plugins/lua.go +++ b/internal/plugins/lua.go @@ -1,7 +1,10 @@ package plugins import ( + "bytes" + "context" "log" + "os/exec" "strings" "time" @@ -171,6 +174,31 @@ func registerUtilities(L *lua.LState, mgr *Manager, p *Plugin) { } return 0 })) + + L.SetGlobal("shell_pipe", L.NewFunction(func(L *lua.LState) int { + cmd := L.CheckString(1) + input := L.OptString(2, "") + + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + defer cancel() + + c := exec.CommandContext(ctx, "sh", "-c", cmd) + c.Stdin = strings.NewReader(input) + + var stdout, stderr bytes.Buffer + c.Stdout = &stdout + c.Stderr = &stderr + + err := c.Run() + if err != nil { + L.Push(lua.LString(stdout.String())) + L.Push(lua.LString(err.Error() + ": " + stderr.String())) + return 2 + } + L.Push(lua.LString(stdout.String())) + L.Push(lua.LNil) + return 2 + })) } func luaTableString(t *lua.LTable, key string) string {