Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 102 additions & 0 deletions bindings/go/descriptor/runtime/sbom.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
package runtime

import (
"fmt"

"ocm.software/open-component-model/bindings/go/runtime"
)

const (
// LabelArtefactReference is the name of the label that links a resource to
// another resource (an "artefact reference"), following the OCM spec
// convention. An SBOM resource (type ResourceTypeSBOM) uses it to point at the
// resource it describes; the SBOM-ness comes from the resource type, not the
// label. Its value is an ArtefactReferenceLabelValue.
//
// Example (component constructor):
//
// - name: cli-sbom
// type: sbom
// labels:
// - name: ocm.software/artefactReference
// version: v1
// value:
// identitySelector:
// name: cli
LabelArtefactReference = "ocm.software/artefactReference"

// ResourceTypeSBOM is the OCM resource type used for resources that carry a
// Software Bill of Materials (SBOM), e.g. in SPDX or CycloneDX format.
ResourceTypeSBOM = "sbom"
)

// ArtefactReferenceLabelValue is the parsed value of the LabelArtefactReference
// label. It selects the resource that the labelled resource refers to.
type ArtefactReferenceLabelValue struct {
// IdentitySelector is the (possibly partial) identity of the referenced
// resource, as a flat map of identity attributes (e.g. {"name": "cli"} or
// {"name": "podinfo", "architecture": "amd64"}). It is matched as a subset
// against the full resource identity.
IdentitySelector runtime.Identity `json:"identitySelector"`
}

// GetLabel returns a pointer to the label with the given name, or nil if the
// element carries no such label. The returned pointer aliases the element's
// label slice; callers must not mutate it.
func (m *ElementMeta) GetLabel(name string) *Label {
if m == nil {
return nil
}
for i := range m.Labels {
if m.Labels[i].Name == name {
return &m.Labels[i]
}
}
return nil
}

// FindSBOMResources returns the resources of type ResourceTypeSBOM in the given
// component version whose LabelArtefactReference label references the target identity.
//
// A reference matches when its (possibly partial) identity is a subset of the
// target identity (see runtime.IdentitySubset). This lets a label that only
// specifies {name: cli} match a resource that additionally carries version and
// extraIdentity attributes.
//
// Multiple matches are possible (e.g. one component may publish both an SPDX and
// a CycloneDX SBOM for the same resource); all matches are returned in
// descriptor order. If no SBOM resource references the target, an empty slice
// and a nil error are returned so callers can distinguish "no SBOM linked" from
// a malformed label (which yields an error).
//
// TODO: Add FindSBOMFromOCIReferrers for OCIImage resources that carry their
// SBOM as an in-index buildx attestation / OCI referrer (per ADR-0016). Callers
// can fall back to it when this function returns no matches. The OCI referrer
// plumbing lives under bindings/go/oci (spec/annotations, ctf/referrers).
func FindSBOMResources(desc *Descriptor, target runtime.Identity) ([]Resource, error) {
if desc == nil {
return nil, nil
}

var matches []Resource
for _, res := range desc.Component.Resources {
if res.Type != ResourceTypeSBOM {
continue
}
label := res.GetLabel(LabelArtefactReference)
if label == nil {
continue
}

var value ArtefactReferenceLabelValue
if err := label.GetValue(&value); err != nil {
return nil, fmt.Errorf("parsing %q label of sbom resource %q failed: %w", LabelArtefactReference, res.Name, err)
}

if runtime.IdentitySubset(value.IdentitySelector, target) {
matches = append(matches, res)
}
}

return matches, nil
}
126 changes: 126 additions & 0 deletions bindings/go/descriptor/runtime/sbom_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
package runtime_test

import (
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

descriptor "ocm.software/open-component-model/bindings/go/descriptor/runtime"
"ocm.software/open-component-model/bindings/go/runtime"
)

// sbomResource builds a resource of type "sbom" carrying a
// ocm.software/artefactReference label whose identitySelector points at the given
// resource identity.
func sbomResource(t *testing.T, name string, selector runtime.Identity) descriptor.Resource {
t.Helper()
label := descriptor.Label{Name: descriptor.LabelArtefactReference, Version: "v1"}
require.NoError(t, label.SetValue(descriptor.ArtefactReferenceLabelValue{IdentitySelector: selector}))
res := descriptor.Resource{Type: descriptor.ResourceTypeSBOM}
res.Name = name
res.Labels = []descriptor.Label{label}
return res
}

func namedResource(name, typ string) descriptor.Resource {
res := descriptor.Resource{Type: typ}
res.Name = name
return res
}

func descWith(resources ...descriptor.Resource) *descriptor.Descriptor {
d := &descriptor.Descriptor{}
d.Component.Resources = resources
return d
}

