Repository: kubernetes-sigs/security-profiles-operator
Pull request #2094 (2024-01-30 23:33:47)

build(deps): bump codecov/codecov-action from 3.1.5 to 3.1.6
Bumps [codecov/codecov-action](https://github.com/codecov/codecov-action) from 3.1.5 to 3.1.6.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a href="https://github.com/codecov/codecov-action/releases">codecov/codecov-action's releases</a>.</em></p>
<blockquote>
<h2>v3.1.6</h2>
<p><strong>Full Changelog</strong>: <a href="https://github.com/codecov/codecov-action/compare/v3.1.5...v3.1.6">https://github.com/codecov/codecov-action/compare/v3.1.5...v3.1.6</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a href="https://github.com/codecov/codecov-action/commit/ab904c41d6ece82784817410c45d8b8c02684457"><code>ab904c4</code></a> chore(release): bump to 3.1.6</li>
<li><a href="https://github.com/codecov/codecov-action/commit/a8c374ae465f56cbb2da206950e903ad74b01bff"><code>a8c374a</code></a> Revert &quot;action.yml: Update to Node.js 20 (<a href="https://redirect.github.com/codecov/codecov-action/issues/1228">#1228</a>)&quot;</li>
<li>See full diff in <a href="https://github.com/codecov/codecov-action/compare/4fe8c5f003fae66aa5ebb77cfd3e7bfbbda0b6b0...ab904c41d6ece82784817410c45d8b8c02684457">compare view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=codecov/codecov-action&package-manager=github_actions&previous-version=3.1.5&new-version=3.1.6)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)


</details>

k8s-ci-robot: [APPROVALNOTIFIER] This PR is **NOT APPROVED**

