package host import ( "context" "errors" "runtime" "testing" "time" "github.com/carlosframework/platform/internal/registry" "github.com/carlosframework/platform/internal/release" ) // Issue #315, through the fast loop's production options: an agent that is // not root hands a named-unit route to root's pass rather than repointing it // and failing systemd's permission check. An agent run as root keeps // restarting the unit itself. func TestFastSweepHandsANamedUnitToRoot(t *testing.T) { for _, tc := range []struct { name string root bool }{{"agent user", false}, {"root", true}} { t.Run(tc.name, func(t *testing.T) { was := agentRunsAsRoot agentRunsAsRoot = func() bool { return tc.root } t.Cleanup(func() { agentRunsAsRoot = was }) env := newFastFixture(t) ctx := context.Background() plat := runtime.GOOS + "-" + runtime.GOARCH for _, v := range []string{"v1", "v2"} { m := release.Manifest{App: "fastapp", Version: v, Kind: "binary", Artifacts: map[string]release.Artifact{plat: {}}} if err := release.Ship(ctx, env.store, "bab", m, map[string][]byte{plat: []byte("build " + v)}); err != nil { t.Fatalf("Ship %s: %v", v, err) } } if err := release.Promote(ctx, env.store, env.priv, "bab", "fastapp", "canary/dev", "v1"); err != nil { t.Fatal(err) } if err := env.reg.Upsert(registry.Route{Host: "console.test", Kind: "instance", App: "fastapp", Channel: "canary/dev", Status: "ready", Addr: "127.0.0.1:8090"}); err != nil { t.Fatal(err) } if err := release.Pass(ctx, env.reg, env.store, env.pub, env.optDir, nil); err != nil { t.Fatal(err) } if err := env.reg.SetUnit("console.test", "console.service"); err != nil { t.Fatal(err) } if err := release.Promote(ctx, env.store, env.priv, "bab", "fastapp", "canary/dev", "v2"); err != nil { t.Fatal(err) } var unitRestarts []string restart := makeRestartRoute(env.reg, func(string) {}, unitOnly(func(u string) error { unitRestarts = append(unitRestarts, u); return nil }), nil) var relayed []error stageReq := func(host, ver string, err error) { if host == "console.test" && ver == "v2" { relayed = append(relayed, err) } } d := env.deps(nil) d.restart = restart d.passOpts = fastPassOpts(env.dataDir, stageReq, restart, nil) fastTick(ctx, d, time.Unix(1754640000, 0)) live, err := release.LiveVersion(env.optDir, "console.test") if err != nil { t.Fatal(err) } if tc.root { if live != "v2" || len(unitRestarts) != 1 || len(relayed) != 0 { t.Fatalf("root agent: live %q, unit restarts %v, relays %v; want v2, one restart, no relay", live, unitRestarts, relayed) } return } if live != "v1" || len(unitRestarts) != 0 { t.Fatalf("agent user: live %q, unit restarts %v; want v1 untouched and no restart", live, unitRestarts) } if len(relayed) != 1 || !errors.Is(relayed[0], release.ErrUnitRestartNeedsRoot) { t.Fatalf("relays = %v, want one ErrUnitRestartNeedsRoot", relayed) } }) } }