Commit the build modules' publish code a bare ignore pattern hid; drop committed go.work.sum
The patterns mesh-build-node and mesh-build-image matched the command directory, so publish.go and its test were never committed and the branch did not compile. Anchored to the binaries now. Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
This commit is contained in:
@@ -1,39 +0,0 @@
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/go-jose/go-jose/v4 v4.1.4/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08=
|
||||
github.com/go-quicktest/qt v1.101.0/go.mod h1:14Bz/f7NwaXPtdYEgzsx46kqSxVwTbzVZsDC26tQJow=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-tpm-tools v0.3.13-0.20230620182252-4639ecce2aba/go.mod h1:EFYHy8/1y2KfgTAsx7Luu7NGhoxtuVHnNo8jE7FikKc=
|
||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU=
|
||||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
||||
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
|
||||
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8=
|
||||
golang.org/x/crypto v0.52.0/go.mod h1:1QgfPxDqh0T2M/elOJtp9RvuR95kVjir0e6/BvEmGbc=
|
||||
golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
|
||||
golang.org/x/mod v0.33.0/go.mod h1:swjeQEj+6r7fODbD2cqrnje9PnziFuw4bmLbBZFrQ5w=
|
||||
golang.org/x/mod v0.39.0/go.mod h1:bvIbwjQ0HUFFf5AKukeeYQG4ZBUG9yxQbR9aEweIwYY=
|
||||
golang.org/x/mod v0.41.0 h1:qJmnOUb4YB+FsEuM3HcWucdZASCPGhsX6uljO6pog0c=
|
||||
golang.org/x/mod v0.41.0/go.mod h1:Ek9pY8RKWXwsWvd3rQiHYtMqkjSUV+s1Rj7j4H5Ur6o=
|
||||
golang.org/x/net v0.58.0/go.mod h1:YwCddHnFlT7eLQqVprV19OnhLGtc5xOKgE0RyqgfWAU=
|
||||
golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||
golang.org/x/sync v0.22.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
|
||||
golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.45.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||
golang.org/x/sys v0.47.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||
golang.org/x/telemetry v0.0.0-20260811182544-a038080d80e5/go.mod h1:LVehoXe41cL5SCVQilsV7Gg6BNG+Js6P9PhSbYTIUkQ=
|
||||
golang.org/x/telemetry v0.0.0-20260924152758-ed294f943157/go.mod h1:i+ivNqjDnTF3WTElsdk5g9V5DTSBYgdNo7xTU9SDwYA=
|
||||
golang.org/x/term v0.46.0/go.mod h1:+K02xbkittuwc0Am4abfA3Fc+XRGXkvBXNO88NCXPoc=
|
||||
golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0=
|
||||
golang.org/x/tools v0.42.0/go.mod h1:Ma6lCIwGZvHK6XtgbswSoWroEkhugApmsXyrUmBhfr0=
|
||||
golang.org/x/tools v0.49.0/go.mod h1:SJNXV9DBKT0UbdttsQjbfJlAE/q+y36++zo3uL3N0Oo=
|
||||
golang.org/x/tools v0.51.0/go.mod h1:9eEncMayCV6zRMGhR5eZEC2iBx98qWcF1HZ9Z7wJOoA=
|
||||
google.golang.org/genproto v0.0.0-20260128011058-8636f8732409 h1:VQZ/yAbAtjkHgH80teYd2em3xtIkkHd7ZhqfH2N9CsM=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
@@ -1 +1,3 @@
|
||||
mesh-build-image
|
||||
# the binary, built at the module or in its command directory; never the command directory itself
|
||||
/mesh-build-image
|
||||
/cmd/mesh-build-image/mesh-build-image
|
||||
|
||||
@@ -0,0 +1,151 @@
|
||||
package main
|
||||
|
||||
// The publish of a trunk build (novox/hq design 51 *Publishing*, ADR 0611; CAT-BI1): after the build has ended, from
|
||||
// the module's own process and not from a Dockerfile step, the image is written as an OCI layout in the step's
|
||||
// workspace and published through the seat container-image-registry's verbs publish and publish-part, which the
|
||||
// manifest `invokes`, with the build modules' one sender (buildstep.PublishFiles): its config, its layers and its
|
||||
// manifest, by their digests, of which only the parts the holder lacks travel. This module holds no registry address and
|
||||
// no credential; the holder checks the build with the builder and says published or refused on the seat's events. The
|
||||
// step answers the seat's reference, container-image-registry/<module>/<artifact>@sha256:<digest>.
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
reg "git.novox.be/novox/mesh-contracts/go/seats/containerimageregistry"
|
||||
stdio "git.novox.be/novox/mesh-sdk/go"
|
||||
"git.novox.be/novox/mesh-sdk/go/catalogue"
|
||||
"git.novox.be/novox/mesh-sdk/go/delivery"
|
||||
|
||||
"git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep"
|
||||
)
|
||||
|
||||
// KindImage is the kind an image is published as on its seat.
|
||||
const KindImage = "image"
|
||||
|
||||
// call is the seat's request: Call when a test set it, else the runtime's request over the bus (stdio.Ask).
|
||||
func (m *Module) call() buildstep.SeatCall {
|
||||
if m.Call != nil {
|
||||
return m.Call
|
||||
}
|
||||
return stdio.Ask
|
||||
}
|
||||
|
||||
// layout is an OCI image layout one build wrote: its one manifest's digest and the files of its parts.
|
||||
type layout struct {
|
||||
Digest string
|
||||
Files []buildstep.File
|
||||
}
|
||||
|
||||
type descriptor struct {
|
||||
MediaType string `json:"mediaType"`
|
||||
Digest string `json:"digest"`
|
||||
Size int64 `json:"size"`
|
||||
}
|
||||
|
||||
// readLayout reads the layout in dir: index.json names exactly one manifest, which names its config and layers; every
|
||||
// part is a blob of the layout, of the size its descriptor says. The manifest comes last, so a holder stores it after
|
||||
// what it names.
|
||||
func readLayout(dir string) (layout, error) {
|
||||
var index struct {
|
||||
Manifests []descriptor `json:"manifests"`
|
||||
}
|
||||
raw, err := os.ReadFile(filepath.Join(dir, "index.json"))
|
||||
if err != nil {
|
||||
return layout{}, fmt.Errorf("the image's layout has no index: %w", err)
|
||||
}
|
||||
if err := json.Unmarshal(raw, &index); err != nil || len(index.Manifests) != 1 {
|
||||
return layout{}, fmt.Errorf("the image's layout names %d manifests, not one (%v)", len(index.Manifests), err)
|
||||
}
|
||||
top := index.Manifests[0]
|
||||
blob := func(d descriptor) (buildstep.File, error) {
|
||||
if !digestOK.MatchString(d.Digest) {
|
||||
return buildstep.File{}, fmt.Errorf("%q is not a digest", d.Digest)
|
||||
}
|
||||
p := filepath.Join(dir, "blobs", "sha256", strings.TrimPrefix(d.Digest, "sha256:"))
|
||||
info, err := os.Stat(p)
|
||||
if err != nil {
|
||||
return buildstep.File{}, fmt.Errorf("the layout lacks the blob %s: %w", d.Digest, err)
|
||||
}
|
||||
if info.Size() != d.Size {
|
||||
return buildstep.File{}, fmt.Errorf("the blob %s holds %d bytes, not the %d its descriptor says", d.Digest, info.Size(), d.Size)
|
||||
}
|
||||
return buildstep.File{Digest: d.Digest, Size: d.Size, Path: p}, nil
|
||||
}
|
||||
manifest, err := blob(top)
|
||||
if err != nil {
|
||||
return layout{}, err
|
||||
}
|
||||
var body struct {
|
||||
Config descriptor `json:"config"`
|
||||
Layers []descriptor `json:"layers"`
|
||||
}
|
||||
raw, err = os.ReadFile(manifest.Path)
|
||||
if err != nil || json.Unmarshal(raw, &body) != nil || body.Config.Digest == "" {
|
||||
return layout{}, fmt.Errorf("the manifest %s names no config (%v)", top.Digest, err)
|
||||
}
|
||||
out := layout{Digest: top.Digest}
|
||||
seen := map[string]bool{}
|
||||
for _, d := range append([]descriptor{body.Config}, body.Layers...) {
|
||||
if seen[d.Digest] {
|
||||
continue
|
||||
}
|
||||
seen[d.Digest] = true
|
||||
f, err := blob(d)
|
||||
if err != nil {
|
||||
return layout{}, err
|
||||
}
|
||||
out.Files = append(out.Files, f)
|
||||
}
|
||||
out.Files = append(out.Files, manifest)
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// publish writes local as an OCI layout and publishes it on the image seat as <module>/<artifact>, at the version the
|
||||
// builder gave it (and the tag the call names): the step answers the layout's manifest digest, checked against the
|
||||
// digest buildah wrote, and the seat's reference; a publish the holder does not take fails `not stored:`.
|
||||
func (m *Module) publish(ctx context.Context, workspace, module, local string, res BuildResult, version, tag string) (any, error) {
|
||||
dir := filepath.Join(m.Work, workspace, "layout."+res.Artifact)
|
||||
digestFile := filepath.Join(m.Work, workspace, "pushed."+res.Artifact)
|
||||
_ = os.RemoveAll(dir)
|
||||
defer os.RemoveAll(dir)
|
||||
argv := append(m.storeFlags(), "push", "--digestfile", digestFile, local, "oci:"+dir)
|
||||
if r := m.Run(ctx, m.env(), "buildah", argv...); r.Status != 0 || r.Err != "" {
|
||||
m.sayFailure("buildah push of "+res.Artifact+" to its layout", r)
|
||||
return nil, fmt.Errorf("%s%s: writing its layout: %s", delivery.NotStored, res.Artifact, cause(r))
|
||||
}
|
||||
img, err := readLayout(dir)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%s%s: %w", delivery.NotStored, res.Artifact, err)
|
||||
}
|
||||
// What buildah wrote is checked against the layout: a digest never goes out unchecked.
|
||||
raw, err := os.ReadFile(digestFile)
|
||||
if pushed := strings.TrimSpace(string(raw)); err != nil || pushed != img.Digest {
|
||||
return nil, fmt.Errorf("%s%s: buildah wrote the digest %q (%v), but its layout's manifest is %s", delivery.NotStored, res.Artifact, pushed, err, img.Digest)
|
||||
}
|
||||
name := module + "/" + res.Artifact
|
||||
q := KindImage
|
||||
if version != "" {
|
||||
q = "v" + version
|
||||
}
|
||||
in := reg.PublishInput{Name: name, Kind: KindImage, Version: version, Tag: tag, Digest: img.Digest,
|
||||
Transfer: buildstep.TransferName(name, q, img.Digest)}
|
||||
sent, err := buildstep.PublishFiles(ctx, m.call(), buildstep.ImageSeat, in, img.Files)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%s%s: %v", delivery.NotStored, res.Artifact, err)
|
||||
}
|
||||
m.say("published %s on %s: %d of its %d parts sent, the rest held", name, buildstep.ImageSeat, len(sent.Parts), len(img.Files))
|
||||
res.Digest, res.Pushed = img.Digest, true
|
||||
res.Reference = catalogue.SeatReference(buildstep.ImageSeat, module, res.Artifact, img.Digest)
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (m *Module) say(format string, a ...any) {
|
||||
if m.Say != nil {
|
||||
m.Say(format, a...)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"slices"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
reg "git.novox.be/novox/mesh-contracts/go/seats/containerimageregistry"
|
||||
"git.novox.be/novox/mesh-sdk/go/delivery"
|
||||
)
|
||||
|
||||
// 1703d/AC (ADR 0487 §5): a candidate's build leaves the image seat unchanged: nothing is written, nothing is asked.
|
||||
func TestACandidatesBuildLeavesTheRegistryUnchanged(t *testing.T) {
|
||||
m, f, states := setup(t, same)
|
||||
res, st := runBuild(t, m, states, nil) // no publish
|
||||
if st.State != delivery.StepPassed || res.Pushed {
|
||||
t.Fatalf("step = %+v result = %+v", st, res)
|
||||
}
|
||||
if len(f.called("push")) != 0 || len(f.published) != 0 {
|
||||
t.Errorf("a candidate's build reached the seat: published %v, calls %v", f.published, f.lines())
|
||||
}
|
||||
}
|
||||
|
||||
// CAT-BI1 (design 51 *Publishing*): a trunk build writes its image as an OCI layout after the build has ended and
|
||||
// publishes it once through container-image-registry, as <module>/<artifact> at the ask's version, its config, layers
|
||||
// and manifest by digest, sending only the parts the holder lacks; the key carries the layout's manifest digest and the
|
||||
// seat's reference. A holder refusing, a digest file that disagrees and a seat other than the image seat each fail.
|
||||
func TestATrunkBuildPublishesThroughTheImageSeatOnlyWhatTheHolderLacks(t *testing.T) {
|
||||
for name, c := range map[string]struct {
|
||||
extra map[string]any
|
||||
heldLayer bool
|
||||
refuse error
|
||||
digestFile string
|
||||
reason string
|
||||
}{
|
||||
"every part sent": {extra: map[string]any{"version": "1.4.0"}},
|
||||
"the held layer is not sent": {extra: map[string]any{"version": "1.4.0"}, heldLayer: true},
|
||||
"a tag of the call's own": {extra: map[string]any{"tag": "fp-abc123"}},
|
||||
"the holder refuses": {refuse: errors.New("refused: the builder did not number it"), reason: "not stored: server: "},
|
||||
"buildah wrote another digest": {digestFile: "other", reason: "not stored: server: buildah wrote the digest"},
|
||||
"buildah wrote no digest": {digestFile: "none", reason: "not stored: server: buildah wrote the digest \"\""},
|
||||
"another seat": {extra: map[string]any{"seat": "oci-artifact-registry"}, reason: "is published through container-image-registry"},
|
||||
} {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
m, f, states := setup(t, same)
|
||||
f.refuse, f.digestFile = c.refuse, c.digestFile
|
||||
args := map[string]any{"publish": true}
|
||||
for k, v := range c.extra {
|
||||
args[k] = v
|
||||
}
|
||||
if c.heldLayer {
|
||||
// The layout's layer is the fake's one fixed layer: held under any name.
|
||||
f.held[sha([]byte("the layer's bytes"))] = true
|
||||
}
|
||||
res, st := runBuild(t, m, states, args)
|
||||
if c.reason != "" {
|
||||
if (st.State != delivery.StepFailed && st.State != delivery.StepRefused) || !strings.Contains(st.Reason, c.reason) {
|
||||
t.Fatalf("step = %+v, want failed with %q", st, c.reason)
|
||||
}
|
||||
return
|
||||
}
|
||||
if st.State != delivery.StepPassed {
|
||||
t.Fatalf("step = %+v", st)
|
||||
}
|
||||
if !res.Pushed || res.Digest != f.pushed || res.Reference != reg.Seat+"/fixture-image/server@"+f.pushed {
|
||||
t.Errorf("result = %+v, want the layout's %s", res, f.pushed)
|
||||
}
|
||||
if len(f.published) != 1 {
|
||||
t.Fatalf("published = %+v", f.published)
|
||||
}
|
||||
p := f.published[0]
|
||||
version, _ := c.extra["version"].(string)
|
||||
tag, _ := c.extra["tag"].(string)
|
||||
if p.Name != "fixture-image/server" || p.Kind != "image" || p.Digest != f.pushed || p.Version != version || p.Tag != tag || p.Transfer == "" {
|
||||
t.Errorf("publish = %+v", p)
|
||||
}
|
||||
var parts []string
|
||||
for _, x := range p.Parts {
|
||||
parts = append(parts, x.Digest)
|
||||
}
|
||||
if !slices.Equal(parts, f.parts) {
|
||||
t.Errorf("parts = %v, want config, layer, manifest %v", parts, f.parts)
|
||||
}
|
||||
want := f.parts
|
||||
if c.heldLayer {
|
||||
want = []string{f.parts[0], f.parts[2]}
|
||||
}
|
||||
if !slices.Equal(f.sent, want) {
|
||||
t.Errorf("sent = %v, want %v", f.sent, want)
|
||||
}
|
||||
push := f.called("push")
|
||||
if len(push) != 1 || !strings.Contains(push[0].line, " oci:"+filepath.Join(m.Work, "ws1", "layout.server")) || strings.Contains(push[0].line, "docker://") {
|
||||
t.Fatalf("push = %v", push)
|
||||
}
|
||||
for _, bad := range []string{"--creds", "--authfile", "--sign", "--tls-verify"} {
|
||||
if strings.Contains(push[0].line, bad) {
|
||||
t.Errorf("the push carries %s", bad)
|
||||
}
|
||||
}
|
||||
if _, err := os.Stat(filepath.Join(m.Work, "ws1", "layout.server")); !os.IsNotExist(err) {
|
||||
t.Errorf("the layout outlived the step: %v", err)
|
||||
}
|
||||
// The layout is written after the build has ended: bud, then images, then push.
|
||||
order := []string{}
|
||||
for _, l := range f.lines() {
|
||||
for _, v := range []string{" bud ", " images ", " push ", " rmi "} {
|
||||
if strings.Contains(l, "buildah") && strings.Contains(l, v) {
|
||||
order = append(order, strings.TrimSpace(v))
|
||||
}
|
||||
}
|
||||
}
|
||||
if strings.Join(order, ",") != "bud,images,push,rmi" {
|
||||
t.Errorf("order = %v", order)
|
||||
}
|
||||
})
|
||||
}
|
||||
m2, f2, states2 := setup(t, same)
|
||||
if _, st := runBuild(t, m2, states2, map[string]any{"publish": true, "tag": "a/b:c"}); st.State != delivery.StepFailed || len(f2.called("bud")) != 0 {
|
||||
t.Errorf("a tag that is not one: step = %+v", st)
|
||||
}
|
||||
}
|
||||
@@ -1 +1,3 @@
|
||||
mesh-build-node
|
||||
# the binary, built at the module or in its command directory; never the command directory itself
|
||||
/mesh-build-node
|
||||
/cmd/mesh-build-node/mesh-build-node
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
package main
|
||||
|
||||
// The publish of a done build's file (novox/hq design 51 *Publishing*, ADR 0611; CAT-BN3): from this module's own
|
||||
// process, after the build step ended, through a registry seat's verbs publish and publish-part, which the manifest
|
||||
// `invokes`, with the build modules' one sender (buildstep.PublishOne): a bundle's archive on oci-artifact-registry, a
|
||||
// trunk package on npm-package-registry under the version the builder gave it. No build step reaches a store, and this
|
||||
// module holds no write credential: the holder checks the build with the builder and says published or refused.
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
stdio "git.novox.be/novox/mesh-sdk/go"
|
||||
|
||||
"git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep"
|
||||
)
|
||||
|
||||
// publishOn publishes body, of digest, as name (at version, when it has one) of kind on seat: through Call when a
|
||||
// test set it, else the runtime's request over the bus (stdio.Ask).
|
||||
func (m *Module) publishOn(ctx context.Context, seat, name, kind, version, digest string, body []byte) error {
|
||||
call := m.Call
|
||||
if call == nil {
|
||||
call = stdio.Ask
|
||||
}
|
||||
q := kind
|
||||
if version != "" {
|
||||
q = "v" + version
|
||||
}
|
||||
return buildstep.PublishOne(ctx, call, seat, name, kind, version, digest, buildstep.TransferName(name, q, digest), body)
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/go-quicktest/qt v1.101.0/go.mod h1:14Bz/f7NwaXPtdYEgzsx46kqSxVwTbzVZsDC26tQJow=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
||||
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
||||
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
|
||||
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
golang.org/x/crypto v0.52.0/go.mod h1:1QgfPxDqh0T2M/elOJtp9RvuR95kVjir0e6/BvEmGbc=
|
||||
golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
|
||||
golang.org/x/mod v0.33.0/go.mod h1:swjeQEj+6r7fODbD2cqrnje9PnziFuw4bmLbBZFrQ5w=
|
||||
golang.org/x/mod v0.39.0/go.mod h1:bvIbwjQ0HUFFf5AKukeeYQG4ZBUG9yxQbR9aEweIwYY=
|
||||
golang.org/x/mod v0.41.0/go.mod h1:Ek9pY8RKWXwsWvd3rQiHYtMqkjSUV+s1Rj7j4H5Ur6o=
|
||||
golang.org/x/net v0.58.0/go.mod h1:YwCddHnFlT7eLQqVprV19OnhLGtc5xOKgE0RyqgfWAU=
|
||||
golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||
golang.org/x/sync v0.22.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
|
||||
golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.45.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||
golang.org/x/sys v0.47.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||
golang.org/x/telemetry v0.0.0-20260811182544-a038080d80e5/go.mod h1:LVehoXe41cL5SCVQilsV7Gg6BNG+Js6P9PhSbYTIUkQ=
|
||||
golang.org/x/term v0.46.0/go.mod h1:+K02xbkittuwc0Am4abfA3Fc+XRGXkvBXNO88NCXPoc=
|
||||
golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0=
|
||||
golang.org/x/tools v0.42.0/go.mod h1:Ma6lCIwGZvHK6XtgbswSoWroEkhugApmsXyrUmBhfr0=
|
||||
golang.org/x/tools v0.49.0/go.mod h1:SJNXV9DBKT0UbdttsQjbfJlAE/q+y36++zo3uL3N0Oo=
|
||||
google.golang.org/genproto v0.0.0-20260128011058-8636f8732409 h1:VQZ/yAbAtjkHgH80teYd2em3xtIkkHd7ZhqfH2N9CsM=
|
||||
Reference in New Issue
Block a user