Files
privatae-bastion/client-go/computer_test.go
T
Privatae e4c9b69b46
ci / personal-data (push) Successful in 5s
ci / test (push) Successful in 3m4s
ci / fuzz (push) Successful in 3m45s
bastion 0.53.2
2026-10-20 04:42:14 +00:00

157 lines
5.9 KiB
Go

package main
import (
"encoding/json"
"os"
"strings"
"testing"
)
// The judgement is platform-neutral and table-driven, so every platform's
// answer is testable from one CI by passing goos explicitly.
func TestWaysInDeepestFirst(t *testing.T) {
got := waysIn("Autodesk Fusion 360", `C:\Users\u\AppData\Local\Autodesk\webdeploy\Fusion360.exe`, "windows", false)
if len(got) < 2 || !strings.HasPrefix(got[0], "script:python") || got[len(got)-1] != wayGUI {
t.Fatalf("Fusion 360 must lead with its Python door and end with gui: %v", got)
}
// per-GOOS doors: Office is COM on Windows, AppleScript on macOS, nothing special elsewhere
if w := waysIn("Microsoft Excel", "", "windows", false); !strings.HasPrefix(w[0], "script:com") {
t.Fatalf("Excel on Windows: %v", w)
}
if w := waysIn("Microsoft Excel", "", "darwin", false); !strings.HasPrefix(w[0], "script:applescript") {
t.Fatalf("Excel on macOS: %v", w)
}
if w := waysIn("Microsoft Excel", "", "linux", false); len(w) != 1 || w[0] != wayGUI {
t.Fatalf("Excel on Linux has only the gui rung: %v", w)
}
// the table's cli flag and the PATH probe both earn the cli rung, once
if w := waysIn("Blender", "/usr/bin/blender", "linux", true); countOf(w, wayCLI) != 1 || w[0] != "script:python (bpy)" {
t.Fatalf("Blender: %v", w)
}
if w := waysIn("Some Tool", "/usr/bin/sometool", "linux", true); len(w) != 2 || w[0] != wayCLI || w[1] != wayGUI {
t.Fatalf("an unknown program on PATH is cli then gui: %v", w)
}
// an unknown app that is not on PATH has exactly the gui rung — never an invented door
if w := waysIn("Mystery App", "", "linux", false); len(w) != 1 || w[0] != wayGUI {
t.Fatalf("unknown app: %v", w)
}
// the exe basename matches too (Office names its binaries, not its products)
if w := waysIn("Word", `C:\Program Files\Microsoft Office\root\Office16\WINWORD.EXE`, "windows", false); !strings.HasPrefix(w[0], "script:com") {
t.Fatalf("winword.exe: %v", w)
}
// siblings are not the app: an updater, a runtime, a theme earn nothing
for _, sib := range []string{"Microsoft Edge WebView2 Runtime", "Microsoft Edge Update", "MATLAB Runtime R2024b", "Cursor Theme Pack"} {
if w := waysIn(sib, "", "windows", false); len(w) != 1 || w[0] != wayGUI {
t.Fatalf("%s must earn only gui: %v", sib, w)
}
}
if w := waysIn("Microsoft Edge", "", "windows", false); !strings.HasPrefix(w[0], "script:chrome-devtools") {
t.Fatalf("the real Edge keeps its door: %v", w)
}
// the new Outlook has no COM object model — no door is asserted
if w := waysIn("Microsoft Outlook", "", "windows", false); len(w) != 1 || w[0] != wayGUI {
t.Fatalf("Outlook: %v", w)
}
// a flatpak's program is the app id, never the flatpak binary — no cli from PATH
if w := waysIn("Obsidian", "flatpak:md.obsidian.Obsidian", "linux", execOnPath("flatpak:md.obsidian.Obsidian")); countOf(w, wayCLI) != 0 {
t.Fatalf("flatpak must not earn cli: %v", w)
}
}
func countOf(xs []string, s string) int {
n := 0
for _, x := range xs {
if x == s {
n++
}
}
return n
}
func TestFinishAppsDedupesAndSorts(t *testing.T) {
apps := finishApps([]computerApp{
{Name: "zed", Source: "desktop"},
{Name: "Blender", Source: "desktop", Path: "/nonexistent/blender"},
{Name: "blender", Source: "flatpak"}, // duplicate by name, first fact wins
{Name: " ", Source: "desktop"}, // no name → dropped
})
if len(apps) != 2 || apps[0].Name != "Blender" || apps[1].Name != "zed" {
t.Fatalf("dedupe+sort: %+v", apps)
}
if apps[0].Source != "desktop" {
t.Fatalf("first fact wins on a duplicate: %+v", apps[0])
}
if len(apps[0].WaysIn) == 0 || apps[0].WaysIn[len(apps[0].WaysIn)-1] != wayGUI {
t.Fatalf("ways_in filled for every app: %+v", apps[0])
}
}
// The wire shape both ops answer with, and the honesty rule: unsupported is a
// true answer with a reason, never an empty list.
func TestComputerReportShape(t *testing.T) {
rep := computerReport{Platform: "plan9", Scan: "unsupported", Reason: "no enumerator"}
b, err := json.Marshal(rep)
if err != nil {
t.Fatal(err)
}
var back map[string]any
if err := json.Unmarshal(b, &back); err != nil {
t.Fatal(err)
}
if back["supported"] != false || back["reason"] != "no enumerator" {
t.Fatalf("unsupported must carry supported:false + reason: %s", b)
}
if _, ok := back["apps"]; ok {
t.Fatalf("an unsupported report must not carry an apps list at all: %s", b)
}
}
// Both ops are in the ONE handler table, so the enforcing report's vocabulary
// carries them (mgmtOpVocabulary reads handlerOps) and a grant can name them.
func TestComputerOpsInVocabulary(t *testing.T) {
vocab := mgmtOpVocabulary()
for _, op := range []string{"computer:inventory", "computer:windows"} {
found := false
for _, v := range vocab {
if v == op {
found = true
}
}
if !found {
t.Fatalf("%s missing from the enforcing vocabulary: %v", op, vocab)
}
if handlerOps[op].root != rootNone {
t.Fatalf("%s must need no configured root", op)
}
}
}
// The real thing, on this machine — same switch as TestScanAgentsLive.
func TestComputerObserveLive(t *testing.T) {
if os.Getenv("PRIVATAE_OBSERVE_LIVE") != "1" {
t.Skip("set PRIVATAE_OBSERVE_LIVE=1 to read this machine")
}
inv := computerInventoryReport()
t.Logf("inventory: platform=%s scan=%s supported=%v reason=%q apps=%d", inv.Platform, inv.Scan, inv.Supported, inv.Reason, len(inv.Apps))
for i, a := range inv.Apps {
if i >= 15 {
break
}
t.Logf(" %-32s %-10s %-24s %s", a.Name, a.Version, a.Source, strings.Join(a.WaysIn, " · "))
}
win := computerWindowsReport()
t.Logf("windows: scan=%s supported=%v reason=%q n=%d", win.Scan, win.Supported, win.Reason, len(win.Windows))
for _, w := range win.Windows {
t.Logf(" pid=%-7d app=%-16s focused=%-5v %s", w.PID, w.App, w.Focused, w.Title)
}
}
func TestExecOnPath(t *testing.T) {
if execOnPath("") || execOnPath("/definitely/not/here/xyz") {
t.Fatal("empty or missing program is never on PATH")
}
if execOnPath("/") {
t.Fatal("a directory is not a program")
}
}