From 9651a8b2da127ed7130fcee8bd5584c17c7f8177 Mon Sep 17 00:00:00 2001 From: jochen Date: Thu, 22 Oct 2026 14:37:00 +0200 Subject: [PATCH] issue 1840/S9: prove pacman's output puts no command line or environment on the bus A fixture of pacman and checkupdates output holding command lines, environment variables and messages leaves only names, versions and repositories in installed, updates and package.changed, and no command the keeper runs names a package, a foreign one least of all. --- .../cmd/pacman-tools/keeper_bus_test.go | 97 +++++++++++++++++++ .../checkupdates | 4 + .../pacman-Q | 9 ++ .../pacman-Qeq | 3 + .../pacman-Sl | 3 + 5 files changed, 116 insertions(+) create mode 100644 modules/pacman/cmd/pacman-tools/keeper_bus_test.go create mode 100644 modules/pacman/cmd/pacman-tools/testdata/pacman-output-with-command-lines-and-environment/checkupdates create mode 100644 modules/pacman/cmd/pacman-tools/testdata/pacman-output-with-command-lines-and-environment/pacman-Q create mode 100644 modules/pacman/cmd/pacman-tools/testdata/pacman-output-with-command-lines-and-environment/pacman-Qeq create mode 100644 modules/pacman/cmd/pacman-tools/testdata/pacman-output-with-command-lines-and-environment/pacman-Sl diff --git a/modules/pacman/cmd/pacman-tools/keeper_bus_test.go b/modules/pacman/cmd/pacman-tools/keeper_bus_test.go new file mode 100644 index 00000000..f337c7e3 --- /dev/null +++ b/modules/pacman/cmd/pacman-tools/keeper_bus_test.go @@ -0,0 +1,97 @@ +package main + +// What the keeper puts on the bus is only its named fields (novox/hq ADR 0507 ยง1; acceptance 1840/AC7): pacman's +// output holding command lines, environment variables and messages leaves none of them in a value or an event, +// and no command the keeper runs names a package, a foreign one least of all. (busshapes_test.go holds every +// shape to its named fields.) + +import ( + "context" + "encoding/json" + "os" + "path/filepath" + "strings" + "testing" + "time" +) + +func TestPacmanOutputHoldingCommandLinesAndEnvironmentPutsNeitherOnTheBus(t *testing.T) { + dir := filepath.Join("testdata", "pacman-output-with-command-lines-and-environment") + read := func(name string) string { + b, err := os.ReadFile(filepath.Join(dir, name)) + if err != nil { + t.Fatal(err) + } + return string(b) + } + db := &pacmanDB{sl: read("pacman-Sl"), checkup: Ran{Stdout: read("checkupdates")}} + db.set(read("pacman-Q"), read("pacman-Qeq")) + k, states, ev, clock, w := newTestKeeper(db) + ctx, cancel := context.WithCancel(context.Background()) + done := make(chan error, 1) + go func() { done <- k.Run(ctx) }() + for deadline := time.Now().Add(5 * time.Second); time.Now().Before(deadline); time.Sleep(time.Millisecond) { + if e, _ := states.store(StateUpdates).Get("node-a"); e != nil { + break + } + } + clock.Advance(time.Minute) + w.c <- LockReleased + w.c <- MirrorsRewritten + time.Sleep(20 * time.Millisecond) + cancel() + <-done + + var onBus []string + for _, name := range []string{StateInstalled, StateUpdates} { + s := states.store(name) + keys, _ := s.Keys() + for _, key := range keys { + e, _ := s.Get(key) + onBus = append(onBus, name+"."+key+" "+string(e.Value)) + } + } + events := ev.Take() + if len(events) == 0 { + t.Fatal("the first write said nothing") + } + for _, e := range events { + body, _ := json.Marshal(e.body) + onBus = append(onBus, e.name+" "+string(body)) + } + if len(onBus) < 3 { + t.Fatalf("on the bus: %v", onBus) + } + whole := strings.Join(onBus, "\n") + for _, never := range []string{"=", "sudo", "--noconfirm", "/", "rm", "warning", "hunter2", "Synchronizing", "HOME", "TOKEN", "SECRET"} { + if strings.Contains(whole, never) { + t.Errorf("%q reached the bus:\n%s", never, whole) + } + } + var inst InstalledValue + e, _ := states.store(StateInstalled).Get("node-a") + json.Unmarshal(e.Value, &inst) + if !samePackages(inst.Packages, []InstalledPackage{{"glibc", "2.42-1", false, "core"}, {"yay", "12.0-1", true, RepoForeign}, {"zsh", "5.9-1", true, "extra"}}) { + t.Errorf("the packages are read, the rest left out: %+v", inst.Packages) + } + var up UpdatesValue + e, _ = states.store(StateUpdates).Get("node-a") + json.Unmarshal(e.Value, &up) + if len(up.Packages) != 1 || up.Packages[0] != (VersionChange{"glibc", "2.42-1", "2.42-2"}) { + t.Errorf("updates: %+v", up) + } + + // no command the keeper ran names a package; the foreign one least of all. + db.mu.Lock() + defer db.mu.Unlock() + for _, c := range db.commands { + switch c { + case "pacman -Q", "pacman -Qeq", "pacman -Sl", "checkupdates": + default: + t.Errorf("the keeper ran %q", c) + } + if strings.Contains(c, "yay") { + t.Errorf("a command named the foreign package: %q", c) + } + } +} diff --git a/modules/pacman/cmd/pacman-tools/testdata/pacman-output-with-command-lines-and-environment/checkupdates b/modules/pacman/cmd/pacman-tools/testdata/pacman-output-with-command-lines-and-environment/checkupdates new file mode 100644 index 00000000..40c952dc --- /dev/null +++ b/modules/pacman/cmd/pacman-tools/testdata/pacman-output-with-command-lines-and-environment/checkupdates @@ -0,0 +1,4 @@ +glibc 2.42-1 -> 2.42-2 +zsh 5.9-1 -> 5.9-2 PASSWORD=hunter2 +env FOO=bar -> /bin/sh +:: Synchronizing package databases... diff --git a/modules/pacman/cmd/pacman-tools/testdata/pacman-output-with-command-lines-and-environment/pacman-Q b/modules/pacman/cmd/pacman-tools/testdata/pacman-output-with-command-lines-and-environment/pacman-Q new file mode 100644 index 00000000..a8c96383 --- /dev/null +++ b/modules/pacman/cmd/pacman-tools/testdata/pacman-output-with-command-lines-and-environment/pacman-Q @@ -0,0 +1,9 @@ +glibc 2.42-1 +sudo pacman -Syu --noconfirm +yay 12.0-1 +LD_PRELOAD=/tmp/hook.so 1.0-1 +zsh 5.9-1 +bash 5.2-1 HOME=/root +evil 1.0;rm-rf +PATH=/usr/bin:/bin +warning: could not get file information for etc/secret diff --git a/modules/pacman/cmd/pacman-tools/testdata/pacman-output-with-command-lines-and-environment/pacman-Qeq b/modules/pacman/cmd/pacman-tools/testdata/pacman-output-with-command-lines-and-environment/pacman-Qeq new file mode 100644 index 00000000..815d6570 --- /dev/null +++ b/modules/pacman/cmd/pacman-tools/testdata/pacman-output-with-command-lines-and-environment/pacman-Qeq @@ -0,0 +1,3 @@ +yay +zsh +TOKEN=abc diff --git a/modules/pacman/cmd/pacman-tools/testdata/pacman-output-with-command-lines-and-environment/pacman-Sl b/modules/pacman/cmd/pacman-tools/testdata/pacman-output-with-command-lines-and-environment/pacman-Sl new file mode 100644 index 00000000..269f745e --- /dev/null +++ b/modules/pacman/cmd/pacman-tools/testdata/pacman-output-with-command-lines-and-environment/pacman-Sl @@ -0,0 +1,3 @@ +core glibc 2.42-1 [installed] +extra zsh 5.9-1 [installed] +extra SECRET=x 1-1