Merge branch 'main' into dependabot/go_modules/github.com/sigstore/sigstore/pkg/signature/kms/gcp-1.8.8
This commit is contained in:
6
go.mod
6
go.mod
@@ -28,8 +28,8 @@ require (
|
|||||||
sigs.k8s.io/yaml v1.4.0
|
sigs.k8s.io/yaml v1.4.0
|
||||||
)
|
)
|
||||||
|
|
||||||
// fork of a fork (in case it goes away) with changes to support ArtifactType (https://github.com/google/go-containerregistry/pull/1931)
|
// fork with changes to support ArtifactType (https://github.com/google/go-containerregistry/pull/1931)
|
||||||
replace github.com/google/go-containerregistry => github.com/kipz/go-containerregistry v0.0.0-20240722163910-ebe90246535d
|
replace github.com/google/go-containerregistry => github.com/docker/go-containerregistry v0.0.0-20240808132857-c8bfc44af7c8
|
||||||
|
|
||||||
require (
|
require (
|
||||||
cloud.google.com/go v0.115.0 // indirect
|
cloud.google.com/go v0.115.0 // indirect
|
||||||
@@ -75,7 +75,7 @@ require (
|
|||||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||||
github.com/digitorus/pkcs7 v0.0.0-20230818184609-3a137a874352 // indirect
|
github.com/digitorus/pkcs7 v0.0.0-20230818184609-3a137a874352 // indirect
|
||||||
github.com/digitorus/timestamp v0.0.0-20231217203849-220c5c2851b7 // indirect
|
github.com/digitorus/timestamp v0.0.0-20231217203849-220c5c2851b7 // indirect
|
||||||
github.com/docker/cli v26.1.3+incompatible // indirect
|
github.com/docker/cli v27.1.1+incompatible // indirect
|
||||||
github.com/docker/distribution v2.8.3+incompatible // indirect
|
github.com/docker/distribution v2.8.3+incompatible // indirect
|
||||||
github.com/docker/docker v27.1.0+incompatible // indirect
|
github.com/docker/docker v27.1.0+incompatible // indirect
|
||||||
github.com/docker/docker-credential-helpers v0.8.1 // indirect
|
github.com/docker/docker-credential-helpers v0.8.1 // indirect
|
||||||
|
|||||||
8
go.sum
8
go.sum
@@ -218,8 +218,8 @@ github.com/dimchansky/utfbom v1.1.1 h1:vV6w1AhK4VMnhBno/TPVCoK9U/LP0PkLCS9tbxHdi
|
|||||||
github.com/dimchansky/utfbom v1.1.1/go.mod h1:SxdoEBH5qIqFocHMyGOXVAybYJdr71b1Q/j0mACtrfE=
|
github.com/dimchansky/utfbom v1.1.1/go.mod h1:SxdoEBH5qIqFocHMyGOXVAybYJdr71b1Q/j0mACtrfE=
|
||||||
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
|
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
|
||||||
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
|
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
|
||||||
github.com/docker/cli v26.1.3+incompatible h1:bUpXT/N0kDE3VUHI2r5VMsYQgi38kYuoC0oL9yt3lqc=
|
github.com/docker/cli v27.1.1+incompatible h1:goaZxOqs4QKxznZjjBWKONQci/MywhtRv2oNn0GkeZE=
|
||||||
github.com/docker/cli v26.1.3+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
github.com/docker/cli v27.1.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
||||||
github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk=
|
github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk=
|
||||||
github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||||
github.com/docker/docker v27.1.0+incompatible h1:rEHVQc4GZ0MIQKifQPHSFGV/dVgaZafgRf8fCPtDYBs=
|
github.com/docker/docker v27.1.0+incompatible h1:rEHVQc4GZ0MIQKifQPHSFGV/dVgaZafgRf8fCPtDYBs=
|
||||||
@@ -228,6 +228,8 @@ github.com/docker/docker-credential-helpers v0.8.1 h1:j/eKUktUltBtMzKqmfLB0PAgqY
|
|||||||
github.com/docker/docker-credential-helpers v0.8.1/go.mod h1:P3ci7E3lwkZg6XiHdRKft1KckHiO9a2rNtyFbZ/ry9M=
|
github.com/docker/docker-credential-helpers v0.8.1/go.mod h1:P3ci7E3lwkZg6XiHdRKft1KckHiO9a2rNtyFbZ/ry9M=
|
||||||
github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c=
|
github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c=
|
||||||
github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc=
|
github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc=
|
||||||
|
github.com/docker/go-containerregistry v0.0.0-20240808132857-c8bfc44af7c8 h1:T/wutVfQ1Oj4H5tbP5IZL5l6PZqzvapVJ5cB4Wy4Ucc=
|
||||||
|
github.com/docker/go-containerregistry v0.0.0-20240808132857-c8bfc44af7c8/go.mod h1:z38EKdKh4h7IP2gSfUUqEvalZBqs6AoLeWfUy34nQC8=
|
||||||
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
|
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
|
||||||
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||||
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
||||||
@@ -417,8 +419,6 @@ github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8Hm
|
|||||||
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
||||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||||
github.com/kipz/go-containerregistry v0.0.0-20240722163910-ebe90246535d h1:5QaWAwKhslfqxEyMZY0ofvsbMJkMLcx5E30JFufMVj8=
|
|
||||||
github.com/kipz/go-containerregistry v0.0.0-20240722163910-ebe90246535d/go.mod h1:YCMFNQeeXeLF+dnhhWkqDItx/JSkH01j1Kis4PsjzFI=
|
|
||||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||||
github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU=
|
github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU=
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import (
|
|||||||
|
|
||||||
"github.com/docker/attest/pkg/attest"
|
"github.com/docker/attest/pkg/attest"
|
||||||
"github.com/docker/attest/pkg/attestation"
|
"github.com/docker/attest/pkg/attestation"
|
||||||
"github.com/docker/attest/pkg/mirror"
|
|
||||||
"github.com/docker/attest/pkg/oci"
|
"github.com/docker/attest/pkg/oci"
|
||||||
"github.com/docker/attest/pkg/signerverifier"
|
"github.com/docker/attest/pkg/signerverifier"
|
||||||
v1 "github.com/google/go-containerregistry/pkg/v1"
|
v1 "github.com/google/go-containerregistry/pkg/v1"
|
||||||
@@ -55,7 +54,7 @@ func ExampleSignStatements_remote() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// push image index with signed attestation-manifests
|
// push image index with signed attestation-manifests
|
||||||
err = mirror.PushIndexToRegistry(signedIndex, ref)
|
err = oci.PushIndexToRegistry(signedIndex, ref)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
@@ -70,7 +69,7 @@ func ExampleSignStatements_remote() {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
err = mirror.SaveIndexAsOCILayout(idx, path)
|
err = oci.SaveIndexAsOCILayout(idx, path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import (
|
|||||||
|
|
||||||
"github.com/docker/attest/internal/test"
|
"github.com/docker/attest/internal/test"
|
||||||
"github.com/docker/attest/pkg/attestation"
|
"github.com/docker/attest/pkg/attestation"
|
||||||
"github.com/docker/attest/pkg/mirror"
|
|
||||||
"github.com/docker/attest/pkg/oci"
|
"github.com/docker/attest/pkg/oci"
|
||||||
"github.com/docker/attest/pkg/policy"
|
"github.com/docker/attest/pkg/policy"
|
||||||
"github.com/google/go-containerregistry/pkg/registry"
|
"github.com/google/go-containerregistry/pkg/registry"
|
||||||
@@ -65,7 +64,7 @@ func TestSignVerifyOCILayout(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
spec, err := oci.ParseImageSpec(oci.LocalPrefix + outputLayout)
|
spec, err := oci.ParseImageSpec(oci.LocalPrefix + outputLayout)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
err = mirror.SaveIndex([]*oci.ImageSpec{spec}, signedIndex, attIdx.Name)
|
err = oci.SaveIndex([]*oci.ImageSpec{spec}, signedIndex, attIdx.Name)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
policy, err := Verify(ctx, spec, policyOpts)
|
policy, err := Verify(ctx, spec, policyOpts)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@@ -226,7 +225,7 @@ func TestSimpleStatementSigning(t *testing.T) {
|
|||||||
indexName := fmt.Sprintf("%s/repo:root", u.Host)
|
indexName := fmt.Sprintf("%s/repo:root", u.Host)
|
||||||
output, err := oci.ParseImageSpecs(indexName)
|
output, err := oci.ParseImageSpecs(indexName)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
err = mirror.SaveReferrers(manifest, output)
|
err = oci.SaveReferrers(manifest, output)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import (
|
|||||||
"github.com/docker/attest/internal/test"
|
"github.com/docker/attest/internal/test"
|
||||||
"github.com/docker/attest/pkg/attestation"
|
"github.com/docker/attest/pkg/attestation"
|
||||||
"github.com/docker/attest/pkg/config"
|
"github.com/docker/attest/pkg/config"
|
||||||
"github.com/docker/attest/pkg/mirror"
|
|
||||||
"github.com/docker/attest/pkg/oci"
|
"github.com/docker/attest/pkg/oci"
|
||||||
"github.com/docker/attest/pkg/policy"
|
"github.com/docker/attest/pkg/policy"
|
||||||
intoto "github.com/in-toto/in-toto-golang/in_toto"
|
intoto "github.com/in-toto/in-toto-golang/in_toto"
|
||||||
@@ -84,7 +83,7 @@ func TestVSA(t *testing.T) {
|
|||||||
// output signed attestations
|
// output signed attestations
|
||||||
spec, err := oci.ParseImageSpec(oci.LocalPrefix+outputLayout, oci.WithPlatform(LinuxAMD64))
|
spec, err := oci.ParseImageSpec(oci.LocalPrefix+outputLayout, oci.WithPlatform(LinuxAMD64))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
err = mirror.SaveIndex([]*oci.ImageSpec{spec}, signedIndex, attIdx.Name)
|
err = oci.SaveIndex([]*oci.ImageSpec{spec}, signedIndex, attIdx.Name)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
// mocked vsa query should pass
|
// mocked vsa query should pass
|
||||||
@@ -134,7 +133,7 @@ func TestVerificationFailure(t *testing.T) {
|
|||||||
// output signed attestations
|
// output signed attestations
|
||||||
spec, err := oci.ParseImageSpec(oci.LocalPrefix+outputLayout, oci.WithPlatform(LinuxAMD64))
|
spec, err := oci.ParseImageSpec(oci.LocalPrefix+outputLayout, oci.WithPlatform(LinuxAMD64))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
err = mirror.SaveIndex([]*oci.ImageSpec{spec}, signedIndex, attIdx.Name)
|
err = oci.SaveIndex([]*oci.ImageSpec{spec}, signedIndex, attIdx.Name)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
// mocked vsa query should fail
|
// mocked vsa query should fail
|
||||||
@@ -208,7 +207,7 @@ func TestSignVerify(t *testing.T) {
|
|||||||
// output signed attestations
|
// output signed attestations
|
||||||
spec, err := oci.ParseImageSpec(oci.LocalPrefix+outputLayout, oci.WithPlatform(LinuxAMD64))
|
spec, err := oci.ParseImageSpec(oci.LocalPrefix+outputLayout, oci.WithPlatform(LinuxAMD64))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
err = mirror.SaveIndex([]*oci.ImageSpec{spec}, signedIndex, imageName)
|
err = oci.SaveIndex([]*oci.ImageSpec{spec}, signedIndex, imageName)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
policyOpts := &policy.Options{
|
policyOpts := &policy.Options{
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package attestation
|
package attestation
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
@@ -249,7 +250,7 @@ func (manifest *Manifest) BuildReferringArtifacts() ([]v1.Image, error) {
|
|||||||
return images, nil
|
return images, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// build and image containing only layers.
|
// build an image containing only layers.
|
||||||
func buildImage(layers []*Layer, manifest *v1.Descriptor, subject *v1.Descriptor, opts *ManifestImageOptions) (v1.Image, error) {
|
func buildImage(layers []*Layer, manifest *v1.Descriptor, subject *v1.Descriptor, opts *ManifestImageOptions) (v1.Image, error) {
|
||||||
newImg := empty.Image
|
newImg := empty.Image
|
||||||
var err error
|
var err error
|
||||||
@@ -329,3 +330,12 @@ func (i *EmptyConfigImage) RawManifest() ([]byte, error) {
|
|||||||
}
|
}
|
||||||
return json.Marshal(mf)
|
return json.Marshal(mf)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (i *EmptyConfigImage) Digest() (v1.Hash, error) {
|
||||||
|
mb, err := i.RawManifest()
|
||||||
|
if err != nil {
|
||||||
|
return v1.Hash{}, err
|
||||||
|
}
|
||||||
|
digest, _, err := v1.SHA256(bytes.NewReader(mb))
|
||||||
|
return digest, err
|
||||||
|
}
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import (
|
|||||||
|
|
||||||
"github.com/docker/attest/pkg/attest"
|
"github.com/docker/attest/pkg/attest"
|
||||||
"github.com/docker/attest/pkg/attestation"
|
"github.com/docker/attest/pkg/attestation"
|
||||||
"github.com/docker/attest/pkg/mirror"
|
|
||||||
"github.com/docker/attest/pkg/oci"
|
"github.com/docker/attest/pkg/oci"
|
||||||
"github.com/docker/attest/pkg/signerverifier"
|
"github.com/docker/attest/pkg/signerverifier"
|
||||||
v1 "github.com/google/go-containerregistry/pkg/v1"
|
v1 "github.com/google/go-containerregistry/pkg/v1"
|
||||||
@@ -80,7 +79,7 @@ func ExampleManifest() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// save the manifest to the registry as a referrers artifact
|
// save the manifest to the registry as a referrers artifact
|
||||||
err = mirror.SaveReferrers(manifest, output)
|
err = oci.SaveReferrers(manifest, output)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,14 +8,15 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/docker/attest/internal/test"
|
"github.com/docker/attest/internal/test"
|
||||||
|
"github.com/docker/attest/internal/util"
|
||||||
"github.com/docker/attest/pkg/attest"
|
"github.com/docker/attest/pkg/attest"
|
||||||
"github.com/docker/attest/pkg/attestation"
|
"github.com/docker/attest/pkg/attestation"
|
||||||
"github.com/docker/attest/pkg/config"
|
"github.com/docker/attest/pkg/config"
|
||||||
"github.com/docker/attest/pkg/mirror"
|
|
||||||
"github.com/docker/attest/pkg/oci"
|
"github.com/docker/attest/pkg/oci"
|
||||||
"github.com/docker/attest/pkg/policy"
|
"github.com/docker/attest/pkg/policy"
|
||||||
"github.com/google/go-containerregistry/pkg/name"
|
"github.com/google/go-containerregistry/pkg/name"
|
||||||
"github.com/google/go-containerregistry/pkg/registry"
|
"github.com/google/go-containerregistry/pkg/registry"
|
||||||
|
"github.com/google/go-containerregistry/pkg/v1/empty"
|
||||||
"github.com/google/go-containerregistry/pkg/v1/remote"
|
"github.com/google/go-containerregistry/pkg/v1/remote"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
@@ -112,14 +113,14 @@ func TestAttestationReferenceTypes(t *testing.T) {
|
|||||||
|
|
||||||
// push subject image so that it can be resolved
|
// push subject image so that it can be resolved
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
err = mirror.PushIndexToRegistry(attIdx.Index, indexName)
|
err = oci.PushIndexToRegistry(attIdx.Index, indexName)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// upload referrers
|
// upload referrers
|
||||||
output, err := oci.ParseImageSpec(outputRepo)
|
output, err := oci.ParseImageSpec(outputRepo)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
for _, attIdx := range signedManifests {
|
for _, attIdx := range signedManifests {
|
||||||
err = mirror.SaveReferrers(attIdx, []*oci.ImageSpec{output})
|
err = oci.SaveReferrers(attIdx, []*oci.ImageSpec{output})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -216,7 +217,7 @@ func TestReferencesInDifferentRepo(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
indexName := fmt.Sprintf("%s/%s:latest", serverURL.Host, repoName)
|
indexName := fmt.Sprintf("%s/%s:latest", serverURL.Host, repoName)
|
||||||
err = mirror.PushIndexToRegistry(attIdx.Index, indexName)
|
err = oci.PushIndexToRegistry(attIdx.Index, indexName)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
signedManifests, err := attest.SignStatements(ctx, attIdx.Index, signer, opts)
|
signedManifests, err := attest.SignStatements(ctx, attIdx.Index, signer, opts)
|
||||||
@@ -227,7 +228,7 @@ func TestReferencesInDifferentRepo(t *testing.T) {
|
|||||||
// push references using subject-digest.att convention
|
// push references using subject-digest.att convention
|
||||||
image, err := signedManifest.BuildAttestationImage()
|
image, err := signedManifest.BuildAttestationImage()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
err = mirror.PushImageToRegistry(image, fmt.Sprintf("%s/%s:tag-does-not-matter", refServerURL.Host, repoName))
|
err = oci.PushImageToRegistry(image, fmt.Sprintf("%s/%s:tag-does-not-matter", refServerURL.Host, repoName))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
refServer := tc.refServer
|
refServer := tc.refServer
|
||||||
@@ -242,7 +243,7 @@ func TestReferencesInDifferentRepo(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
indexName := fmt.Sprintf("%s/%s:latest", serverURL.Host, repoName)
|
indexName := fmt.Sprintf("%s/%s:latest", serverURL.Host, repoName)
|
||||||
err = mirror.PushIndexToRegistry(attIdx.Index, indexName)
|
err = oci.PushIndexToRegistry(attIdx.Index, indexName)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
signedManifests, err := attest.SignStatements(ctx, attIdx.Index, signer, opts)
|
signedManifests, err := attest.SignStatements(ctx, attIdx.Index, signer, opts)
|
||||||
@@ -254,7 +255,7 @@ func TestReferencesInDifferentRepo(t *testing.T) {
|
|||||||
imgs, err := mf.BuildReferringArtifacts()
|
imgs, err := mf.BuildReferringArtifacts()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
for _, img := range imgs {
|
for _, img := range imgs {
|
||||||
err = mirror.PushImageToRegistry(img, fmt.Sprintf("%s/%s:tag-does-not-matter", refServerURL.Host, repoName))
|
err = oci.PushImageToRegistry(img, fmt.Sprintf("%s/%s:tag-does-not-matter", refServerURL.Host, repoName))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -297,7 +298,7 @@ func TestCorrectArtifactTypeInTagFallback(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
indexName := fmt.Sprintf("%s/%s:latest", serverURL.Host, repoName)
|
indexName := fmt.Sprintf("%s/%s:latest", serverURL.Host, repoName)
|
||||||
err = mirror.PushIndexToRegistry(attIdx.Index, indexName)
|
err = oci.PushIndexToRegistry(attIdx.Index, indexName)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
signedManifests, err := attest.SignStatements(ctx, attIdx.Index, signer, opts)
|
signedManifests, err := attest.SignStatements(ctx, attIdx.Index, signer, opts)
|
||||||
@@ -308,7 +309,7 @@ func TestCorrectArtifactTypeInTagFallback(t *testing.T) {
|
|||||||
imgs, err := mf.BuildReferringArtifacts()
|
imgs, err := mf.BuildReferringArtifacts()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
for _, img := range imgs {
|
for _, img := range imgs {
|
||||||
err = mirror.PushImageToRegistry(img, fmt.Sprintf("%s/%s:tag-does-not-matter", serverURL.Host, repoName))
|
err = oci.PushImageToRegistry(img, fmt.Sprintf("%s/%s:tag-does-not-matter", serverURL.Host, repoName))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
mf, err := img.Manifest()
|
mf, err := img.Manifest()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@@ -326,3 +327,14 @@ func TestCorrectArtifactTypeInTagFallback(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestEmptyConfigImageDigest(t *testing.T) {
|
||||||
|
empty := empty.Image
|
||||||
|
img := attestation.EmptyConfigImage{empty}
|
||||||
|
mf, err := img.RawManifest()
|
||||||
|
require.NoError(t, err)
|
||||||
|
hash := util.SHA256Hex(mf)
|
||||||
|
digest, err := img.Digest()
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Equal(t, digest.Hex, hash)
|
||||||
|
}
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/docker/attest/pkg/mirror"
|
|
||||||
"github.com/docker/attest/pkg/oci"
|
"github.com/docker/attest/pkg/oci"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
@@ -25,7 +24,7 @@ func TestRegistryAuth(t *testing.T) {
|
|||||||
}
|
}
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
t.Run(tc.Image, func(t *testing.T) {
|
t.Run(tc.Image, func(t *testing.T) {
|
||||||
err := mirror.PushIndexToRegistry(attIdx.Index, tc.Image)
|
err := oci.PushIndexToRegistry(attIdx.Index, tc.Image)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
_, err = oci.IndexFromRemote(tc.Image)
|
_, err = oci.IndexFromRemote(tc.Image)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import (
|
|||||||
|
|
||||||
"github.com/docker/attest/internal/embed"
|
"github.com/docker/attest/internal/embed"
|
||||||
"github.com/docker/attest/pkg/mirror"
|
"github.com/docker/attest/pkg/mirror"
|
||||||
|
"github.com/docker/attest/pkg/oci"
|
||||||
"github.com/docker/attest/pkg/tuf"
|
"github.com/docker/attest/pkg/tuf"
|
||||||
v1 "github.com/google/go-containerregistry/pkg/v1"
|
v1 "github.com/google/go-containerregistry/pkg/v1"
|
||||||
)
|
)
|
||||||
@@ -80,7 +81,7 @@ func ExampleNewTUFMirror() {
|
|||||||
func mirrorToRegistry(o *TufMirrorOutput) error {
|
func mirrorToRegistry(o *TufMirrorOutput) error {
|
||||||
// push metadata to registry
|
// push metadata to registry
|
||||||
metadataRepo := "registry-1.docker.io/docker/tuf-metadata:latest"
|
metadataRepo := "registry-1.docker.io/docker/tuf-metadata:latest"
|
||||||
err := mirror.PushImageToRegistry(o.metadata, metadataRepo)
|
err := oci.PushImageToRegistry(o.metadata, metadataRepo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -91,7 +92,7 @@ func mirrorToRegistry(o *TufMirrorOutput) error {
|
|||||||
return fmt.Errorf("failed to get repo without tag: %s", metadataRepo)
|
return fmt.Errorf("failed to get repo without tag: %s", metadataRepo)
|
||||||
}
|
}
|
||||||
imageName := fmt.Sprintf("%s:%s", repo, metadata.Tag)
|
imageName := fmt.Sprintf("%s:%s", repo, metadata.Tag)
|
||||||
err = mirror.PushImageToRegistry(metadata.Image, imageName)
|
err = oci.PushImageToRegistry(metadata.Image, imageName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -101,7 +102,7 @@ func mirrorToRegistry(o *TufMirrorOutput) error {
|
|||||||
targetsRepo := "registry-1.docker.io/docker/tuf-targets"
|
targetsRepo := "registry-1.docker.io/docker/tuf-targets"
|
||||||
for _, target := range o.targets {
|
for _, target := range o.targets {
|
||||||
imageName := fmt.Sprintf("%s:%s", targetsRepo, target.Tag)
|
imageName := fmt.Sprintf("%s:%s", targetsRepo, target.Tag)
|
||||||
err = mirror.PushImageToRegistry(target.Image, imageName)
|
err = oci.PushImageToRegistry(target.Image, imageName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -109,7 +110,7 @@ func mirrorToRegistry(o *TufMirrorOutput) error {
|
|||||||
// push delegated targets to registry
|
// push delegated targets to registry
|
||||||
for _, target := range o.delegatedTargets {
|
for _, target := range o.delegatedTargets {
|
||||||
imageName := fmt.Sprintf("%s:%s", targetsRepo, target.Tag)
|
imageName := fmt.Sprintf("%s:%s", targetsRepo, target.Tag)
|
||||||
err = mirror.PushIndexToRegistry(target.Index, imageName)
|
err = oci.PushIndexToRegistry(target.Index, imageName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -119,14 +120,14 @@ func mirrorToRegistry(o *TufMirrorOutput) error {
|
|||||||
|
|
||||||
func mirrorToLocal(o *TufMirrorOutput, outputPath string) error {
|
func mirrorToLocal(o *TufMirrorOutput, outputPath string) error {
|
||||||
// output metadata to local directory
|
// output metadata to local directory
|
||||||
err := mirror.SaveImageAsOCILayout(o.metadata, outputPath)
|
err := oci.SaveImageAsOCILayout(o.metadata, outputPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// output delegated metadata to local directory
|
// output delegated metadata to local directory
|
||||||
for _, metadata := range o.delegatedMetadata {
|
for _, metadata := range o.delegatedMetadata {
|
||||||
path := filepath.Join(outputPath, metadata.Tag)
|
path := filepath.Join(outputPath, metadata.Tag)
|
||||||
err = mirror.SaveImageAsOCILayout(metadata.Image, path)
|
err = oci.SaveImageAsOCILayout(metadata.Image, path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -135,7 +136,7 @@ func mirrorToLocal(o *TufMirrorOutput, outputPath string) error {
|
|||||||
// output top-level targets to local directory
|
// output top-level targets to local directory
|
||||||
for _, target := range o.targets {
|
for _, target := range o.targets {
|
||||||
path := filepath.Join(outputPath, target.Tag)
|
path := filepath.Join(outputPath, target.Tag)
|
||||||
err = mirror.SaveImageAsOCILayout(target.Image, path)
|
err = oci.SaveImageAsOCILayout(target.Image, path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -143,7 +144,7 @@ func mirrorToLocal(o *TufMirrorOutput, outputPath string) error {
|
|||||||
// output delegated targets to local directory
|
// output delegated targets to local directory
|
||||||
for _, target := range o.delegatedTargets {
|
for _, target := range o.delegatedTargets {
|
||||||
path := filepath.Join(outputPath, target.Tag)
|
path := filepath.Join(outputPath, target.Tag)
|
||||||
err = mirror.SaveIndexAsOCILayout(target.Index, path)
|
err = oci.SaveIndexAsOCILayout(target.Index, path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,18 +2,9 @@ package mirror
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
|
||||||
|
|
||||||
"github.com/docker/attest/internal/embed"
|
"github.com/docker/attest/internal/embed"
|
||||||
"github.com/docker/attest/pkg/attestation"
|
|
||||||
"github.com/docker/attest/pkg/oci"
|
|
||||||
"github.com/docker/attest/pkg/tuf"
|
"github.com/docker/attest/pkg/tuf"
|
||||||
"github.com/google/go-containerregistry/pkg/name"
|
|
||||||
v1 "github.com/google/go-containerregistry/pkg/v1"
|
|
||||||
"github.com/google/go-containerregistry/pkg/v1/empty"
|
|
||||||
"github.com/google/go-containerregistry/pkg/v1/layout"
|
|
||||||
"github.com/google/go-containerregistry/pkg/v1/mutate"
|
|
||||||
"github.com/google/go-containerregistry/pkg/v1/remote"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewTUFMirror(root []byte, tufPath, metadataURL, targetsURL string, versionChecker tuf.VersionChecker) (*TUFMirror, error) {
|
func NewTUFMirror(root []byte, tufPath, metadataURL, targetsURL string, versionChecker tuf.VersionChecker) (*TUFMirror, error) {
|
||||||
@@ -26,133 +17,3 @@ func NewTUFMirror(root []byte, tufPath, metadataURL, targetsURL string, versionC
|
|||||||
}
|
}
|
||||||
return &TUFMirror{TUFClient: tufClient, tufPath: tufPath, metadataURL: metadataURL, targetsURL: targetsURL}, nil
|
return &TUFMirror{TUFClient: tufClient, tufPath: tufPath, metadataURL: metadataURL, targetsURL: targetsURL}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func PushImageToRegistry(image v1.Image, imageName string) error {
|
|
||||||
ref, err := name.ParseReference(imageName)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("Failed to parse image name '%s': %w", imageName, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Push the image to the registry
|
|
||||||
return remote.Write(ref, image, oci.MultiKeychainOption())
|
|
||||||
}
|
|
||||||
|
|
||||||
func PushIndexToRegistry(index v1.ImageIndex, imageName string) error {
|
|
||||||
// Parse the index name
|
|
||||||
ref, err := name.ParseReference(imageName)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("Failed to parse image name: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Push the index to the registry
|
|
||||||
return remote.WriteIndex(ref, index, oci.MultiKeychainOption())
|
|
||||||
}
|
|
||||||
|
|
||||||
func SaveImageAsOCILayout(image v1.Image, path string) error {
|
|
||||||
// Save the image to the local filesystem
|
|
||||||
err := os.MkdirAll(path, os.ModePerm)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to create directory: %w", err)
|
|
||||||
}
|
|
||||||
index := empty.Index
|
|
||||||
l, err := layout.Write(path, index)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to create index: %w", err)
|
|
||||||
}
|
|
||||||
return l.AppendImage(image)
|
|
||||||
}
|
|
||||||
|
|
||||||
func SaveIndexAsOCILayout(image v1.ImageIndex, path string) error {
|
|
||||||
// Save the index to the local filesystem
|
|
||||||
err := os.MkdirAll(path, os.ModePerm)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to create directory: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = layout.Write(path, image)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to create index: %w", err)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func SaveIndex(outputs []*oci.ImageSpec, index v1.ImageIndex, indexName string) error {
|
|
||||||
// split output by comma and write or push each one
|
|
||||||
for _, output := range outputs {
|
|
||||||
if output.Type == oci.OCI {
|
|
||||||
idx := v1.ImageIndex(empty.Index)
|
|
||||||
idx = mutate.AppendManifests(idx, mutate.IndexAddendum{
|
|
||||||
Add: index,
|
|
||||||
Descriptor: v1.Descriptor{
|
|
||||||
Annotations: map[string]string{
|
|
||||||
oci.OCIReferenceTarget: indexName,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
err := SaveIndexAsOCILayout(idx, output.Identifier)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to write signed image: %w", err)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
err := PushIndexToRegistry(index, output.Identifier)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to push signed image: %w", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func SaveImage(output *oci.ImageSpec, image v1.Image, imageName string) error {
|
|
||||||
if output.Type == oci.OCI {
|
|
||||||
idx := v1.ImageIndex(empty.Index)
|
|
||||||
idx = mutate.AppendManifests(idx, mutate.IndexAddendum{
|
|
||||||
Add: image,
|
|
||||||
Descriptor: v1.Descriptor{
|
|
||||||
Annotations: map[string]string{
|
|
||||||
oci.OCIReferenceTarget: imageName,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
err := SaveIndexAsOCILayout(idx, output.Identifier)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to write signed image: %w", err)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
err := PushImageToRegistry(image, output.Identifier)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to push signed image: %w", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func SaveReferrers(manifest *attestation.Manifest, outputs []*oci.ImageSpec) error {
|
|
||||||
for _, output := range outputs {
|
|
||||||
// OCI layout output for referrers not supported
|
|
||||||
if output.Type == oci.OCI {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
// so that we use the same tag each time to reduce number of tags (tags aren't needed for referrers but we must push one)
|
|
||||||
attOut, err := oci.ReplaceTagInSpec(output, manifest.SubjectDescriptor.Digest)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
// otherwise we end up with the detected platform, though I'm not sure it matters
|
|
||||||
attOut.Platform = &v1.Platform{
|
|
||||||
OS: "unknown",
|
|
||||||
Architecture: "unknown",
|
|
||||||
}
|
|
||||||
images, err := manifest.BuildReferringArtifacts()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to build image: %w", err)
|
|
||||||
}
|
|
||||||
for _, image := range images {
|
|
||||||
err := PushImageToRegistry(image, attOut.Identifier)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to push image: %w", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import (
|
|||||||
"github.com/docker/attest/internal/test"
|
"github.com/docker/attest/internal/test"
|
||||||
"github.com/docker/attest/pkg/attest"
|
"github.com/docker/attest/pkg/attest"
|
||||||
"github.com/docker/attest/pkg/attestation"
|
"github.com/docker/attest/pkg/attestation"
|
||||||
"github.com/docker/attest/pkg/mirror"
|
|
||||||
"github.com/docker/attest/pkg/oci"
|
"github.com/docker/attest/pkg/oci"
|
||||||
"github.com/docker/attest/pkg/policy"
|
"github.com/docker/attest/pkg/policy"
|
||||||
v1 "github.com/google/go-containerregistry/pkg/v1"
|
v1 "github.com/google/go-containerregistry/pkg/v1"
|
||||||
@@ -34,7 +33,7 @@ func TestAttestationFromOCILayout(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
spec, err := oci.ParseImageSpec(oci.LocalPrefix + outputLayout)
|
spec, err := oci.ParseImageSpec(oci.LocalPrefix + outputLayout)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
err = mirror.SaveIndex([]*oci.ImageSpec{spec}, signedIndex, outputLayout)
|
err = oci.SaveIndex([]*oci.ImageSpec{spec}, signedIndex, outputLayout)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
|
|||||||
@@ -172,3 +172,26 @@ func replaceTag(image string, digest v1.Hash) (string, error) {
|
|||||||
}
|
}
|
||||||
return fmt.Sprintf("%s:%s-%s.att", notag, digest.Algorithm, digest.Hex), nil
|
return fmt.Sprintf("%s:%s-%s.att", notag, digest.Algorithm, digest.Hex), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ReplaceDigestInSpec(src *ImageSpec, digest v1.Hash) (*ImageSpec, error) {
|
||||||
|
newName, err := replaceDigest(src.Identifier, digest)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to parse repo name: %w", err)
|
||||||
|
}
|
||||||
|
return &ImageSpec{
|
||||||
|
Identifier: newName,
|
||||||
|
Type: src.Type,
|
||||||
|
Platform: src.Platform,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func replaceDigest(image string, digest v1.Hash) (string, error) {
|
||||||
|
if strings.HasPrefix(image, LocalPrefix) {
|
||||||
|
return image, nil
|
||||||
|
}
|
||||||
|
notag, err := WithoutTag(image)
|
||||||
|
if err != nil {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%s@%s:%s", notag, digest.Algorithm, digest.Hex), nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ import (
|
|||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var UnsignedTestImage = filepath.Join("..", "..", "test", "testdata", "unsigned-test-image")
|
||||||
|
|
||||||
func TestRefToPurl(t *testing.T) {
|
func TestRefToPurl(t *testing.T) {
|
||||||
arm, err := ParsePlatform("arm64/linux")
|
arm, err := ParsePlatform("arm64/linux")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@@ -54,8 +56,6 @@ func TestRefToPurl(t *testing.T) {
|
|||||||
assert.True(t, canonical)
|
assert.True(t, canonical)
|
||||||
}
|
}
|
||||||
|
|
||||||
var UnsignedTestImage = filepath.Join("..", "..", "test", "testdata", "unsigned-test-image")
|
|
||||||
|
|
||||||
// Test fix for https://github.com/docker/secure-artifacts-team-issues/issues/202
|
// Test fix for https://github.com/docker/secure-artifacts-team-issues/issues/202
|
||||||
func TestImageDigestForPlatform(t *testing.T) {
|
func TestImageDigestForPlatform(t *testing.T) {
|
||||||
idx, err := layout.ImageIndexFromPath(UnsignedTestImage)
|
idx, err := layout.ImageIndexFromPath(UnsignedTestImage)
|
||||||
|
|||||||
142
pkg/oci/output.go
Normal file
142
pkg/oci/output.go
Normal file
@@ -0,0 +1,142 @@
|
|||||||
|
package oci
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/docker/attest/pkg/attestation"
|
||||||
|
"github.com/google/go-containerregistry/pkg/name"
|
||||||
|
v1 "github.com/google/go-containerregistry/pkg/v1"
|
||||||
|
"github.com/google/go-containerregistry/pkg/v1/empty"
|
||||||
|
"github.com/google/go-containerregistry/pkg/v1/layout"
|
||||||
|
"github.com/google/go-containerregistry/pkg/v1/mutate"
|
||||||
|
"github.com/google/go-containerregistry/pkg/v1/remote"
|
||||||
|
)
|
||||||
|
|
||||||
|
func PushImageToRegistry(image v1.Image, imageName string) error {
|
||||||
|
ref, err := name.ParseReference(imageName)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Failed to parse image name '%s': %w", imageName, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Push the image to the registry
|
||||||
|
return remote.Write(ref, image, MultiKeychainOption())
|
||||||
|
}
|
||||||
|
|
||||||
|
func PushIndexToRegistry(index v1.ImageIndex, imageName string) error {
|
||||||
|
// Parse the index name
|
||||||
|
ref, err := name.ParseReference(imageName)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Failed to parse image name: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Push the index to the registry
|
||||||
|
return remote.WriteIndex(ref, index, MultiKeychainOption())
|
||||||
|
}
|
||||||
|
|
||||||
|
func SaveImageAsOCILayout(image v1.Image, path string) error {
|
||||||
|
// Save the image to the local filesystem
|
||||||
|
err := os.MkdirAll(path, os.ModePerm)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to create directory: %w", err)
|
||||||
|
}
|
||||||
|
index := empty.Index
|
||||||
|
l, err := layout.Write(path, index)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to create index: %w", err)
|
||||||
|
}
|
||||||
|
return l.AppendImage(image)
|
||||||
|
}
|
||||||
|
|
||||||
|
func SaveIndexAsOCILayout(image v1.ImageIndex, path string) error {
|
||||||
|
// Save the index to the local filesystem
|
||||||
|
err := os.MkdirAll(path, os.ModePerm)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to create directory: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = layout.Write(path, image)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to create index: %w", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func SaveIndex(outputs []*ImageSpec, index v1.ImageIndex, indexName string) error {
|
||||||
|
// split output by comma and write or push each one
|
||||||
|
for _, output := range outputs {
|
||||||
|
if output.Type == OCI {
|
||||||
|
idx := v1.ImageIndex(empty.Index)
|
||||||
|
idx = mutate.AppendManifests(idx, mutate.IndexAddendum{
|
||||||
|
Add: index,
|
||||||
|
Descriptor: v1.Descriptor{
|
||||||
|
Annotations: map[string]string{
|
||||||
|
OCIReferenceTarget: indexName,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
err := SaveIndexAsOCILayout(idx, output.Identifier)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to write signed image: %w", err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
err := PushIndexToRegistry(index, output.Identifier)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to push signed image: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func SaveImage(output *ImageSpec, image v1.Image, imageName string) error {
|
||||||
|
if output.Type == OCI {
|
||||||
|
idx := v1.ImageIndex(empty.Index)
|
||||||
|
idx = mutate.AppendManifests(idx, mutate.IndexAddendum{
|
||||||
|
Add: image,
|
||||||
|
Descriptor: v1.Descriptor{
|
||||||
|
Annotations: map[string]string{
|
||||||
|
OCIReferenceTarget: imageName,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
err := SaveIndexAsOCILayout(idx, output.Identifier)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to write signed image: %w", err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
err := PushImageToRegistry(image, output.Identifier)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to push signed image: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func SaveReferrers(manifest *attestation.Manifest, outputs []*ImageSpec) error {
|
||||||
|
for _, output := range outputs {
|
||||||
|
// OCI layout output for referrers not supported
|
||||||
|
if output.Type == OCI {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
images, err := manifest.BuildReferringArtifacts()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to build image: %w", err)
|
||||||
|
}
|
||||||
|
for _, image := range images {
|
||||||
|
digest, err := image.Digest()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to get attestation image digest: %w", err)
|
||||||
|
}
|
||||||
|
attOut, err := ReplaceDigestInSpec(output, digest)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to create attestation image spec: %w", err)
|
||||||
|
}
|
||||||
|
err = PushImageToRegistry(image, attOut.Identifier)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to push image: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package mirror
|
package oci_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
@@ -33,12 +33,12 @@ func TestSavingIndex(t *testing.T) {
|
|||||||
indexName := fmt.Sprintf("%s/repo:root", u.Host)
|
indexName := fmt.Sprintf("%s/repo:root", u.Host)
|
||||||
output, err := oci.ParseImageSpecs(indexName)
|
output, err := oci.ParseImageSpecs(indexName)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
err = SaveIndex(output, attIdx.Index, indexName)
|
err = oci.SaveIndex(output, attIdx.Index, indexName)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
ociOutput, err := oci.ParseImageSpecs(oci.LocalPrefix + outputLayout)
|
ociOutput, err := oci.ParseImageSpecs(oci.LocalPrefix + outputLayout)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
err = SaveIndex(ociOutput, attIdx.Index, indexName)
|
err = oci.SaveIndex(ociOutput, attIdx.Index, indexName)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,12 +56,12 @@ func TestSavingImage(t *testing.T) {
|
|||||||
indexName := fmt.Sprintf("%s/repo:root", u.Host)
|
indexName := fmt.Sprintf("%s/repo:root", u.Host)
|
||||||
output, err := oci.ParseImageSpec(indexName)
|
output, err := oci.ParseImageSpec(indexName)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
err = SaveImage(output, img, indexName)
|
err = oci.SaveImage(output, img, indexName)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
ociOutput, err := oci.ParseImageSpec(oci.LocalPrefix + outputLayout)
|
ociOutput, err := oci.ParseImageSpec(oci.LocalPrefix + outputLayout)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
err = SaveImage(ociOutput, img, indexName)
|
err = oci.SaveImage(ociOutput, img, indexName)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,7 +93,7 @@ func TestSavingReferrers(t *testing.T) {
|
|||||||
indexName := fmt.Sprintf("%s/repo:root", u.Host)
|
indexName := fmt.Sprintf("%s/repo:root", u.Host)
|
||||||
output, err := oci.ParseImageSpecs(indexName)
|
output, err := oci.ParseImageSpecs(indexName)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
err = SaveReferrers(manifest, output)
|
err = oci.SaveReferrers(manifest, output)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
reg := &oci.MockRegistryResolver{
|
reg := &oci.MockRegistryResolver{
|
||||||
@@ -10,7 +10,6 @@ import (
|
|||||||
"github.com/docker/attest/internal/test"
|
"github.com/docker/attest/internal/test"
|
||||||
"github.com/docker/attest/pkg/attest"
|
"github.com/docker/attest/pkg/attest"
|
||||||
"github.com/docker/attest/pkg/attestation"
|
"github.com/docker/attest/pkg/attestation"
|
||||||
"github.com/docker/attest/pkg/mirror"
|
|
||||||
"github.com/docker/attest/pkg/oci"
|
"github.com/docker/attest/pkg/oci"
|
||||||
"github.com/docker/attest/pkg/policy"
|
"github.com/docker/attest/pkg/policy"
|
||||||
"github.com/google/go-containerregistry/pkg/registry"
|
"github.com/google/go-containerregistry/pkg/registry"
|
||||||
@@ -36,7 +35,7 @@ func TestRegistry(t *testing.T) {
|
|||||||
|
|
||||||
indexName := fmt.Sprintf("%s/repo:root", u.Host)
|
indexName := fmt.Sprintf("%s/repo:root", u.Host)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
err = mirror.PushIndexToRegistry(signedIndex, indexName)
|
err = oci.PushIndexToRegistry(signedIndex, indexName)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
spec, err := oci.ParseImageSpec(indexName)
|
spec, err := oci.ParseImageSpec(indexName)
|
||||||
|
|||||||
Reference in New Issue
Block a user