This pull-request has been approved by: *<a href="https://github.com/kubernetes-sigs/security-profiles-operator/pull/2094#" title="Author self-approved">dependabot[bot]</a>*
**Once this PR has been reviewed and has the lgtm label**, please assign [saschagrunert](https://github.com/saschagrunert) for approval. For more information see [the Kubernetes Code Review Process](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process).

The full list of commands accepted by this bot can be found [here](https://go.k8s.io/bot-commands?repo=kubernetes-sigs%2Fsecurity-profiles-operator).

<details open>
Needs approval from an approver in each of these files:

- **[OWNERS](https://github.com/kubernetes-sigs/security-profiles-operator/blob/main/OWNERS)**

Approvers can indicate their approval by writing `/approve` in a comment
Approvers can cancel approval by writing `/approve cancel` in a comment
</details>
<!-- META={"approvers":["saschagrunert"]} -->
k8s-ci-robot: Hi @dependabot[bot]. Thanks for your PR.

I'm waiting for a [kubernetes-sigs](https://github.com/orgs/kubernetes-sigs/people) member to verify that this patch is reasonable to test. If it is, they should reply with `/ok-to-test` on its own line. Until that is done, I will not automatically test new commits in this PR, but the usual testing commands by org members will still work. Regular contributors should [join the org](https://git.k8s.io/community/community-membership.md#member) to skip this step.

Once the patch is verified, the new status will be reflected by the `ok-to-test` label.

I understand the commands that are listed [here](https://go.k8s.io/bot-commands?repo=kubernetes-sigs%2Fsecurity-profiles-operator).

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository.
</details>

codecov-commenter: ## [Codecov](https://app.codecov.io/gh/kubernetes-sigs/security-profiles-operator/pull/2094?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kubernetes-sigs) Report
> Merging [#2094](https://app.codecov.io/gh/kubernetes-sigs/security-profiles-operator/pull/2094?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kubernetes-sigs) (1e41a66) into [main](https://app.codecov.io/gh/kubernetes-sigs/security-profiles-operator/commit/57d38f9aaac4a59bfb6f83ef2ebfecba7907c984?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kubernetes-sigs) (57d38f9) will **not change** coverage.
> The diff coverage is `n/a`.

<details><summary>Additional details and impacted files</summary>


```diff
@@           Coverage Diff           @@
##             main    #2094   +/-   ##
=======================================
  Coverage   45.50%   45.50%           
=======================================
  Files          79       79           
  Lines        7782     7782           
=======================================
  Hits         3541     3541           
  Misses       4099     4099           
  Partials      142      142           
```

</details>
k8s-ci-robot: [APPROVALNOTIFIER] This PR is **APPROVED**

This pull-request has been approved by: *<a href="https://github.com/kubernetes-sigs/security-profiles-operator/pull/2094#" title="Author self-approved">dependabot[bot]</a>*, *<a href="https://github.com/kubernetes-sigs/security-profiles-operator/pull/2094#pullrequestreview-1852853508" title="Approved">JAORMX</a>*

The full list of commands accepted by this bot can be found [here](https://go.k8s.io/bot-commands?repo=kubernetes-sigs%2Fsecurity-profiles-operator).

The pull request process is described [here](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process)

<details >
Needs approval from an approver in each of these files:

- ~~[OWNERS](https://github.com/kubernetes-sigs/security-profiles-operator/blob/main/OWNERS)~~ [JAORMX]

Approvers can indicate their approval by writing `/approve` in a comment
Approvers can cancel approval by writing `/approve cancel` in a comment
</details>
<!-- META={"approvers":[]} -->

Patch:
diff --git a/go.mod b/go.mod
index c1541f0bf..959974651 100644
--- a/go.mod
+++ b/go.mod
@@ -16,7 +16,7 @@ require (
 	github.com/maxbrunsfeld/counterfeiter/v6 v6.8.1
 	github.com/mogensen/kubernetes-split-yaml v0.4.0
 	github.com/nxadm/tail v1.4.11
-	github.com/opencontainers/image-spec v1.1.0-rc5
+	github.com/opencontainers/image-spec v1.1.0-rc6
 	github.com/opencontainers/runc v1.1.11
 	github.com/opencontainers/runtime-spec v1.1.0
 	github.com/openshift/api v0.0.0-20221205111557-f2fbb1d1cd5e
@@ -39,7 +39,7 @@ require (
 	k8s.io/cli-runtime v0.29.1
 	k8s.io/client-go v0.29.1
 	k8s.io/klog/v2 v2.120.1
-	oras.land/oras-go/v2 v2.3.1
+	oras.land/oras-go/v2 v2.4.0
 	sigs.k8s.io/controller-runtime v0.17.0
 	sigs.k8s.io/controller-tools v0.14.0
 	sigs.k8s.io/mdtoc v1.1.0
diff --git a/go.sum b/go.sum
index f13ffd6f8..ac784a271 100644
--- a/go.sum
+++ b/go.sum
@@ -666,8 +666,8 @@ github.com/open-policy-agent/opa v0.59.0 h1:1WFU/KUhJAr3qatm0Lf8Ea5jp10ZmlE2M07o
 github.com/open-policy-agent/opa v0.59.0/go.mod h1:rdJSkEc4oQ+0074/3Fsgno5bkPsYxTjU5aLNmMujIvI=
 github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
 github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
-github.com/opencontainers/image-spec v1.1.0-rc5 h1:Ygwkfw9bpDvs+c9E34SdgGOj41dX/cbdlwvlWt0pnFI=
-github.com/opencontainers/image-spec v1.1.0-rc5/go.mod h1:X4pATf0uXsnn3g5aiGIsVnJBR4mxhKzfwmvK/B2NTm8=
+github.com/opencontainers/image-spec v1.1.0-rc6 h1:XDqvyKsJEbRtATzkgItUqBA7QHk58yxX1Ov9HERHNqU=
+github.com/opencontainers/image-spec v1.1.0-rc6/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM=
 github.com/opencontainers/runc v1.1.11 h1:9LjxyVlE0BPMRP2wuQDRlHV4941Jp9rc3F0+YKimopA=
 github.com/opencontainers/runc v1.1.11/go.mod h1:S+lQwSfncpBha7XTy/5lBwWgm5+y5Ma/O44Ekby9FK8=
 github.com/opencontainers/runtime-spec v1.1.0 h1:HHUyrt9mwHUjtasSbXSMvs4cyFxh+Bll4AjJ9odEGpg=
@@ -1334,8 +1334,8 @@ k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 h1:aVUu9fTY98ivBPKR9Y5w/A
 k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00/go.mod h1:AsvuZPBlUDVuCdzJ87iajxtXuR9oktsTctW/R9wwouA=
 k8s.io/utils v0.0.0-20231127182322-b307cd553661 h1:FepOBzJ0GXm8t0su67ln2wAZjbQ6RxQGZDnzuLcrUTI=
 k8s.io/utils v0.0.0-20231127182322-b307cd553661/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
-oras.land/oras-go/v2 v2.3.1 h1:lUC6q8RkeRReANEERLfH86iwGn55lbSWP20egdFHVec=
-oras.land/oras-go/v2 v2.3.1/go.mod h1:5AQXVEu1X/FKp1F9DMOb5ZItZBOa0y5dha0yCm4NR9c=
+oras.land/oras-go/v2 v2.4.0 h1:i+Wt5oCaMHu99guBD0yuBjdLvX7Lz8ukPbwXdR7uBMs=
+oras.land/oras-go/v2 v2.4.0/go.mod h1:osvtg0/ClRq1KkydMAEu/IxFieyjItcsQ4ut4PPF+f8=
 rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
 rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
 rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
diff --git a/vendor/github.com/opencontainers/image-spec/specs-go/v1/mediatype.go b/vendor/github.com/opencontainers/image-spec/specs-go/v1/mediatype.go
index 892ba3de9..ce8313e79 100644
--- a/vendor/github.com/opencontainers/image-spec/specs-go/v1/mediatype.go
+++ b/vendor/github.com/opencontainers/image-spec/specs-go/v1/mediatype.go
@@ -21,12 +21,20 @@ const (
 	// MediaTypeLayoutHeader specifies the media type for the oci-layout.
 	MediaTypeLayoutHeader = "application/vnd.oci.layout.header.v1+json"
 
+	// MediaTypeImageIndex specifies the media type for an image index.
+	MediaTypeImageIndex = "application/vnd.oci.image.index.v1+json"
+
 	// MediaTypeImageManifest specifies the media type for an image manifest.
 	MediaTypeImageManifest = "application/vnd.oci.image.manifest.v1+json"
 
-	// MediaTypeImageIndex specifies the media type for an image index.
-	MediaTypeImageIndex = "application/vnd.oci.image.index.v1+json"
+	// MediaTypeImageConfig specifies the media type for the image configuration.
+	MediaTypeImageConfig = "application/vnd.oci.image.config.v1+json"
+
+	// MediaTypeEmptyJSON specifies the media type for an unused blob containing the value "{}".
+	MediaTypeEmptyJSON = "application/vnd.oci.empty.v1+json"
+)
 
+const (
 	// MediaTypeImageLayer is the media type used for layers referenced by the manifest.
 	MediaTypeImageLayer = "application/vnd.oci.image.layer.v1.tar"
 
@@ -37,7 +45,15 @@ const (
 	// MediaTypeImageLayerZstd is the media type used for zstd compressed
 	// layers referenced by the manifest.
 	MediaTypeImageLayerZstd = "application/vnd.oci.image.layer.v1.tar+zstd"
+)
 
+// Non-distributable layer media-types.
+//
+// Deprecated: Non-distributable layers are deprecated, and not recommended
+// for future use. Implementations SHOULD NOT produce new non-distributable
+// layers.
+// https://github.com/opencontainers/image-spec/pull/965
+const (
 	// MediaTypeImageLayerNonDistributable is the media type for layers referenced by
 	// the manifest but with distribution restrictions.
 	//
@@ -66,10 +82,4 @@ const (
 	// layers.
 	// https://github.com/opencontainers/image-spec/pull/965
 	MediaTypeImageLayerNonDistributableZstd = "application/vnd.oci.image.layer.nondistributable.v1.tar+zstd"
-
-	// MediaTypeImageConfig specifies the media type for the image configuration.
-	MediaTypeImageConfig = "application/vnd.oci.image.config.v1+json"
-
-	// MediaTypeEmptyJSON specifies the media type for an unused blob containing the value `{}`
-	MediaTypeEmptyJSON = "application/vnd.oci.empty.v1+json"
 )
diff --git a/vendor/github.com/opencontainers/image-spec/specs-go/version.go b/vendor/github.com/opencontainers/image-spec/specs-go/version.go
index 11e09b584..6d01f6e71 100644
--- a/vendor/github.com/opencontainers/image-spec/specs-go/version.go
+++ b/vendor/github.com/opencontainers/image-spec/specs-go/version.go
@@ -25,7 +25,7 @@ const (
 	VersionPatch = 0
 
 	// VersionDev indicates development branch. Releases will be empty string.
-	VersionDev = "-rc.5"
+	VersionDev = "-rc.6"
 )
 
 // Version is the specification version that the package types support.
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 00c3474fd..f143851a4 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -899,7 +899,7 @@ github.com/open-policy-agent/opa/version
 # github.com/opencontainers/go-digest v1.0.0
 ## explicit; go 1.13
 github.com/opencontainers/go-digest
-# github.com/opencontainers/image-spec v1.1.0-rc5
+# github.com/opencontainers/image-spec v1.1.0-rc6
 ## explicit; go 1.18
 github.com/opencontainers/image-spec/specs-go
 github.com/opencontainers/image-spec/specs-go/v1
@@ -1911,7 +1911,7 @@ k8s.io/utils/pointer
 k8s.io/utils/ptr
 k8s.io/utils/strings/slices
 k8s.io/utils/trace
-# oras.land/oras-go/v2 v2.3.1
+# oras.land/oras-go/v2 v2.4.0
 ## explicit; go 1.20
 oras.land/oras-go/v2
 oras.land/oras-go/v2/content
diff --git a/vendor/oras.land/oras-go/v2/content.go b/vendor/oras.land/oras-go/v2/content.go
index 53eb6c75a..b8bf26386 100644
--- a/vendor/oras.land/oras-go/v2/content.go
+++ b/vendor/oras.land/oras-go/v2/content.go
@@ -29,7 +29,6 @@ import (
 	"oras.land/oras-go/v2/internal/docker"
 	"oras.land/oras-go/v2/internal/interfaces"
 	"oras.land/oras-go/v2/internal/platform"
-	"oras.land/oras-go/v2/internal/registryutil"
 	"oras.land/oras-go/v2/internal/syncutil"
 	"oras.land/oras-go/v2/registry"
 	"oras.land/oras-go/v2/registry/remote/auth"
@@ -91,7 +90,7 @@ func TagN(ctx context.Context, target Target, srcReference string, dstReferences
 			if err != nil {
 				return ocispec.Descriptor{}, err
 			}
-			ctx = registryutil.WithScopeHint(ctx, ref, auth.ActionPull, auth.ActionPush)
+			ctx = auth.AppendRepositoryScope(ctx, ref, auth.ActionPull, auth.ActionPush)
 		}
 
 		desc, contentBytes, err := FetchBytes(ctx, target, srcReference, FetchBytesOptions{
@@ -149,7 +148,7 @@ func Tag(ctx context.Context, target Target, src, dst string) (ocispec.Descripto
 			if err != nil {
 				return ocispec.Descriptor{}, err
 			}
-			ctx = registryutil.WithScopeHint(ctx, ref, auth.ActionPull, auth.ActionPush)
+			ctx = auth.AppendRepositoryScope(ctx, ref, auth.ActionPull, auth.ActionPush)
 		}
 		desc, rc, err := refFetcher.FetchReference(ctx, src)
 		if err != nil {
diff --git a/vendor/oras.land/oras-go/v2/content/file/file.go b/vendor/oras.land/oras-go/v2/content/file/file.go
index 57d583e8f..dc560f5a7 100644
--- a/vendor/oras.land/oras-go/v2/content/file/file.go
+++ b/vendor/oras.land/oras-go/v2/content/file/file.go
@@ -104,6 +104,10 @@ type Store struct {
 	// manifest and config file, while leaving only named layer files.
 	// Default value: false.
 	IgnoreNoName bool
+	// SkipUnpack controls if push operations should skip unpacking files. This
+	// value overrides the [AnnotationUnpack].
+	// Default value: false.
+	SkipUnpack bool
 
 	workingDir   string   // the working directory of the file store
 	closed       int32    // if the store is closed - 0: false, 1: true.
@@ -265,7 +269,7 @@ func (s *Store) push(ctx context.Context, expected ocispec.Descriptor, content i
 		return fmt.Errorf("failed to resolve path for writing: %w", err)
 	}
 
-	if needUnpack := expected.Annotations[AnnotationUnpack]; needUnpack == "true" {
+	if needUnpack := expected.Annotations[AnnotationUnpack]; needUnpack == "true" && !s.SkipUnpack {
 		err = s.pushDir(name, target, expected, content)
 	} else {
 		err = s.pushFile(target, expected, content)
diff --git a/vendor/oras.land/oras-go/v2/content/resolver.go b/vendor/oras.land/oras-go/v2/content/resolver.go
index b536b5ddc..bc0fd8df9 100644
--- a/vendor/oras.land/oras-go/v2/content/resolver.go
+++ b/vendor/oras.land/oras-go/v2/content/resolver.go
@@ -39,3 +39,9 @@ type TagResolver interface {
 	Tagger
 	Resolver
 }
+
+// Untagger untags reference tags.
+type Untagger interface {
+	// Untag untags the given reference string.
+	Untag(ctx context.Context, reference string) error
+}
diff --git a/vendor/oras.land/oras-go/v2/copy.go b/vendor/oras.land/oras-go/v2/copy.go
index ca0f5d6f5..2f131a8c6 100644
--- a/vendor/oras.land/oras-go/v2/copy.go
+++ b/vendor/oras.land/oras-go/v2/copy.go
@@ -37,8 +37,9 @@ import (
 // defaultConcurrency is the default value of CopyGraphOptions.Concurrency.
 const defaultConcurrency int = 3 // This value is consistent with dockerd and containerd.
 
-// errSkipDesc signals copyNode() to stop processing a descriptor.
-var errSkipDesc = errors.New("skip descriptor")
+// SkipNode signals to stop copying a node. When returned from PreCopy the blob must exist in the target.
+// This can be used to signal that a blob has been made available in the target repository by "Mount()" or some other technique.
+var SkipNode = errors.New("skip node")
 
 // DefaultCopyOptions provides the default CopyOptions.
 var DefaultCopyOptions CopyOptions = CopyOptions{
@@ -95,13 +96,21 @@ type CopyGraphOptions struct {
 	// cached in the memory.
 	// If less than or equal to 0, a default (currently 4 MiB) is used.
 	MaxMetadataBytes int64
-	// PreCopy handles the current descriptor before copying it.
+	// PreCopy handles the current descriptor before it is copied. PreCopy can
+	// return a SkipNode to signal that desc should be skipped when it already
+	// exists in the target.
 	PreCopy func(ctx context.Context, desc ocispec.Descriptor) error
-	// PostCopy handles the current descriptor after copying it.
+	// PostCopy handles the current descriptor after it is copied.
 	PostCopy func(ctx context.Context, desc ocispec.Descriptor) error
 	// OnCopySkipped will be called when the sub-DAG rooted by the current node
 	// is skipped.
 	OnCopySkipped func(ctx context.Context, desc ocispec.Descriptor) error
+	// MountFrom returns the candidate repositories that desc may be mounted from.
+	// The OCI references will be tried in turn.  If mounting fails on all of them,
+	// then it falls back to a copy.
+	MountFrom func(ctx context.Context, desc ocispec.Descriptor) ([]string, error)
+	// OnMounted will be invoked when desc is mounted.
+	OnMounted func(ctx context.Context, desc ocispec.Descriptor) error
 	// FindSuccessors finds the successors of the current node.
 	// fetcher provides cached access to the source storage, and is suitable
 	// for fetching non-leaf nodes like manifests. Since anything fetched from
@@ -256,12 +265,85 @@ func copyGraph(ctx context.Context, src content.ReadOnlyStorage, dst content.Sto
 		if exists {
 			return copyNode(ctx, proxy.Cache, dst, desc, opts)
 		}
-		return copyNode(ctx, src, dst, desc, opts)
+		return mountOrCopyNode(ctx, src, dst, desc, opts)
 	}
 
 	return syncutil.Go(ctx, limiter, fn, root)
 }
 
+// mountOrCopyNode tries to mount the node, if not falls back to copying.
+func mountOrCopyNode(ctx context.Context, src content.ReadOnlyStorage, dst content.Storage, desc ocispec.Descriptor, opts CopyGraphOptions) error {
+	// Need MountFrom and it must be a blob
+	if opts.MountFrom == nil || descriptor.IsManifest(desc) {
+		return copyNode(ctx, src, dst, desc, opts)
+	}
+
+	mounter, ok := dst.(registry.Mounter)
+	if !ok {
+		// mounting is not supported by the destination
+		return copyNode(ctx, src, dst, desc, opts)
+	}
+
+	sourceRepositories, err := opts.MountFrom(ctx, desc)
+	if err != nil {
+		// Technically this error is not fatal, we can still attempt to copy the node
+		// But for consistency with the other callbacks we bail out.
+		return err
+	}
+
+	if len(sourceRepositories) == 0 {
+		return copyNode(ctx, src, dst, desc, opts)
+	}
+
+	skipSource := errors.New("skip source")
+	for i, sourceRepository := range sourceRepositories {
+		// try mounting this source repository
+		var mountFailed bool
+		getContent := func() (io.ReadCloser, error) {
+			// the invocation of getContent indicates that mounting has failed
+			mountFailed = true
+
+			if i < len(sourceRepositories)-1 {
+				// If this is not the last one, skip this source and try next one
+				// We want to return an error that we will test for from mounter.Mount()
+				return nil, skipSource
+			}
+			// this is the last iteration so we need to actually get the content and do the copy
+			// but first call the PreCopy function
+			if opts.PreCopy != nil {
+				if err := opts.PreCopy(ctx, desc); err != nil {
+					return nil, err
+				}
+			}
+			return src.Fetch(ctx, desc)
+		}
+
+		// Mount or copy
+		if err := mounter.Mount(ctx, desc, sourceRepository, getContent); err != nil && !errors.Is(err, skipSource) {
+			return err
+		}
+
+		if !mountFailed {
+			// mounted, success
+			if opts.OnMounted != nil {
+				if err := opts.OnMounted(ctx, desc); err != nil {
+					return err
+				}
+			}
+			return nil
+		}
+	}
+
+	// we copied it
+	if opts.PostCopy != nil {
+		if err := opts.PostCopy(ctx, desc); err != nil {
+			return err
+		}
+	}
+
+	return nil
+}
+
 // doCopyNode copies a single content from the source CAS to the destination CAS.
 func doCopyNode(ctx context.Context, src content.ReadOnlyStorage, dst content.Storage, desc ocispec.Descriptor) error {
 	rc, err := src.Fetch(ctx, desc)
@@ -281,7 +363,7 @@ func doCopyNode(ctx context.Context, src content.ReadOnlyStorage, dst content.St
 func copyNode(ctx context.Context, src content.ReadOnlyStorage, dst content.Storage, desc ocispec.Descriptor, opts CopyGraphOptions) error {
 	if opts.PreCopy != nil {
 		if err := opts.PreCopy(ctx, desc); err != nil {
-			if err == errSkipDesc {
+			if err == SkipNode {
 				return nil
 			}
 			return err
@@ -373,7 +455,7 @@ func prepareCopy(ctx context.Context, dst Target, dstRef string, proxy *cas.Prox
 				}
 			}
 			// skip the regular copy workflow
-			return errSkipDesc
+			return SkipNode
 		}
 	} else {
 		postCopy := opts.PostCopy
diff --git a/vendor/oras.land/oras-go/v2/internal/container/set/set.go b/vendor/oras.land/oras-go/v2/internal/container/set/set.go
index a084e2889..07c96d47d 100644
--- a/vendor/oras.land/oras-go/v2/internal/container/set/set.go
+++ b/vendor/oras.land/oras-go/v2/internal/container/set/set.go
@@ -33,3 +33,8 @@ func (s Set[T]) Contains(item T) bool {
 	_, ok := s[item]
 	return ok
 }
+
+// Delete deletes an item from the set.
+func (s Set[T]) Delete(item T) {
+	delete(s, item)
+}
diff --git a/vendor/oras.land/oras-go/v2/internal/graph/memory.go b/vendor/oras.land/oras-go/v2/internal/graph/memory.go
index 0aa25aee8..016e5f96a 100644
--- a/vendor/oras.land/oras-go/v2/internal/graph/memory.go
+++ b/vendor/oras.land/oras-go/v2/internal/graph/memory.go
@@ -20,9 +20,11 @@ import (
 	"errors"
 	"sync"
 
+	"github.com/opencontainers/go-digest"
 	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
 	"oras.land/oras-go/v2/content"
 	"oras.land/oras-go/v2/errdef"
+	"oras.land/oras-go/v2/internal/container/set"
 	"oras.land/oras-go/v2/internal/descriptor"
 	"oras.land/oras-go/v2/internal/status"
 	"oras.land/oras-go/v2/internal/syncutil"
@@ -30,35 +32,49 @@ import (
 
 // Memory is a memory based PredecessorFinder.
 type Memory struct {
-	predecessors sync.Map // map[descriptor.Descriptor]map[descriptor.Descriptor]ocispec.Descriptor
-	indexed      sync.Map // map[descriptor.Descriptor]any
+	// nodes has the following properties and behaviors:
+	//  1. a node exists in Memory.nodes if and only if it exists in the memory
+	//  2. Memory.nodes saves the ocispec.Descriptor map keys, which are used by
+	//    the other fields.
+	nodes map[descriptor.Descriptor]ocispec.Descriptor
+
+	// predecessors has the following properties and behaviors:
+	//  1. a node exists in Memory.predecessors if it has at least one predecessor
+	//    in the memory, regardless of whether or not the node itself exists in
+	//    the memory.
+	//  2. a node does not exist in Memory.predecessors, if it doesn't have any predecessors
+	//    in the memory.
+	predecessors map[descriptor.Descriptor]set.Set[descriptor.Descriptor]
+
+	// successors has the following properties and behaviors:
+	//  1. a node exists in Memory.successors if and only if it exists in the memory.
+	//  2. a node's entry in Memory.successors is always consistent with the actual
+	//    content of the node, regardless of whether or not each successor exists
+	//    in the memory.
+	successors map[descriptor.Descriptor]set.Set[descriptor.Descriptor]
+
+	lock sync.RWMutex
 }
 
 // NewMemory creates a new memory PredecessorFinder.
 func NewMemory() *Memory {
-	return &Memory{}
+	return &Memory{
+		nodes:        make(map[descriptor.Descriptor]ocispec.Descriptor),
+		predecessors: make(map[descriptor.Descriptor]set.Set[descriptor.Descriptor]),
+		successors:   make(map[descriptor.Descriptor]set.Set[descriptor.Descriptor]),
+	}
 }
 
 // Index indexes predecessors for each direct successor of the given node.
-// There is no data consistency issue as long as deletion is not implemented
-// for the underlying storage.
 func (m *Memory) Index(ctx context.Context, fetcher content.Fetcher, node ocispec.Descriptor) error {
-	successors, err := content.Successors(ctx, fetcher, node)
-	if err != nil {
-		return err
-	}
-
-	m.index(ctx, node, successors)
-	return nil
+	_, err := m.index(ctx, fetcher, node)
+	return err
 }
 
 // Index indexes predecessors for all the successors of the given node.
-// There is no data consistency issue as long as deletion is not implemented
-// for the underlying storage.
 func (m *Memory) IndexAll(ctx context.Context, fetcher content.Fetcher, node ocispec.Descriptor) error {
 	// track content status
 	tracker := status.NewTracker()
-
 	var fn syncutil.GoFunc[ocispec.Descriptor]
 	fn = func(ctx context.Context, region *syncutil.LimitedRegion, desc ocispec.Descriptor) error {
 		// skip the node if other go routine is working on it
@@ -66,15 +82,7 @@ func (m *Memory) IndexAll(ctx context.Context, fetcher content.Fetcher, node oci
 		if !committed {
 			return nil
 		}
-
-		// skip the node if it has been indexed
-		key := descriptor.FromOCI(desc)
-		_, exists := m.indexed.Load(key)
-		if exists {
-			return nil
-		}
-
-		successors, err := content.Successors(ctx, fetcher, desc)
+		successors, err := m.index(ctx, fetcher, desc)
 		if err != nil {
 			if errors.Is(err, errdef.ErrNotFound) {
 				// skip the node if it does not exist
@@ -82,9 +90,6 @@ func (m *Memory) IndexAll(ctx context.Context, fetcher content.Fetcher, node oci
 			}
 			return err
 		}
-		m.index(ctx, desc, successors)
-		m.indexed.Store(key, nil)
-
 		if len(successors) > 0 {
 			// traverse and index successors
 			return syncutil.Go(ctx, nil, fn, successors...)
@@ -96,39 +101,101 @@ func (m *Memory) IndexAll(ctx context.Context, fetcher content.Fetcher, node oci
 
 // Predecessors returns the nodes directly pointing to the current node.
 // Predecessors returns nil without error if the node does not exists in the
-// store.
-// Like other operations, calling Predecessors() is go-routine safe. However,
-// it does not necessarily correspond to any consistent snapshot of the stored
-// contents.
+// store. Like other operations, calling Predecessors() is go-routine safe.
+// However, it does not necessarily correspond to any consistent snapshot of
+// the stored contents.
 func (m *Memory) Predecessors(_ context.Context, node ocispec.Descriptor) ([]ocispec.Descriptor, error) {
+	m.lock.RLock()
+	defer m.lock.RUnlock()
+
 	key := descriptor.FromOCI(node)
-	value, exists := m.predecessors.Load(key)
+	set, exists := m.predecessors[key]
 	if !exists {
 		return nil, nil
 	}
-	predecessors := value.(*sync.Map)
-
 	var res []ocispec.Descriptor
-	predecessors.Range(func(key, value interface{}) bool {
-		res = append(res, value.(ocispec.Descriptor))
-		return true
-	})
+	for k := range set {
+		res = append(res, m.nodes[k])
+	}
 	return res, nil
 }
 
+// Remove removes the node from its predecessors and successors, and returns the
+// dangling root nodes caused by the deletion.
+func (m *Memory) Remove(node ocispec.Descriptor) []ocispec.Descriptor {
+	m.lock.Lock()
+	defer m.lock.Unlock()
+
+	nodeKey := descriptor.FromOCI(node)
+	var danglings []ocispec.Descriptor
+	// remove the node from its successors' predecessor list
+	for successorKey := range m.successors[nodeKey] {
+		predecessorEntry := m.predecessors[successorKey]
+		predecessorEntry.Delete(nodeKey)
+
+		// if none of the predecessors of the node still exists, we remove the
+		// predecessors entry and return it as a dangling node. Otherwise, we do
+		// not remove the entry.
+		if len(predecessorEntry) == 0 {
+			delete(m.predecessors, successorKey)
+			if _, exists := m.nodes[successorKey]; exists {
+				danglings = append(danglings, m.nodes[successorKey])
+			}
+		}
+	}
+	delete(m.successors, nodeKey)
+	delete(m.nodes, nodeKey)
+	return danglings
+}
+
+// DigestSet returns the set of node digest in memory.
+func (m *Memory) DigestSet() set.Set[digest.Digest] {
+	m.lock.RLock()
+	defer m.lock.RUnlock()
+
+	s := set.New[digest.Digest]()
+	for desc := range m.nodes {
+		s.Add(desc.Digest)
+	}
+	return s
+}
+
 // index indexes predecessors for each direct successor of the given node.
-// There is no data consistency issue as long as deletion is not implemented
-// for the underlying storage.
-func (m *Memory) index(ctx context.Context, node ocispec.Descriptor, successors []ocispec.Descriptor) {
-	if len(successors) == 0 {
-		return
+func (m *Memory) index(ctx context.Context, fetcher content.Fetcher, node ocispec.Descriptor) ([]ocispec.Descriptor, error) {
+	successors, err := content.Successors(ctx, fetcher, node)
+	if err != nil {
+		return nil, err
 	}
+	m.lock.Lock()
+	defer m.lock.Unlock()
 
-	predecessorKey := descriptor.FromOCI(node)
+	// index the node
+	nodeKey := descriptor.FromOCI(node)
+	m.nodes[nodeKey] = node
+
+	// for each successor, put it into the node's successors list, and
+	// put node into the succeesor's predecessors list
+	successorSet := set.New[descriptor.Descriptor]()
+	m.successors[nodeKey] = successorSet
 	for _, successor := range successors {
 		successorKey := descriptor.FromOCI(successor)
-		value, _ := m.predecessors.LoadOrStore(successorKey, &sync.Map{})
-		predecessors := value.(*sync.Map)
-		predecessors.Store(predecessorKey, node)
+		successorSet.Add(successorKey)
+		predecessorSet, exists := m.predecessors[successorKey]
+		if !exists {
+			predecessorSet = set.New[descriptor.Descriptor]()
+			m.predecessors[successorKey] = predecessorSet
+		}
+		predecessorSet.Add(nodeKey)
 	}
+	return successors, nil
+}
+
+// Exists checks if the node exists in the graph
+func (m *Memory) Exists(node ocispec.Descriptor) bool {
+	m.lock.RLock()
+	defer m.lock.RUnlock()
+
+	nodeKey := descriptor.FromOCI(node)
+	_, exists := m.nodes[nodeKey]
+	return exists
 }
diff --git a/vendor/oras.land/oras-go/v2/internal/manifestutil/parser.go b/vendor/oras.land/oras-go/v2/internal/manifestutil/parser.go
index c904dc690..89d556b8f 100644
--- a/vendor/oras.land/oras-go/v2/internal/manifestutil/parser.go
+++ b/vendor/oras.land/oras-go/v2/internal/manifestutil/parser.go
@@ -22,6 +22,7 @@ import (
 	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
 	"oras.land/oras-go/v2/content"
 	"oras.land/oras-go/v2/internal/docker"
+	"oras.land/oras-go/v2/internal/spec"
 )
 
 // Config returns the config of desc, if present.
@@ -61,3 +62,23 @@ func Manifests(ctx context.Context, fetcher content.Fetcher, desc ocispec.Descri
 		return nil, nil
 	}
 }
+
+// Subject returns the subject of desc, if present.
+func Subject(ctx context.Context, fetcher content.Fetcher, desc ocispec.Descriptor) (*ocispec.Descriptor, error) {
+	switch desc.MediaType {
+	case ocispec.MediaTypeImageManifest, ocispec.MediaTypeImageIndex, spec.MediaTypeArtifactManifest:
+		content, err := content.FetchAll(ctx, fetcher, desc)
+		if err != nil {
+			return nil, err
+		}
+		var manifest struct {
+			Subject *ocispec.Descriptor `json:"subject,omitempty"`
+		}
+		if err := json.Unmarshal(content, &manifest); err != nil {
+			return nil, err
+		}
+		return manifest.Subject, nil
+	default:
+		return nil, nil
+	}
+}
diff --git a/vendor/oras.land/oras-go/v2/internal/platform/platform.go b/vendor/oras.land/oras-go/v2/internal/platform/platform.go
index e903fe3d5..3aea3a1b1 100644
--- a/vendor/oras.land/oras-go/v2/internal/platform/platform.go
+++ b/vendor/oras.land/oras-go/v2/internal/platform/platform.go
@@ -38,6 +38,14 @@ import (
 // Note: Variant, OSVersion and OSFeatures are optional fields, will skip
 // the comparison if the target platform does not provide specific value.
 func Match(got *ocispec.Platform, want *ocispec.Platform) bool {
+	if got == nil && want == nil {
+		return true
+	}
+
+	if got == nil || want == nil {
+		return false
+	}
+
 	if got.Architecture != want.Architecture || got.OS != want.OS {
 		return false
 	}
diff --git a/vendor/oras.land/oras-go/v2/internal/registryutil/auth.go b/vendor/oras.land/oras-go/v2/internal/registryutil/auth.go
deleted file mode 100644
index 4a601f0c6..000000000
--- a/vendor/oras.land/oras-go/v2/internal/registryutil/auth.go
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
-Copyright The ORAS 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 registryutil
-
-import (
-	"context"
-
-	"oras.land/oras-go/v2/registry"
-	"oras.land/oras-go/v2/registry/remote/auth"
-)
-
-// WithScopeHint adds a hinted scope to the context.
-func WithScopeHint(ctx context.Context, ref registry.Reference, actions ...string) context.Context {
-	scope := auth.ScopeRepository(ref.Repository, actions...)
-	return auth.AppendScopes(ctx, scope)
-}
diff --git a/vendor/oras.land/oras-go/v2/internal/resolver/memory.go b/vendor/oras.land/oras-go/v2/internal/resolver/memory.go
index 6fac5e2d0..80843e437 100644
--- a/vendor/oras.land/oras-go/v2/internal/resolver/memory.go
+++ b/vendor/oras.land/oras-go/v2/internal/resolver/memory.go
@@ -19,43 +19,93 @@ import (
 	"context"
 	"sync"
 
+	"github.com/opencontainers/go-digest"
 	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
 	"oras.land/oras-go/v2/errdef"
+	"oras.land/oras-go/v2/internal/container/set"
 )
 
 // Memory is a memory based resolver.
 type Memory struct {
-	index sync.Map // map[string]ocispec.Descriptor
+	lock  sync.RWMutex
+	index map[string]ocispec.Descriptor
+	tags  map[digest.Digest]set.Set[string]
 }
 
 // NewMemory creates a new Memory resolver.
 func NewMemory() *Memory {
-	return &Memory{}
+	return &Memory{
+		index: make(map[string]ocispec.Descriptor),
+		tags:  make(map[digest.Digest]set.Set[string]),
+	}
 }
 
 // Resolve resolves a reference to a descriptor.
 func (m *Memory) Resolve(_ context.Context, reference string) (ocispec.Descriptor, error) {
-	desc, ok := m.index.Load(reference)
+	m.lock.RLock()
+	defer m.lock.RUnlock()
+
+	desc, ok := m.index[reference]
 	if !ok {
 		return ocispec.Descriptor{}, errdef.ErrNotFound
 	}
-	return desc.(ocispec.Descriptor), nil
+	return desc, nil
 }
 
 // Tag tags a descriptor with a reference string.
 func (m *Memory) Tag(_ context.Context, desc ocispec.Descriptor, reference string) error {
-	m.index.Store(reference, desc)
+	m.lock.Lock()
+	defer m.lock.Unlock()
+
+	m.index[reference] = desc
+	tagSet, ok := m.tags[desc.Digest]
+	if !ok {
+		tagSet = set.New[string]()
+		m.tags[desc.Digest] = tagSet
+	}
+	tagSet.Add(reference)
 	return nil
 }
 
+// Untag removes a reference from index map.
+func (m *Memory) Untag(reference string) {
+	m.lock.Lock()
+	defer m.lock.Unlock()
+
+	desc, ok := m.index[reference]
+	if !ok {
+		return
+	}
+	delete(m.index, reference)
+	tagSet := m.tags[desc.Digest]
+	tagSet.Delete(reference)
+	if len(tagSet) == 0 {
+		delete(m.tags, desc.Digest)
+	}
+}
+
 // Map dumps the memory into a built-in map structure.
-// Like other operations, calling Map() is go-routine safe. However, it does not
-// necessarily correspond to any consistent snapshot of the storage contents.
+// Like other operations, calling Map() is go-routine safe.
 func (m *Memory) Map() map[string]ocispec.Descriptor {
-	res := make(map[string]ocispec.Descriptor)
-	m.index.Range(func(key, value interface{}) bool {
-		res[key.(string)] = value.(ocispec.Descriptor)
-		return true
-	})
+	m.lock.RLock()
+	defer m.lock.RUnlock()
+
+	res := make(map[string]ocispec.Descriptor, len(m.index))
+	for key, value := range m.index {
+		res[key] = value
+	}
+	return res
+}
+
+// TagSet returns the set of tags of the descriptor.
+func (m *Memory) TagSet(desc ocispec.Descriptor) set.Set[string] {
+	m.lock.RLock()
+	defer m.lock.RUnlock()
+
+	tagSet := m.tags[desc.Digest]
+	res := make(set.Set[string], len(tagSet))
+	for tag := range tagSet {
+		res.Add(tag)
+	}
 	return res
 }
diff --git a/vendor/oras.land/oras-go/v2/registry/reference.go b/vendor/oras.land/oras-go/v2/registry/reference.go
index 7661a162b..a8ad16f2a 100644
--- a/vendor/oras.land/oras-go/v2/registry/reference.go
+++ b/vendor/oras.land/oras-go/v2/registry/reference.go
@@ -34,13 +34,13 @@ var (
 	//
 	// References:
 	//   - https://github.com/distribution/distribution/blob/v2.7.1/reference/regexp.go#L53
-	//   - https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc3/spec.md#pulling-manifests
+	//   - https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc4/spec.md#pulling-manifests
 	repositoryRegexp = regexp.MustCompile(`^[a-z0-9]+(?:(?:[._]|__|[-]*)[a-z0-9]+)*(?:/[a-z0-9]+(?:(?:[._]|__|[-]*)[a-z0-9]+)*)*$`)
 
 	// tagRegexp checks the tag name.
 	// The docker and OCI spec have the same regular expression.
 	//
-	// Reference: https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc3/spec.md#pulling-manifests
+	// Reference: https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc4/spec.md#pulling-manifests
 	tagRegexp = regexp.MustCompile(`^[\w][\w.-]{0,127}$`)
 )
 
@@ -64,6 +64,9 @@ type Reference struct {
 }
 
 // ParseReference parses a string (artifact) into an `artifact reference`.
+// Corresponding cryptographic hash implementations are required to be imported
+// as specified by https://pkg.go.dev/github.com/opencontainers/go-digest#readme-usage
+// if the string contains a digest.
 //
 // Note: An "image" is an "artifact", however, an "artifact" is not necessarily
 // an "image".
@@ -117,7 +120,7 @@ func ParseReference(artifact string) (Reference, error) {
 	parts := strings.SplitN(artifact, "/", 2)
 	if len(parts) == 1 {
 		// Invalid Form
-		return Reference{}, fmt.Errorf("%w: missing repository", errdef.ErrInvalidReference)
+		return Reference{}, fmt.Errorf("%w: missing registry or repository", errdef.ErrInvalidReference)
 	}
 	registry, path := parts[0], parts[1]
 
@@ -190,7 +193,7 @@ func (r Reference) Validate() error {
 // ValidateRegistry validates the registry.
 func (r Reference) ValidateRegistry() error {
 	if uri, err := url.ParseRequestURI("dummy://" + r.Registry); err != nil || uri.Host != r.Registry {
-		return fmt.Errorf("%w: invalid registry", errdef.ErrInvalidReference)
+		return fmt.Errorf("%w: invalid registry %q", errdef.ErrInvalidReference, r.Registry)
 	}
 	return nil
 }
@@ -198,7 +201,7 @@ func (r Reference) ValidateRegistry() error {
 // ValidateRepository validates the repository.
 func (r Reference) ValidateRepository() error {
 	if !repositoryRegexp.MatchString(r.Repository) {
-		return fmt.Errorf("%w: invalid repository", errdef.ErrInvalidReference)
+		return fmt.Errorf("%w: invalid repository %q", errdef.ErrInvalidReference, r.Repository)
 	}
 	return nil
 }
@@ -206,7 +209,7 @@ func (r Reference) ValidateRepository() error {
 // ValidateReferenceAsTag validates the reference as a tag.
 func (r Reference) ValidateReferenceAsTag() error {
 	if !tagRegexp.MatchString(r.Reference) {
-		return fmt.Errorf("%w: invalid tag", errdef.ErrInvalidReference)
+		return fmt.Errorf("%w: invalid tag %q", errdef.ErrInvalidReference, r.Reference)
 	}
 	return nil
 }
@@ -214,7 +217,7 @@ func (r Reference) ValidateReferenceAsTag() error {
 // ValidateReferenceAsDigest validates the reference as a digest.
 func (r Reference) ValidateReferenceAsDigest() error {
 	if _, err := r.Digest(); err != nil {
-		return fmt.Errorf("%w: invalid digest; %v", errdef.ErrInvalidReference, err)
+		return fmt.Errorf("%w: invalid digest %q: %v", errdef.ErrInvalidReference, r.Reference, err)
 	}
 	return nil
 }
@@ -250,6 +253,8 @@ func (r Reference) ReferenceOrDefault() string {
 }
 
 // Digest returns the reference as a digest.
+// Corresponding cryptographic hash implementations are required to be imported
+// as specified by https://pkg.go.dev/github.com/opencontainers/go-digest#readme-usage
 func (r Reference) Digest() (digest.Digest, error) {
 	return digest.Parse(r.Reference)
 }
diff --git a/vendor/oras.land/oras-go/v2/registry/remote/auth/cache.go b/vendor/oras.land/oras-go/v2/registry/remote/auth/cache.go
index 91a52e1c1..d11c092bf 100644
--- a/vendor/oras.land/oras-go/v2/registry/remote/auth/cache.go
+++ b/vendor/oras.land/oras-go/v2/registry/remote/auth/cache.go
@@ -157,3 +157,76 @@ func (noCache) GetToken(ctx context.Context, registry string, scheme Scheme, key
 func (noCache) Set(ctx context.Context, registry string, scheme Scheme, key string, fetch func(context.Context) (string, error)) (string, error) {
 	return fetch(ctx)
 }
+
+// hostCache is an auth cache that ignores scopes.  Uses only the registry's hostname to find a token.
+type hostCache struct {
+	Cache
+}
+
+// GetToken implements Cache.
+func (c *hostCache) GetToken(ctx context.Context, registry string, scheme Scheme, key string) (string, error) {
+	return c.Cache.GetToken(ctx, registry, scheme, "")
+}
+
+// Set implements Cache.
+func (c *hostCache) Set(ctx context.Context, registry string, scheme Scheme, key string, fetch func(context.Context) (string, error)) (string, error) {
+	return c.Cache.Set(ctx, registry, scheme, "", fetch)
+}
+
+// fallbackCache tries the primary cache then falls back to the secondary cache.
+type fallbackCache struct {
+	primary   Cache
+	secondary Cache
+}
+
+// GetScheme implements Cache.
+func (fc *fallbackCache) GetScheme(ctx context.Context, registry string) (Scheme, error) {
+	scheme, err := fc.primary.GetScheme(ctx, registry)
+	if err == nil {
+		return scheme, nil
+	}
+
+	// fallback
+	return fc.secondary.GetScheme(ctx, registry)
+}
+
+// GetToken implements Cache.
+func (fc *fallbackCache) GetToken(ctx context.Context, registry string, scheme Scheme, key string) (string, error) {
+	token, err := fc.primary.GetToken(ctx, registry, scheme, key)
+	if err == nil {
+		return token, nil
+	}
+
+	// fallback
+	return fc.secondary.GetToken(ctx, registry, scheme, key)
+}
+
+// Set implements Cache.
+func (fc *fallbackCache) Set(ctx context.Context, registry string, scheme Scheme, key string, fetch func(context.Context) (string, error)) (string, error) {
+	token, err := fc.primary.Set(ctx, registry, scheme, key, fetch)
+	if err != nil {
+		return "", err
+	}
+
+	return fc.secondary.Set(ctx, registry, scheme, key, func(ctx context.Context) (string, error) {
+		return token, nil
+	})
+}
+
+// NewSingleContextCache creates a host-based cache for optimizing the auth flow for non-compliant registries.
+// It is intended to be used in a single context, such as pulling from a single repository.
+// This cache should not be shared.
+//
+// Note: [NewCache] should be used for compliant registries as it can be shared
+// across context and will generally make less re-authentication requests.
+func NewSingleContextCache() Cache {
+	cache := NewCache()
+	return &fallbackCache{
+		primary: cache,
+		// We can re-use the came concurrentCache here because the key space is different
+		// (keys are always empty for the hostCache) so there is no collision.
+		// Even if there is a collision it is not an issue.
+		// Re-using saves a little memory.
+		secondary: &hostCache{cache},
+	}
+}
diff --git a/vendor/oras.land/oras-go/v2/registry/remote/auth/client.go b/vendor/oras.land/oras-go/v2/registry/remote/auth/client.go
index 37eb65ed2..8d9685a21 100644
--- a/vendor/oras.land/oras-go/v2/registry/remote/auth/client.go
+++ b/vendor/oras.land/oras-go/v2/registry/remote/auth/client.go
@@ -31,6 +31,10 @@ import (
 	"oras.land/oras-go/v2/registry/remote/retry"
 )
 
+// ErrBasicCredentialNotFound is returned  when the credential is not found for
+// basic auth.
+var ErrBasicCredentialNotFound = errors.New("basic credential not found")
+
 // DefaultClient is the default auth-decorated client.
 var DefaultClient = &Client{
 	Client: retry.DefaultClient,
@@ -54,16 +58,23 @@ var maxResponseBytes int64 = 128 * 1024 // 128 KiB
 // See also ClientID.
 var defaultClientID = "oras-go"
 
+// CredentialFunc represents a function that resolves the credential for the
+// given registry (i.e. host:port).
+//
+// [EmptyCredential] is a valid return value and should not be considered as
+// an error.
+type CredentialFunc func(ctx context.Context, hostport string) (Credential, error)
+
 // StaticCredential specifies static credentials for the given host.
-func StaticCredential(registry string, cred Credential) func(context.Context, string) (Credential, error) {
+func StaticCredential(registry string, cred Credential) CredentialFunc {
 	if registry == "docker.io" {
 		// it is expected that traffic targeting "docker.io" will be redirected
 		// to "registry-1.docker.io"
 		// reference: https://github.com/moby/moby/blob/v24.0.0-beta.2/registry/config.go#L25-L48
 		registry = "registry-1.docker.io"
 	}
-	return func(_ context.Context, target string) (Credential, error) {
-		if target == registry {
+	return func(_ context.Context, hostport string) (Credential, error) {
+		if hostport == registry {
 			return cred, nil
 		}
 		return EmptyCredential, nil
@@ -88,10 +99,10 @@ type Client struct {
 
 	// Credential specifies the function for resolving the credential for the
 	// given registry (i.e. host:port).
-	// `EmptyCredential` is a valid return value and should not be considered as
+	// EmptyCredential is a valid return value and should not be considered as
 	// an error.
-	// If nil, the credential is always resolved to `EmptyCredential`.
-	Credential func(context.Context, string) (Credential, error)
+	// If nil, the credential is always resolved to EmptyCredential.
+	Credential CredentialFunc
 
 	// Cache caches credentials for direct accessing the remote registry.
 	// If nil, no cache is used.
@@ -170,19 +181,19 @@ func (c *Client) Do(originalReq *http.Request) (*http.Response, error) {
 	// attempt cached auth token
 	var attemptedKey string
 	cache := c.cache()
-	registry := originalReq.Host
-	scheme, err := cache.GetScheme(ctx, registry)
+	host := originalReq.Host
+	scheme, err := cache.GetScheme(ctx, host)
 	if err == nil {
 		switch scheme {
 		case SchemeBasic:
-			token, err := cache.GetToken(ctx, registry, SchemeBasic, "")
+			token, err := cache.GetToken(ctx, host, SchemeBasic, "")
 			if err == nil {
 				req.Header.Set("Authorization", "Basic "+token)
 			}
 		case SchemeBearer:
-			scopes := GetScopes(ctx)
+			scopes := GetAllScopesForHost(ctx, host)
 			attemptedKey = strings.Join(scopes, " ")
-			token, err := cache.GetToken(ctx, registry, SchemeBearer, attemptedKey)
+			token, err := cache.GetToken(ctx, host, SchemeBearer, attemptedKey)
 			if err == nil {
 				req.Header.Set("Authorization", "Bearer "+token)
 			}
@@ -204,8 +215,8 @@ func (c *Client) Do(originalReq *http.Request) (*http.Response, error) {
 	case SchemeBasic:
 		resp.Body.Close()
 
-		token, err := cache.Set(ctx, registry, SchemeBasic, "", func(ctx context.Context) (string, error) {
-			return c.fetchBasicAuth(ctx, registry)
+		token, err := cache.Set(ctx, host, SchemeBasic, "", func(ctx context.Context) (string, error) {
+			return c.fetchBasicAuth(ctx, host)
 		})
 		if err != nil {
 			return nil, fmt.Errorf("%s %q: %w", resp.Request.Method, resp.Request.URL, err)
@@ -216,17 +227,17 @@ func (c *Client) Do(originalReq *http.Request) (*http.Response, error) {
 	case SchemeBearer:
 		resp.Body.Close()
 
-		// merge hinted scopes with challenged scopes
-		scopes := GetScopes(ctx)
-		if scope := params["scope"]; scope != "" {
-			scopes = append(scopes, strings.Split(scope, " ")...)
+		scopes := GetAllScopesForHost(ctx, host)
+		if paramScope := params["scope"]; paramScope != "" {
+			// merge hinted scopes with challenged scopes
+			scopes = append(scopes, strings.Split(paramScope, " ")...)
 			scopes = CleanScopes(scopes)
 		}
 		key := strings.Join(scopes, " ")
 
 		// attempt the cache again if there is a scope change
 		if key != attemptedKey {
-			if token, err := cache.GetToken(ctx, registry, SchemeBearer, key); err == nil {
+			if token, err := cache.GetToken(ctx, host, SchemeBearer, key); err == nil {
 				req = originalReq.Clone(ctx)
 				req.Header.Set("Authorization", "Bearer "+token)
 				if err := rewindRequestBody(req); err != nil {
@@ -247,8 +258,8 @@ func (c *Client) Do(originalReq *http.Request) (*http.Response, error) {
 		// attempt with credentials
 		realm := params["realm"]
 		service := params["service"]
-		token, err := cache.Set(ctx, registry, SchemeBearer, key, func(ctx context.Context) (string, error) {
-			return c.fetchBearerToken(ctx, registry, realm, service, scopes)
+		token, err := cache.Set(ctx, host, SchemeBearer, key, func(ctx context.Context) (string, error) {
+			return c.fetchBearerToken(ctx, host, realm, service, scopes)
 		})
 		if err != nil {
 			return nil, fmt.Errorf("%s %q: %w", resp.Request.Method, resp.Request.URL, err)
@@ -273,7 +284,7 @@ func (c *Client) fetchBasicAuth(ctx context.Context, registry string) (string, e
 		return "", fmt.Errorf("failed to resolve credential: %w", err)
 	}
 	if cred == EmptyCredential {
-		return "", errors.New("credential required for basic auth")
+		return "", ErrBasicCredentialNotFound
 	}
 	if cred.Username == "" || cred.Password == "" {
 		return "", errors.New("missing username or password for basic auth")
diff --git a/vendor/oras.land/oras-go/v2/registry/remote/auth/scope.go b/vendor/oras.land/oras-go/v2/registry/remote/auth/scope.go
index 24a0f8983..fabc2af26 100644
--- a/vendor/oras.land/oras-go/v2/registry/remote/auth/scope.go
+++ b/vendor/oras.land/oras-go/v2/registry/remote/auth/scope.go
@@ -19,6 +19,9 @@ import (
 	"context"
 	"sort"
 	"strings"
+
+	"oras.land/oras-go/v2/internal/slices"
+	"oras.land/oras-go/v2/registry"
 )
 
 // Actions used in scopes.
@@ -54,6 +57,28 @@ func ScopeRepository(repository string, actions ...string) string {
 	}, ":")
 }
 
+// AppendRepositoryScope returns a new context containing scope hints for the
+// auth client to fetch bearer tokens with the given actions on the repository.
+// If called multiple times, the new scopes will be appended to the existing
+// scopes. The resulted scopes are de-duplicated.
+//
+// For example, uploading blob to the repository "hello-world" does HEAD request
+// first then POST and PUT. The HEAD request will return a challenge for scope
+// `repository:hello-world:pull`, and the auth client will fetch a token for
+// that challenge. Later, the POST request will return a challenge for scope
+// `repository:hello-world:push`, and the auth client will fetch a token for
+// that challenge again. By invoking AppendRepositoryScope with the actions
+// [ActionPull] and [ActionPush] for the repository `hello-world`,
+// the auth client with cache is hinted to fetch a token via a single token
+// fetch request for all the HEAD, POST, PUT requests.
+func AppendRepositoryScope(ctx context.Context, ref registry.Reference, actions ...string) context.Context {
+	if len(actions) == 0 {
+		return ctx
+	}
+	scope := ScopeRepository(ref.Repository, actions...)
+	return AppendScopesForHost(ctx, ref.Host(), scope)
+}
+
 // scopesContextKey is the context key for scopes.
 type scopesContextKey struct{}
 
@@ -66,7 +91,7 @@ type scopesContextKey struct{}
 // `repository:hello-world:pull`, and the auth client will fetch a token for
 // that challenge. Later, the POST request will return a challenge for scope
 // `repository:hello-world:push`, and the auth client will fetch a token for
-// that challenge again. By invoking `WithScopes()` with the scope
+// that challenge again. By invoking WithScopes with the scope
 // `repository:hello-world:pull,push`, the auth client with cache is hinted to
 // fetch a token via a single token fetch request for all the HEAD, POST, PUT
 // requests.
@@ -93,11 +118,76 @@ func AppendScopes(ctx context.Context, scopes ...string) context.Context {
 // GetScopes returns the scopes in the context.
 func GetScopes(ctx context.Context) []string {
 	if scopes, ok := ctx.Value(scopesContextKey{}).([]string); ok {
-		return append([]string(nil), scopes...)
+		return slices.Clone(scopes)
+	}
+	return nil
+}
+
+// scopesForHostContextKey is the context key for per-host scopes.
+type scopesForHostContextKey string
+
+// WithScopesForHost returns a context with per-host scopes added.
+// Scopes are de-duplicated.
+// Scopes are used as hints for the auth client to fetch bearer tokens with
+// larger scopes.
+//
+// For example, uploading blob to the repository "hello-world" does HEAD request
+// first then POST and PUT. The HEAD request will return a challenge for scope
+// `repository:hello-world:pull`, and the auth client will fetch a token for
+// that challenge. Later, the POST request will return a challenge for scope
+// `repository:hello-world:push`, and the auth client will fetch a token for
+// that challenge again. By invoking WithScopesForHost with the scope
+// `repository:hello-world:pull,push`, the auth client with cache is hinted to
+// fetch a token via a single token fetch request for all the HEAD, POST, PUT
+// requests.
+//
+// Passing an empty list of scopes will virtually remove the scope hints in the
+// context for the given host.
+//
+// Reference: https://docs.docker.com/registry/spec/auth/scope/
+func WithScopesForHost(ctx context.Context, host string, scopes ...string) context.Context {
+	scopes = CleanScopes(scopes)
+	return context.WithValue(ctx, scopesForHostContextKey(host), scopes)
+}
+
+// AppendScopesForHost appends additional scopes to the existing scopes
+// in the context for the given host and returns a new context.
+// The resulted scopes are de-duplicated.
+// The append operation does modify the existing scope in the context passed in.
+func AppendScopesForHost(ctx context.Context, host string, scopes ...string) context.Context {
+	if len(scopes) == 0 {
+		return ctx
+	}
+	oldScopes := GetScopesForHost(ctx, host)
+	return WithScopesForHost(ctx, host, append(oldScopes, scopes...)...)
+}
+
+// GetScopesForHost returns the scopes in the context for the given host,
+// excluding global scopes added by [WithScopes] and [AppendScopes].
+func GetScopesForHost(ctx context.Context, host string) []string {
+	if scopes, ok := ctx.Value(scopesForHostContextKey(host)).([]string); ok {
+		return slices.Clone(scopes)
 	}
 	return nil
 }
 
+// GetAllScopesForHost returns the scopes in the context for the given host,
+// including global scopes added by [WithScopes] and [AppendScopes].
+func GetAllScopesForHost(ctx context.Context, host string) []string {
+	scopes := GetScopesForHost(ctx, host)
+	globalScopes := GetScopes(ctx)
+
+	if len(scopes) == 0 {
+		return globalScopes
+	}
+	if len(globalScopes) == 0 {
+		return scopes
+	}
+	// re-clean the scopes
+	allScopes := append(scopes, globalScopes...)
+	return CleanScopes(allScopes)
+}
+
 // CleanScopes merges and sort the actions in ascending order if the scopes have
 // the same resource type and name. The final scopes are sorted in ascending
 // order. In other words, the scopes passed in are de-duplicated and sorted.
diff --git a/vendor/oras.land/oras-go/v2/registry/remote/errcode/errors.go b/vendor/oras.land/oras-go/v2/registry/remote/errcode/errors.go
index fb192aa8a..78c6557ab 100644
--- a/vendor/oras.land/oras-go/v2/registry/remote/errcode/errors.go
+++ b/vendor/oras.land/oras-go/v2/registry/remote/errcode/errors.go
@@ -24,7 +24,7 @@ import (
 )
 
 // References:
-//   - https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc3/spec.md#error-codes
+//   - https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc4/spec.md#error-codes
 //   - https://docs.docker.com/registry/spec/api/#errors-2
 const (
 	ErrorCodeBlobUnknown         = "BLOB_UNKNOWN"
@@ -45,7 +45,7 @@ const (
 // Error represents a response inner error returned by the remote
 // registry.
 // References:
-//   - https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc3/spec.md#error-codes
+//   - https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc4/spec.md#error-codes
 //   - https://docs.docker.com/registry/spec/api/#errors-2
 type Error struct {
 	Code    string `json:"code"`
@@ -73,7 +73,7 @@ func (e Error) Error() string {
 // Errors represents a list of response inner errors returned by the remote
 // server.
 // References:
-//   - https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc3/spec.md#error-codes
+//   - https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc4/spec.md#error-codes
 //   - https://docs.docker.com/registry/spec/api/#errors-2
 type Errors []Error
 
diff --git a/vendor/oras.land/oras-go/v2/registry/remote/referrers.go b/vendor/oras.land/oras-go/v2/registry/remote/referrers.go
index 191db9d17..45c738a05 100644
--- a/vendor/oras.land/oras-go/v2/registry/remote/referrers.go
+++ b/vendor/oras.land/oras-go/v2/registry/remote/referrers.go
@@ -102,7 +102,7 @@ func (e *ReferrersError) IsReferrersIndexDelete() bool {
 
 // buildReferrersTag builds the referrers tag for the given manifest descriptor.
 // Format: <algorithm>-<digest>
-// Reference: https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc3/spec.md#unavailable-referrers-api
+// Reference: https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc4/spec.md#unavailable-referrers-api
 func buildReferrersTag(desc ocispec.Descriptor) string {
 	alg := desc.Digest.Algorithm().String()
 	encoded := desc.Digest.Encoded()
diff --git a/vendor/oras.land/oras-go/v2/registry/remote/registry.go b/vendor/oras.land/oras-go/v2/registry/remote/registry.go
index 8ae538d96..9af3f3a42 100644
--- a/vendor/oras.land/oras-go/v2/registry/remote/registry.go
+++ b/vendor/oras.land/oras-go/v2/registry/remote/registry.go
@@ -94,7 +94,7 @@ func (r *Registry) do(req *http.Request) (*http.Response, error) {
 //
 // References:
 //   - https://docs.docker.com/registry/spec/api/#base
-//   - https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc3/spec.md#api
+//   - https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc4/spec.md#api
 func (r *Registry) Ping(ctx context.Context) error {
 	url := buildRegistryBaseURL(r.PlainHTTP, r.Reference)
 	req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
@@ -127,7 +127,7 @@ func (r *Registry) Ping(ctx context.Context) error {
 //
 // Reference: https://docs.docker.com/registry/spec/api/#catalog
 func (r *Registry) Repositories(ctx context.Context, last string, fn func(repos []string) error) error {
-	ctx = auth.AppendScopes(ctx, auth.ScopeRegistryCatalog)
+	ctx = auth.AppendScopesForHost(ctx, r.Reference.Host(), auth.ScopeRegistryCatalog)
 	url := buildRegistryCatalogURL(r.PlainHTTP, r.Reference)
 	var err error
 	for err == nil {
diff --git a/vendor/oras.land/oras-go/v2/registry/remote/repository.go b/vendor/oras.land/oras-go/v2/registry/remote/repository.go
index 769f614d2..def5f56b6 100644
--- a/vendor/oras.land/oras-go/v2/registry/remote/repository.go
+++ b/vendor/oras.land/oras-go/v2/registry/remote/repository.go
@@ -37,7 +37,6 @@ import (
 	"oras.land/oras-go/v2/internal/cas"
 	"oras.land/oras-go/v2/internal/httputil"
 	"oras.land/oras-go/v2/internal/ioutil"
-	"oras.land/oras-go/v2/internal/registryutil"
 	"oras.land/oras-go/v2/internal/slices"
 	"oras.land/oras-go/v2/internal/spec"
 	"oras.land/oras-go/v2/internal/syncutil"
@@ -54,7 +53,7 @@ const (
 	//
 	// References:
 	//   - https://docs.docker.com/registry/spec/api/#digest-header
-	//   - https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc3/spec.md#pull
+	//   - https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc4/spec.md#pull
 	headerDockerContentDigest = "Docker-Content-Digest"
 
 	// headerOCIFiltersApplied is the "OCI-Filters-Applied" header.
@@ -62,7 +61,7 @@ const (
 	// applied filters.
 	//
 	// Reference:
-	//   - https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc3/spec.md#listing-referrers
+	//   - https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc4/spec.md#listing-referrers
 	headerOCIFiltersApplied = "OCI-Filters-Applied"
 
 	// headerOCISubject is the "OCI-Subject" header.
@@ -75,7 +74,7 @@ const (
 // referrers.
 //
 // References:
-//   - Latest spec: https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc3/spec.md#listing-referrers
+//   - Latest spec: https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc4/spec.md#listing-referrers
 //   - Compatible spec: https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc1/spec.md#listing-referrers
 const filterTypeArtifactType = "artifactType"
 
@@ -119,7 +118,7 @@ type Repository struct {
 	// ReferrerListPageSize specifies the page size when invoking the Referrers
 	// API.
 	// If zero, the page size is determined by the remote registry.
-	// Reference: https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc3/spec.md#listing-referrers
+	// Reference: https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc4/spec.md#listing-referrers
 	ReferrerListPageSize int
 
 	// MaxMetadataBytes specifies a limit on how many response bytes are allowed
@@ -134,16 +133,16 @@ type Repository struct {
 	//    is successfully uploaded.
 	//  - If true, the old referrers index is kept.
 	// By default, it is disabled (set to false). See also:
-	//  - https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc3/spec.md#referrers-tag-schema
-	//  - https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc3/spec.md#pushing-manifests-with-subject
-	//  - https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc3/spec.md#deleting-manifests
+	//  - https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc4/spec.md#referrers-tag-schema
+	//  - https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc4/spec.md#pushing-manifests-with-subject
+	//  - https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc4/spec.md#deleting-manifests
 	SkipReferrersGC bool
 
 	// HandleWarning handles the warning returned by the remote server.
 	// Callers SHOULD deduplicate warnings from multiple associated responses.
 	//
 	// References:
-	//   - https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc3/spec.md#warnings
+	//   - https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc4/spec.md#warnings
 	//   - https://www.rfc-editor.org/rfc/rfc7234#section-5.5
 	HandleWarning func(warning Warning)
 
@@ -213,9 +212,9 @@ func (r *Repository) clone() *Repository {
 // SetReferrersCapability returns ErrReferrersCapabilityAlreadySet if the
 // Referrers API capability has been already set.
 //   - When the capability is set to true, the Referrers() function will always
-//     request the Referrers API. Reference: https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc3/spec.md#listing-referrers
+//     request the Referrers API. Reference: https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc4/spec.md#listing-referrers
 //   - When the capability is set to false, the Referrers() function will always
-//     request the Referrers Tag. Reference: https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc3/spec.md#referrers-tag-schema
+//     request the Referrers Tag. Reference: https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc4/spec.md#referrers-tag-schema
 //   - When the capability is not set, the Referrers() function will automatically
 //     determine which API to use.
 func (r *Repository) SetReferrersCapability(capable bool) error {
@@ -389,10 +388,10 @@ func (r *Repository) ParseReference(reference string) (registry.Reference, error
 // of the Tags list.
 //
 // References:
-//   - https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc3/spec.md#content-discovery
+//   - https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc4/spec.md#content-discovery
 //   - https://docs.docker.com/registry/spec/api/#tags
 func (r *Repository) Tags(ctx context.Context, last string, fn func(tags []string) error) error {
-	ctx = registryutil.WithScopeHint(ctx, r.Reference, auth.ActionPull)
+	ctx = auth.AppendRepositoryScope(ctx, r.Reference, auth.ActionPull)
 	url := buildRepositoryTagListURL(r.PlainHTTP, r.Reference)
 	var err error
 	for err == nil {
@@ -448,7 +447,7 @@ func (r *Repository) tags(ctx context.Context, last string, fn func(tags []strin
 // Predecessors returns the descriptors of image or artifact manifests directly
 // referencing the given manifest descriptor.
 // Predecessors internally leverages Referrers.
-// Reference: https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc3/spec.md#listing-referrers
+// Reference: https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc4/spec.md#listing-referrers
 func (r *Repository) Predecessors(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
 	var res []ocispec.Descriptor
 	if err := r.Referrers(ctx, desc, "", func(referrers []ocispec.Descriptor) error {
@@ -467,7 +466,7 @@ func (r *Repository) Predecessors(ctx context.Context, desc ocispec.Descriptor)
 // If artifactType is not empty, only referrers of the same artifact type are
 // fed to fn.
 //
-// Reference: https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc3/spec.md#listing-referrers
+// Reference: https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc4/spec.md#listing-referrers
 func (r *Repository) Referrers(ctx context.Context, desc ocispec.Descriptor, artifactType string, fn func(referrers []ocispec.Descriptor) error) error {
 	state := r.loadReferrersState()
 	if state == referrersStateUnsupported {
@@ -484,18 +483,12 @@ func (r *Repository) Referrers(ctx context.Context, desc ocispec.Descriptor, art
 
 	// The referrers state is unknown.
 	if err != nil {
-		var errResp *errcode.ErrorResponse
-		if !errors.As(err, &errResp) || errResp.StatusCode != http.StatusNotFound {
-			return err
-		}
-		if errutil.IsErrorCode(errResp, errcode.ErrorCodeNameUnknown) {
-			// The repository is not found, no fallback.
-			return err
+		if errors.Is(err, errdef.ErrUnsupported) {
+			// Referrers API is not supported, fallback to referrers tag schema.
+			r.SetReferrersCapability(false)
+			return r.referrersByTagSchema(ctx, desc, artifactType, fn)
 		}
-		// A 404 returned by Referrers API indicates that Referrers API is
-		// not supported. Fallback to referrers tag schema.
-		r.SetReferrersCapability(false)
-		return r.referrersByTagSchema(ctx, desc, artifactType, fn)
+		return err
 	}
 
 	r.SetReferrersCapability(true)
@@ -509,7 +502,7 @@ func (r *Repository) Referrers(ctx context.Context, desc ocispec.Descriptor, art
 func (r *Repository) referrersByAPI(ctx context.Context, desc ocispec.Descriptor, artifactType string, fn func(referrers []ocispec.Descriptor) error) error {
 	ref := r.Reference
 	ref.Reference = desc.Digest.String()
-	ctx = registryutil.WithScopeHint(ctx, ref, auth.ActionPull)
+	ctx = auth.AppendRepositoryScope(ctx, ref, auth.ActionPull)
 
 	url := buildReferrersURL(r.PlainHTTP, ref, artifactType)
 	var err error
@@ -545,10 +538,24 @@ func (r *Repository) referrersPageByAPI(ctx context.Context, artifactType string
 	}
 	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusOK {
+	switch resp.StatusCode {
+	case http.StatusOK:
+	case http.StatusNotFound:
+		if errResp := errutil.ParseErrorResponse(resp); errutil.IsErrorCode(errResp, errcode.ErrorCodeNameUnknown) {
+			// The repository is not found, Referrers API status is unknown
+			return "", errResp
+		}
+		// Referrers API is not supported.
+		return "", fmt.Errorf("failed to query referrers API: %w", errdef.ErrUnsupported)
+	default:
 		return "", errutil.ParseErrorResponse(resp)
 	}
 
+	// also check the content type
+	if ct := resp.Header.Get("Content-Type"); ct != ocispec.MediaTypeImageIndex {
+		return "", fmt.Errorf("unknown content returned (%s), expecting image index: %w", ct, errdef.ErrUnsupported)
+	}
+
 	var index ocispec.Index
 	lr := limitReader(resp.Body, r.MaxMetadataBytes)
 	if err := json.NewDecoder(lr).Decode(&index); err != nil {
@@ -558,7 +565,7 @@ func (r *Repository) referrersPageByAPI(ctx context.Context, artifactType string
 	referrers := index.Manifests
 	if artifactType != "" {
 		// check both filters header and filters annotations for compatibility
-		// latest spec for filters header: https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc3/spec.md#listing-referrers
+		// latest spec for filters header: https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc4/spec.md#listing-referrers
 		// older spec for filters annotations: https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc1/spec.md#listing-referrers
 		filtersHeader := resp.Header.Get(headerOCIFiltersApplied)
 		filtersAnnotation := index.Annotations[spec.AnnotationReferrersFiltersApplied]
@@ -580,7 +587,7 @@ func (r *Repository) referrersPageByAPI(ctx context.Context, artifactType string
 // referencing the given manifest descriptor by requesting referrers tag.
 // fn is called for the referrers result. If artifactType is not empty,
 // only referrers of the same artifact type are fed to fn.
-// reference: https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc3/spec.md#backwards-compatibility
+// reference: https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc4/spec.md#backwards-compatibility
 func (r *Repository) referrersByTagSchema(ctx context.Context, desc ocispec.Descriptor, artifactType string, fn func(referrers []ocispec.Descriptor) error) error {
 	referrersTag := buildReferrersTag(desc)
 	_, referrers, err := r.referrersFromIndex(ctx, referrersTag)
@@ -643,7 +650,7 @@ func (r *Repository) pingReferrers(ctx context.Context) (bool, error) {
 
 	ref := r.Reference
 	ref.Reference = zeroDigest
-	ctx = registryutil.WithScopeHint(ctx, ref, auth.ActionPull)
+	ctx = auth.AppendRepositoryScope(ctx, ref, auth.ActionPull)
 
 	url := buildReferrersURL(r.PlainHTTP, ref, "")
 	req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
@@ -658,8 +665,9 @@ func (r *Repository) pingReferrers(ctx context.Context) (bool, error) {
 
 	switch resp.StatusCode {
 	case http.StatusOK:
-		r.SetReferrersCapability(true)
-		return true, nil
+		supported := resp.Header.Get("Content-Type") == ocispec.MediaTypeImageIndex
+		r.SetReferrersCapability(supported)
+		return supported, nil
 	case http.StatusNotFound:
 		if err := errutil.ParseErrorResponse(resp); errutil.IsErrorCode(err, errcode.ErrorCodeNameUnknown) {
 			// repository not found
@@ -677,7 +685,7 @@ func (r *Repository) pingReferrers(ctx context.Context) (bool, error) {
 func (r *Repository) delete(ctx context.Context, target ocispec.Descriptor, isManifest bool) error {
 	ref := r.Reference
 	ref.Reference = target.Digest.String()
-	ctx = registryutil.WithScopeHint(ctx, ref, auth.ActionDelete)
+	ctx = auth.AppendRepositoryScope(ctx, ref, auth.ActionDelete)
 	buildURL := buildRepositoryBlobURL
 	if isManifest {
 		buildURL = buildRepositoryManifestURL
@@ -713,7 +721,7 @@ type blobStore struct {
 func (s *blobStore) Fetch(ctx context.Context, target ocispec.Descriptor) (rc io.ReadCloser, err error) {
 	ref := s.repo.Reference
 	ref.Reference = target.Digest.String()
-	ctx = registryutil.WithScopeHint(ctx, ref, auth.ActionPull)
+	ctx = auth.AppendRepositoryScope(ctx, ref, auth.ActionPull)
 	url := buildRepositoryBlobURL(s.repo.PlainHTTP, ref)
 	req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
 	if err != nil {
@@ -755,12 +763,12 @@ func (s *blobStore) Fetch(ctx context.Context, target ocispec.Descriptor) (rc io
 func (s *blobStore) Mount(ctx context.Context, desc ocispec.Descriptor, fromRepo string, getContent func() (io.ReadCloser, error)) error {
 	// pushing usually requires both pull and push actions.
 	// Reference: https://github.com/distribution/distribution/blob/v2.7.1/registry/handlers/app.go#L921-L930
-	ctx = registryutil.WithScopeHint(ctx, s.repo.Reference, auth.ActionPull, auth.ActionPush)
+	ctx = auth.AppendRepositoryScope(ctx, s.repo.Reference, auth.ActionPull, auth.ActionPush)
 
 	// We also need pull access to the source repo.
 	fromRef := s.repo.Reference
 	fromRef.Repository = fromRepo
-	ctx = registryutil.WithScopeHint(ctx, fromRef, auth.ActionPull)
+	ctx = auth.AppendRepositoryScope(ctx, fromRef, auth.ActionPull)
 
 	url := buildRepositoryBlobMountURL(s.repo.PlainHTTP, s.repo.Reference, desc.Digest, fromRepo)
 	req, err := http.NewRequestWithContext(ctx, http.MethodPost, url, nil)
@@ -793,7 +801,7 @@ func (s *blobStore) Mount(ctx context.Context, desc ocispec.Descriptor, fromRepo
 	// push it. If the caller has provided a getContent function, we
 	// can use that, otherwise pull the content from the source repository.
 	//
-	// [spec]: https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc3/spec.md#mounting-a-blob-from-another-repository
+	// [spec]: https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc4/spec.md#mounting-a-blob-from-another-repository
 
 	var r io.ReadCloser
 	if getContent != nil {
@@ -828,12 +836,12 @@ func (s *blobStore) sibling(otherRepoName string) *blobStore {
 // References:
 //   - https://docs.docker.com/registry/spec/api/#pushing-an-image
 //   - https://docs.docker.com/registry/spec/api/#initiate-blob-upload
-//   - https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc3/spec.md#pushing-a-blob-monolithically
+//   - https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc4/spec.md#pushing-a-blob-monolithically
 func (s *blobStore) Push(ctx context.Context, expected ocispec.Descriptor, content io.Reader) error {
 	// start an upload
 	// pushing usually requires both pull and push actions.
 	// Reference: https://github.com/distribution/distribution/blob/v2.7.1/registry/handlers/app.go#L921-L930
-	ctx = registryutil.WithScopeHint(ctx, s.repo.Reference, auth.ActionPull, auth.ActionPush)
+	ctx = auth.AppendRepositoryScope(ctx, s.repo.Reference, auth.ActionPull, auth.ActionPush)
 	url := buildRepositoryBlobUploadURL(s.repo.PlainHTTP, s.repo.Reference)
 	req, err := http.NewRequestWithContext(ctx, http.MethodPost, url, nil)
 	if err != nil {
@@ -934,7 +942,7 @@ func (s *blobStore) Resolve(ctx context.Context, reference string) (ocispec.Desc
 	if err != nil {
 		return ocispec.Descriptor{}, err
 	}
-	ctx = registryutil.WithScopeHint(ctx, ref, auth.ActionPull)
+	ctx = auth.AppendRepositoryScope(ctx, ref, auth.ActionPull)
 	url := buildRepositoryBlobURL(s.repo.PlainHTTP, ref)
 	req, err := http.NewRequestWithContext(ctx, http.MethodHead, url, nil)
 	if err != nil {
@@ -969,7 +977,7 @@ func (s *blobStore) FetchReference(ctx context.Context, reference string) (desc
 		return ocispec.Descriptor{}, nil, err
 	}
 
-	ctx = registryutil.WithScopeHint(ctx, ref, auth.ActionPull)
+	ctx = auth.AppendRepositoryScope(ctx, ref, auth.ActionPull)
 	url := buildRepositoryBlobURL(s.repo.PlainHTTP, ref)
 	req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
 	if err != nil {
@@ -1044,7 +1052,7 @@ type manifestStore struct {
 func (s *manifestStore) Fetch(ctx context.Context, target ocispec.Descriptor) (rc io.ReadCloser, err error) {
 	ref := s.repo.Reference
 	ref.Reference = target.Digest.String()
-	ctx = registryutil.WithScopeHint(ctx, ref, auth.ActionPull)
+	ctx = auth.AppendRepositoryScope(ctx, ref, auth.ActionPull)
 	url := buildRepositoryManifestURL(s.repo.PlainHTTP, ref)
 	req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
 	if err != nil {
@@ -1121,7 +1129,7 @@ func (s *manifestStore) deleteWithIndexing(ctx context.Context, target ocispec.D
 		if err := limitSize(target, s.repo.MaxMetadataBytes); err != nil {
 			return err
 		}
-		ctx = registryutil.WithScopeHint(ctx, s.repo.Reference, auth.ActionPull, auth.ActionDelete)
+		ctx = auth.AppendRepositoryScope(ctx, s.repo.Reference, auth.ActionPull, auth.ActionDelete)
 		manifestJSON, err := content.FetchAll(ctx, s, target)
 		if err != nil {
 			return err
@@ -1138,7 +1146,7 @@ func (s *manifestStore) deleteWithIndexing(ctx context.Context, target ocispec.D
 // on manifest delete.
 //
 // References:
-//   - Latest spec: https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc3/spec.md#deleting-manifests
+//   - Latest spec: https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc4/spec.md#deleting-manifests
 //   - Compatible spec: https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc1/spec.md#deleting-manifests
 func (s *manifestStore) indexReferrersForDelete(ctx context.Context, desc ocispec.Descriptor, manifestJSON []byte) error {
 	var manifest struct {
@@ -1171,7 +1179,7 @@ func (s *manifestStore) Resolve(ctx context.Context, reference string) (ocispec.
 	if err != nil {
 		return ocispec.Descriptor{}, err
 	}
-	ctx = registryutil.WithScopeHint(ctx, ref, auth.ActionPull)
+	ctx = auth.AppendRepositoryScope(ctx, ref, auth.ActionPull)
 	url := buildRepositoryManifestURL(s.repo.PlainHTTP, ref)
 	req, err := http.NewRequestWithContext(ctx, http.MethodHead, url, nil)
 	if err != nil {
@@ -1203,7 +1211,7 @@ func (s *manifestStore) FetchReference(ctx context.Context, reference string) (d
 		return ocispec.Descriptor{}, nil, err
 	}
 
-	ctx = registryutil.WithScopeHint(ctx, ref, auth.ActionPull)
+	ctx = auth.AppendRepositoryScope(ctx, ref, auth.ActionPull)
 	url := buildRepositoryManifestURL(s.repo.PlainHTTP, ref)
 	req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
 	if err != nil {
@@ -1246,7 +1254,7 @@ func (s *manifestStore) Tag(ctx context.Context, desc ocispec.Descriptor, refere
 		return err
 	}
 
-	ctx = registryutil.WithScopeHint(ctx, ref, auth.ActionPull, auth.ActionPush)
+	ctx = auth.AppendRepositoryScope(ctx, ref, auth.ActionPull, auth.ActionPush)
 	rc, err := s.Fetch(ctx, desc)
 	if err != nil {
 		return err
@@ -1271,7 +1279,7 @@ func (s *manifestStore) push(ctx context.Context, expected ocispec.Descriptor, c
 	ref.Reference = reference
 	// pushing usually requires both pull and push actions.
 	// Reference: https://github.com/distribution/distribution/blob/v2.7.1/registry/handlers/app.go#L921-L930
-	ctx = registryutil.WithScopeHint(ctx, ref, auth.ActionPull, auth.ActionPush)
+	ctx = auth.AppendRepositoryScope(ctx, ref, auth.ActionPull, auth.ActionPush)
 	url := buildRepositoryManifestURL(s.repo.PlainHTTP, ref)
 	// unwrap the content for optimizations of built-in types.
 	body := ioutil.UnwrapNopCloser(content)
@@ -1324,13 +1332,19 @@ func (s *manifestStore) push(ctx context.Context, expected ocispec.Descriptor, c
 
 // checkOCISubjectHeader checks the "OCI-Subject" header in the response and
 // sets referrers capability accordingly.
-// Reference: https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc3/spec.md#pushing-manifests-with-subject
+// Reference: https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc4/spec.md#pushing-manifests-with-subject
 func (s *manifestStore) checkOCISubjectHeader(resp *http.Response) {
-	// Referrers capability is not set to false when the subject header is not
-	// present, as the server may still conform to an older version of the spec
+	// If the "OCI-Subject" header is set, it indicates that the registry
+	// supports the Referrers API and has processed the subject of the manifest.
 	if subjectHeader := resp.Header.Get(headerOCISubject); subjectHeader != "" {
 		s.repo.SetReferrersCapability(true)
 	}
+
+	// If the "OCI-Subject" header is NOT set, it means that either the manifest
+	// has no subject OR the referrers API is NOT supported by the registry.
+	//
+	// Since we don't know whether the pushed manifest has a subject or not,
+	// we do not set the referrers capability to false at here.
 }
 
 // pushWithIndexing pushes the manifest content matching the expected descriptor,
@@ -1355,6 +1369,8 @@ func (s *manifestStore) pushWithIndexing(ctx context.Context, expected ocispec.D
 		}
 		// check referrers API availability again after push
 		if state := s.repo.loadReferrersState(); state == referrersStateSupported {
+			// the subject has been processed the registry, no client-side
+			// indexing needed
 			return nil
 		}
 		return s.indexReferrersForPush(ctx, expected, manifestJSON)
@@ -1367,7 +1383,7 @@ func (s *manifestStore) pushWithIndexing(ctx context.Context, expected ocispec.D
 // on manifest push.
 //
 // References:
-//   - Latest spec: https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc3/spec.md#pushing-manifests-with-subject
+//   - Latest spec: https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc4/spec.md#pushing-manifests-with-subject
 //   - Compatible spec: https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc1/spec.md#pushing-manifests-with-subject
 func (s *manifestStore) indexReferrersForPush(ctx context.Context, desc ocispec.Descriptor, manifestJSON []byte) error {
 	var subject ocispec.Descriptor
@@ -1415,22 +1431,17 @@ func (s *manifestStore) indexReferrersForPush(ctx context.Context, desc ocispec.
 		return nil
 	}
 
-	ok, err := s.repo.pingReferrers(ctx)
-	if err != nil {
-		return err
-	}
-	if ok {
-		// referrers API is available, no client-side indexing needed
-		return nil
-	}
+	// if the manifest has a subject but the remote registry does not process it,
+	// it means that the Referrers API is not supported by the registry.
+	s.repo.SetReferrersCapability(false)
 	return s.updateReferrersIndex(ctx, subject, referrerChange{desc, referrerOperationAdd})
 }
 
 // updateReferrersIndex updates the referrers index for desc referencing subject
 // on manifest push and manifest delete.
 // References:
-//   - https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc3/spec.md#pushing-manifests-with-subject
-//   - https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc3/spec.md#deleting-manifests
+//   - https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc4/spec.md#pushing-manifests-with-subject
+//   - https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc4/spec.md#deleting-manifests
 func (s *manifestStore) updateReferrersIndex(ctx context.Context, subject ocispec.Descriptor, change referrerChange) (err error) {
 	referrersTag := buildReferrersTag(subject)
 
diff --git a/vendor/oras.land/oras-go/v2/registry/remote/url.go b/vendor/oras.land/oras-go/v2/registry/remote/url.go
index 74258de7a..903ee088d 100644
--- a/vendor/oras.land/oras-go/v2/registry/remote/url.go
+++ b/vendor/oras.land/oras-go/v2/registry/remote/url.go
@@ -101,7 +101,7 @@ func buildRepositoryBlobMountURL(plainHTTP bool, ref registry.Reference, d diges
 
 // buildReferrersURL builds the URL for querying the Referrers API.
 // Format: <scheme>://<registry>/v2/<repository>/referrers/<digest>?artifactType=<artifactType>
-// Reference: https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc3/spec.md#listing-referrers
+// Reference: https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc4/spec.md#listing-referrers
 func buildReferrersURL(plainHTTP bool, ref registry.Reference, artifactType string) string {
 	var query string
 	if artifactType != "" {
diff --git a/vendor/oras.land/oras-go/v2/registry/remote/warning.go b/vendor/oras.land/oras-go/v2/registry/remote/warning.go
index ff8f9c029..5eb98e782 100644
--- a/vendor/oras.land/oras-go/v2/registry/remote/warning.go
+++ b/vendor/oras.land/oras-go/v2/registry/remote/warning.go
@@ -43,7 +43,7 @@ var errUnexpectedWarningFormat = errors.New("unexpected warning format")
 // WarningValue represents the value of the Warning header.
 //
 // References:
-//   - https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc3/spec.md#warnings
+//   - https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc4/spec.md#warnings
 //   - https://www.rfc-editor.org/rfc/rfc7234#section-5.5
 type WarningValue struct {
 	// Code is the warn-code.
@@ -58,7 +58,7 @@ type WarningValue struct {
 // other information related to the warning.
 //
 // References:
-//   - https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc3/spec.md#warnings
+//   - https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc4/spec.md#warnings
 //   - https://www.rfc-editor.org/rfc/rfc7234#section-5.5
 type Warning struct {
 	// WarningValue is the value of the warning header.
diff --git a/vendor/oras.land/oras-go/v2/registry/repository.go b/vendor/oras.land/oras-go/v2/registry/repository.go
index b75b7b8ea..90c269050 100644
--- a/vendor/oras.land/oras-go/v2/registry/repository.go
+++ b/vendor/oras.land/oras-go/v2/registry/repository.go
@@ -17,10 +17,15 @@ package registry
 
 import (
 	"context"
+	"encoding/json"
+	"fmt"
 	"io"
 
 	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
 	"oras.land/oras-go/v2/content"
+	"oras.land/oras-go/v2/errdef"
+	"oras.land/oras-go/v2/internal/descriptor"
+	"oras.land/oras-go/v2/internal/spec"
 )
 
 // Repository is an ORAS target and an union of the blob and the manifest CASs.
@@ -82,7 +87,7 @@ type ReferenceFetcher interface {
 }
 
 // ReferrerLister provides the Referrers API.
-// Reference: https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc3/spec.md#listing-referrers
+// Reference: https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc4/spec.md#listing-referrers
 type ReferrerLister interface {
 	Referrers(ctx context.Context, desc ocispec.Descriptor, artifactType string, fn func(referrers []ocispec.Descriptor) error) error
 }
@@ -104,7 +109,7 @@ type TagLister interface {
 	// specification.
 	//
 	// References:
-	//   - https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc3/spec.md#content-discovery
+	//   - https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc4/spec.md#content-discovery
 	//   - https://docs.docker.com/registry/spec/api/#tags
 	// See also `Tags()` in this package.
 	Tags(ctx context.Context, last string, fn func(tags []string) error) error
@@ -134,3 +139,88 @@ func Tags(ctx context.Context, repo TagLister) ([]string, error) {
 	}
 	return res, nil
 }
+
+// Referrers lists the descriptors of image or artifact manifests directly
+// referencing the given manifest descriptor.
+//
+// Reference: https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc4/spec.md#listing-referrers
+func Referrers(ctx context.Context, store content.ReadOnlyGraphStorage, desc ocispec.Descriptor, artifactType string) ([]ocispec.Descriptor, error) {
+	if !descriptor.IsManifest(desc) {
+		return nil, fmt.Errorf("the descriptor %v is not a manifest: %w", desc, errdef.ErrUnsupported)
+	}
+
+	var results []ocispec.Descriptor
+
+	// use the Referrer API if it is available
+	if rf, ok := store.(ReferrerLister); ok {
+		if err := rf.Referrers(ctx, desc, artifactType, func(referrers []ocispec.Descriptor) error {
+			results = append(results, referrers...)
+			return nil
+		}); err != nil {
+			return nil, err
+		}
+		return results, nil
+	}
+
+	predecessors, err := store.Predecessors(ctx, desc)
+	if err != nil {
+		return nil, err
+	}
+	for _, node := range predecessors {
+		switch node.MediaType {
+		case ocispec.MediaTypeImageManifest:
+			fetched, err := content.FetchAll(ctx, store, node)
+			if err != nil {
+				return nil, err
+			}
+			var manifest ocispec.Manifest
+			if err := json.Unmarshal(fetched, &manifest); err != nil {
+				return nil, err
+			}
+			if manifest.Subject == nil || !content.Equal(*manifest.Subject, desc) {
+				continue
+			}
+			node.ArtifactType = manifest.ArtifactType
+			if node.ArtifactType == "" {
+				node.ArtifactType = manifest.Config.MediaType
+			}
+			node.Annotations = manifest.Annotations
+		case ocispec.MediaTypeImageIndex:
+			fetched, err := content.FetchAll(ctx, store, node)
+			if err != nil {
+				return nil, err
+			}
+			var index ocispec.Index
+			if err := json.Unmarshal(fetched, &index); err != nil {
+				return nil, err
+			}
+			if index.Subject == nil || !content.Equal(*index.Subject, desc) {
+				continue
+			}
+			node.ArtifactType = index.ArtifactType
+			node.Annotations = index.Annotations
+		case spec.MediaTypeArtifactManifest:
+			fetched, err := content.FetchAll(ctx, store, node)
+			if err != nil {
+				return nil, err
+			}
+			var artifact spec.Artifact
+			if err := json.Unmarshal(fetched, &artifact); err != nil {
+				return nil, err
+			}
+			if artifact.Subject == nil || !content.Equal(*artifact.Subject, desc) {
+				continue
+			}
+			node.ArtifactType = artifact.ArtifactType
+			node.Annotations = artifact.Annotations
+		default:
+			continue
+		}
+		if artifactType == "" || artifactType == node.ArtifactType {
+			// the field artifactType in referrers descriptor is allowed to be empty
+			// https://github.com/opencontainers/distribution-spec/issues/458
+			results = append(results, node)
+		}
+	}
+	return results, nil
+}


Test patch:
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 69cd3a769..eb7b24bd3 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -38,7 +38,7 @@ jobs:
           sudo apt install -y libseccomp-dev libelf-dev libapparmor-dev
           sudo hack/install-libbpf.sh
       - run: make test-unit
-      - uses: codecov/codecov-action@4fe8c5f003fae66aa5ebb77cfd3e7bfbbda0b6b0
+      - uses: codecov/codecov-action@ab904c41d6ece82784817410c45d8b8c02684457
         with:
           files: build/coverage.out
           flags: unittests