bastion 0.53.2
This commit is contained in:
@@ -0,0 +1,156 @@
|
||||
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")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user