Modified how created annotation is populated based on package creation time

Signed-off-by: Andrew Block <andy.block@gmail.com>
pull/12903/head
Andrew Block 3 months ago
parent 976ed8c0be
commit 0a69a0dea6
No known key found for this signature in database
GPG Key ID: 02DFE631AEF35EBC

@ -29,6 +29,7 @@ import (
"helm.sh/helm/v3/internal/tlsutil" "helm.sh/helm/v3/internal/tlsutil"
"helm.sh/helm/v3/pkg/chart/loader" "helm.sh/helm/v3/pkg/chart/loader"
"helm.sh/helm/v3/pkg/registry" "helm.sh/helm/v3/pkg/registry"
"helm.sh/helm/v3/pkg/time/ctime"
) )
// OCIPusher is the default OCI backend handler // OCIPusher is the default OCI backend handler
@ -89,6 +90,9 @@ func (pusher *OCIPusher) push(chartRef, href string) error {
path.Join(strings.TrimPrefix(href, fmt.Sprintf("%s://", registry.OCIScheme)), meta.Metadata.Name), path.Join(strings.TrimPrefix(href, fmt.Sprintf("%s://", registry.OCIScheme)), meta.Metadata.Name),
meta.Metadata.Version) meta.Metadata.Version)
chartCreationTime := ctime.Created(stat)
pushOpts = append(pushOpts, registry.PushOptCreationTime(chartCreationTime.Format(time.RFC3339)))
_, err = client.Push(chartBytes, ref, pushOpts...) _, err = client.Push(chartBytes, ref, pushOpts...)
return err return err
} }

@ -527,9 +527,9 @@ type (
} }
pushOperation struct { pushOperation struct {
provData []byte provData []byte
strictMode bool strictMode bool
test bool creationTime string
} }
) )
@ -583,7 +583,7 @@ func (c *Client) Push(data []byte, ref string, options ...PushOption) (*PushResu
descriptors = append(descriptors, provDescriptor) descriptors = append(descriptors, provDescriptor)
} }
ociAnnotations := generateOCIAnnotations(meta, operation.test) ociAnnotations := generateOCIAnnotations(meta, operation.creationTime)
manifestData, manifest, err := content.GenerateManifest(&configDescriptor, ociAnnotations, descriptors...) manifestData, manifest, err := content.GenerateManifest(&configDescriptor, ociAnnotations, descriptors...)
if err != nil { if err != nil {
@ -652,10 +652,10 @@ func PushOptStrictMode(strictMode bool) PushOption {
} }
} }
// PushOptTest returns a function that sets whether test setting on push // PushOptCreationDate returns a function that sets the creation time
func PushOptTest(test bool) PushOption { func PushOptCreationTime(creationTime string) PushOption {
return func(operation *pushOperation) { return func(operation *pushOperation) {
operation.test = test operation.creationTime = creationTime
} }
} }

