diff --git a/conformance/03_discovery_test.go b/conformance/03_discovery_test.go index 90af746d..c0ab1932 100644 --- a/conformance/03_discovery_test.go +++ b/conformance/03_discovery_test.go @@ -237,6 +237,18 @@ var test03ContentDiscovery = func() { BeNumerically(">=", 200), BeNumerically("<", 300))) Expect(resp.Header().Get("OCI-Subject")).To(Equal(manifests[4].Digest)) + + // Populate registry with test references manifest to a non-existent subject + req = client.NewRequest(reggie.PUT, "/v2//manifests/", + reggie.WithReference(refsManifestCLayerArtifactDigest)). + SetHeader("Content-Type", "application/vnd.oci.image.manifest.v1+json"). + SetBody(refsManifestCLayerArtifactContent) + resp, err = client.Do(req) + Expect(err).To(BeNil()) + Expect(resp.StatusCode()).To(SatisfyAll( + BeNumerically(">=", 200), + BeNumerically("<", 300))) + Expect(resp.Header().Get("OCI-Subject")).To(Equal(manifests[3].Digest)) }) }) @@ -351,6 +363,22 @@ var test03ContentDiscovery = func() { Warn("filtering by artifact-type is not implemented") } }) + + g.Specify("GET request to missing manifest should yield 200", func() { + SkipIfDisabled(contentDiscovery) + req := client.NewRequest(reggie.GET, "/v2//referrers/", + reggie.WithDigest(manifests[3].Digest)) + resp, err := client.Do(req) + Expect(err).To(BeNil()) + Expect(resp.StatusCode()).To(Equal(http.StatusOK)) + Expect(resp.Header().Get("Content-Type")).To(Equal("application/vnd.oci.image.index.v1+json")) + + var index index + err = json.Unmarshal(resp.Body(), &index) + Expect(err).To(BeNil()) + Expect(len(index.Manifests)).To(Equal(1)) + Expect(index.Manifests[0].Digest.String()).To(Equal(refsManifestCLayerArtifactDigest)) + }) }) g.Context("Teardown", func() { @@ -367,6 +395,7 @@ var test03ContentDiscovery = func() { testTagName, refsManifestBConfigArtifactDigest, refsManifestBLayerArtifactDigest, + refsManifestCLayerArtifactDigest, } for _, ref := range references { req := client.NewRequest(reggie.DELETE, "/v2//manifests/", reggie.WithDigest(ref)) @@ -427,6 +456,7 @@ var test03ContentDiscovery = func() { testTagName, refsManifestBConfigArtifactDigest, refsManifestBLayerArtifactDigest, + refsManifestCLayerArtifactDigest, } for _, ref := range references { req := client.NewRequest(reggie.DELETE, "/v2//manifests/", reggie.WithDigest(ref)) diff --git a/conformance/setup.go b/conformance/setup.go index c1e166b0..50ff4c81 100644 --- a/conformance/setup.go +++ b/conformance/setup.go @@ -149,6 +149,8 @@ var ( refsManifestBConfigArtifactDigest string refsManifestBLayerArtifactContent []byte refsManifestBLayerArtifactDigest string + refsManifestCLayerArtifactContent []byte + refsManifestCLayerArtifactDigest string refsIndexArtifactContent []byte refsIndexArtifactDigest string reportJUnitFilename string @@ -461,6 +463,33 @@ func init() { refsManifestBLayerArtifactDigest = godigest.FromBytes(refsManifestBLayerArtifactContent).String() testAnnotationValues[refsManifestBLayerArtifactDigest] = refsManifestBLayerArtifact.Annotations[testAnnotationKey] + // ManifestCLayerArtifact is the same as B but based on a subject that has not been pushed + refsManifestCLayerArtifact := manifest{ + SchemaVersion: 2, + MediaType: "application/vnd.oci.image.manifest.v1+json", + ArtifactType: testRefArtifactTypeB, + Config: emptyJSONDescriptor, + Subject: &descriptor{ + MediaType: "application/vnd.oci.image.manifest.v1+json", + Size: int64(len(manifests[3].Content)), + Digest: godigest.FromBytes(manifests[3].Content), + }, + Layers: []descriptor{ + { + MediaType: testRefArtifactTypeB, + Size: int64(len(testRefBlobB)), + Digest: godigest.FromBytes(testRefBlobB), + }, + }, + } + + refsManifestCLayerArtifactContent, err = json.MarshalIndent(&refsManifestCLayerArtifact, "", "\t") + if err != nil { + log.Fatal(err) + } + + refsManifestCLayerArtifactDigest = godigest.FromBytes(refsManifestCLayerArtifactContent).String() + testRefArtifactTypeIndex = "application/vnd.food.stand" refsIndexArtifact := index{ SchemaVersion: 2, diff --git a/spec.md b/spec.md index e69dc4dc..a286e221 100644 --- a/spec.md +++ b/spec.md @@ -567,8 +567,6 @@ If the `artifactType` is empty or missing in the image manifest, the value of `a If the `artifactType` is empty or missing in an index, the `artifactType` MUST be omitted. The descriptors MUST include annotations from the image manifest or index. If a query results in no matching referrers, an empty manifest list MUST be returned. -If a manifest with the digest `` does not exist, a registry MAY return an empty manifest list. -After a manifest with the digest `` is pushed, the registry MUST include previously pushed entries in the referrers list. ```json {