mirror of
https://github.com/distribution/distribution.git
synced 2025-09-17 15:50:20 +00:00
Remove references to schema1 pacakge from handlers
schema1 package was deprecated a while ago so we are removing any references to it from handlers. in preparation to removing it from the codebase altogether. Signed-off-by: Milos Gajdos <milosthegajdos@gmail.com>
This commit is contained in:
@@ -23,7 +23,6 @@ import (
|
||||
"github.com/distribution/distribution/v3/configuration"
|
||||
"github.com/distribution/distribution/v3/manifest"
|
||||
"github.com/distribution/distribution/v3/manifest/manifestlist"
|
||||
"github.com/distribution/distribution/v3/manifest/schema1" //nolint:staticcheck // Ignore SA1019: "github.com/distribution/distribution/v3/manifest/schema1" is deprecated, as it's used for backward compatibility.
|
||||
"github.com/distribution/distribution/v3/manifest/schema2"
|
||||
"github.com/distribution/distribution/v3/reference"
|
||||
"github.com/distribution/distribution/v3/registry/api/errcode"
|
||||
@@ -421,7 +420,8 @@ func TestCatalogAPI(t *testing.T) {
|
||||
|
||||
envWithLessImages := newTestEnv(t, false)
|
||||
for _, image := range allCatalog[0:(maxEntries - 1)] {
|
||||
createRepository(envWithLessImages, t, image, "sometag")
|
||||
imageName, _ := reference.WithName(image)
|
||||
testManifestAPISchema2(t, envWithLessImages, imageName, "sometag")
|
||||
}
|
||||
|
||||
catalogURL, err = envWithLessImages.builder.BuildCatalogURL(values)
|
||||
@@ -1245,21 +1245,18 @@ type manifestArgs struct {
|
||||
}
|
||||
|
||||
func TestManifestAPI(t *testing.T) {
|
||||
schema1Repo, _ := reference.WithName("foo/schema1")
|
||||
schema2Repo, _ := reference.WithName("foo/schema2")
|
||||
|
||||
deleteEnabled := false
|
||||
env1 := newTestEnv(t, deleteEnabled)
|
||||
defer env1.Shutdown()
|
||||
testManifestAPISchema1(t, env1, schema1Repo)
|
||||
schema2Args := testManifestAPISchema2(t, env1, schema2Repo)
|
||||
schema2Args := testManifestAPISchema2(t, env1, schema2Repo, "schema2tag")
|
||||
testManifestAPIManifestList(t, env1, schema2Args)
|
||||
|
||||
deleteEnabled = true
|
||||
env2 := newTestEnv(t, deleteEnabled)
|
||||
defer env2.Shutdown()
|
||||
testManifestAPISchema1(t, env2, schema1Repo)
|
||||
schema2Args = testManifestAPISchema2(t, env2, schema2Repo)
|
||||
schema2Args = testManifestAPISchema2(t, env2, schema2Repo, "schema2tag")
|
||||
testManifestAPIManifestList(t, env2, schema2Args)
|
||||
}
|
||||
|
||||
@@ -1438,24 +1435,21 @@ func TestGetManifestWithStorageError(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestManifestDelete(t *testing.T) {
|
||||
schema1Repo, _ := reference.WithName("foo/schema1")
|
||||
schema2Repo, _ := reference.WithName("foo/schema2")
|
||||
|
||||
deleteEnabled := true
|
||||
env := newTestEnv(t, deleteEnabled)
|
||||
defer env.Shutdown()
|
||||
schema1Args := testManifestAPISchema1(t, env, schema1Repo)
|
||||
testManifestDelete(t, env, schema1Args)
|
||||
schema2Args := testManifestAPISchema2(t, env, schema2Repo)
|
||||
schema2Args := testManifestAPISchema2(t, env, schema2Repo, "schema2tag")
|
||||
testManifestDelete(t, env, schema2Args)
|
||||
}
|
||||
|
||||
func TestManifestDeleteDisabled(t *testing.T) {
|
||||
schema1Repo, _ := reference.WithName("foo/schema1")
|
||||
schema2Repo, _ := reference.WithName("foo/schema2")
|
||||
deleteEnabled := false
|
||||
env := newTestEnv(t, deleteEnabled)
|
||||
defer env.Shutdown()
|
||||
testManifestDeleteDisabled(t, env, schema1Repo)
|
||||
testManifestDeleteDisabled(t, env, schema2Repo)
|
||||
}
|
||||
|
||||
func testManifestDeleteDisabled(t *testing.T, env *testEnv, imageName reference.Named) {
|
||||
@@ -1493,324 +1487,7 @@ func testManifestWithStorageError(t *testing.T, env *testEnv, imageName referenc
|
||||
checkBodyHasErrorCodes(t, "getting non-existent manifest", resp, expectedErrorCode)
|
||||
}
|
||||
|
||||
func testManifestAPISchema1(t *testing.T, env *testEnv, imageName reference.Named) manifestArgs {
|
||||
tag := "thetag"
|
||||
args := manifestArgs{imageName: imageName}
|
||||
|
||||
tagRef, _ := reference.WithTag(imageName, tag)
|
||||
manifestURL, err := env.builder.BuildManifestURL(tagRef)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error getting manifest url: %v", err)
|
||||
}
|
||||
|
||||
// -----------------------------
|
||||
// Attempt to fetch the manifest
|
||||
resp, err := http.Get(manifestURL)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error getting manifest: %v", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
checkResponse(t, "getting non-existent manifest", resp, http.StatusNotFound)
|
||||
checkBodyHasErrorCodes(t, "getting non-existent manifest", resp, v2.ErrorCodeManifestUnknown)
|
||||
|
||||
tagsURL, err := env.builder.BuildTagsURL(imageName)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error building tags url: %v", err)
|
||||
}
|
||||
|
||||
resp, err = http.Get(tagsURL)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error getting unknown tags: %v", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
// Check that we get an unknown repository error when asking for tags
|
||||
checkResponse(t, "getting unknown manifest tags", resp, http.StatusNotFound)
|
||||
checkBodyHasErrorCodes(t, "getting unknown manifest tags", resp, v2.ErrorCodeNameUnknown)
|
||||
|
||||
// --------------------------------
|
||||
// Attempt to push unsigned manifest with missing layers
|
||||
unsignedManifest := &schema1.Manifest{ //nolint:staticcheck // Ignore SA1019: "github.com/distribution/distribution/v3/manifest/schema1" is deprecated, as it's used for backward compatibility.
|
||||
Versioned: manifest.Versioned{
|
||||
SchemaVersion: 1,
|
||||
},
|
||||
Name: imageName.Name(),
|
||||
Tag: tag,
|
||||
FSLayers: []schema1.FSLayer{ //nolint:staticcheck // Ignore SA1019: "github.com/distribution/distribution/v3/manifest/schema1" is deprecated, as it's used for backward compatibility.
|
||||
{
|
||||
BlobSum: "asdf",
|
||||
},
|
||||
{
|
||||
BlobSum: "qwer",
|
||||
},
|
||||
},
|
||||
History: []schema1.History{ //nolint:staticcheck // Ignore SA1019: "github.com/distribution/distribution/v3/manifest/schema1" is deprecated, as it's used for backward compatibility.
|
||||
{
|
||||
V1Compatibility: "",
|
||||
},
|
||||
{
|
||||
V1Compatibility: "",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
resp = putManifest(t, "putting unsigned manifest", manifestURL, "", unsignedManifest)
|
||||
defer resp.Body.Close()
|
||||
checkResponse(t, "putting unsigned manifest", resp, http.StatusBadRequest)
|
||||
_, p, counts := checkBodyHasErrorCodes(t, "putting unsigned manifest", resp, v2.ErrorCodeManifestInvalid)
|
||||
|
||||
expectedCounts := map[errcode.ErrorCode]int{
|
||||
v2.ErrorCodeManifestInvalid: 1,
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(counts, expectedCounts) {
|
||||
t.Fatalf("unexpected number of error codes encountered: %v\n!=\n%v\n---\n%s", counts, expectedCounts, string(p))
|
||||
}
|
||||
|
||||
// sign the manifest and still get some interesting errors.
|
||||
sm, err := schema1.Sign(unsignedManifest, env.pk) //nolint:staticcheck // Ignore SA1019: "github.com/distribution/distribution/v3/manifest/schema1" is deprecated, as it's used for backward compatibility.
|
||||
if err != nil {
|
||||
t.Fatalf("error signing manifest: %v", err)
|
||||
}
|
||||
|
||||
resp = putManifest(t, "putting signed manifest with errors", manifestURL, "", sm)
|
||||
defer resp.Body.Close()
|
||||
checkResponse(t, "putting signed manifest with errors", resp, http.StatusBadRequest)
|
||||
_, p, counts = checkBodyHasErrorCodes(t, "putting signed manifest with errors", resp,
|
||||
v2.ErrorCodeManifestBlobUnknown, v2.ErrorCodeDigestInvalid)
|
||||
|
||||
expectedCounts = map[errcode.ErrorCode]int{
|
||||
v2.ErrorCodeManifestBlobUnknown: 2,
|
||||
v2.ErrorCodeDigestInvalid: 2,
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(counts, expectedCounts) {
|
||||
t.Fatalf("unexpected number of error codes encountered: %v\n!=\n%v\n---\n%s", counts, expectedCounts, string(p))
|
||||
}
|
||||
|
||||
// TODO(stevvooe): Add a test case where we take a mostly valid registry,
|
||||
// tamper with the content and ensure that we get an unverified manifest
|
||||
// error.
|
||||
|
||||
// Push 2 random layers
|
||||
expectedLayers := make(map[digest.Digest]io.ReadSeeker)
|
||||
|
||||
for i := range unsignedManifest.FSLayers {
|
||||
rs, dgst, err := testutil.CreateRandomTarFile()
|
||||
if err != nil {
|
||||
t.Fatalf("error creating random layer %d: %v", i, err)
|
||||
}
|
||||
|
||||
expectedLayers[dgst] = rs
|
||||
unsignedManifest.FSLayers[i].BlobSum = dgst
|
||||
|
||||
uploadURLBase, _ := startPushLayer(t, env, imageName)
|
||||
pushLayer(t, env.builder, imageName, dgst, uploadURLBase, rs)
|
||||
}
|
||||
|
||||
// -------------------
|
||||
// Push the signed manifest with all layers pushed.
|
||||
signedManifest, err := schema1.Sign(unsignedManifest, env.pk) //nolint:staticcheck // Ignore SA1019: "github.com/distribution/distribution/v3/manifest/schema1" is deprecated, as it's used for backward compatibility.
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error signing manifest: %v", err)
|
||||
}
|
||||
|
||||
dgst := digest.FromBytes(signedManifest.Canonical)
|
||||
args.manifest = signedManifest
|
||||
args.dgst = dgst
|
||||
|
||||
digestRef, _ := reference.WithDigest(imageName, dgst)
|
||||
manifestDigestURL, err := env.builder.BuildManifestURL(digestRef)
|
||||
checkErr(t, err, "building manifest url")
|
||||
|
||||
resp = putManifest(t, "putting signed manifest no error", manifestURL, "", signedManifest)
|
||||
checkResponse(t, "putting signed manifest no error", resp, http.StatusCreated)
|
||||
checkHeaders(t, resp, http.Header{
|
||||
"Location": []string{manifestDigestURL},
|
||||
"Docker-Content-Digest": []string{dgst.String()},
|
||||
})
|
||||
|
||||
// --------------------
|
||||
// Push by digest -- should get same result
|
||||
resp = putManifest(t, "putting signed manifest", manifestDigestURL, "", signedManifest)
|
||||
checkResponse(t, "putting signed manifest", resp, http.StatusCreated)
|
||||
checkHeaders(t, resp, http.Header{
|
||||
"Location": []string{manifestDigestURL},
|
||||
"Docker-Content-Digest": []string{dgst.String()},
|
||||
})
|
||||
|
||||
// ------------------
|
||||
// Fetch by tag name
|
||||
resp, err = http.Get(manifestURL)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error fetching manifest: %v", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
checkResponse(t, "fetching uploaded manifest", resp, http.StatusOK)
|
||||
checkHeaders(t, resp, http.Header{
|
||||
"Docker-Content-Digest": []string{dgst.String()},
|
||||
"ETag": []string{fmt.Sprintf(`"%s"`, dgst)},
|
||||
})
|
||||
|
||||
var fetchedManifest schema1.SignedManifest //nolint:staticcheck // Ignore SA1019: "github.com/distribution/distribution/v3/manifest/schema1" is deprecated, as it's used for backward compatibility.
|
||||
dec := json.NewDecoder(resp.Body)
|
||||
|
||||
if err := dec.Decode(&fetchedManifest); err != nil {
|
||||
t.Fatalf("error decoding fetched manifest: %v", err)
|
||||
}
|
||||
|
||||
if !bytes.Equal(fetchedManifest.Canonical, signedManifest.Canonical) {
|
||||
t.Fatalf("manifests do not match")
|
||||
}
|
||||
|
||||
// ---------------
|
||||
// Fetch by digest
|
||||
resp, err = http.Get(manifestDigestURL)
|
||||
checkErr(t, err, "fetching manifest by digest")
|
||||
defer resp.Body.Close()
|
||||
|
||||
checkResponse(t, "fetching uploaded manifest", resp, http.StatusOK)
|
||||
checkHeaders(t, resp, http.Header{
|
||||
"Docker-Content-Digest": []string{dgst.String()},
|
||||
"ETag": []string{fmt.Sprintf(`"%s"`, dgst)},
|
||||
})
|
||||
|
||||
var fetchedManifestByDigest schema1.SignedManifest //nolint:staticcheck // Ignore SA1019: "github.com/distribution/distribution/v3/manifest/schema1" is deprecated, as it's used for backward compatibility.
|
||||
dec = json.NewDecoder(resp.Body)
|
||||
if err := dec.Decode(&fetchedManifestByDigest); err != nil {
|
||||
t.Fatalf("error decoding fetched manifest: %v", err)
|
||||
}
|
||||
|
||||
if !bytes.Equal(fetchedManifestByDigest.Canonical, signedManifest.Canonical) {
|
||||
t.Fatalf("manifests do not match")
|
||||
}
|
||||
|
||||
// check signature was roundtripped
|
||||
signatures, err := fetchedManifestByDigest.Signatures() //nolint:staticcheck // Ignore SA1019: "github.com/distribution/distribution/v3/manifest/schema1" is deprecated, as it's used for backward compatibility.
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if len(signatures) != 1 {
|
||||
t.Fatalf("expected 1 signature from manifest, got: %d", len(signatures))
|
||||
}
|
||||
|
||||
// Re-sign, push and pull the same digest
|
||||
sm2, err := schema1.Sign(&fetchedManifestByDigest.Manifest, env.pk) //nolint:staticcheck // Ignore SA1019: "github.com/distribution/distribution/v3/manifest/schema1" is deprecated, as it's used for backward compatibility.
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Re-push with a few different Content-Types. The official schema1
|
||||
// content type should work, as should application/json with/without a
|
||||
// charset.
|
||||
resp = putManifest(t, "re-putting signed manifest", manifestDigestURL, schema1.MediaTypeSignedManifest, sm2) //nolint:staticcheck // Ignore SA1019: "github.com/distribution/distribution/v3/manifest/schema1" is deprecated, as it's used for backward compatibility.
|
||||
checkResponse(t, "re-putting signed manifest", resp, http.StatusCreated)
|
||||
resp = putManifest(t, "re-putting signed manifest", manifestDigestURL, "application/json", sm2)
|
||||
checkResponse(t, "re-putting signed manifest", resp, http.StatusCreated)
|
||||
resp = putManifest(t, "re-putting signed manifest", manifestDigestURL, "application/json", sm2)
|
||||
checkResponse(t, "re-putting signed manifest", resp, http.StatusCreated)
|
||||
|
||||
resp, err = http.Get(manifestDigestURL)
|
||||
checkErr(t, err, "re-fetching manifest by digest")
|
||||
defer resp.Body.Close()
|
||||
|
||||
checkResponse(t, "re-fetching uploaded manifest", resp, http.StatusOK)
|
||||
checkHeaders(t, resp, http.Header{
|
||||
"Docker-Content-Digest": []string{dgst.String()},
|
||||
"ETag": []string{fmt.Sprintf(`"%s"`, dgst)},
|
||||
})
|
||||
|
||||
dec = json.NewDecoder(resp.Body)
|
||||
if err := dec.Decode(&fetchedManifestByDigest); err != nil {
|
||||
t.Fatalf("error decoding fetched manifest: %v", err)
|
||||
}
|
||||
|
||||
// check only 1 signature is returned
|
||||
signatures, err = fetchedManifestByDigest.Signatures() //nolint:staticcheck // Ignore SA1019: "github.com/distribution/distribution/v3/manifest/schema1" is deprecated, as it's used for backward compatibility.
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if len(signatures) != 1 {
|
||||
t.Fatalf("expected 2 signature from manifest, got: %d", len(signatures))
|
||||
}
|
||||
|
||||
// Get by name with etag, gives 304
|
||||
etag := resp.Header.Get("Etag")
|
||||
req, err := http.NewRequest(http.MethodGet, manifestURL, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Error constructing request: %s", err)
|
||||
}
|
||||
req.Header.Set("If-None-Match", etag)
|
||||
resp, err = http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
t.Fatalf("Error constructing request: %s", err)
|
||||
}
|
||||
|
||||
checkResponse(t, "fetching manifest by name with etag", resp, http.StatusNotModified)
|
||||
|
||||
// Get by digest with etag, gives 304
|
||||
req, err = http.NewRequest(http.MethodGet, manifestDigestURL, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Error constructing request: %s", err)
|
||||
}
|
||||
req.Header.Set("If-None-Match", etag)
|
||||
resp, err = http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
t.Fatalf("Error constructing request: %s", err)
|
||||
}
|
||||
|
||||
checkResponse(t, "fetching manifest by dgst with etag", resp, http.StatusNotModified)
|
||||
|
||||
// Ensure that the tag is listed.
|
||||
resp, err = http.Get(tagsURL)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error getting unknown tags: %v", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
checkResponse(t, "getting tags", resp, http.StatusOK)
|
||||
dec = json.NewDecoder(resp.Body)
|
||||
|
||||
var tagsResponse tagsAPIResponse
|
||||
|
||||
if err := dec.Decode(&tagsResponse); err != nil {
|
||||
t.Fatalf("unexpected error decoding error response: %v", err)
|
||||
}
|
||||
|
||||
if tagsResponse.Name != imageName.Name() {
|
||||
t.Fatalf("tags name should match image name: %v != %v", tagsResponse.Name, imageName.Name())
|
||||
}
|
||||
|
||||
if len(tagsResponse.Tags) != 1 {
|
||||
t.Fatalf("expected some tags in response: %v", tagsResponse.Tags)
|
||||
}
|
||||
|
||||
if tagsResponse.Tags[0] != tag {
|
||||
t.Fatalf("tag not as expected: %q != %q", tagsResponse.Tags[0], tag)
|
||||
}
|
||||
|
||||
// Attempt to put a manifest with mismatching FSLayer and History array cardinalities
|
||||
|
||||
unsignedManifest.History = append(unsignedManifest.History, schema1.History{ //nolint:staticcheck // Ignore SA1019: "github.com/distribution/distribution/v3/manifest/schema1" is deprecated, as it's used for backward compatibility.
|
||||
V1Compatibility: "",
|
||||
})
|
||||
invalidSigned, err := schema1.Sign(unsignedManifest, env.pk) //nolint:staticcheck // Ignore SA1019: "github.com/distribution/distribution/v3/manifest/schema1" is deprecated, as it's used for backward compatibility.
|
||||
if err != nil {
|
||||
t.Fatalf("error signing manifest")
|
||||
}
|
||||
|
||||
resp = putManifest(t, "putting invalid signed manifest", manifestDigestURL, "", invalidSigned)
|
||||
checkResponse(t, "putting invalid signed manifest", resp, http.StatusBadRequest)
|
||||
|
||||
return args
|
||||
}
|
||||
|
||||
func testManifestAPISchema2(t *testing.T, env *testEnv, imageName reference.Named) manifestArgs {
|
||||
tag := "schema2tag"
|
||||
func testManifestAPISchema2(t *testing.T, env *testEnv, imageName reference.Named, tag string) manifestArgs {
|
||||
args := manifestArgs{
|
||||
imageName: imageName,
|
||||
mediaType: schema2.MediaTypeManifest,
|
||||
@@ -2101,63 +1778,6 @@ func testManifestAPISchema2(t *testing.T, env *testEnv, imageName reference.Name
|
||||
t.Fatalf("tag not as expected: %q != %q", tagsResponse.Tags[0], tag)
|
||||
}
|
||||
|
||||
// ------------------
|
||||
// Fetch as a schema1 manifest
|
||||
resp, err = http.Get(manifestURL)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error fetching manifest as schema1: %v", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
manifestBytes, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
t.Fatalf("error reading response body: %v", err)
|
||||
}
|
||||
|
||||
checkResponse(t, "fetching uploaded manifest as schema1", resp, http.StatusOK)
|
||||
|
||||
m, desc, err := distribution.UnmarshalManifest(schema1.MediaTypeManifest, manifestBytes) //nolint:staticcheck // Ignore SA1019: "github.com/distribution/distribution/v3/manifest/schema1" is deprecated, as it's used for backward compatibility.
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error unmarshalling manifest: %v", err)
|
||||
}
|
||||
|
||||
fetchedSchema1Manifest, ok := m.(*schema1.SignedManifest) //nolint:staticcheck // Ignore SA1019: "github.com/distribution/distribution/v3/manifest/schema1" is deprecated, as it's used for backward compatibility.
|
||||
if !ok {
|
||||
t.Fatalf("expecting schema1 manifest")
|
||||
}
|
||||
|
||||
checkHeaders(t, resp, http.Header{
|
||||
"Docker-Content-Digest": []string{desc.Digest.String()},
|
||||
"ETag": []string{fmt.Sprintf(`"%s"`, desc.Digest)},
|
||||
})
|
||||
|
||||
if fetchedSchema1Manifest.Manifest.SchemaVersion != 1 {
|
||||
t.Fatal("wrong schema version")
|
||||
}
|
||||
if fetchedSchema1Manifest.Architecture != "amd64" {
|
||||
t.Fatal("wrong architecture")
|
||||
}
|
||||
if fetchedSchema1Manifest.Name != imageName.Name() {
|
||||
t.Fatal("wrong image name")
|
||||
}
|
||||
if fetchedSchema1Manifest.Tag != tag {
|
||||
t.Fatal("wrong tag")
|
||||
}
|
||||
if len(fetchedSchema1Manifest.FSLayers) != 2 {
|
||||
t.Fatal("wrong number of FSLayers")
|
||||
}
|
||||
for i := range manifest.Layers {
|
||||
if fetchedSchema1Manifest.FSLayers[i].BlobSum != manifest.Layers[len(manifest.Layers)-i-1].Digest {
|
||||
t.Fatalf("blob digest mismatch in schema1 manifest for layer %d", i)
|
||||
}
|
||||
}
|
||||
if len(fetchedSchema1Manifest.History) != 2 {
|
||||
t.Fatal("wrong number of History entries")
|
||||
}
|
||||
|
||||
// Don't check V1Compatibility fields because we're using randomly-generated
|
||||
// layers.
|
||||
|
||||
return args
|
||||
}
|
||||
|
||||
@@ -2246,7 +1866,7 @@ func testManifestAPIManifestList(t *testing.T, env *testEnv, args manifestArgs)
|
||||
t.Fatalf("Error constructing request: %s", err)
|
||||
}
|
||||
// multiple headers in mixed list format to ensure we parse correctly server-side
|
||||
req.Header.Set("Accept", fmt.Sprintf(` %s ; q=0.8 , %s ; q=0.5 `, manifestlist.MediaTypeManifestList, schema1.MediaTypeSignedManifest)) //nolint:staticcheck // Ignore SA1019: "github.com/distribution/distribution/v3/manifest/schema1" is deprecated, as it's used for backward compatibility.
|
||||
req.Header.Set("Accept", fmt.Sprintf(` %s ; q=0.8 `, manifestlist.MediaTypeManifestList))
|
||||
req.Header.Add("Accept", schema2.MediaTypeManifest)
|
||||
resp, err = http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
@@ -2334,64 +1954,6 @@ func testManifestAPIManifestList(t *testing.T, env *testEnv, args manifestArgs)
|
||||
}
|
||||
|
||||
checkResponse(t, "fetching manifest by dgst with etag", resp, http.StatusNotModified)
|
||||
|
||||
// ------------------
|
||||
// Fetch as a schema1 manifest
|
||||
resp, err = http.Get(manifestURL)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error fetching manifest list as schema1: %v", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
manifestBytes, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
t.Fatalf("error reading response body: %v", err)
|
||||
}
|
||||
|
||||
checkResponse(t, "fetching uploaded manifest list as schema1", resp, http.StatusOK)
|
||||
|
||||
m, desc, err := distribution.UnmarshalManifest(schema1.MediaTypeManifest, manifestBytes) //nolint:staticcheck // Ignore SA1019: "github.com/distribution/distribution/v3/manifest/schema1" is deprecated, as it's used for backward compatibility.
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error unmarshalling manifest: %v", err)
|
||||
}
|
||||
|
||||
fetchedSchema1Manifest, ok := m.(*schema1.SignedManifest) //nolint:staticcheck // Ignore SA1019: "github.com/distribution/distribution/v3/manifest/schema1" is deprecated, as it's used for backward compatibility.
|
||||
if !ok {
|
||||
t.Fatalf("expecting schema1 manifest")
|
||||
}
|
||||
|
||||
checkHeaders(t, resp, http.Header{
|
||||
"Docker-Content-Digest": []string{desc.Digest.String()},
|
||||
"ETag": []string{fmt.Sprintf(`"%s"`, desc.Digest)},
|
||||
})
|
||||
|
||||
if fetchedSchema1Manifest.Manifest.SchemaVersion != 1 {
|
||||
t.Fatal("wrong schema version")
|
||||
}
|
||||
if fetchedSchema1Manifest.Architecture != "amd64" {
|
||||
t.Fatal("wrong architecture")
|
||||
}
|
||||
if fetchedSchema1Manifest.Name != imageName.Name() {
|
||||
t.Fatal("wrong image name")
|
||||
}
|
||||
if fetchedSchema1Manifest.Tag != tag {
|
||||
t.Fatal("wrong tag")
|
||||
}
|
||||
if len(fetchedSchema1Manifest.FSLayers) != 2 {
|
||||
t.Fatal("wrong number of FSLayers")
|
||||
}
|
||||
layers := args.manifest.(*schema2.DeserializedManifest).Layers
|
||||
for i := range layers {
|
||||
if fetchedSchema1Manifest.FSLayers[i].BlobSum != layers[len(layers)-i-1].Digest {
|
||||
t.Fatalf("blob digest mismatch in schema1 manifest for layer %d", i)
|
||||
}
|
||||
}
|
||||
if len(fetchedSchema1Manifest.History) != 2 {
|
||||
t.Fatal("wrong number of History entries")
|
||||
}
|
||||
|
||||
// Don't check V1Compatibility fields because we're using randomly-generated
|
||||
// layers.
|
||||
}
|
||||
|
||||
func testManifestDelete(t *testing.T, env *testEnv, args manifestArgs) {
|
||||
@@ -2556,7 +2118,6 @@ func newTestEnvMirror(t *testing.T, deleteEnabled bool) *testEnv {
|
||||
MaxEntries: 5,
|
||||
},
|
||||
}
|
||||
config.Compatibility.Schema1.Enabled = true //nolint:staticcheck // Ignore SA1019: "github.com/distribution/distribution/v3/manifest/schema1" is deprecated, as it's used for backward compatibility.
|
||||
|
||||
return newTestEnvWithConfig(t, &config)
|
||||
}
|
||||
@@ -2575,7 +2136,6 @@ func newTestEnv(t *testing.T, deleteEnabled bool) *testEnv {
|
||||
},
|
||||
}
|
||||
|
||||
config.Compatibility.Schema1.Enabled = true //nolint:staticcheck // Ignore SA1019: "github.com/distribution/distribution/v3/manifest/schema1" is deprecated, as it's used for backward compatibility.
|
||||
config.HTTP.Headers = headerConfig
|
||||
|
||||
return newTestEnvWithConfig(t, &config)
|
||||
@@ -2615,12 +2175,6 @@ func putManifest(t *testing.T, msg, url, contentType string, v interface{}) *htt
|
||||
var body []byte
|
||||
|
||||
switch m := v.(type) {
|
||||
case *schema1.SignedManifest: //nolint:staticcheck // Ignore SA1019: "github.com/distribution/distribution/v3/manifest/schema1" is deprecated, as it's used for backward compatibility.
|
||||
_, pl, err := m.Payload() //nolint:staticcheck // Ignore SA1019: "github.com/distribution/distribution/v3/manifest/schema1" is deprecated, as it's used for backward compatibility.
|
||||
if err != nil {
|
||||
t.Fatalf("error getting payload: %v", err)
|
||||
}
|
||||
body = pl
|
||||
case *manifestlist.DeserializedManifestList:
|
||||
_, pl, err := m.Payload()
|
||||
if err != nil {
|
||||
@@ -2968,61 +2522,89 @@ func createRepository(env *testEnv, t *testing.T, imageName string, tag string)
|
||||
t.Fatalf("unable to parse reference: %v", err)
|
||||
}
|
||||
|
||||
unsignedManifest := &schema1.Manifest{ //nolint:staticcheck // Ignore SA1019: "github.com/distribution/distribution/v3/manifest/schema1" is deprecated, as it's used for backward compatibility.
|
||||
tagRef, _ := reference.WithTag(imageNameRef, tag)
|
||||
manifestURL, err := env.builder.BuildManifestURL(tagRef)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error getting manifest url: %v", err)
|
||||
}
|
||||
|
||||
manifest := &schema2.Manifest{
|
||||
Versioned: manifest.Versioned{
|
||||
SchemaVersion: 1,
|
||||
SchemaVersion: 2,
|
||||
MediaType: schema2.MediaTypeManifest,
|
||||
},
|
||||
Name: imageName,
|
||||
Tag: tag,
|
||||
FSLayers: []schema1.FSLayer{ //nolint:staticcheck // Ignore SA1019: "github.com/distribution/distribution/v3/manifest/schema1" is deprecated, as it's used for backward compatibility.
|
||||
{
|
||||
BlobSum: "asdf",
|
||||
},
|
||||
Config: distribution.Descriptor{
|
||||
Digest: "sha256:1a9ec845ee94c202b2d5da74a24f0ed2058318bfa9879fa541efaecba272e86b",
|
||||
Size: 3253,
|
||||
MediaType: schema2.MediaTypeImageConfig,
|
||||
},
|
||||
History: []schema1.History{ //nolint:staticcheck // Ignore SA1019: "github.com/distribution/distribution/v3/manifest/schema1" is deprecated, as it's used for backward compatibility.
|
||||
Layers: []distribution.Descriptor{
|
||||
{
|
||||
V1Compatibility: "",
|
||||
Digest: "sha256:463434349086340864309863409683460843608348608934092322395278926a",
|
||||
Size: 6323,
|
||||
MediaType: schema2.MediaTypeLayer,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// Push 2 random layers
|
||||
expectedLayers := make(map[digest.Digest]io.ReadSeeker)
|
||||
// Push a config, and reference it in the manifest
|
||||
sampleConfig := []byte(`{
|
||||
"architecture": "amd64",
|
||||
"history": [
|
||||
{
|
||||
"created": "2015-10-31T22:22:54.690851953Z",
|
||||
"created_by": "/bin/sh -c #(nop) ADD file:a3bc1e842b69636f9df5256c49c5374fb4eef1e281fe3f282c65fb853ee171c5 in /"
|
||||
},
|
||||
],
|
||||
"rootfs": {
|
||||
"diff_ids": [
|
||||
"sha256:c6f988f4874bb0add23a778f753c65efe992244e148a1d2ec2a8b664fb66bbd1",
|
||||
],
|
||||
"type": "layers"
|
||||
}
|
||||
}`)
|
||||
sampleConfigDigest := digest.FromBytes(sampleConfig)
|
||||
|
||||
for i := range unsignedManifest.FSLayers {
|
||||
uploadURLBase, _ := startPushLayer(t, env, imageNameRef)
|
||||
pushLayer(t, env.builder, imageNameRef, sampleConfigDigest, uploadURLBase, bytes.NewReader(sampleConfig))
|
||||
manifest.Config.Digest = sampleConfigDigest
|
||||
manifest.Config.Size = int64(len(sampleConfig))
|
||||
|
||||
// Push random layers
|
||||
|
||||
for i := range manifest.Layers {
|
||||
rs, dgst, err := testutil.CreateRandomTarFile()
|
||||
if err != nil {
|
||||
t.Fatalf("error creating random layer %d: %v", i, err)
|
||||
}
|
||||
manifest.Layers[i].Digest = dgst
|
||||
|
||||
expectedLayers[dgst] = rs
|
||||
unsignedManifest.FSLayers[i].BlobSum = dgst
|
||||
uploadURLBase, _ := startPushLayer(t, env, imageNameRef)
|
||||
pushLayer(t, env.builder, imageNameRef, dgst, uploadURLBase, rs)
|
||||
}
|
||||
|
||||
signedManifest, err := schema1.Sign(unsignedManifest, env.pk) //nolint:staticcheck // Ignore SA1019: "github.com/distribution/distribution/v3/manifest/schema1" is deprecated, as it's used for backward compatibility.
|
||||
// -------------------
|
||||
// Push the manifest with all layers pushed.
|
||||
deserializedManifest, err := schema2.FromStruct(*manifest)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error signing manifest: %v", err)
|
||||
t.Fatalf("could not create DeserializedManifest: %v", err)
|
||||
}
|
||||
|
||||
dgst := digest.FromBytes(signedManifest.Canonical)
|
||||
|
||||
// Create this repository by tag to ensure the tag mapping is made in the registry
|
||||
tagRef, _ := reference.WithTag(imageNameRef, tag)
|
||||
manifestDigestURL, err := env.builder.BuildManifestURL(tagRef)
|
||||
_, canonical, err := deserializedManifest.Payload()
|
||||
if err != nil {
|
||||
t.Fatalf("could not get manifest payload: %v", err)
|
||||
}
|
||||
dgst := digest.FromBytes(canonical)
|
||||
digestRef, _ := reference.WithDigest(imageNameRef, dgst)
|
||||
manifestDigestURL, err := env.builder.BuildManifestURL(digestRef)
|
||||
checkErr(t, err, "building manifest url")
|
||||
|
||||
digestRef, _ := reference.WithDigest(imageNameRef, dgst)
|
||||
location, err := env.builder.BuildManifestURL(digestRef)
|
||||
checkErr(t, err, "building location URL")
|
||||
|
||||
resp := putManifest(t, "putting signed manifest", manifestDigestURL, "", signedManifest)
|
||||
checkResponse(t, "putting signed manifest", resp, http.StatusCreated)
|
||||
resp := putManifest(t, "putting manifest no error", manifestURL, schema2.MediaTypeManifest, manifest)
|
||||
checkResponse(t, "putting manifest no error", resp, http.StatusCreated)
|
||||
checkHeaders(t, resp, http.Header{
|
||||
"Location": []string{location},
|
||||
"Location": []string{manifestDigestURL},
|
||||
"Docker-Content-Digest": []string{dgst.String()},
|
||||
})
|
||||
|
||||
return dgst
|
||||
}
|
||||
|
||||
@@ -3042,27 +2624,36 @@ func TestRegistryAsCacheMutationAPIs(t *testing.T) {
|
||||
}
|
||||
|
||||
// Manifest upload
|
||||
m := &schema1.Manifest{ //nolint:staticcheck // Ignore SA1019: "github.com/distribution/distribution/v3/manifest/schema1" is deprecated, as it's used for backward compatibility.
|
||||
manifest := &schema2.Manifest{
|
||||
Versioned: manifest.Versioned{
|
||||
SchemaVersion: 1,
|
||||
SchemaVersion: 2,
|
||||
MediaType: schema2.MediaTypeManifest,
|
||||
},
|
||||
Config: distribution.Descriptor{
|
||||
Digest: "sha256:1a9ec845ee94c202b2d5da74a24f0ed2058318bfa9879fa541efaecba272e86b",
|
||||
Size: 3253,
|
||||
MediaType: schema2.MediaTypeImageConfig,
|
||||
},
|
||||
Layers: []distribution.Descriptor{
|
||||
{
|
||||
Digest: "sha256:463434349086340864309863409683460843608348608934092322395278926a",
|
||||
Size: 6323,
|
||||
MediaType: schema2.MediaTypeLayer,
|
||||
},
|
||||
{
|
||||
Digest: "sha256:630923423623623423352523525237238023652897356239852383652aaaaaaa",
|
||||
Size: 6863,
|
||||
MediaType: schema2.MediaTypeLayer,
|
||||
},
|
||||
},
|
||||
Name: imageName.Name(),
|
||||
Tag: tag,
|
||||
FSLayers: []schema1.FSLayer{}, //nolint:staticcheck // Ignore SA1019: "github.com/distribution/distribution/v3/manifest/schema1" is deprecated, as it's used for backward compatibility.
|
||||
History: []schema1.History{}, //nolint:staticcheck // Ignore SA1019: "github.com/distribution/distribution/v3/manifest/schema1" is deprecated, as it's used for backward compatibility.
|
||||
}
|
||||
|
||||
sm, err := schema1.Sign(m, env.pk) //nolint:staticcheck // Ignore SA1019: "github.com/distribution/distribution/v3/manifest/schema1" is deprecated, as it's used for backward compatibility.
|
||||
if err != nil {
|
||||
t.Fatalf("error signing manifest: %v", err)
|
||||
}
|
||||
|
||||
resp := putManifest(t, "putting unsigned manifest", manifestURL, "", sm)
|
||||
checkResponse(t, "putting signed manifest to cache", resp, errcode.ErrorCodeUnsupported.Descriptor().HTTPStatusCode)
|
||||
resp := putManifest(t, "putting missing config manifest", manifestURL, schema2.MediaTypeManifest, manifest)
|
||||
checkResponse(t, "putting missing config manifest", resp, errcode.ErrorCodeUnsupported.Descriptor().HTTPStatusCode)
|
||||
|
||||
// Manifest Delete
|
||||
resp, _ = httpDelete(manifestURL)
|
||||
checkResponse(t, "deleting signed manifest from cache", resp, errcode.ErrorCodeUnsupported.Descriptor().HTTPStatusCode)
|
||||
checkResponse(t, "deleting config manifest from cache", resp, errcode.ErrorCodeUnsupported.Descriptor().HTTPStatusCode)
|
||||
|
||||
// Blob upload initialization
|
||||
layerUploadURL, err := env.builder.BuildBlobUploadURL(imageName)
|
||||
@@ -3094,7 +2685,6 @@ func TestProxyManifestGetByTag(t *testing.T) {
|
||||
}},
|
||||
},
|
||||
}
|
||||
truthConfig.Compatibility.Schema1.Enabled = true //nolint:staticcheck // Ignore SA1019: "github.com/distribution/distribution/v3/manifest/schema1" is deprecated, as it's used for backward compatibility.
|
||||
truthConfig.HTTP.Headers = headerConfig
|
||||
|
||||
imageName, _ := reference.WithName("foo/bar")
|
||||
@@ -3113,7 +2703,6 @@ func TestProxyManifestGetByTag(t *testing.T) {
|
||||
RemoteURL: truthEnv.server.URL,
|
||||
},
|
||||
}
|
||||
proxyConfig.Compatibility.Schema1.Enabled = true //nolint:staticcheck // Ignore SA1019: "github.com/distribution/distribution/v3/manifest/schema1" is deprecated, as it's used for backward compatibility.
|
||||
proxyConfig.HTTP.Headers = headerConfig
|
||||
|
||||
proxyEnv := newTestEnvWithConfig(t, &proxyConfig)
|
||||
|
Reference in New Issue
Block a user