Publish OCI Annotations

closes #11062

Signed-off-by: Jérôme Foray <moi@foray-jero.me>
pull/11128/head
Jérôme Foray 3 years ago
parent 001850aa4f
commit 2f0bdeda99

@ -16,6 +16,7 @@ limitations under the License.
package chart package chart
import ( import (
"fmt"
"strings" "strings"
"unicode" "unicode"
@ -32,6 +33,12 @@ type Maintainer struct {
URL string `json:"url,omitempty"` URL string `json:"url,omitempty"`
} }
var _ fmt.Stringer = &Maintainer{}
func (m *Maintainer) String() string {
return fmt.Sprintf("%s (%s)", m.Name, m.Email)
}
// Validate checks valid data and sanitizes string characters. // Validate checks valid data and sanitizes string characters.
func (m *Maintainer) Validate() error { func (m *Maintainer) Validate() error {
m.Name = sanitizeString(m.Name) m.Name = sanitizeString(m.Name)

@ -25,6 +25,7 @@ import (
"net/http" "net/http"
"sort" "sort"
"strings" "strings"
"time"
"github.com/Masterminds/semver/v3" "github.com/Masterminds/semver/v3"
"github.com/containerd/containerd/remotes" "github.com/containerd/containerd/remotes"
@ -527,7 +528,33 @@ func (c *Client) Push(data []byte, ref string, options ...PushOption) (*PushResu
descriptors = append(descriptors, provDescriptor) descriptors = append(descriptors, provDescriptor)
} }
manifestData, manifest, err := content.GenerateManifest(&configDescriptor, nil, descriptors...) annotations := make(map[string]string)
annotations[ocispec.AnnotationCreated] = Timestamper().Format(time.RFC3339)
if len(meta.Maintainers) > 0 {
authors := make([]string, len(meta.Maintainers))
for i, m := range meta.Maintainers {
authors[i] = m.String()
}
annotations[ocispec.AnnotationAuthors] = strings.Join(authors, ", ")
}
if len(meta.Sources) > 0 {
annotations[ocispec.AnnotationSource] = meta.Sources[0]
}
if len(meta.Home) > 0 {
annotations[ocispec.AnnotationURL] = meta.Home
}
if len(meta.Version) > 0 {
annotations[ocispec.AnnotationVersion] = meta.Version
}
if len(meta.Name) > 0 {
annotations[ocispec.AnnotationTitle] = meta.Name
}
if len(meta.Description) > 0 {
annotations[ocispec.AnnotationDescription] = meta.Description
}
manifestData, manifest, err := content.GenerateManifest(&configDescriptor, annotations, descriptors...)
if err != nil { if err != nil {
return nil, err return nil, err
} }

@ -39,6 +39,8 @@ import (
"github.com/phayes/freeport" "github.com/phayes/freeport"
"github.com/stretchr/testify/suite" "github.com/stretchr/testify/suite"
"golang.org/x/crypto/bcrypt" "golang.org/x/crypto/bcrypt"
helmtime "helm.sh/helm/v3/pkg/time"
) )
var ( var (
@ -57,6 +59,12 @@ type RegistryClientTestSuite struct {
RegistryClient *Client RegistryClient *Client
} }
func testTimestamper() helmtime.Time { return helmtime.Unix(242085845, 0).UTC() }
func init() {
Timestamper = testTimestamper
}
func (suite *RegistryClientTestSuite) SetupSuite() { func (suite *RegistryClientTestSuite) SetupSuite() {
suite.WorkspaceDir = testWorkspaceDir suite.WorkspaceDir = testWorkspaceDir
os.RemoveAll(suite.WorkspaceDir) os.RemoveAll(suite.WorkspaceDir)
@ -198,12 +206,12 @@ func (suite *RegistryClientTestSuite) Test_1_Push() {
suite.Equal(ref, result.Ref) suite.Equal(ref, result.Ref)
suite.Equal(meta.Name, result.Chart.Meta.Name) suite.Equal(meta.Name, result.Chart.Meta.Name)
suite.Equal(meta.Version, result.Chart.Meta.Version) suite.Equal(meta.Version, result.Chart.Meta.Version)
suite.Equal(int64(512), result.Manifest.Size) suite.Equal(int64(742), result.Manifest.Size)
suite.Equal(int64(99), result.Config.Size) suite.Equal(int64(99), result.Config.Size)
suite.Equal(int64(973), result.Chart.Size) suite.Equal(int64(973), result.Chart.Size)
suite.Equal(int64(695), result.Prov.Size) suite.Equal(int64(695), result.Prov.Size)
suite.Equal( suite.Equal(
"sha256:af4c20a1df1431495e673c14ecfa3a2ba24839a7784349d6787cd67957392e83", "sha256:fbbade96da6050f68f94f122881e3b80051a18f13ab5f4081868dd494538f5c2",
result.Manifest.Digest) result.Manifest.Digest)
suite.Equal( suite.Equal(
"sha256:8d17cb6bf6ccd8c29aace9a658495cbd5e2e87fc267876e86117c7db681c9580", "sha256:8d17cb6bf6ccd8c29aace9a658495cbd5e2e87fc267876e86117c7db681c9580",
@ -271,12 +279,12 @@ func (suite *RegistryClientTestSuite) Test_2_Pull() {
suite.Equal(ref, result.Ref) suite.Equal(ref, result.Ref)
suite.Equal(meta.Name, result.Chart.Meta.Name) suite.Equal(meta.Name, result.Chart.Meta.Name)
suite.Equal(meta.Version, result.Chart.Meta.Version) suite.Equal(meta.Version, result.Chart.Meta.Version)
suite.Equal(int64(512), result.Manifest.Size) suite.Equal(int64(742), result.Manifest.Size)
suite.Equal(int64(99), result.Config.Size) suite.Equal(int64(99), result.Config.Size)
suite.Equal(int64(973), result.Chart.Size) suite.Equal(int64(973), result.Chart.Size)
suite.Equal(int64(695), result.Prov.Size) suite.Equal(int64(695), result.Prov.Size)
suite.Equal( suite.Equal(
"sha256:af4c20a1df1431495e673c14ecfa3a2ba24839a7784349d6787cd67957392e83", "sha256:fbbade96da6050f68f94f122881e3b80051a18f13ab5f4081868dd494538f5c2",
result.Manifest.Digest) result.Manifest.Digest)
suite.Equal( suite.Equal(
"sha256:8d17cb6bf6ccd8c29aace9a658495cbd5e2e87fc267876e86117c7db681c9580", "sha256:8d17cb6bf6ccd8c29aace9a658495cbd5e2e87fc267876e86117c7db681c9580",
@ -287,7 +295,7 @@ func (suite *RegistryClientTestSuite) Test_2_Pull() {
suite.Equal( suite.Equal(
"sha256:b0a02b7412f78ae93324d48df8fcc316d8482e5ad7827b5b238657a29a22f256", "sha256:b0a02b7412f78ae93324d48df8fcc316d8482e5ad7827b5b238657a29a22f256",
result.Prov.Digest) result.Prov.Digest)
suite.Equal("{\"schemaVersion\":2,\"config\":{\"mediaType\":\"application/vnd.cncf.helm.config.v1+json\",\"digest\":\"sha256:8d17cb6bf6ccd8c29aace9a658495cbd5e2e87fc267876e86117c7db681c9580\",\"size\":99},\"layers\":[{\"mediaType\":\"application/vnd.cncf.helm.chart.provenance.v1.prov\",\"digest\":\"sha256:b0a02b7412f78ae93324d48df8fcc316d8482e5ad7827b5b238657a29a22f256\",\"size\":695},{\"mediaType\":\"application/vnd.cncf.helm.chart.content.v1.tar+gzip\",\"digest\":\"sha256:e5ef611620fb97704d8751c16bab17fedb68883bfb0edc76f78a70e9173f9b55\",\"size\":973}]}", suite.Equal("{\"schemaVersion\":2,\"config\":{\"mediaType\":\"application/vnd.cncf.helm.config.v1+json\",\"digest\":\"sha256:8d17cb6bf6ccd8c29aace9a658495cbd5e2e87fc267876e86117c7db681c9580\",\"size\":99},\"layers\":[{\"mediaType\":\"application/vnd.cncf.helm.chart.provenance.v1.prov\",\"digest\":\"sha256:b0a02b7412f78ae93324d48df8fcc316d8482e5ad7827b5b238657a29a22f256\",\"size\":695},{\"mediaType\":\"application/vnd.cncf.helm.chart.content.v1.tar+gzip\",\"digest\":\"sha256:e5ef611620fb97704d8751c16bab17fedb68883bfb0edc76f78a70e9173f9b55\",\"size\":973}],\"annotations\":{\"org.opencontainers.image.created\":\"1977-09-02T22:04:05Z\",\"org.opencontainers.image.description\":\"A Helm chart for Kubernetes\",\"org.opencontainers.image.title\":\"signtest\",\"org.opencontainers.image.version\":\"0.1.0\"}}",
string(result.Manifest.Data)) string(result.Manifest.Data))
suite.Equal("{\"name\":\"signtest\",\"version\":\"0.1.0\",\"description\":\"A Helm chart for Kubernetes\",\"apiVersion\":\"v1\"}", suite.Equal("{\"name\":\"signtest\",\"version\":\"0.1.0\",\"description\":\"A Helm chart for Kubernetes\",\"apiVersion\":\"v1\"}",
string(result.Config.Data)) string(result.Config.Data))

@ -31,8 +31,15 @@ import (
"helm.sh/helm/v3/pkg/chart" "helm.sh/helm/v3/pkg/chart"
"helm.sh/helm/v3/pkg/chart/loader" "helm.sh/helm/v3/pkg/chart/loader"
"helm.sh/helm/v3/pkg/time"
) )
// Timestamper is a function capable of producing a timestamp.Timestamper.
//
// By default, this is a time.Time function from the Helm time package. This can
// be overridden for testing though, so that timestamps are predictable.
var Timestamper = time.Now
// IsOCI determines whether or not a URL is to be treated as an OCI URL // IsOCI determines whether or not a URL is to be treated as an OCI URL
func IsOCI(url string) bool { func IsOCI(url string) bool {
return strings.HasPrefix(url, fmt.Sprintf("%s://", OCIScheme)) return strings.HasPrefix(url, fmt.Sprintf("%s://", OCIScheme))

Loading…
Cancel
Save