@ -166,10 +166,10 @@ func NewRegistryClientWithTLS(out io.Writer, certFile, keyFile, caFile string, i
} }
// generateOCIAnnotations will generate OCI annotations to include within the OCI manifest // generateOCIAnnotations will generate OCI annotations to include within the OCI manifest
func generateOCIAnnotations(meta *chart.Metadata, test bool) map[string]string { func generateOCIAnnotations(meta *chart.Metadata, creationTime string) map[string]string {
// Get annotations from Chart attributes // Get annotations from Chart attributes
ociAnnotations := generateChartOCIAnnotations(meta, test) ociAnnotations := generateChartOCIAnnotations(meta, creationTime)
// Copy Chart annotations // Copy Chart annotations
annotations: annotations:
@ -190,7 +190,7 @@ annotations:
} }
// getChartOCIAnnotations will generate OCI annotations from the provided chart // getChartOCIAnnotations will generate OCI annotations from the provided chart
func generateChartOCIAnnotations(meta *chart.Metadata, test bool) map[string]string { func generateChartOCIAnnotations(meta *chart.Metadata, creationTime string) map[string]string {
chartOCIAnnotations := map[string]string{} chartOCIAnnotations := map[string]string{}
chartOCIAnnotations = addToMap(chartOCIAnnotations, ocispec.AnnotationDescription, meta.Description) chartOCIAnnotations = addToMap(chartOCIAnnotations, ocispec.AnnotationDescription, meta.Description)
@ -198,10 +198,12 @@ func generateChartOCIAnnotations(meta *chart.Metadata, test bool) map[string]str
chartOCIAnnotations = addToMap(chartOCIAnnotations, ocispec.AnnotationVersion, meta.Version) chartOCIAnnotations = addToMap(chartOCIAnnotations, ocispec.AnnotationVersion, meta.Version)
chartOCIAnnotations = addToMap(chartOCIAnnotations, ocispec.AnnotationURL, meta.Home) chartOCIAnnotations = addToMap(chartOCIAnnotations, ocispec.AnnotationURL, meta.Home)
if !test { if len(creationTime) == 0 {
chartOCIAnnotations = addToMap(chartOCIAnnotations, ocispec.AnnotationCreated, helmtime.Now().UTC().Format(time.RFC3339)) creationTime = helmtime.Now().UTC().Format(time.RFC3339)
} }
chartOCIAnnotations = addToMap(chartOCIAnnotations, ocispec.AnnotationCreated, creationTime)
if len(meta.Sources) > 0 { if len(meta.Sources) > 0 {
chartOCIAnnotations = addToMap(chartOCIAnnotations, ocispec.AnnotationSource, meta.Sources[0]) chartOCIAnnotations = addToMap(chartOCIAnnotations, ocispec.AnnotationSource, meta.Sources[0])
} }

@ -29,6 +29,8 @@ import (
func TestGenerateOCIChartAnnotations(t *testing.T) { func TestGenerateOCIChartAnnotations(t *testing.T) {
nowString := helmtime.Now().Format(time.RFC3339)
tests := []struct { tests := []struct {
name string name string
chart *chart.Metadata chart *chart.Metadata
@ -43,6 +45,7 @@ func TestGenerateOCIChartAnnotations(t *testing.T) {
map[string]string{ map[string]string{
"org.opencontainers.image.title": "oci", "org.opencontainers.image.title": "oci",
"org.opencontainers.image.version": "0.0.1", "org.opencontainers.image.version": "0.0.1",
"org.opencontainers.image.created": nowString,
}, },
}, },
{ {
@ -56,6 +59,7 @@ func TestGenerateOCIChartAnnotations(t *testing.T) {
map[string]string{ map[string]string{
"org.opencontainers.image.title": "oci", "org.opencontainers.image.title": "oci",
"org.opencontainers.image.version": "0.0.1", "org.opencontainers.image.version": "0.0.1",
"org.opencontainers.image.created": nowString,
"org.opencontainers.image.description": "OCI Helm Chart", "org.opencontainers.image.description": "OCI Helm Chart",
"org.opencontainers.image.url": "https://helm.sh", "org.opencontainers.image.url": "https://helm.sh",
}, },
@ -76,6 +80,7 @@ func TestGenerateOCIChartAnnotations(t *testing.T) {
map[string]string{ map[string]string{
"org.opencontainers.image.title": "oci", "org.opencontainers.image.title": "oci",
"org.opencontainers.image.version": "0.0.1", "org.opencontainers.image.version": "0.0.1",
"org.opencontainers.image.created": nowString,
"org.opencontainers.image.description": "OCI Helm Chart", "org.opencontainers.image.description": "OCI Helm Chart",
"org.opencontainers.image.url": "https://helm.sh", "org.opencontainers.image.url": "https://helm.sh",
"org.opencontainers.image.authors": "John Snow", "org.opencontainers.image.authors": "John Snow",
@ -95,6 +100,7 @@ func TestGenerateOCIChartAnnotations(t *testing.T) {
map[string]string{ map[string]string{
"org.opencontainers.image.title": "oci", "org.opencontainers.image.title": "oci",
"org.opencontainers.image.version": "0.0.1", "org.opencontainers.image.version": "0.0.1",
"org.opencontainers.image.created": nowString,
"org.opencontainers.image.description": "OCI Helm Chart", "org.opencontainers.image.description": "OCI Helm Chart",
"org.opencontainers.image.url": "https://helm.sh", "org.opencontainers.image.url": "https://helm.sh",
"org.opencontainers.image.authors": "John Snow (john@winterfell.com)", "org.opencontainers.image.authors": "John Snow (john@winterfell.com)",
@ -115,6 +121,7 @@ func TestGenerateOCIChartAnnotations(t *testing.T) {
map[string]string{ map[string]string{
"org.opencontainers.image.title": "oci", "org.opencontainers.image.title": "oci",
"org.opencontainers.image.version": "0.0.1", "org.opencontainers.image.version": "0.0.1",
"org.opencontainers.image.created": nowString,
"org.opencontainers.image.description": "OCI Helm Chart", "org.opencontainers.image.description": "OCI Helm Chart",
"org.opencontainers.image.url": "https://helm.sh", "org.opencontainers.image.url": "https://helm.sh",
"org.opencontainers.image.authors": "John Snow (john@winterfell.com), Jane Snow", "org.opencontainers.image.authors": "John Snow (john@winterfell.com), Jane Snow",
@ -133,6 +140,7 @@ func TestGenerateOCIChartAnnotations(t *testing.T) {
map[string]string{ map[string]string{
"org.opencontainers.image.title": "oci", "org.opencontainers.image.title": "oci",
"org.opencontainers.image.version": "0.0.1", "org.opencontainers.image.version": "0.0.1",
"org.opencontainers.image.created": nowString,
"org.opencontainers.image.description": "OCI Helm Chart", "org.opencontainers.image.description": "OCI Helm Chart",
"org.opencontainers.image.source": "https://github.com/helm/helm", "org.opencontainers.image.source": "https://github.com/helm/helm",
}, },
@ -141,7 +149,7 @@ func TestGenerateOCIChartAnnotations(t *testing.T) {
for _, tt := range tests { for _, tt := range tests {
result := generateChartOCIAnnotations(tt.chart, true) result := generateChartOCIAnnotations(tt.chart, nowString)
if !reflect.DeepEqual(tt.expect, result) { if !reflect.DeepEqual(tt.expect, result) {
t.Errorf("%s: expected map %v, got %v", tt.name, tt.expect, result) t.Errorf("%s: expected map %v, got %v", tt.name, tt.expect, result)
@ -152,6 +160,8 @@ func TestGenerateOCIChartAnnotations(t *testing.T) {
func TestGenerateOCIAnnotations(t *testing.T) { func TestGenerateOCIAnnotations(t *testing.T) {
nowString := helmtime.Now().Format(time.RFC3339)
tests := []struct { tests := []struct {
name string name string
chart *chart.Metadata chart *chart.Metadata
@ -166,6 +176,7 @@ func TestGenerateOCIAnnotations(t *testing.T) {
map[string]string{ map[string]string{
"org.opencontainers.image.title": "oci", "org.opencontainers.image.title": "oci",
"org.opencontainers.image.version": "0.0.1", "org.opencontainers.image.version": "0.0.1",
"org.opencontainers.image.created": nowString,
}, },
}, },
{ {
@ -183,6 +194,7 @@ func TestGenerateOCIAnnotations(t *testing.T) {
"org.opencontainers.image.title": "oci", "org.opencontainers.image.title": "oci",
"org.opencontainers.image.version": "0.0.1", "org.opencontainers.image.version": "0.0.1",
"org.opencontainers.image.description": "OCI Helm Chart", "org.opencontainers.image.description": "OCI Helm Chart",
"org.opencontainers.image.created": nowString,
"extrakey": "extravlue", "extrakey": "extravlue",
"anotherkey": "anothervalue", "anotherkey": "anothervalue",
}, },
@ -203,6 +215,7 @@ func TestGenerateOCIAnnotations(t *testing.T) {
"org.opencontainers.image.title": "oci", "org.opencontainers.image.title": "oci",
"org.opencontainers.image.version": "0.0.1", "org.opencontainers.image.version": "0.0.1",
"org.opencontainers.image.description": "OCI Helm Chart", "org.opencontainers.image.description": "OCI Helm Chart",
"org.opencontainers.image.created": nowString,
"extrakey": "extravlue", "extrakey": "extravlue",
}, },
}, },
@ -210,7 +223,7 @@ func TestGenerateOCIAnnotations(t *testing.T) {
for _, tt := range tests { for _, tt := range tests {
result := generateOCIAnnotations(tt.chart, true) result := generateOCIAnnotations(tt.chart, nowString)
if !reflect.DeepEqual(tt.expect, result) { if !reflect.DeepEqual(tt.expect, result) {
t.Errorf("%s: expected map %v, got %v", tt.name, tt.expect, result) t.Errorf("%s: expected map %v, got %v", tt.name, tt.expect, result)
@ -220,12 +233,16 @@ func TestGenerateOCIAnnotations(t *testing.T) {
} }
func TestGenerateOCICreatedAnnotations(t *testing.T) { func TestGenerateOCICreatedAnnotations(t *testing.T) {
nowTime := helmtime.Now()
nowTimeString := nowTime.Format(time.RFC3339)
chart := &chart.Metadata{ chart := &chart.Metadata{
Name: "oci", Name: "oci",
Version: "0.0.1", Version: "0.0.1",
} }
result := generateOCIAnnotations(chart, false) result := generateOCIAnnotations(chart, nowTimeString)
// Check that created annotation exists // Check that created annotation exists
if _, ok := result[ocispec.AnnotationCreated]; !ok { if _, ok := result[ocispec.AnnotationCreated]; !ok {
@ -237,4 +254,22 @@ func TestGenerateOCICreatedAnnotations(t *testing.T) {
t.Errorf("%s annotation with value '%s' not in RFC3339 format", ocispec.AnnotationCreated, result[ocispec.AnnotationCreated]) t.Errorf("%s annotation with value '%s' not in RFC3339 format", ocispec.AnnotationCreated, result[ocispec.AnnotationCreated])
} }
// Verify default creation time set
result = generateOCIAnnotations(chart, "")
// Check that created annotation exists
if _, ok := result[ocispec.AnnotationCreated]; !ok {
t.Errorf("%s annotation not created", ocispec.AnnotationCreated)
}
if createdTimeAnnotation, err := helmtime.Parse(time.RFC3339, result[ocispec.AnnotationCreated]); err != nil {
t.Errorf("%s annotation with value '%s' not in RFC3339 format", ocispec.AnnotationCreated, result[ocispec.AnnotationCreated])
// Verify creation annotation after time test began
if !nowTime.Before(createdTimeAnnotation) {
t.Errorf("%s annotation with value '%s' not configured properly. Annotation value is not after %s", ocispec.AnnotationCreated, result[ocispec.AnnotationCreated], nowTimeString)
}
}
} }

@ -216,9 +216,12 @@ func initCompromisedRegistryTestServer() string {
} }
func testPush(suite *TestSuite) { func testPush(suite *TestSuite) {
testingChartCreationTime := "1977-09-02T22:04:05Z"
// Bad bytes // Bad bytes
ref := fmt.Sprintf("%s/testrepo/testchart:1.2.3", suite.DockerRegistryHost) ref := fmt.Sprintf("%s/testrepo/testchart:1.2.3", suite.DockerRegistryHost)
_, err := suite.RegistryClient.Push([]byte("hello"), ref, PushOptTest(true)) _, err := suite.RegistryClient.Push([]byte("hello"), ref, PushOptCreationTime(testingChartCreationTime))
suite.NotNil(err, "error pushing non-chart bytes") suite.NotNil(err, "error pushing non-chart bytes")
// Load a test chart // Load a test chart
@ -229,20 +232,20 @@ func testPush(suite *TestSuite) {
// non-strict ref (chart name) // non-strict ref (chart name)
ref = fmt.Sprintf("%s/testrepo/boop:%s", suite.DockerRegistryHost, meta.Version) ref = fmt.Sprintf("%s/testrepo/boop:%s", suite.DockerRegistryHost, meta.Version)
_, err = suite.RegistryClient.Push(chartData, ref, PushOptTest(true)) _, err = suite.RegistryClient.Push(chartData, ref, PushOptCreationTime(testingChartCreationTime))
suite.NotNil(err, "error pushing non-strict ref (bad basename)") suite.NotNil(err, "error pushing non-strict ref (bad basename)")
// non-strict ref (chart name), with strict mode disabled // non-strict ref (chart name), with strict mode disabled
_, err = suite.RegistryClient.Push(chartData, ref, PushOptStrictMode(false), PushOptTest(true)) _, err = suite.RegistryClient.Push(chartData, ref, PushOptStrictMode(false), PushOptCreationTime(testingChartCreationTime))
suite.Nil(err, "no error pushing non-strict ref (bad basename), with strict mode disabled") suite.Nil(err, "no error pushing non-strict ref (bad basename), with strict mode disabled")
// non-strict ref (chart version) // non-strict ref (chart version)
ref = fmt.Sprintf("%s/testrepo/%s:latest", suite.DockerRegistryHost, meta.Name) ref = fmt.Sprintf("%s/testrepo/%s:latest", suite.DockerRegistryHost, meta.Name)
_, err = suite.RegistryClient.Push(chartData, ref, PushOptTest(true)) _, err = suite.RegistryClient.Push(chartData, ref, PushOptCreationTime(testingChartCreationTime))
suite.NotNil(err, "error pushing non-strict ref (bad tag)") suite.NotNil(err, "error pushing non-strict ref (bad tag)")
// non-strict ref (chart version), with strict mode disabled // non-strict ref (chart version), with strict mode disabled
_, err = suite.RegistryClient.Push(chartData, ref, PushOptStrictMode(false), PushOptTest(true)) _, err = suite.RegistryClient.Push(chartData, ref, PushOptStrictMode(false), PushOptCreationTime(testingChartCreationTime))
suite.Nil(err, "no error pushing non-strict ref (bad tag), with strict mode disabled") suite.Nil(err, "no error pushing non-strict ref (bad tag), with strict mode disabled")
// basic push, good ref // basic push, good ref
@ -251,7 +254,7 @@ func testPush(suite *TestSuite) {
meta, err = extractChartMeta(chartData) meta, err = extractChartMeta(chartData)
suite.Nil(err, "no error extracting chart meta") suite.Nil(err, "no error extracting chart meta")
ref = fmt.Sprintf("%s/testrepo/%s:%s", suite.DockerRegistryHost, meta.Name, meta.Version) ref = fmt.Sprintf("%s/testrepo/%s:%s", suite.DockerRegistryHost, meta.Name, meta.Version)
_, err = suite.RegistryClient.Push(chartData, ref, PushOptTest(true)) _, err = suite.RegistryClient.Push(chartData, ref, PushOptCreationTime(testingChartCreationTime))
suite.Nil(err, "no error pushing good ref") suite.Nil(err, "no error pushing good ref")
_, err = suite.RegistryClient.Pull(ref) _, err = suite.RegistryClient.Pull(ref)
@ -269,7 +272,7 @@ func testPush(suite *TestSuite) {
// push with prov // push with prov
ref = fmt.Sprintf("%s/testrepo/%s:%s", suite.DockerRegistryHost, meta.Name, meta.Version) ref = fmt.Sprintf("%s/testrepo/%s:%s", suite.DockerRegistryHost, meta.Name, meta.Version)
result, err := suite.RegistryClient.Push(chartData, ref, PushOptProvData(provData), PushOptTest(true)) result, err := suite.RegistryClient.Push(chartData, ref, PushOptProvData(provData), PushOptCreationTime(testingChartCreationTime))
suite.Nil(err, "no error pushing good ref with prov") suite.Nil(err, "no error pushing good ref with prov")
_, err = suite.RegistryClient.Pull(ref) _, err = suite.RegistryClient.Pull(ref)
@ -281,12 +284,12 @@ func testPush(suite *TestSuite) {
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(684), 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:b57e8ffd938c43253f30afedb3c209136288e6b3af3b33473e95ea3b805888e6", "sha256:fbbade96da6050f68f94f122881e3b80051a18f13ab5f4081868dd494538f5c2",
result.Manifest.Digest) result.Manifest.Digest)
suite.Equal( suite.Equal(
"sha256:8d17cb6bf6ccd8c29aace9a658495cbd5e2e87fc267876e86117c7db681c9580", "sha256:8d17cb6bf6ccd8c29aace9a658495cbd5e2e87fc267876e86117c7db681c9580",
@ -354,12 +357,12 @@ func testPull(suite *TestSuite) {
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(684), 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:b57e8ffd938c43253f30afedb3c209136288e6b3af3b33473e95ea3b805888e6", "sha256:fbbade96da6050f68f94f122881e3b80051a18f13ab5f4081868dd494538f5c2",
result.Manifest.Digest) result.Manifest.Digest)
suite.Equal( suite.Equal(
"sha256:8d17cb6bf6ccd8c29aace9a658495cbd5e2e87fc267876e86117c7db681c9580", "sha256:8d17cb6bf6ccd8c29aace9a658495cbd5e2e87fc267876e86117c7db681c9580",
@ -370,7 +373,7 @@ func testPull(suite *TestSuite) {
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}],\"annotations\":{\"org.opencontainers.image.description\":\"A Helm chart for Kubernetes\",\"org.opencontainers.image.title\":\"signtest\",\"org.opencontainers.image.version\":\"0.1.0\"}}", 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))

@ -0,0 +1,25 @@
/*
Copyright The Helm Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package ctime
import (
"os"
"time"
)
func Created(fi os.FileInfo) time.Time {
return created(fi)
}

@ -0,0 +1,30 @@
//go:build linux
/*
Copyright The Helm Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package ctime
import (
"os"
"syscall"
"time"
)
func created(fi os.FileInfo) time.Time {
st := fi.Sys().(*syscall.Stat_t)
//nolint
return time.Unix(int64(st.Ctim.Sec), int64(st.Ctim.Nsec))
}

@ -0,0 +1,27 @@
//go:build !linux
/*
Copyright The Helm Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package ctime
import (
"os"
"time"
)
func created(fi os.FileInfo) time.Time {
return fi.ModTime()
}
Loading…
Cancel
Save