feat(go): add Phase 1 parity sidecar

This commit is contained in:
Luna 2026-07-10 05:02:50 -07:00
parent 65f5be6420
commit f02509aab5
22 changed files with 947 additions and 6 deletions

View file

@ -0,0 +1,58 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Package system captures one cached, injectable view of live host state.
package system
import (
"os"
"path/filepath"
"sort"
"strconv"
"strings"
"codeberg.org/anassaeneroi/enodia-sentinal/go-agent/internal/model"
)
// Capture reads process state once from procRoot. Transient per-process read
// failures degrade to empty fields, matching Python's fail-open Process view.
func Capture(procRoot string) (model.State, error) {
if procRoot == "" {
procRoot = "/proc"
}
entries, err := os.ReadDir(procRoot)
if err != nil {
return model.State{}, err
}
processes := make([]model.Process, 0, len(entries))
for _, entry := range entries {
pid, err := strconv.Atoi(entry.Name())
if err != nil || !entry.IsDir() {
continue
}
base := filepath.Join(procRoot, entry.Name())
processes = append(processes, model.Process{
PID: pid,
Comm: strings.TrimSpace(readText(filepath.Join(base, "comm"))),
Cmdline: strings.TrimSpace(strings.ReplaceAll(readText(filepath.Join(base, "cmdline")), "\x00", " ")),
Exe: readLink(filepath.Join(base, "exe")),
})
}
sort.Slice(processes, func(i, j int) bool { return processes[i].PID < processes[j].PID })
return model.State{Processes: processes}, nil
}
func readText(path string) string {
raw, err := os.ReadFile(path)
if err != nil {
return ""
}
return string(raw)
}
func readLink(path string) string {
target, err := os.Readlink(path)
if err != nil {
return ""
}
return target
}

View file

@ -0,0 +1,37 @@
// SPDX-License-Identifier: GPL-3.0-or-later
package system
import (
"os"
"path/filepath"
"testing"
)
func TestCaptureUsesInjectableProcRoot(t *testing.T) {
root := t.TempDir()
proc := filepath.Join(root, "42")
if err := os.Mkdir(proc, 0o700); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(filepath.Join(proc, "comm"), []byte("bash\n"), 0o600); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(filepath.Join(proc, "cmdline"), []byte("bash\x00-i\x00"), 0o600); err != nil {
t.Fatal(err)
}
if err := os.Symlink("/tmp/x (deleted)", filepath.Join(proc, "exe")); err != nil {
t.Fatal(err)
}
state, err := Capture(root)
if err != nil {
t.Fatal(err)
}
if len(state.Processes) != 1 {
t.Fatalf("unexpected processes: %#v", state.Processes)
}
got := state.Processes[0]
if got.PID != 42 || got.Comm != "bash" || got.Cmdline != "bash -i" || got.Exe != "/tmp/x (deleted)" {
t.Fatalf("unexpected process: %#v", got)
}
}