func TestFindSBOMResources(t *testing.T) {
cli := namedResource("cli", "executable")
cliSBOM := sbomResource(t, "cli-sbom", runtime.Identity{"name": "cli"})

t.Run("matches by partial identity (name only)", func(t *testing.T) {
desc := descWith(cli, cliSBOM)
got, err := descriptor.FindSBOMResources(desc, runtime.Identity{"name": "cli"})
require.NoError(t, err)
require.Len(t, got, 1)
assert.Equal(t, "cli-sbom", got[0].Name)
})

t.Run("matches full identity incl. extra identity", func(t *testing.T) {
desc := descWith(cli, cliSBOM)
target := runtime.Identity{"name": "cli", "version": "0.11.0", "os": "linux", "architecture": "amd64"}
got, err := descriptor.FindSBOMResources(desc, target)
require.NoError(t, err)
require.Len(t, got, 1)
assert.Equal(t, "cli-sbom", got[0].Name)
})

t.Run("no match returns empty slice and nil error", func(t *testing.T) {
desc := descWith(cli, cliSBOM)
got, err := descriptor.FindSBOMResources(desc, runtime.Identity{"name": "other"})
require.NoError(t, err)
assert.Empty(t, got)
})

t.Run("ignores non-sbom resource types even with the label", func(t *testing.T) {
mislabeled := sbomResource(t, "not-really", runtime.Identity{"name": "cli"})
mislabeled.Type = "executable"
desc := descWith(cli, mislabeled)
got, err := descriptor.FindSBOMResources(desc, runtime.Identity{"name": "cli"})
require.NoError(t, err)
assert.Empty(t, got)
})

t.Run("returns all matching sbom resources in descriptor order", func(t *testing.T) {
spdx := sbomResource(t, "cli-sbom-spdx", runtime.Identity{"name": "cli"})
cyclonedx := sbomResource(t, "cli-sbom-cyclonedx", runtime.Identity{"name": "cli"})
desc := descWith(cli, spdx, cyclonedx)
got, err := descriptor.FindSBOMResources(desc, runtime.Identity{"name": "cli"})
require.NoError(t, err)
require.Len(t, got, 2)
assert.Equal(t, "cli-sbom-spdx", got[0].Name)
assert.Equal(t, "cli-sbom-cyclonedx", got[1].Name)
})

t.Run("sbom resource without the label is skipped", func(t *testing.T) {
bare := namedResource("bare-sbom", descriptor.ResourceTypeSBOM)
desc := descWith(cli, bare)
got, err := descriptor.FindSBOMResources(desc, runtime.Identity{"name": "cli"})
require.NoError(t, err)
assert.Empty(t, got)
})

t.Run("malformed label value returns an error", func(t *testing.T) {
bad := namedResource("bad-sbom", descriptor.ResourceTypeSBOM)
bad.Labels = []descriptor.Label{{Name: descriptor.LabelArtefactReference, Value: []byte(`"not-an-object"`)}}
desc := descWith(cli, bad)
_, err := descriptor.FindSBOMResources(desc, runtime.Identity{"name": "cli"})
require.Error(t, err)
})

t.Run("nil descriptor returns nil", func(t *testing.T) {
got, err := descriptor.FindSBOMResources(nil, runtime.Identity{"name": "cli"})
require.NoError(t, err)
assert.Nil(t, got)
})
}

func TestElementMetaGetLabel(t *testing.T) {
res := sbomResource(t, "cli-sbom", runtime.Identity{"name": "cli"})

t.Run("present", func(t *testing.T) {
got := res.GetLabel(descriptor.LabelArtefactReference)
require.NotNil(t, got)
assert.Equal(t, descriptor.LabelArtefactReference, got.Name)
})

t.Run("absent", func(t *testing.T) {
assert.Nil(t, res.GetLabel("does-not-exist"))
})

t.Run("nil receiver", func(t *testing.T) {
var m *descriptor.ElementMeta
assert.Nil(t, m.GetLabel(descriptor.LabelArtefactReference))
})
}
38 changes: 38 additions & 0 deletions bindings/go/input/sbom/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
module ocm.software/open-component-model/bindings/go/input/sbom

go 1.26.4

require (
github.com/opencontainers/image-spec v1.1.1
github.com/stretchr/testify v1.11.1
ocm.software/open-component-model/bindings/go/blob v0.0.13
ocm.software/open-component-model/bindings/go/constructor v0.0.11
ocm.software/open-component-model/bindings/go/descriptor/runtime v0.0.0-20260717060357-df059e15a4cb
ocm.software/open-component-model/bindings/go/oci v0.0.48
ocm.software/open-component-model/bindings/go/runtime v0.0.8
)

