package policy import ( "log" "os" "path" "runtime" "testing" "postern/internal/db" "go.starlark.net/starlark" ) func TestExecModule(t *testing.T) { if runtime.GOOS == "windows" { t.Skip("POSIX-specific test") } posternDB, err := db.OpenDB(&db.Config{ DBPath: path.Join(t.TempDir(), "meta.db"), }) if err != nil { t.Fatal(err) } defer func(posternDB *db.DB) { err := posternDB.Close() if err != nil { log.Fatal(err) } }(posternDB) policy := ` def init(): return None def test_success(): res = exec.pipe_to_process("/bin/sh", args=["-c", "echo hello"]) return {"code": res.code, "stdout": res.stdout, "stderr": res.stderr, "timed_out": res.timed_out} def test_input_piping(): res = exec.pipe_to_process("/bin/cat", input_data="ping") return {"code": res.code, "stdout": res.stdout, "stderr": res.stderr, "timed_out": res.timed_out} def test_args(): res = exec.pipe_to_process("/bin/sh", args=["-c", "echo $1", "_", "arg1"]) return {"code": res.code, "stdout": res.stdout, "stderr": res.stderr, "timed_out": res.timed_out} def test_nonzero_exit(): res = exec.pipe_to_process("/bin/sh", args=["-c", "exit 42"]) return {"code": res.code, "stdout": res.stdout, "stderr": res.stderr, "timed_out": res.timed_out} def test_stderr(): res = exec.pipe_to_process("/bin/sh", args=["-c", "echo err >&2"]) return {"code": res.code, "stdout": res.stdout, "stderr": res.stderr, "timed_out": res.timed_out} def test_environment(): res = exec.pipe_to_process("/bin/sh", args=["-c", "echo $FOO"], environment={"FOO": "bar"}) return {"code": res.code, "stdout": res.stdout, "stderr": res.stderr, "timed_out": res.timed_out} def test_env_no_leak(): res = exec.pipe_to_process("/bin/sh", args=["-c", "echo ${HOME:-empty}"]) return {"code": res.code, "stdout": res.stdout, "stderr": res.stderr, "timed_out": res.timed_out} def test_timeout(): res = exec.pipe_to_process("/bin/sh", args=["-c", "sleep 10"], timeout=1) return {"code": res.code, "stdout": res.stdout, "stderr": res.stderr, "timed_out": res.timed_out} def test_timeout_float(): res = exec.pipe_to_process("/bin/sh", args=["-c", "sleep 1"], timeout=0.5) return {"code": res.code, "stdout": res.stdout, "stderr": res.stderr, "timed_out": res.timed_out} def test_not_found(): return exec.pipe_to_process("/nonexistent/binary/xyz") ` policyFile := path.Join(t.TempDir(), "policy.star") err = os.WriteFile(policyFile, []byte(policy), 0644) if err != nil { t.Fatal(err) } e, err := NewEngine(policyFile, posternDB) if err != nil { t.Fatal(err) } s := e.state.Load() tests := []struct { name string fnName string wantCode int wantOut string wantErr string wantTimeout bool }{ {"success", "test_success", 0, "hello\n", "", false}, {"input_piping", "test_input_piping", 0, "ping", "", false}, {"args", "test_args", 0, "arg1\n", "", false}, {"nonzero_exit", "test_nonzero_exit", 42, "", "", false}, {"stderr", "test_stderr", 0, "", "err\n", false}, {"environment", "test_environment", 0, "bar\n", "", false}, {"env_no_leak", "test_env_no_leak", 0, "empty\n", "", false}, {"timeout", "test_timeout", -1, "", "", true}, {"timeout_float", "test_timeout_float", -1, "", "", true}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { hookVal, ok := s.globals[tt.fnName] if !ok { t.Fatalf("%s not found in engine globals", tt.fnName) } res, err := starlark.Call(s.thread, hookVal, nil, nil) if err != nil { t.Fatal(err) } dict, ok := res.(*starlark.Dict) if !ok { t.Fatalf("expected dict, got %s", res.Type()) } assertDictField(t, dict, "code", starlark.MakeInt(tt.wantCode)) assertDictField(t, dict, "stdout", starlark.String(tt.wantOut)) assertDictField(t, dict, "stderr", starlark.String(tt.wantErr)) assertDictField(t, dict, "timed_out", starlark.Bool(tt.wantTimeout)) }) } t.Run("not_found", func(t *testing.T) { hookVal, ok := s.globals["test_not_found"] if !ok { t.Fatal("test_not_found not found in engine globals") } _, err := starlark.Call(s.thread, hookVal, nil, nil) if err == nil { t.Fatal("expected error for nonexistent binary") } }) } func assertDictField(t *testing.T, d *starlark.Dict, key string, want starlark.Value) { t.Helper() v, found, err := d.Get(starlark.String(key)) if err != nil { t.Fatalf("key %q err %q", key, err) } if !found { t.Fatalf("key %q not found", key) } if v != want { t.Errorf("field %q: got %v, want %v", key, v, want) } }