package guesthook import ( "context" "io" "os" "path/filepath" "testing" ) // recordingRunner is a fake proxmox.Runner that records every call and snapshots the content of the // install SOURCE file at call time (the deferred os.Remove would erase it before the test can look). type recordingRunner struct { calls [][]string srcContent []string } func (r *recordingRunner) Run(_ context.Context, name string, args ...string) ([]byte, []byte, error) { r.calls = append(r.calls, append([]string{name}, args...)) if name == "install" && len(args) > 0 { src := args[len(args)-2] b, _ := os.ReadFile(src) r.srcContent = append(r.srcContent, string(b)) } return nil, nil, nil } func (r *recordingRunner) RunStdin(ctx context.Context, _ io.Reader, name string, args ...string) ([]byte, []byte, error) { return r.Run(ctx, name, args...) } // R-861 (agent v0.146.0): the hook file comes with the signed config bundle; the agent never installs it, only checks. // RED-PROOF (audits/hub-safety-2026-10-05/partF/red-proof.txt): make SnippetReady accept any content → the // "differs" case fails. func TestSnippetReady(t *testing.T) { d := t.TempDir() p := filepath.Join(d, "felhom-guest-hook.sh") if err := SnippetReady(p); err == nil { t.Fatal("a missing hook read as ready — the guest would get a hookscript that does not exist") } _ = os.WriteFile(p, []byte("#!/bin/sh\nid > /tmp/x\n"), 0o755) if err := SnippetReady(p); err == nil { t.Fatal("a hook with other content read as ready") } _ = os.WriteFile(p, []byte(snippetBody), 0o755) if err := SnippetReady(p); err != nil { t.Fatalf("the bundle's hook was not accepted: %v", err) } l := filepath.Join(d, "link.sh") _ = os.Symlink(p, l) if err := SnippetReady(l); err == nil { t.Fatal("a symlink read as the hook") } } // The bundle's copy is byte-identical to the body the agent checks against. func TestSnippetEqualsTheBundle(t *testing.T) { got, err := os.ReadFile(filepath.Join("..", "..", "configs", "felhom-guest-hook.sh")) if err != nil || string(got) != snippetBody { t.Fatalf("configs/felhom-guest-hook.sh differs from snippetBody (err %v)", err) } }