From 8dc0bc98bd53f64f56b906d67df4ce842f688fae Mon Sep 17 00:00:00 2001 From: mesh-tools Date: Tue, 20 Oct 2026 20:45:35 +0000 Subject: [PATCH] Move ssh-client's tests and dependencies onto the SDK's forgekey (issue 1480), part 3 of 17 --- .../cmd/ssh-client-tools/helpers_test.go | 21 +++++ .../cmd/ssh-client-tools/keeper_test.go | 82 +++++++++++++++++++ .../ssh-client-tools/keykeeper_bus_test.go | 5 +- .../cmd/ssh-client-tools/ssh_test.go | 56 +++++++------ .../cmd/ssh-client-tools/sweep_test.go | 4 +- modules/ssh-client/go.mod | 14 ++-- modules/ssh-client/go.sum | 14 ++++ 7 files changed, 159 insertions(+), 37 deletions(-) create mode 100644 modules/ssh-client/cmd/ssh-client-tools/helpers_test.go create mode 100644 modules/ssh-client/cmd/ssh-client-tools/keeper_test.go diff --git a/modules/ssh-client/cmd/ssh-client-tools/helpers_test.go b/modules/ssh-client/cmd/ssh-client-tools/helpers_test.go new file mode 100644 index 00000000..d2b180af --- /dev/null +++ b/modules/ssh-client/cmd/ssh-client-tools/helpers_test.go @@ -0,0 +1,21 @@ +package main + +import ( + "encoding/base64" + "encoding/binary" +) + +// ed25519Line is a public key line with a well-formed ed25519 blob. +func ed25519Line(seed byte, comment string) string { + blob := []byte{} + for _, part := range [][]byte{[]byte("ssh-ed25519"), make([]byte, 32)} { + part2 := append([]byte(nil), part...) + if len(part2) == 32 { + part2[0] = seed + } + l := make([]byte, 4) + binary.BigEndian.PutUint32(l, uint32(len(part2))) + blob = append(append(blob, l...), part2...) + } + return "ssh-ed25519 " + base64.StdEncoding.EncodeToString(blob) + " " + comment +} diff --git a/modules/ssh-client/cmd/ssh-client-tools/keeper_test.go b/modules/ssh-client/cmd/ssh-client-tools/keeper_test.go new file mode 100644 index 00000000..0be30473 --- /dev/null +++ b/modules/ssh-client/cmd/ssh-client-tools/keeper_test.go @@ -0,0 +1,82 @@ +package main + +import ( + "context" + "encoding/json" + "os" + "path/filepath" + "regexp" + "strings" + "testing" + "time" + + "git.novox.be/novox/mesh-sdk/go/forgekey" +) + +// Issue 1480: the bundle's keeper is go/forgekey's, kind machine; no copy of it is left in this module. + +type recordState struct{ puts map[string][]byte } + +func (r *recordState) Put(key string, value any) (uint64, error) { + raw, _ := json.Marshal(value) + if r.puts == nil { + r.puts = map[string][]byte{} + } + r.puts[key] = raw + return uint64(len(r.puts)), nil +} + +// keygenStandIn writes the pair ssh-keygen -f names, as ssh-keygen would. +func keygenStandIn(ctx context.Context, env []string, name string, args ...string) forgekey.Ran { + var file, comment string + for i, a := range args { + switch a { + case "-f": + file = args[i+1] + case "-C": + comment = args[i+1] + } + } + if name != "ssh-keygen" || file == "" { + return forgekey.Ran{Status: 1, Stderr: "unexpected"} + } + os.WriteFile(file, []byte("PRIVATE\n"), 0o600) + os.WriteFile(file+".pub", []byte(ed25519Line(7, comment)+"\n"), 0o644) + return forgekey.Ran{} +} + +// 1480/AC1 +func TestTheBundlesKeeperIsForgekeysOfKindMachineWithItsEntryAtNodeAccount(t *testing.T) { + home, st := t.TempDir(), &recordState{} + k := keeperFor(home, "g14", "nox", keygenStandIn, st) + k.Now = func() time.Time { return time.Date(2026, 10, 20, 12, 0, 0, 0, time.UTC) } + if err := k.Once(context.Background()); err != nil { + t.Fatal(err) + } + if _, err := os.Stat(filepath.Join(home, ".ssh", "mesh_ed25519")); err != nil { + t.Errorf("the key file mesh_ed25519 was not made in an empty home: %v", err) + } + raw, ok := st.puts["g14.nox"] + if !ok || len(st.puts) != 1 { + t.Fatalf("entries = %v, want one at g14.nox", st.puts) + } + var e forgekey.KeyEntry + if err := json.Unmarshal(raw, &e); err != nil { + t.Fatal(err) + } + if e.Kind != "machine" || e.Node != "g14" || e.Account != "nox" || !strings.HasSuffix(e.Public, " nox@g14 (mesh)") { + t.Errorf("entry = %s", raw) + } +} + +// 1480/AC2 +func TestNoCopyOfTheKeeperIsLeftInThisModule(t *testing.T) { + copyOf := regexp.MustCompile(`(?m)^(type (KeyKeeper|KeyEntry|Runner|Ran)\b|func ParseKeyLine\b|func ExecRunner\b)`) + files, _ := filepath.Glob("*.go") + for _, f := range files { + raw, _ := os.ReadFile(f) + if m := copyOf.Find(raw); m != nil { + t.Errorf("%s declares %q, which go/forgekey holds", f, m) + } + } +} diff --git a/modules/ssh-client/cmd/ssh-client-tools/keykeeper_bus_test.go b/modules/ssh-client/cmd/ssh-client-tools/keykeeper_bus_test.go index 80df4fb5..cea182b5 100644 --- a/modules/ssh-client/cmd/ssh-client-tools/keykeeper_bus_test.go +++ b/modules/ssh-client/cmd/ssh-client-tools/keykeeper_bus_test.go @@ -15,6 +15,7 @@ import ( "testing" "time" + "git.novox.be/novox/mesh-sdk/go/forgekey" "github.com/nats-io/nats-server/v2/server" "github.com/nats-io/nats.go" "github.com/nats-io/nats.go/jetstream" @@ -170,7 +171,7 @@ func TestTheKeyProcessMakesTheKeyAndPutsItsEntryOverTheBus(t *testing.T) { if raw == nil { t.Fatalf("no entry %s in the keys state within 60 s", key) } - var e KeyEntry + var e forgekey.KeyEntry if err := json.Unmarshal(raw, &e); err != nil { t.Fatal(err) } @@ -180,7 +181,7 @@ func TestTheKeyProcessMakesTheKeyAndPutsItsEntryOverTheBus(t *testing.T) { if strings.Contains(strings.ToUpper(string(raw)), "PRIVATE") { t.Errorf("the entry carries private material: %s", raw) } - info, err := os.Stat(filepath.Join(home, ".ssh", KeyFile)) + info, err := os.Stat(filepath.Join(home, ".ssh", forgekey.KeyFile)) if err != nil { t.Fatal(err) } diff --git a/modules/ssh-client/cmd/ssh-client-tools/ssh_test.go b/modules/ssh-client/cmd/ssh-client-tools/ssh_test.go index 763540cb..3428e042 100644 --- a/modules/ssh-client/cmd/ssh-client-tools/ssh_test.go +++ b/modules/ssh-client/cmd/ssh-client-tools/ssh_test.go @@ -12,6 +12,8 @@ import ( "sync" "testing" "time" + + "git.novox.be/novox/mesh-sdk/go/forgekey" ) // Public keys made for these tests only; their private halves were never kept. @@ -29,7 +31,7 @@ type call struct { } type fake struct { - answer func(c call) Ran + answer func(c call) forgekey.Ran mu sync.Mutex calls []call } @@ -41,13 +43,13 @@ func (f *fake) recorded() []call { return append([]call(nil), f.calls...) } -func (f *fake) run(_ context.Context, env []string, name string, args ...string) Ran { +func (f *fake) run(_ context.Context, env []string, name string, args ...string) forgekey.Ran { c := call{env, name, args} f.mu.Lock() f.calls = append(f.calls, c) f.mu.Unlock() if f.answer == nil { - return Ran{Status: 1} + return forgekey.Ran{Status: 1} } return f.answer(c) } @@ -130,19 +132,19 @@ func TestKeysAreDescribedByTheirPublicHalfAndAPassphraseIsAskedNotRead(t *testin files := map[string]string{"config": layout["config"], "id_ed25519": "-----BEGIN OPENSSH PRIVATE KEY-----\nnot a key\n", "id_ed25519.pub": edPub + "\n", "id_box": "-----BEGIN OPENSSH PRIVATE KEY-----\nnot a key\n", "id_box.pub": rsaPub + "\n", "stray": "-----BEGIN RSA PRIVATE KEY-----\nnot a key\n", "notes.txt": "hello\n"} - f := &fake{answer: func(c call) Ran { + f := &fake{answer: func(c call) forgekey.Ran { if c.name == "ssh-keygen" && c.args[0] == "-y" { if strings.HasSuffix(c.args[len(c.args)-1], "id_box") { - return Ran{Status: 1, Stderr: "Load key \"id_box\": incorrect passphrase supplied to decrypt private key\n"} + return forgekey.Ran{Status: 1, Stderr: "Load key \"id_box\": incorrect passphrase supplied to decrypt private key\n"} } if strings.HasSuffix(c.args[len(c.args)-1], "id_ed25519") { - return Ran{Stdout: edPub + "\n"} + return forgekey.Ran{Stdout: edPub + "\n"} } } if c.name == "ssh-keygen" && c.args[0] == "-l" { - return Ran{Stdout: "256 " + edFP + " no comment (ED25519)\n"} + return forgekey.Ran{Stdout: "256 " + edFP + " no comment (ED25519)\n"} } - return Ran{Status: 1, Stderr: "unexpected"} + return forgekey.Ran{Status: 1, Stderr: "unexpected"} }} keys, err := client(home(t, files), f).Keys(context.Background()) if err != nil { @@ -173,7 +175,7 @@ func TestKeysAreDescribedByTheirPublicHalfAndAPassphraseIsAskedNotRead(t *testin func TestAPublicHalfThatIsAnotherKeysIsFound(t *testing.T) { files := map[string]string{"config": layout["config"], "id_ed25519": "-----BEGIN OPENSSH PRIVATE KEY-----\n", "id_ed25519.pub": rsaPub + "\n"} - f := &fake{answer: func(c call) Ran { return Ran{Stdout: edPub + "\n"} }} + f := &fake{answer: func(c call) forgekey.Ran { return forgekey.Ran{Stdout: edPub + "\n"} }} keys, _ := client(home(t, files), f).Keys(context.Background()) if len(keys) != 1 || keys[0].PublicMismatch == "" || keys[0].Fingerprint != edFP { t.Fatalf("%+v", keys) @@ -181,15 +183,15 @@ func TestAPublicHalfThatIsAnotherKeysIsFound(t *testing.T) { } func TestFingerprintsAreSshKeygens(t *testing.T) { - k, err := ParseKeyLine("from=\"10.0.0.0/8,192.0.2.1\",no-pty " + edPub) + k, err := forgekey.ParseKeyLine("from=\"10.0.0.0/8,192.0.2.1\",no-pty " + edPub) if err != nil || k.Fingerprint != edFP || k.Bits != 256 || k.Comment != "op@laptop" || !strings.HasPrefix(k.Options, "from=") { t.Fatalf("%+v %v", k, err) } - k, _ = ParseKeyLine(rsaPub) + k, _ = forgekey.ParseKeyLine(rsaPub) if k.Fingerprint != rsaFP || k.Bits != 2048 || !strings.Contains(k.Weak, "below 3072") { t.Fatalf("%+v", k) } - if _, err := ParseKeyLine("ssh-ed25519 !!!notbase64"); err == nil { + if _, err := forgekey.ParseKeyLine("ssh-ed25519 !!!notbase64"); err == nil { t.Fatal("garbage accepted") } } @@ -245,16 +247,16 @@ func scanOf(host, pub string) string { return host + " " + pub + "\n" } func TestKnownHostComparesWhatIsKnownWithWhatIsOffered(t *testing.T) { h := home(t, map[string]string{"config": layout["config"], "known_hosts": "ace.internal " + edPub + "\n"}) offered := edPub - f := &fake{answer: func(c call) Ran { + f := &fake{answer: func(c call) forgekey.Ran { switch { case c.name == "ssh-keygen" && c.args[0] == "-F": - return Ran{Stdout: "# Host ace.internal found: line 1\nace.internal " + edPub + "\n"} + return forgekey.Ran{Stdout: "# Host ace.internal found: line 1\nace.internal " + edPub + "\n"} case c.name == "ssh-keyscan": - return Ran{Stdout: scanOf("ace.internal", offered)} + return forgekey.Ran{Stdout: scanOf("ace.internal", offered)} case c.name == "ssh-keygen" && c.args[0] == "-R": - return Ran{} + return forgekey.Ran{} } - return Ran{Status: 1} + return forgekey.Ran{Status: 1} }} c := client(h, f) got, err := c.KnownHost(context.Background(), "ace.internal", 22, false) @@ -293,11 +295,11 @@ func TestKnownHostComparesWhatIsKnownWithWhatIsOffered(t *testing.T) { func TestAnUnreachableHostIsNotRefreshed(t *testing.T) { h := home(t, map[string]string{"known_hosts": ""}) - f := &fake{answer: func(c call) Ran { + f := &fake{answer: func(c call) forgekey.Ran { if c.name == "ssh-keyscan" { - return Ran{Status: 1} + return forgekey.Ran{Status: 1} } - return Ran{Status: 1} + return forgekey.Ran{Status: 1} }} got, err := client(h, f).KnownHost(context.Background(), "gone.example", 22, false) if err != nil || !strings.HasPrefix(got["state"].(string), "unreachable") { @@ -310,7 +312,7 @@ func TestAnUnreachableHostIsNotRefreshed(t *testing.T) { func TestTestSaysHowItAuthenticatedOrWhyNot(t *testing.T) { ok := "debug1: Connecting to ace.internal [10.0.0.2] port 22.\ndebug1: Server accepts key: /h/.ssh/id_ed25519 ED25519 " + edFP + "\nAuthenticated to ace.internal ([10.0.0.2]:22) using \"publickey\".\n" - f := &fake{answer: func(c call) Ran { return Ran{Stderr: ok} }} + f := &fake{answer: func(c call) forgekey.Ran { return forgekey.Ran{Stderr: ok} }} got, err := client(t.TempDir(), f).Test(context.Background(), "ace") if err != nil || got["ok"] != true || got["method"] != "publickey" || got["connected_to"] != "10.0.0.2:22" { t.Fatalf("%v %v", got, err) @@ -320,7 +322,7 @@ func TestTestSaysHowItAuthenticatedOrWhyNot(t *testing.T) { t.Fatalf("not a batch test: %s", args) } denied := "debug1: Offering public key: /h/.ssh/id_box RSA " + rsaFP + "\nop@ace.internal: Permission denied (publickey).\n" - f = &fake{answer: func(c call) Ran { return Ran{Status: 255, Stderr: denied} }} + f = &fake{answer: func(c call) forgekey.Ran { return forgekey.Ran{Status: 255, Stderr: denied} }} got, _ = client(t.TempDir(), f).Test(context.Background(), "ace") if got["ok"] != false || got["why"] != "no key it offered was accepted" || !reflect.DeepEqual(got["offered"], []string{"/h/.ssh/id_box"}) { t.Fatalf("%v", got) @@ -337,14 +339,14 @@ func TestCheckFindsWhatIsWrongAndSaysWhatItDidNotCheck(t *testing.T) { h := home(t, files) os.Chmod(filepath.Join(h, ".ssh", "config"), 0o666) os.Chmod(filepath.Join(h, ".ssh", "id_ed25519"), 0o644) - f := &fake{answer: func(c call) Ran { + f := &fake{answer: func(c call) forgekey.Ran { switch { case c.name == "ssh-keygen" && c.args[0] == "-y": - return Ran{Stdout: edPub} + return forgekey.Ran{Stdout: edPub} case c.name == "ssh-keyscan": - return Ran{Stdout: scanOf("x", edPub)} + return forgekey.Ran{Stdout: scanOf("x", edPub)} } - return Ran{Status: 1} + return forgekey.Ran{Status: 1} }} got, err := client(h, f).Check(context.Background(), true) if err != nil { @@ -381,7 +383,7 @@ func TestCheckFindsWhatIsWrongAndSaysWhatItDidNotCheck(t *testing.T) { // as problems, and says when no sweep has run. func TestCheckShowsAFailedSweep(t *testing.T) { h := home(t, map[string]string{"config": layout["config"], "known_hosts": ""}) - f := &fake{answer: func(call) Ran { return Ran{Status: 1} }} + f := &fake{answer: func(call) forgekey.Ran { return forgekey.Ran{Status: 1} }} c := client(h, f) got, _ := c.Check(context.Background(), false) if !slices.ContainsFunc(got["not_checked"].([]string), func(s string) bool { return strings.Contains(s, "the sweep") }) { diff --git a/modules/ssh-client/cmd/ssh-client-tools/sweep_test.go b/modules/ssh-client/cmd/ssh-client-tools/sweep_test.go index ede72c84..cf60a604 100644 --- a/modules/ssh-client/cmd/ssh-client-tools/sweep_test.go +++ b/modules/ssh-client/cmd/ssh-client-tools/sweep_test.go @@ -12,6 +12,8 @@ import ( "syscall" "testing" "time" + + "git.novox.be/novox/mesh-sdk/go/forgekey" ) // ADR 0415, issue 1017: the sweep keeps ~/.ssh to what this module knows and moves the rest out. @@ -73,7 +75,7 @@ func TestSweepKeepsWhatItKnows(t *testing.T) { t.Fatal(err) } for _, rel := range []string{"config", "known_hosts", "authorized_keys", "config.d/00-mesh", "config.d/10-forge", - KeyFile, KeyFile + ".pub", "id_ed25519", "id_ed25519.pub", "work_key", "work_key.pub", "work_key-cert.pub", "agent_only.pub", "removed-drone-20261004/id_drone", "authorized_keys2", "id_token"} { + forgekey.KeyFile, forgekey.KeyFile + ".pub", "id_ed25519", "id_ed25519.pub", "work_key", "work_key.pub", "work_key-cert.pub", "agent_only.pub", "removed-drone-20261004/id_drone", "authorized_keys2", "id_token"} { if !exists(filepath.Join(dir, rel)) { t.Errorf("%s was moved; it is known", rel) } diff --git a/modules/ssh-client/go.mod b/modules/ssh-client/go.mod index 9be3c232..4c94ce78 100644 --- a/modules/ssh-client/go.mod +++ b/modules/ssh-client/go.mod @@ -1,22 +1,22 @@ module sshclient -go 1.25.0 +go 1.26.0 require ( - git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261013182924-5933eb757d44 + git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261020203945-1572e50e0ef0 github.com/nats-io/nats-server/v2 v2.11.17 - github.com/nats-io/nats.go v1.51.0 + github.com/nats-io/nats.go v1.54.0 ) require ( github.com/antithesishq/antithesis-sdk-go v0.7.0-default-no-op // indirect github.com/google/go-tpm v0.9.8 // indirect - github.com/klauspost/compress v1.18.5 // indirect + github.com/klauspost/compress v1.20.0 // indirect github.com/minio/highwayhash v1.0.4 // indirect github.com/nats-io/jwt/v2 v2.8.1 // indirect - github.com/nats-io/nkeys v0.4.15 // indirect + github.com/nats-io/nkeys v0.4.16 // indirect github.com/nats-io/nuid v1.0.1 // indirect - golang.org/x/crypto v0.50.0 // indirect - golang.org/x/sys v0.43.0 // indirect + golang.org/x/crypto v0.57.0 // indirect + golang.org/x/sys v0.48.0 // indirect golang.org/x/time v0.15.0 // indirect ) diff --git a/modules/ssh-client/go.sum b/modules/ssh-client/go.sum index f84463ba..50cbe31a 100644 --- a/modules/ssh-client/go.sum +++ b/modules/ssh-client/go.sum @@ -1,11 +1,17 @@ git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261013182924-5933eb757d44 h1:r5xIo5qWOXQdCSMxvqJy8kV4U+P/QWXFK6971Ha6wU8= git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261013182924-5933eb757d44/go.mod h1:GFuZUElBZ9A++mxgIKo97aXXo+kV0uJ/UkbhQPPIbrY= +git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261020200715-9e296295c05e h1:uf2o2A6dBOrISDUVw6U7+fv8ylwwF+UfRrGWKIQMFOE= +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= 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= github.com/google/go-tpm v0.9.8/go.mod h1:h9jEsEECg7gtLis0upRBQU+GhYVH6jMjrFxI8u6bVUY= github.com/klauspost/compress v1.18.5 h1:/h1gH5Ce+VWNLSWqPzOVn6XBO+vJbCNGvjoaGBFW2IE= github.com/klauspost/compress v1.18.5/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ= +github.com/klauspost/compress v1.20.0 h1:a3C1ke2ohxFymNlb2HWAHjDeKCI90scRskErZkR0ezA= +github.com/klauspost/compress v1.20.0/go.mod h1:LUdAzn7YLVvxLpc7y3V1m40wESHTgc1422pwwBSKYuI= github.com/minio/highwayhash v1.0.4 h1:asJizugGgchQod2ja9NJlGOWq4s7KsAWr5XUc9Clgl4= github.com/minio/highwayhash v1.0.4/go.mod h1:GGYsuwP/fPD6Y9hMiXuapVvlIUEhFhMTh0rxU3ik1LQ= github.com/nats-io/jwt/v2 v2.8.1 h1:V0xpGuD/N8Mi+fQNDynXohVvp7ZztevW5io8CUWlPmU= @@ -14,14 +20,22 @@ github.com/nats-io/nats-server/v2 v2.11.17 h1:GKEghcFK6A+aFx11Yf1LjgLC3txAwvyhnY github.com/nats-io/nats-server/v2 v2.11.17/go.mod h1:B1sFVz4StNosQ903ak4N1G01Fl/9f8e06mXpFIE2K24= github.com/nats-io/nats.go v1.51.0 h1:ByW84XTz6W03GSSsygsZcA+xgKK8vPGaa/FCAAEHnAI= github.com/nats-io/nats.go v1.51.0/go.mod h1:26HypzazeOkyO3/mqd1zZd53STJN0EjCYF9Uy2ZOBno= +github.com/nats-io/nats.go v1.54.0 h1:vsXoOxjHp/GmPUN+EcI7uOf/uB+iAP+kEsAFNQN0yzA= +github.com/nats-io/nats.go v1.54.0/go.mod h1:y+DZoD1oBOYfZTU681eTUiUjI0vbqYGixNVFHcjHJ0k= github.com/nats-io/nkeys v0.4.15 h1:JACV5jRVO9V856KOapQ7x+EY8Jo3qw1vJt/9Jpwzkk4= github.com/nats-io/nkeys v0.4.15/go.mod h1:CpMchTXC9fxA5zrMo4KpySxNjiDVvr8ANOSZdiNfUrs= +github.com/nats-io/nkeys v0.4.16 h1:rd5oAuLOb8mnAycB0xleuEBNS1pVVnN0fv/FF34Eypg= +github.com/nats-io/nkeys v0.4.16/go.mod h1:llLgWoI0o4z/Q57q2R1kHfmocyhGV6VG/U18Glg1Afs= github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw= github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= golang.org/x/crypto v0.50.0 h1:zO47/JPrL6vsNkINmLoo/PH1gcxpls50DNogFvB5ZGI= golang.org/x/crypto v0.50.0/go.mod h1:3muZ7vA7PBCE6xgPX7nkzzjiUq87kRItoJQM1Yo8S+Q= +golang.org/x/crypto v0.57.0 h1:3ZVCjf8Ggz7zneR/EHRVx68Ctf+2pmIMP2UFhh9cC6M= +golang.org/x/crypto v0.57.0/go.mod h1:Fdz0i5U6CoizGwLda9DttjSk6qlZo25zYNtR+ycvuZA= golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI= golang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/sys v0.48.0 h1:bbX/i/6MgT9BVLM9RT1thmxL04yeTAhbEz4SyadbXoo= +golang.org/x/sys v0.48.0/go.mod h1:hNLxWAXmnKAxqDtdwIYC4bM9oQPEecfsnNMuSxOs3og= golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U= golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno=