From 7e7cc27c3024d3102773f851d2edcf7d929298ed Mon Sep 17 00:00:00 2001 From: mesh-tools Date: Tue, 20 Oct 2026 21:09:36 +0000 Subject: [PATCH] Review round 1 for the checks, ssh-client and the Go build module: sshdir (1484), socket path (1486), over_bound (1290, 1486), toolchain.reported and streams (1483), re-pin to mesh-sdk 36d6f774; delta part 2 of 4 --- checks/sshdir/main.go | 60 ++++++++++++++++--- checks/sshdir/main_test.go | 17 +++++- modules/mesh-build-go/README.md | 4 +- .../cmd/mesh-build-go/emit_test.go | 55 +++++++++++++++++ .../mesh-build-go/integration_level_test.go | 58 ++++++++++++++++-- .../mesh-build-go/cmd/mesh-build-go/levels.go | 21 ++++--- .../mesh-build-go/cmd/mesh-build-go/main.go | 1 + .../mesh-build-go/cmd/mesh-build-go/module.go | 23 ++++++- .../mesh-build-go/cmd/mesh-build-go/store.go | 25 +++++++- .../test_real_integration_test.go | 7 ++- .../cmd/mesh-build-go/test_test.go | 6 +- modules/mesh-build-go/go.mod | 2 +- modules/mesh-build-go/go.sum | 2 + modules/mesh-build-go/module.json | 6 ++ modules/ssh-client/go.mod | 2 +- modules/ssh-client/go.sum | 2 + 16 files changed, 258 insertions(+), 33 deletions(-) create mode 100644 modules/mesh-build-go/cmd/mesh-build-go/emit_test.go diff --git a/checks/sshdir/main.go b/checks/sshdir/main.go index da83ca49..babf2c5c 100644 --- a/checks/sshdir/main.go +++ b/checks/sshdir/main.go @@ -61,7 +61,7 @@ func Check(root string) ([]Finding, error) { if module == SSHModule { continue } - walk(m, "", func(key, value string) { + walk(m, "", dirsOf(m), func(key, value string) { out = append(out, Finding{Module: module, Key: key, Value: value}) }) } @@ -69,7 +69,7 @@ func Check(root string) ([]Finding, error) { } // walk calls found for every string under v, outside Prose, that names a path under ~/.ssh. -func walk(v any, key string, found func(key, value string)) { +func walk(v any, key string, dirs map[string]string, found func(key, value string)) { switch x := v.(type) { case map[string]any: keys := make([]string, 0, len(x)) @@ -79,22 +79,68 @@ func walk(v any, key string, found func(key, value string)) { sort.Strings(keys) for _, k := range keys { if !Prose[k] { - walk(x[k], k, found) + walk(x[k], k, dirs, found) } } case []any: for _, e := range x { - walk(e, key, found) + walk(e, key, dirs, found) } case string: - // A path under a directory of the module's own (${dir:}, as a runs-as module's home) is that account's - // own .ssh, not the operator's ~/.ssh that ssh-client sweeps (issue 1484, ADR 0466 §4). - if underSSH.MatchString(x) && !strings.HasPrefix(x, "${dir:") { + // A path under a directory the mesh places for the module (${dir:} of a directory with a place and no path, + // as a runs-as module's home) is that account's own .ssh, not the operator's ~/.ssh that ssh-client sweeps + // (issue 1484, ADR 0466 §4). Any other ${dir:} is resolved to the path its resource declares and judged. + if resolved, placed := resolveDir(x, dirs); !placed && underSSH.MatchString(resolved) { found(key, x) } } } +var ofDir = regexp.MustCompile(`^\$\{dir:([a-z0-9][a-z0-9_-]*)\}`) + +// placedDir marks a directory the mesh places for the module: it has no path of its own. +const placedDir = "\x00placed" + +// dirsOf are the module's directories by id: the path each declares, or placedDir for one with a place and no path. +func dirsOf(m any) map[string]string { + dirs := map[string]string{} + obj, _ := m.(map[string]any) + list, _ := obj["resources"].([]any) + for _, r := range list { + res, _ := r.(map[string]any) + id, _ := res["id"].(string) + path, _ := res["path"].(string) + switch { + case id == "": + case path != "": + dirs[id] = path + case res["type"] == "directory": + dirs[id] = placedDir + } + } + return dirs +} + +// resolveDir follows a leading ${dir:} through the module's directories. It answers the path with the references +// resolved, and whether it ends under a placed directory. +func resolveDir(x string, dirs map[string]string) (string, bool) { + for i := 0; i < 8; i++ { + m := ofDir.FindStringSubmatch(x) + if m == nil { + return x, false + } + to, ok := dirs[m[1]] + if !ok { + return x, false + } + if to == placedDir { + return x, true + } + x = to + strings.TrimPrefix(x, m[0]) + } + return x, false +} + func main() { root := "." if len(os.Args) > 1 { diff --git a/checks/sshdir/main_test.go b/checks/sshdir/main_test.go index 411fd995..a7df3332 100644 --- a/checks/sshdir/main_test.go +++ b/checks/sshdir/main_test.go @@ -41,7 +41,7 @@ func TestAnotherModuleNamingSSHIsRefused(t *testing.T) { // that is not the operator's ~/.ssh, which only ssh-client names. A path outside any ${dir:} is still refused. func TestAModulesOwnDirectoryMayHoldADotSSH(t *testing.T) { root := t.TempDir() - manifest(t, root, "builder", `{"module":"builder","resources":[{"path":"${dir:state}/.ssh"},{"path":"${dir:ssh-dir}/config"}]}`) + manifest(t, root, "builder", `{"module":"builder","resources":[{"id":"state","type":"directory","place":"."},{"id":"ssh-dir","type":"directory","path":"${dir:state}/.ssh"},{"path":"${dir:ssh-dir}/config"}]}`) manifest(t, root, "other", `{"module":"other","resources":[{"path":"${machine:account-home}/.ssh/config"}]}`) found, err := Check(root) if err != nil { @@ -52,6 +52,21 @@ func TestAModulesOwnDirectoryMayHoldADotSSH(t *testing.T) { } } +// Issue 1484 review: only a directory the mesh places is the module's own home. A ${dir:} that resolves to the +// operator's home is judged by the path it resolves to. +func TestADirResolvingToTheOperatorsHomeIsStillRefused(t *testing.T) { + root := t.TempDir() + manifest(t, root, "escape", `{"module":"escape","resources":[{"id":"h","type":"directory","path":"${machine:account-home}","unknown":"module"},{"path":"${dir:h}/.ssh/config"}]}`) + manifest(t, root, "placed", `{"module":"placed","resources":[{"id":"state","type":"directory","place":".","unknown":"program"},{"id":"s","type":"directory","path":"${dir:state}/.ssh"},{"path":"${dir:s}/config"}]}`) + found, err := Check(root) + if err != nil { + t.Fatal(err) + } + if len(found) != 1 || found[0].Module != "escape" { + t.Fatalf("refused %+v; want only escape", found) + } +} + func TestTheCatalogueHasNone(t *testing.T) { found, err := Check("../..") if err != nil { diff --git a/modules/mesh-build-go/README.md b/modules/mesh-build-go/README.md index 45afecf2..61433b7e 100644 --- a/modules/mesh-build-go/README.md +++ b/modules/mesh-build-go/README.md @@ -42,7 +42,7 @@ time. The unit level is `go test -json` over every package without the `integrat with a `go.mod`, judged by its one bound: its running time, that of the slowest package (compile not counted), within five seconds. The step ends passed when the level ran, and its result says whether the level did: `passed`, the packages with their times, the tests that failed with their first lines of output, the five slowest tests, and `why` -when it failed (a failed test, a build that failed, a bound kept or not). A step ends failed only when go test could not +when it failed (a failed test, a build that failed) or ran over a bound. `passed` is the tests' own verdict: a level over its bound still passes and says `over_bound` (and `over_which`, setup or run) with the slowest tests, and the checker judges the bounds (ADR 0453 §9). A step ends failed only when go test could not run. A repository with no tests at the level has none, and the result says so: that is a pass. `testdata/captured` holds the output of the real go for the fixture repositories in `testdata/repos`; the unit tests read it, and the integration-tagged test runs the real go on the fixtures. @@ -59,7 +59,7 @@ loopback port of its own, its address on the first line, stopped when its input Both run inside the step, are stopped, and the run's directory is removed whatever the tests did. Setup (compiling the tests, the store, the bus) is judged within 30 s and the tests' running time (the wall time of -`go test`) within 60 s, apart; a level over either fails and names the bound, with the slowest tests for the running +`go test`) within 60 s, apart; a level over either says `over_bound` and names the bound, with the slowest tests for the running time. A machine whose installed postgres major is not the recipe's refuses this level, naming both; the unit level still runs. The result names the postgres major and the nats-server version it ran against. The mesh's own store major is not named: no state or grant gives it to this module (ADR 0470 §4 asks for it when it differs), so only the recipe's diff --git a/modules/mesh-build-go/cmd/mesh-build-go/emit_test.go b/modules/mesh-build-go/cmd/mesh-build-go/emit_test.go new file mode 100644 index 00000000..71fb11d5 --- /dev/null +++ b/modules/mesh-build-go/cmd/mesh-build-go/emit_test.go @@ -0,0 +1,55 @@ +package main + +import ( + "context" + "encoding/json" + "os" + "path/filepath" + "slices" + "testing" +) + +// Issues 1483 and 1488 (for the indexer, issue 1444): the guard emits toolchain.reported after each write of the +// toolchains key, with the node and the language. +func TestTheGuardEmitsToolchainReportedAfterEachWrite(t *testing.T) { + m := moduleWith(newStates(), "go1.27.1") + type event struct { + typ string + body map[string]string + } + var got []event + m.Emit = func(typ string, body any) error { + raw, _ := json.Marshal(body) + var b map[string]string + json.Unmarshal(raw, &b) + got = append(got, event{typ, b}) + return nil + } + if err := m.Check(context.Background()); err != nil { + t.Fatal(err) + } + if len(got) != 1 || got[0].typ != "toolchain.reported" || got[0].body["node"] != "ace" || got[0].body["language"] != "go" || len(got[0].body) != 2 { + t.Errorf("events = %+v, want one toolchain.reported for ace, go", got) + } + m.Check(context.Background()) + if len(got) != 2 { + t.Errorf("a second guard pass emitted %d events in all, want 2", len(got)) + } +} + +// The event is carried by the module's stream, not named in emits (ADR 0363: one place); the validator checks that. +func TestTheManifestDeclaresTheToolchainsStream(t *testing.T) { + raw, err := os.ReadFile(filepath.Join("..", "..", "module.json")) + if err != nil { + t.Fatal(err) + } + var m struct { + Streams []struct { + Name string `json:"name"` + Events []string `json:"events"` + } `json:"streams"` + } + if err := json.Unmarshal(raw, &m); err != nil || len(m.Streams) != 1 || m.Streams[0].Name != "toolchains-go" || !slices.Equal(m.Streams[0].Events, []string{"toolchain.**"}) { + t.Errorf("streams = %+v (%v)", m.Streams, err) + } +} diff --git a/modules/mesh-build-go/cmd/mesh-build-go/integration_level_test.go b/modules/mesh-build-go/cmd/mesh-build-go/integration_level_test.go index 65f91ad3..7f51597f 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/integration_level_test.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/integration_level_test.go @@ -155,7 +155,12 @@ func TestTheStoreListensOnASocketUnderTheRunAndNowhereElse(t *testing.T) { if !strings.HasPrefix(run, filepath.Join(m.Work, "ws1", "run-")) { t.Errorf("the run directory is %s, not under the workspace's", run) } - for _, want := range []string{"listen_addresses=''", "-k " + filepath.Join(run, "pg", "socket"), "fsync=off", "-w"} { + _, afterK, _ := strings.Cut(start, "-k ") + socket, _, _ := strings.Cut(afterK, " ") + if len(socket)+len(socketName) >= 100 { + t.Errorf("the socket %q is too long for postgres", socket) + } + for _, want := range []string{"listen_addresses=''", "-k " + socket, "fsync=off", "-w"} { if !strings.Contains(start, want) { t.Errorf("the store's start %q lacks %q", start, want) } @@ -181,7 +186,7 @@ func TestTheStoreListensOnASocketUnderTheRunAndNowhereElse(t *testing.T) { env[k] = v } u, err := url.Parse(env["MESH_TEST_POSTGRES"]) - if err != nil || u.Scheme != "postgres" || u.Query().Get("host") != filepath.Join(run, "pg", "socket") || u.Host != "" { + if err != nil || u.Scheme != "postgres" || u.Query().Get("host") != socket || u.Host != "" { t.Errorf("MESH_TEST_POSTGRES = %q", env["MESH_TEST_POSTGRES"]) } if strings.Count(strings.TrimPrefix(env["MESH_TEST_POSTGRES"], "postgres://"), "/") != 1 { @@ -220,7 +225,7 @@ func TestSetupAndRunningTimeAreJudgedApart(t *testing.T) { f.advance["compile"], f.advance["start"] = 20*time.Second, 15*time.Second m, states := integModule(t, f) res, _ := runLevelTool(t, m, states, "integration") - if res.Passed || res.Setup != 35 || !strings.Contains(res.Why, "setup took 35.00 s, over its setup bound of 30 s") || strings.Contains(res.Why, "slowest tests") { + if !res.Passed || !res.OverBound || res.OverWhich != "setup" || res.Setup != 35 || !strings.Contains(res.Why, "setup took 35.00 s, over its setup bound of 30 s") || strings.Contains(res.Why, "slowest tests") { t.Errorf("a setup of 35 s: %+v", res) } @@ -228,14 +233,14 @@ func TestSetupAndRunningTimeAreJudgedApart(t *testing.T) { g.advance["test"] = 61 * time.Second m, states = integModule(t, g) res, _ = runLevelTool(t, m, states, "integration") - if res.Passed || res.Elapsed != 61 || !strings.Contains(res.Why, "took 61.00 s, over its bound of 60 s; the slowest tests: fixture/slow TestTakesAWhile") || strings.Contains(res.Why, "setup") { + if !res.Passed || res.OverWhich != "run" || res.Elapsed != 61 || !strings.Contains(res.Why, "took 61.00 s, over its bound of 60 s; the slowest tests: fixture/slow TestTakesAWhile") || strings.Contains(res.Why, "setup") { t.Errorf("a run of 61 s: %+v", res) } h := newIntegFake(t, "slow") h.advance["compile"], h.advance["test"] = 29*time.Second, 59*time.Second m, states = integModule(t, h) - if res, _ = runLevelTool(t, m, states, "integration"); !res.Passed || res.Setup != 29 || res.Elapsed != 59 { + if res, _ = runLevelTool(t, m, states, "integration"); !res.Passed || res.OverBound || res.Setup != 29 || res.Elapsed != 59 { t.Errorf("29 s of setup and 59 s of running are within both bounds: %+v", res) } } @@ -316,3 +321,46 @@ func TestThePostgresMajorIsReadFromTheVersionLine(t *testing.T) { t.Errorf("accepted a line that is not postgres's") } } + +// Issue 1486 review: postgres refuses a socket path of 108 bytes and over. A run directory deep in the work directory +// gets a short directory of its own for the socket, removed with the store; a short one keeps it under the run. +func TestTheSocketPathStaysUnderTheLimitForALongRunDirectory(t *testing.T) { + long := filepath.Join(t.TempDir(), strings.Repeat("deep", 20), "ws1", "run-mvh5uc96142806") + if err := os.MkdirAll(long, 0o700); err != nil { + t.Fatal(err) + } + dir, short, err := socketDir(long) + if err != nil || !short || len(dir)+len(socketName) >= 100 { + t.Fatalf("socketDir(long) = %q, %v, %v", dir, short, err) + } + if _, err := os.Stat(dir); err != nil { + t.Errorf("the short directory was not made: %v", err) + } + os.RemoveAll(dir) + + near := t.TempDir() + if dir, short, err := socketDir(near); err != nil || (len(near) < 50 && (short || !strings.HasPrefix(dir, near))) { + t.Errorf("socketDir(short) = %q, %v, %v", dir, short, err) + } + + // Through the store: the short directory is removed when the store is stopped. + f := newIntegFake(t, "slow") + m, _ := integModule(t, f) + _, stop, err := m.startStore(context.Background(), long) + if err != nil { + t.Fatal(err) + } + var sock string + for _, c := range f.calls { + if _, a, ok := strings.Cut(c.line, "-k "); ok && strings.HasPrefix(c.line, "pg_ctl") { + sock, _, _ = strings.Cut(a, " ") + } + } + if sock == "" || len(sock)+len(socketName) >= 100 { + t.Fatalf("the store was started with the socket %q", sock) + } + stop() + if _, err := os.Stat(sock); !os.IsNotExist(err) { + t.Errorf("the short socket directory %s outlived the store (%v)", sock, err) + } +} diff --git a/modules/mesh-build-go/cmd/mesh-build-go/levels.go b/modules/mesh-build-go/cmd/mesh-build-go/levels.go index 8c24cead..9631252a 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/levels.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/levels.go @@ -77,8 +77,12 @@ type TestResult struct { Failed []Failure `json:"failed,omitempty"` // Store and Bus are what the integration level ran against: the postgres major version and the nats-server // version (ADR 0470 §4). - Store string `json:"store,omitempty"` - Bus string `json:"bus,omitempty"` + // OverBound says a bound was kept no longer, and OverWhich which: setup, run or both. The level's verdict, Passed, is + // the tests' own: the checker judges the bounds (ADR 0453 §9), with the slowest tests this result names. + OverBound bool `json:"over_bound"` + OverWhich string `json:"over_which,omitempty"` + Store string `json:"store,omitempty"` + Bus string `json:"bus,omitempty"` } // event is one line of `go test -json` (test2json, and the build events go test adds). @@ -221,7 +225,7 @@ func (res *TestResult) judge(b Bounds) { res.Slowest = res.Slowest[:5] } res.Bound, res.SetupBound = b.Run.Seconds(), b.Setup.Seconds() - var why []string + var why, over []string if n := len(res.Failed); n > 0 { names := []string{} for _, f := range res.Failed { @@ -229,28 +233,27 @@ func (res *TestResult) judge(b Bounds) { } why = append(why, fmt.Sprintf("%d failed: %s", n, strings.Join(names, ", "))) } + res.Passed = len(res.Failed) == 0 if b.Setup > 0 && res.Setup > b.Setup.Seconds() { + over = append(over, "setup") why = append(why, fmt.Sprintf("the %s level's setup took %.2f s, over its setup bound of %s", res.Level, res.Setup, seconds(b.Setup))) } if b.Run > 0 && res.Elapsed > b.Run.Seconds() { + over = append(over, "run") slow := []string{} for _, s := range res.Slowest { slow = append(slow, fmt.Sprintf("%s %s (%.2f s)", s.Package, s.Test, s.Elapsed)) } why = append(why, fmt.Sprintf("the %s level took %.2f s, over its bound of %s; the slowest tests: %s", res.Level, res.Elapsed, seconds(b.Run), strings.Join(slow, ", "))) } + res.OverBound, res.OverWhich = len(over) > 0, strings.Join(over, ",") res.NoTests = res.Tests == 0 && len(res.Failed) == 0 switch { case len(why) > 0: res.Why = strings.Join(why, "; ") case res.NoTests: - res.Passed, res.Why = true, "the repository has no tests at the "+res.Level+" level" - return - default: - res.Passed = true - return + res.Why = "the repository has no tests at the " + res.Level + " level" } - res.Passed = false } // seconds is a duration as seconds, without trailing zeros: "5 s", "0.01 s". diff --git a/modules/mesh-build-go/cmd/mesh-build-go/main.go b/modules/mesh-build-go/cmd/mesh-build-go/main.go index 12317389..2764e81a 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/main.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/main.go @@ -35,6 +35,7 @@ func main() { Recipe: Current(), Probe: ProbeGo, Toolchains: stdio.State(delivery.ToolchainsState).Put, + Emit: func(t string, b any) error { return stdio.Emit(t, b) }, Steps: stdio.State(delivery.StepsState).Put, Ctx: ctx, Say: logf, diff --git a/modules/mesh-build-go/cmd/mesh-build-go/module.go b/modules/mesh-build-go/cmd/mesh-build-go/module.go index 61f8ce2f..5c0fbc79 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/module.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/module.go @@ -24,6 +24,9 @@ type Module struct { Probe func(ctx context.Context) (string, error) // Toolchains and Steps are the Put of the states of those names. Toolchains, Steps buildstep.Put + // Emit tells the bus an event (stdio.Emit); nil emits nothing. The guard emits toolchain.reported after each write of + // the toolchains key, so the indexer, which holds no timer, learns that the bucket exists (issue 1444). + Emit func(eventType string, body any) error // Ctx is the process's context, which a step runs under (the tool call's is cut at 30 s, the step's is not). Ctx context.Context Say func(format string, a ...any) @@ -43,7 +46,7 @@ type Module struct { } func (m *Module) guard() buildstep.Guard { - return buildstep.Guard{Language: "go", Want: m.Recipe.Go, Recipe: m.Recipe.Version(), Probe: m.Probe, Node: m.Node, Put: m.Toolchains} + return buildstep.Guard{Language: "go", Want: m.Recipe.Go, Recipe: m.Recipe.Version(), Probe: m.Probe, Node: m.Node, Put: m.reportingPut()} } // Check reads the installed toolchain, writes .go of the toolchains state and answers nil, or the refusal @@ -123,3 +126,21 @@ func (m *Module) Status(ctx context.Context) map[string]any { } return out } + +// ToolchainReported is the event the guard emits after it writes the toolchains key. +const ToolchainReported = "toolchain.reported" + +// reportingPut is the toolchains Put that then emits toolchain.reported with the node and the language. A write that +// failed emits nothing; an emit that failed is said and does not refuse the step. +func (m *Module) reportingPut() buildstep.Put { + return func(key string, value any) (uint64, error) { + rev, err := m.Toolchains(key, value) + if err != nil || m.Emit == nil { + return rev, err + } + if eerr := m.Emit(ToolchainReported, map[string]string{"node": m.Node, "language": "go"}); eerr != nil && m.Say != nil { + m.Say("the event %s could not be emitted: %v", ToolchainReported, eerr) + } + return rev, nil + } +} diff --git a/modules/mesh-build-go/cmd/mesh-build-go/store.go b/modules/mesh-build-go/cmd/mesh-build-go/store.go index 032d64d5..db64d76e 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/store.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/store.go @@ -49,6 +49,24 @@ func (m *Module) checkPostgres(ctx context.Context) (int, error) { return major, nil } +// socketLimit is the longest path of a socket postgres accepts, with the file's name: it refuses 108 bytes and over. +const socketLimit = 100 + +// socketName is the file postgres makes in the socket directory. +const socketName = "/.s.PGSQL.5432" + +// socketDir makes the directory of the store's socket: under the run when the socket's path stays under socketLimit, +// else a short directory of its own under /tmp (answering short, so the caller removes it). A unix socket's path is +// bounded far below a file's, and a work directory deep in a data root is over it. +func socketDir(run string) (dir string, short bool, err error) { + dir = filepath.Join(run, "pg", "socket") + if len(dir)+len(socketName) < socketLimit { + return dir, false, os.MkdirAll(dir, 0o700) + } + dir, err = os.MkdirTemp("/tmp", "pg") + return dir, true, err +} + // storeSettings are the server's own settings: no TCP address, a socket directory, and no durability. func storeOptions(socket string) string { return "-k " + socket + " -c listen_addresses='' -c fsync=off -c synchronous_commit=off -c full_page_writes=off" @@ -59,11 +77,14 @@ func storeOptions(socket string) string { // tests cut the URL at its last slash to name their own databases. func (m *Module) startStore(ctx context.Context, run string) (string, func(), error) { data := filepath.Join(run, "pg", "data") - socket := filepath.Join(run, "pg", "socket") - if err := os.MkdirAll(socket, 0o700); err != nil { + socket, short, err := socketDir(run) + if err != nil { return "", nil, err } stop := func() { + if short { + defer os.RemoveAll(socket) + } sctx, cancel := context.WithTimeout(context.Background(), storeStopBound) defer cancel() m.Run(sctx, nil, "pg_ctl", "-D", data, "-m", "immediate", "-w", "stop") diff --git a/modules/mesh-build-go/cmd/mesh-build-go/test_real_integration_test.go b/modules/mesh-build-go/cmd/mesh-build-go/test_real_integration_test.go index fa0b5ac5..b847d8d4 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/test_real_integration_test.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/test_real_integration_test.go @@ -85,7 +85,12 @@ func processesNamed(text string) []string { // It starts postgres and a bus, so it runs in the merge check and in a try, never on the way. func TestIntegrationLevelRunsAgainstARealStoreAndBusAndLeavesNothing(t *testing.T) { tree := repository(t, "store") - work := t.TempDir() + // A short work directory: a unix socket's path is bounded at 108 bytes. + work, err := os.MkdirTemp("/tmp", "w") + if err != nil { + t.Fatal(err) + } + t.Cleanup(func() { os.RemoveAll(work) }) if err := os.MkdirAll(filepath.Join(work, "ws1"), 0o755); err != nil { t.Fatal(err) } diff --git a/modules/mesh-build-go/cmd/mesh-build-go/test_test.go b/modules/mesh-build-go/cmd/mesh-build-go/test_test.go index 563b3194..c13e8085 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/test_test.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/test_test.go @@ -107,8 +107,8 @@ func TestUnitLevelOverItsBoundFailsNamingTheBoundAndTheSlowestTests(t *testing.T m, states, ws, _ := workspaceFor(t, "slow") m.UnitBound = 10 * time.Millisecond res, _ := runUnit(t, m, states, ws) - if res.Passed { - t.Fatalf("a level of %.3f s passed under a bound of %v", res.Elapsed, m.UnitBound) + if !res.Passed || !res.OverBound || res.OverWhich != "run" { + t.Fatalf("a level of %.3f s under a bound of %v: passed %v, over_bound %v (%s); the tests passed and the bound was kept no longer", res.Elapsed, m.UnitBound, res.Passed, res.OverBound, res.OverWhich) } for _, want := range []string{"over its bound of 0.01 s", "fixture/slow TestTakesAWhile"} { if !strings.Contains(res.Why, want) { @@ -120,7 +120,7 @@ func TestUnitLevelOverItsBoundFailsNamingTheBoundAndTheSlowestTests(t *testing.T } m2, states2, ws2, _ := workspaceFor(t, "slow") - if res, _ := runUnit(t, m2, states2, ws2); !res.Passed || res.Bound != 5 { + if res, _ := runUnit(t, m2, states2, ws2); !res.Passed || res.OverBound || res.Bound != 5 { t.Errorf("under the bound of five seconds: %+v", res) } } diff --git a/modules/mesh-build-go/go.mod b/modules/mesh-build-go/go.mod index 25a34806..464af931 100644 --- a/modules/mesh-build-go/go.mod +++ b/modules/mesh-build-go/go.mod @@ -3,7 +3,7 @@ module meshbuildgo go 1.26.0 require ( - git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261020203945-1572e50e0ef0 + git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261020204626-36d6f7745c8d github.com/nats-io/nats-server/v2 v2.11.17 ) diff --git a/modules/mesh-build-go/go.sum b/modules/mesh-build-go/go.sum index 37931482..4ef33264 100644 --- a/modules/mesh-build-go/go.sum +++ b/modules/mesh-build-go/go.sum @@ -2,6 +2,8 @@ git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261020200715-9e296295c05e h1:uf2o2A6d git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261020200715-9e296295c05e/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY= git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261020203945-1572e50e0ef0 h1:mr9HyARwzeZT7FxFHv1Xc2z7QErvDZ/F/pBMIpjGSd0= git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261020203945-1572e50e0ef0/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY= +git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261020204626-36d6f7745c8d h1:mmOCJphjQN15jNVh+sMQqnmJ3UiYltiuQRg/zw3wFtw= +git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261020204626-36d6f7745c8d/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY= github.com/antithesishq/antithesis-sdk-go v0.7.0-default-no-op h1:Z/MZK75wC/NSrkgqeNIa7jexam9uWzhLmFTSCPI/kn0= github.com/antithesishq/antithesis-sdk-go v0.7.0-default-no-op/go.mod h1:FQyySiasQQM8735Ddel3MRojmy4dA1IqCeyJ5jmPMbI= github.com/google/go-tpm v0.9.8 h1:slArAR9Ft+1ybZu0lBwpSmpwhRXaa85hWtMinMyRAWo= diff --git a/modules/mesh-build-go/module.json b/modules/mesh-build-go/module.json index ea4a5a01..85944415 100644 --- a/modules/mesh-build-go/module.json +++ b/modules/mesh-build-go/module.json @@ -19,6 +19,12 @@ "build_go_status", "build_go_health" ], + "streams": [ + { + "name": "toolchains-go", + "events": ["toolchain.**"] + } + ], "requires": [ "forge-account" ], diff --git a/modules/ssh-client/go.mod b/modules/ssh-client/go.mod index 4c94ce78..77590b40 100644 --- a/modules/ssh-client/go.mod +++ b/modules/ssh-client/go.mod @@ -3,7 +3,7 @@ module sshclient go 1.26.0 require ( - git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261020203945-1572e50e0ef0 + git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261020204626-36d6f7745c8d github.com/nats-io/nats-server/v2 v2.11.17 github.com/nats-io/nats.go v1.54.0 ) diff --git a/modules/ssh-client/go.sum b/modules/ssh-client/go.sum index 50cbe31a..a1de2261 100644 --- a/modules/ssh-client/go.sum +++ b/modules/ssh-client/go.sum @@ -4,6 +4,8 @@ git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261020200715-9e296295c05e h1:uf2o2A6d git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261020200715-9e296295c05e/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY= git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261020203945-1572e50e0ef0 h1:mr9HyARwzeZT7FxFHv1Xc2z7QErvDZ/F/pBMIpjGSd0= git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261020203945-1572e50e0ef0/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY= +git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261020204626-36d6f7745c8d h1:mmOCJphjQN15jNVh+sMQqnmJ3UiYltiuQRg/zw3wFtw= +git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261020204626-36d6f7745c8d/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY= github.com/antithesishq/antithesis-sdk-go v0.7.0-default-no-op h1:Z/MZK75wC/NSrkgqeNIa7jexam9uWzhLmFTSCPI/kn0= github.com/antithesishq/antithesis-sdk-go v0.7.0-default-no-op/go.mod h1:FQyySiasQQM8735Ddel3MRojmy4dA1IqCeyJ5jmPMbI= github.com/google/go-tpm v0.9.8 h1:slArAR9Ft+1ybZu0lBwpSmpwhRXaa85hWtMinMyRAWo=