require (
github.com/Masterminds/semver/v3 v3.5.0 // indirect
github.com/cyberphone/json-canonicalization v0.0.0-20241213102144-19d51d7fe467 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/go-logr/logr v1.4.3 // indirect
github.com/nlepage/go-tarfs v1.2.1 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 // indirect
github.com/veqryn/slog-context v0.9.0 // indirect
go.yaml.in/yaml/v2 v2.4.4 // indirect
golang.org/x/sync v0.21.0 // indirect
golang.org/x/text v0.38.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
ocm.software/open-component-model/bindings/go/configuration v0.0.15 // indirect
ocm.software/open-component-model/bindings/go/credentials v0.0.14 // indirect
ocm.software/open-component-model/bindings/go/ctf v0.4.1 // indirect
ocm.software/open-component-model/bindings/go/dag v0.0.6 // indirect
ocm.software/open-component-model/bindings/go/descriptor/normalisation v0.0.0-20260625071532-ea5a17b8a42c // indirect
ocm.software/open-component-model/bindings/go/descriptor/v2 v2.0.3-alpha3 // indirect
ocm.software/open-component-model/bindings/go/repository v0.0.10 // indirect
oras.land/oras-go/v2 v2.6.1 // indirect
sigs.k8s.io/yaml v1.6.0 // indirect
)
77 changes: 77 additions & 0 deletions bindings/go/input/sbom/go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
github.com/Masterminds/semver/v3 v3.5.0 h1:kQceYJfbupGfZOKZQg0kou0DgAKhzDg2NZPAwZ/2OOE=
github.com/Masterminds/semver/v3 v3.5.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM=
github.com/cyberphone/json-canonicalization v0.0.0-20241213102144-19d51d7fe467 h1:uX1JmpONuD549D73r6cgnxyUu18Zb7yHAy5AYU0Pm4Q=
github.com/cyberphone/json-canonicalization v0.0.0-20241213102144-19d51d7fe467/go.mod h1:uzvlm1mxhHkdfqitSA92i7Se+S9ksOn3a3qmv/kyOCw=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dlclark/regexp2 v1.12.0 h1:0j4c5qQmnC6XOWNjP3PIXURXN2gWx76rd3KvgdPkCz8=
github.com/dlclark/regexp2 v1.12.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/nlepage/go-tarfs v1.2.1 h1:o37+JPA+ajllGKSPfy5+YpsNHDjZnAoyfvf5GsUa+Ks=
github.com/nlepage/go-tarfs v1.2.1/go.mod h1:rno18mpMy9aEH1IiJVftFsqPyIpwqSUiAOpJYjlV2NA=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040=
github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 h1:KRzFb2m7YtdldCEkzs6KqmJw4nqEVZGK7IN2kJkjTuQ=
github.com/santhosh-tekuri/jsonschema/v6 v6.0.2/go.mod h1:JXeL+ps8p7/KNMjDQk3TCwPpBy0wYklyWTfbkIzdIFU=
github.com/stretchr/objx v0.5.3 h1:jmXUvGomnU1o3W/V5h2VEradbpJDwGrzugQQvL0POH4=
github.com/stretchr/objx v0.5.3/go.mod h1:rDQraq+vQZU7Fde9LOZLr8Tax6zZvy4kuNKF+QYS+U0=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
github.com/veqryn/slog-context v0.9.0 h1:VNXHBWufRGfKiumi7cYoh7p2iElquZ4v8AnAumFOhEI=
github.com/veqryn/slog-context v0.9.0/go.mod h1:l953waOLsWW6hArZeJDGGKZYLrsOIPBeJ/QQnOA8RU0=
go.yaml.in/yaml/v2 v2.4.4 h1:tuyd0P+2Ont/d6e2rl3be67goVK4R6deVxCUX5vyPaQ=
go.yaml.in/yaml/v2 v2.4.4/go.mod h1:gMZqIpDtDqOfM0uNfy0SkpRhvUryYH0Z6wdMYcacYXQ=
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
golang.org/x/sync v0.21.0 h1:HLII4xRRTtCRkxYp4HNFF0Js/Og6q2i++KXbg0gHCwM=
golang.org/x/sync v0.21.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
golang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI=
golang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
golang.org/x/text v0.38.0 h1:sXmwo9DwP3OK9EZ7PqAdaooSGozfl/3a6/xJcbzPRhE=
golang.org/x/text v0.38.0/go.mod h1:YXZt3QhHUKYT53r2lLKFIVi6Ao1jdzrTR/KQ09qyxF4=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
ocm.software/open-component-model/bindings/go/blob v0.0.13 h1:hLM+KUV9QbLVC5rQvCFwPiQLkjuNLjrtVdZc4A8mGZA=
ocm.software/open-component-model/bindings/go/blob v0.0.13/go.mod h1:nJqz2QmNoODFNFGDtd4d577RQ+vvlLI1u9G2O1sRmNc=
ocm.software/open-component-model/bindings/go/configuration v0.0.15 h1:f0ZI/wYoLAnfxYNyXTitpc1CKQgquWdcn8tbeMr7DuY=
ocm.software/open-component-model/bindings/go/configuration v0.0.15/go.mod h1:UF5HzB5QbNap6oHx0/ul7FRPSMSl0dyobMV3vhYQGZc=
ocm.software/open-component-model/bindings/go/constructor v0.0.11 h1:I3L2u4oYaOPcQUkDPV+JmS7aKppAnd3FXEMSi5PsudU=
ocm.software/open-component-model/bindings/go/constructor v0.0.11/go.mod h1:gYOMoRMwy5Wd1pNz2E8dy9wl+ooBEFSRRXXOWrNC8fI=
ocm.software/open-component-model/bindings/go/credentials v0.0.14 h1:M8mePKu0J7RvVx2Sn9hc7nv7xb8Wkwbn756HdFttSmo=
ocm.software/open-component-model/bindings/go/credentials v0.0.14/go.mod h1:h8tZ4xnr3mKpe5vSZTkIGjxRKGiVDr6jOLFuZhMoAeM=
ocm.software/open-component-model/bindings/go/ctf v0.4.1 h1:rzSzKGuUkO6ykPLd49Z4m8bONs3exkpLPmaeNln8YQA=
ocm.software/open-component-model/bindings/go/ctf v0.4.1/go.mod h1:5EoiS3GHkAWBCSyx2i06Prg0sBays8v3tc8Qzq8DguM=
ocm.software/open-component-model/bindings/go/dag v0.0.6 h1:To76QJAmFD88C101oB/HgYvtomp8mm0270ewDLcVncw=
ocm.software/open-component-model/bindings/go/dag v0.0.6/go.mod h1:mQbO95zYvX59VXNJGer4+wGsKY0BVI4FKwlR5BlPugM=
ocm.software/open-component-model/bindings/go/descriptor/normalisation v0.0.0-20260625071532-ea5a17b8a42c h1:5f7p51nUp6hBCmu34B+7Btj0qJfyPZQE7VlUjhMGBCI=
ocm.software/open-component-model/bindings/go/descriptor/normalisation v0.0.0-20260625071532-ea5a17b8a42c/go.mod h1:7mHAbmEdMAhgZgHLs7IVHpp1x4I6mMnSz3hiTWINs88=
ocm.software/open-component-model/bindings/go/descriptor/runtime v0.0.0-20260717060357-df059e15a4cb h1:3REIxy7p/tF3GC8aIZvUUB8zOfmKQtYHAwsi/jTH0O0=
ocm.software/open-component-model/bindings/go/descriptor/runtime v0.0.0-20260717060357-df059e15a4cb/go.mod h1:EzsJGXfl7q6O7FZlbF5rySawZ6oG0K8qexQXkZOehUU=
ocm.software/open-component-model/bindings/go/descriptor/v2 v2.0.3-alpha3 h1:bTb7LgRFAAuhr5FGkkBVStU4YLtFZz3uhO9V4VFhW64=
ocm.software/open-component-model/bindings/go/descriptor/v2 v2.0.3-alpha3/go.mod h1:miNDxmNWsrYI9f3QNZIOBrK6jVmWnyFj0Z/ZGFjR5Qk=
ocm.software/open-component-model/bindings/go/oci v0.0.48 h1:tZWOKqioUVevy7sXPMVCSz5CP1mIyJvmnIjEJvlzL6s=
ocm.software/open-component-model/bindings/go/oci v0.0.48/go.mod h1:2uUqkKBSdwSxvLVu+JIR/LqzyEJXAM+Tgcv2IUM5ylE=
ocm.software/open-component-model/bindings/go/repository v0.0.10 h1:0SoP3zB/B5w1AK1xXJHQYrmiCLyvj9UEeSWBT5MQWbI=
ocm.software/open-component-model/bindings/go/repository v0.0.10/go.mod h1:O8oHfL2KT7S3Om8aE1dbeca+oex5fsLCcBxpZc0XoiY=
ocm.software/open-component-model/bindings/go/runtime v0.0.8 h1:NIN8smq0Fs64N10UCSx7RrysIB/u8ukVF/GeT76uQRE=
ocm.software/open-component-model/bindings/go/runtime v0.0.8/go.mod h1:sRm+ybi9yjJGAgMSUHr0xdaSobsmeU8DWGP4Xonaso8=
oras.land/oras-go/v2 v2.6.1 h1:bonOEkjLfp8tt6qXWRRWP6p1F+9octchOf2EqnWB4Zs=
oras.land/oras-go/v2 v2.6.1/go.mod h1:dhtFrFOuZuDtAVeZ9FUnaa5zfzplG3ZnFX9/uH1J/Yk=
sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs=
sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4=
Loading