Repository: sigstore/cosign
Pull request #3032 (2023-06-02 16:59:10)

chore(deps): bump golangci/golangci-lint-action from 3.4.0 to 3.5.0
Bumps [golangci/golangci-lint-action](https://github.com/golangci/golangci-lint-action) from 3.4.0 to 3.5.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a href="https://github.com/golangci/golangci-lint-action/releases">golangci/golangci-lint-action's releases</a>.</em></p>
<blockquote>
<h2>v3.5.0</h2>
<h2>What's Changed</h2>
<ul>
<li>build(deps-dev): bump eslint from 8.32.0 to 8.33.0 by <a href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a href="https://redirect.github.com/golangci/golangci-lint-action/pull/659">golangci/golangci-lint-action#659</a></li>
<li>build(deps-dev): bump <code>@​typescript-eslint/eslint-plugin</code> from 5.48.2 to 5.49.0 by <a href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a href="https://redirect.github.com/golangci/golangci-lint-action/pull/661">golangci/golangci-lint-action#661</a></li>
<li>build(deps-dev): bump eslint-plugin-simple-import-sort from 9.0.0 to 10.0.0 by <a href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a href="https://redirect.github.com/golangci/golangci-lint-action/pull/662">golangci/golangci-lint-action#662</a></li>
<li>build(deps-dev): bump <code>@​vercel/ncc</code> from 0.36.0 to 0.36.1 by <a href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a href="https://redirect.github.com/golangci/golangci-lint-action/pull/660">golangci/golangci-lint-action#660</a></li>
<li>build(deps-dev): bump <code>@​typescript-eslint/parser</code> from 5.48.2 to 5.49.0 by <a href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a href="https://redirect.github.com/golangci/golangci-lint-action/pull/663">golangci/golangci-lint-action#663</a></li>
<li>build(deps-dev): bump <code>@​typescript-eslint/eslint-plugin</code> from 5.49.0 to 5.50.0 by <a href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a href="https://redirect.github.com/golangci/golangci-lint-action/pull/665">golangci/golangci-lint-action#665</a></li>
<li>build(deps-dev): bump <code>@​typescript-eslint/parser</code> from 5.49.0 to 5.50.0 by <a href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a href="https://redirect.github.com/golangci/golangci-lint-action/pull/666">golangci/golangci-lint-action#666</a></li>
<li>build(deps-dev): bump typescript from 4.9.4 to 4.9.5 by <a href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a href="https://redirect.github.com/golangci/golangci-lint-action/pull/667">golangci/golangci-lint-action#667</a></li>
<li>build(deps): bump <code>@​types/node</code> from 18.11.18 to 18.11.19 by <a href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a href="https://redirect.github.com/golangci/golangci-lint-action/pull/668">golangci/golangci-lint-action#668</a></li>
<li>doc: add quote aroung go version by <a href="https://github.com/vaughany"><code>@​vaughany</code></a> in <a href="https://redirect.github.com/golangci/golangci-lint-action/pull/670">golangci/golangci-lint-action#670</a></li>
<li>build(deps-dev): bump <code>@​typescript-eslint/parser</code> from 5.50.0 to 5.51.0 by <a href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a href="https://redirect.github.com/golangci/golangci-lint-action/pull/671">golangci/golangci-lint-action#671</a></li>
<li>build(deps-dev): bump prettier from 2.8.3 to 2.8.4 by <a href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a href="https://redirect.github.com/golangci/golangci-lint-action/pull/673">golangci/golangci-lint-action#673</a></li>
<li>build(deps): bump <code>@​types/node</code> from 18.11.19 to 18.13.0 by <a href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a href="https://redirect.github.com/golangci/golangci-lint-action/pull/674">golangci/golangci-lint-action#674</a></li>
<li>build(deps-dev): bump <code>@​typescript-eslint/eslint-plugin</code> from 5.50.0 to 5.51.0 by <a href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a href="https://redirect.github.com/golangci/golangci-lint-action/pull/675">golangci/golangci-lint-action#675</a></li>
<li>build(deps): bump <code>@​actions/cache</code> from 3.1.2 to 3.1.3 by <a href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a href="https://redirect.github.com/golangci/golangci-lint-action/pull/672">golangci/golangci-lint-action#672</a></li>
<li>build(deps-dev): bump <code>@​typescript-eslint/parser</code> from 5.51.0 to 5.52.0 by <a href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a href="https://redirect.github.com/golangci/golangci-lint-action/pull/678">golangci/golangci-lint-action#678</a></li>
<li>build(deps): bump <code>@​types/node</code> from 18.13.0 to 18.14.0 by <a href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a href="https://redirect.github.com/golangci/golangci-lint-action/pull/679">golangci/golangci-lint-action#679</a></li>
<li>build(deps-dev): bump eslint from 8.33.0 to 8.34.0 by <a href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a href="https://redirect.github.com/golangci/golangci-lint-action/pull/680">golangci/golangci-lint-action#680</a></li>
<li>build(deps-dev): bump <code>@​typescript-eslint/eslint-plugin</code> from 5.51.0 to 5.52.0 by <a href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a href="https://redirect.github.com/golangci/golangci-lint-action/pull/681">golangci/golangci-lint-action#681</a></li>
<li>build(deps-dev): bump <code>@​typescript-eslint/eslint-plugin</code> from 5.52.0 to 5.53.0 by <a href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a href="https://redirect.github.com/golangci/golangci-lint-action/pull/684">golangci/golangci-lint-action#684</a></li>
<li>build(deps-dev): bump eslint from 8.34.0 to 8.35.0 by <a href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a href="https://redirect.github.com/golangci/golangci-lint-action/pull/685">golangci/golangci-lint-action#685</a></li>
<li>build(deps): bump <code>@​types/node</code> from 18.14.0 to 18.14.2 by <a href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a href="https://redirect.github.com/golangci/golangci-lint-action/pull/688">golangci/golangci-lint-action#688</a></li>
<li>build(deps-dev): bump <code>@​typescript-eslint/parser</code> from 5.52.0 to 5.53.0 by <a href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a href="https://redirect.github.com/golangci/golangci-lint-action/pull/687">golangci/golangci-lint-action#687</a></li>
<li>build(deps): bump <code>@​actions/cache</code> from 3.1.3 to 3.1.4 by <a href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a href="https://redirect.github.com/golangci/golangci-lint-action/pull/686">golangci/golangci-lint-action#686</a></li>
<li>build(deps): bump <code>@​types/node</code> from 18.14.2 to 18.14.6 by <a href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a href="https://redirect.github.com/golangci/golangci-lint-action/pull/691">golangci/golangci-lint-action#691</a></li>
<li>build(deps-dev): bump <code>@​typescript-eslint/parser</code> from 5.53.0 to 5.54.0 by <a href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a href="https://redirect.github.com/golangci/golangci-lint-action/pull/692">golangci/golangci-lint-action#692</a></li>
<li>build(deps-dev): bump <code>@​typescript-eslint/eslint-plugin</code> from 5.53.0 to 5.54.0 by <a href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a href="https://redirect.github.com/golangci/golangci-lint-action/pull/693">golangci/golangci-lint-action#693</a></li>
<li>build(deps-dev): bump eslint-config-prettier from 8.6.0 to 8.7.0 by <a href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a href="https://redirect.github.com/golangci/golangci-lint-action/pull/694">golangci/golangci-lint-action#694</a></li>
<li>build(deps-dev): bump eslint from 8.35.0 to 8.36.0 by <a href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a href="https://redirect.github.com/golangci/golangci-lint-action/pull/699">golangci/golangci-lint-action#699</a></li>
<li>build(deps-dev): bump <code>@​typescript-eslint/eslint-plugin</code> from 5.54.0 to 5.54.1 by <a href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a href="https://redirect.github.com/golangci/golangci-lint-action/pull/700">golangci/golangci-lint-action#700</a></li>
<li>build(deps): bump <code>@​types/node</code> from 18.14.6 to 18.15.1 by <a href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a href="https://redirect.github.com/golangci/golangci-lint-action/pull/701">golangci/golangci-lint-action#701</a></li>
<li>docs/build: update to setup-go@v4 by <a href="https://github.com/caarlos0"><code>@​caarlos0</code></a> in <a href="https://redirect.github.com/golangci/golangci-lint-action/pull/704">golangci/golangci-lint-action#704</a></li>
<li>build(deps-dev): bump typescript from 4.9.5 to 5.0.2 by <a href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a href="https://redirect.github.com/golangci/golangci-lint-action/pull/705">golangci/golangci-lint-action#705</a></li>
<li>build(deps): bump <code>@​types/node</code> from 18.15.1 to 18.15.3 by <a href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a href="https://redirect.github.com/golangci/golangci-lint-action/pull/706">golangci/golangci-lint-action#706</a></li>
<li>build(deps): bump <code>@​actions/http-client</code> from 2.0.1 to 2.1.0 by <a href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a href="https://redirect.github.com/golangci/golangci-lint-action/pull/697">golangci/golangci-lint-action#697</a></li>
<li>build(deps-dev): bump prettier from 2.8.4 to 2.8.5 by <a href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a href="https://redirect.github.com/golangci/golangci-lint-action/pull/707">golangci/golangci-lint-action#707</a></li>
<li>build(deps): bump <code>@​actions/cache</code> from 3.1.4 to 3.2.1 by <a href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a href="https://redirect.github.com/golangci/golangci-lint-action/pull/698">golangci/golangci-lint-action#698</a></li>
<li>build(deps-dev): bump eslint-config-prettier from 8.7.0 to 8.8.0 by <a href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a href="https://redirect.github.com/golangci/golangci-lint-action/pull/709">golangci/golangci-lint-action#709</a></li>
<li>build(deps): bump <code>@​types/node</code> from 18.15.3 to 18.15.10 by <a href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a href="https://redirect.github.com/golangci/golangci-lint-action/pull/710">golangci/golangci-lint-action#710</a></li>
<li>build(deps-dev): bump prettier from 2.8.5 to 2.8.7 by <a href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a href="https://redirect.github.com/golangci/golangci-lint-action/pull/711">golangci/golangci-lint-action#711</a></li>
<li>build(deps-dev): bump <code>@​typescript-eslint/eslint-plugin</code> from 5.54.1 to 5.56.0 by <a href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a href="https://redirect.github.com/golangci/golangci-lint-action/pull/712">golangci/golangci-lint-action#712</a></li>
<li>build(deps-dev): bump <code>@​typescript-eslint/parser</code> from 5.54.0 to 5.56.0 by <a href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a href="https://redirect.github.com/golangci/golangci-lint-action/pull/713">golangci/golangci-lint-action#713</a></li>
<li>build(deps-dev): bump <code>@​typescript-eslint/eslint-plugin</code> from 5.56.0 to 5.57.0 by <a href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a href="https://redirect.github.com/golangci/golangci-lint-action/pull/718">golangci/golangci-lint-action#718</a></li>
<li>build(deps-dev): bump typescript from 5.0.2 to 5.0.3 by <a href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a href="https://redirect.github.com/golangci/golangci-lint-action/pull/717">golangci/golangci-lint-action#717</a></li>
<li>build(deps-dev): bump eslint from 8.36.0 to 8.37.0 by <a href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a href="https://redirect.github.com/golangci/golangci-lint-action/pull/719">golangci/golangci-lint-action#719</a></li>
<li>build(deps-dev): bump <code>@​typescript-eslint/parser</code> from 5.56.0 to 5.57.0 by <a href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a href="https://redirect.github.com/golangci/golangci-lint-action/pull/720">golangci/golangci-lint-action#720</a></li>
<li>build(deps): bump <code>@​types/node</code> from 18.15.10 to 18.15.11 by <a href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a href="https://redirect.github.com/golangci/golangci-lint-action/pull/721">golangci/golangci-lint-action#721</a></li>
<li>build(deps-dev): bump <code>@​typescript-eslint/eslint-plugin</code> from 5.57.0 to 5.57.1 by <a href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a href="https://redirect.github.com/golangci/golangci-lint-action/pull/722">golangci/golangci-lint-action#722</a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a href="https://github.com/golangci/golangci-lint-action/commit/5f1fec7010f6ae3b84ea4f7b2129beb8639b564f"><code>5f1fec7</code></a> build(deps-dev): bump <code>@​typescript-eslint/parser</code> from 5.59.6 to 5.59.7 (<a href="https://redirect.github.com/golangci/golangci-lint-action/issues/758">#758</a>)</li>
<li><a href="https://github.com/golangci/golangci-lint-action/commit/601007b788a335933ba460298a9c9da82a9460b1"><code>601007b</code></a> build(deps): bump <code>@​types/node</code> from 20.2.3 to 20.2.5 (<a href="https://redirect.github.com/golangci/golangci-lint-action/issues/756">#756</a>)</li>
<li><a href="https://github.com/golangci/golangci-lint-action/commit/d2a913e97bbaf8323bd27da961ba33426726000f"><code>d2a913e</code></a> build(deps-dev): bump <code>@​typescript-eslint/eslint-plugin</code> from 5.59.6 to 5.59.7 ...</li>
<li><a href="https://github.com/golangci/golangci-lint-action/commit/7233bd71cb7be55595200383f0b95fe1639ce9ed"><code>7233bd7</code></a> build(deps-dev): bump <code>@​typescript-eslint/eslint-plugin</code> from 5.59.5 to 5.59.6 ...</li>
<li><a href="https://github.com/golangci/golangci-lint-action/commit/687f029324d5666f0f5911bbbc7921193af5d8a4"><code>687f029</code></a> build(deps): bump <code>@​types/node</code> from 20.1.4 to 20.2.3 (<a href="https://redirect.github.com/golangci/golangci-lint-action/issues/755">#755</a>)</li>
<li><a href="https://github.com/golangci/golangci-lint-action/commit/f9990cd216ef435f7c8f9afbb7e713dda02231c9"><code>f9990cd</code></a> build(deps-dev): bump <code>@​typescript-eslint/parser</code> from 5.59.5 to 5.59.6 (<a href="https://redirect.github.com/golangci/golangci-lint-action/issues/754">#754</a>)</li>
<li><a href="https://github.com/golangci/golangci-lint-action/commit/f30aa514f95287b12eb5bca55b54b8e026cde352"><code>f30aa51</code></a> build(deps-dev): bump eslint from 8.40.0 to 8.41.0 (<a href="https://redirect.github.com/golangci/golangci-lint-action/issues/753">#753</a>)</li>
<li><a href="https://github.com/golangci/golangci-lint-action/commit/6b21f586ed8efa6be5638dfa9e4e1766e9da8bcf"><code>6b21f58</code></a> build(deps-dev): bump <code>@​typescript-eslint/eslint-plugin</code> from 5.59.2 to 5.59.5 ...</li>
<li><a href="https://github.com/golangci/golangci-lint-action/commit/535ed3a04b2d201195fae99ee856f62d8582826b"><code>535ed3a</code></a> build(deps): bump <code>@​types/semver</code> from 7.3.13 to 7.5.0 (<a href="https://redirect.github.com/golangci/golangci-lint-action/issues/748">#748</a>)</li>
<li><a href="https://github.com/golangci/golangci-lint-action/commit/0078ef00ab9386a0b13f3f1c1de23eace0a5d6c7"><code>0078ef0</code></a> build(deps-dev): bump <code>@​typescript-eslint/parser</code> from 5.59.1 to 5.59.5 (<a href="https://redirect.github.com/golangci/golangci-lint-action/issues/750">#750</a>)</li>
<li>Additional commits viewable in <a href="https://github.com/golangci/golangci-lint-action/compare/08e2f20817b15149a52b5b3ebe7de50aff2ba8c5...5f1fec7010f6ae3b84ea4f7b2129beb8639b564f">compare view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=golangci/golangci-lint-action&package-manager=github_actions&previous-version=3.4.0&new-version=3.5.0)](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 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>

codecov[bot]: ## [Codecov](https://app.codecov.io/gh/sigstore/cosign/pull/3032?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=sigstore) Report
> Merging [#3032](https://app.codecov.io/gh/sigstore/cosign/pull/3032?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=sigstore) (d6fd617) into [main](https://app.codecov.io/gh/sigstore/cosign/commit/83c08ce4f35116da7c74350a67d5740ca5e28ca5?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=sigstore) (83c08ce) will **not change** coverage.
> The diff coverage is `n/a`.

```diff
@@           Coverage Diff           @@
##             main    #3032   +/-   ##
=======================================
  Coverage   30.45%   30.45%           
=======================================
  Files         152      152           
  Lines        9586     9586           
=======================================
  Hits         2919     2919           
  Misses       6210     6210           
  Partials      457      457           
```





Patch:
diff --git a/cmd/cosign/cli/sign/sign.go b/cmd/cosign/cli/sign/sign.go
index a09bc339..c262c9ae 100644
--- a/cmd/cosign/cli/sign/sign.go
+++ b/cmd/cosign/cli/sign/sign.go
@@ -179,7 +179,9 @@ func SignCmd(ro *options.RootOptions, ko options.KeyOpts, signOpts options.SignO
 
 		if digest, ok := ref.(name.Digest); ok && !signOpts.Recursive {
 			se, err := ociremote.SignedEntity(ref, opts...)
-			if err != nil {
+			if err == ociremote.ErrEntityNotFound {
+				se = ociremote.SignedUnknown(digest)
+			} else if err != nil {
 				return fmt.Errorf("accessing image: %w", err)
 			}
 			err = signDigest(ctx, digest, staticPayload, ko, signOpts, annotations, dd, sv, se)
diff --git a/pkg/oci/mutate/mutate.go b/pkg/oci/mutate/mutate.go
index ce667750..32d37be5 100644
--- a/pkg/oci/mutate/mutate.go
+++ b/pkg/oci/mutate/mutate.go
@@ -135,7 +135,7 @@ func AttachSignatureToEntity(se oci.SignedEntity, sig oci.Signature, opts ...Sig
 	case oci.SignedImageIndex:
 		return AttachSignatureToImageIndex(obj, sig, opts...)
 	default:
-		return nil, fmt.Errorf("unsupported type: %T", se)
+		return AttachSignatureToUnknown(obj, sig, opts...)
 	}
 }
 
@@ -147,7 +147,7 @@ func AttachAttestationToEntity(se oci.SignedEntity, att oci.Signature, opts ...S
 	case oci.SignedImageIndex:
 		return AttachAttestationToImageIndex(obj, att, opts...)
 	default:
-		return nil, fmt.Errorf("unsupported type: %T", se)
+		return AttachAttestationToUnknown(obj, att, opts...)
 	}
 }
 
@@ -159,7 +159,7 @@ func AttachFileToEntity(se oci.SignedEntity, name string, f oci.File, opts ...Si
 	case oci.SignedImageIndex:
 		return AttachFileToImageIndex(obj, name, f, opts...)
 	default:
-		return nil, fmt.Errorf("unsupported type: %T", se)
+		return AttachFileToUnknown(obj, name, f, opts...)
 	}
 }
 
@@ -348,3 +348,108 @@ func (sii *signedImageIndex) Attachment(attName string) (oci.File, error) {
 	}
 	return nil, fmt.Errorf("attachment %q not found", attName)
 }
+
+// AttachSignatureToUnknown attaches the provided signature to the provided image.
+func AttachSignatureToUnknown(se oci.SignedEntity, sig oci.Signature, opts ...SignOption) (oci.SignedEntity, error) {
+	return &signedUnknown{
+		SignedEntity: se,
+		sig:          sig,
+		attachments:  make(map[string]oci.File),
+		so:           makeSignOpts(opts...),
+	}, nil
+}
+
+// AttachAttestationToUnknown attaches the provided attestation to the provided image.
+func AttachAttestationToUnknown(se oci.SignedEntity, att oci.Signature, opts ...SignOption) (oci.SignedEntity, error) {
+	return &signedUnknown{
+		SignedEntity: se,
+		att:          att,
+		attachments:  make(map[string]oci.File),
+		so:           makeSignOpts(opts...),
+	}, nil
+}
+
+// AttachFileToUnknown attaches the provided file to the provided image.
+func AttachFileToUnknown(se oci.SignedEntity, name string, f oci.File, opts ...SignOption) (oci.SignedEntity, error) {
+	return &signedUnknown{
+		SignedEntity: se,
+		attachments: map[string]oci.File{
+			name: f,
+		},
+		so: makeSignOpts(opts...),
+	}, nil
+}
+
+type signedUnknown struct {
+	oci.SignedEntity
+	sig         oci.Signature
+	att         oci.Signature
+	so          *signOpts
+	attachments map[string]oci.File
+}
+
+type digestable interface {
+	Digest() (v1.Hash, error)
+}
+
+// Digest is generally implemented by oci.SignedEntity implementations.
+func (si *signedUnknown) Digest() (v1.Hash, error) {
+	d, ok := si.SignedEntity.(digestable)
+	if !ok {
+		return v1.Hash{}, fmt.Errorf("underlying signed entity not digestable: %T", si.SignedEntity)
+	}
+	return d.Digest()
+}
+
+// Signatures implements oci.SignedEntity
+func (si *signedUnknown) Signatures() (oci.Signatures, error) {
+	base, err := si.SignedEntity.Signatures()
+	if err != nil {
+		return nil, err
+	} else if si.sig == nil {
+		return base, nil
+	}
+	if si.so.dd != nil {
+		if existing, err := si.so.dd.Find(base, si.sig); err != nil {
+			return nil, err
+		} else if existing != nil {
+			// Just return base if the signature is redundant
+			return base, nil
+		}
+	}
+	return AppendSignatures(base, si.sig)
+}
+
+// Attestations implements oci.SignedEntity
+func (si *signedUnknown) Attestations() (oci.Signatures, error) {
+	base, err := si.SignedEntity.Attestations()
+	if err != nil {
+		return nil, err
+	} else if si.att == nil {
+		return base, nil
+	}
+	if si.so.dd != nil {
+		if existing, err := si.so.dd.Find(base, si.att); err != nil {
+			return nil, err
+		} else if existing != nil {
+			// Just return base if the signature is redundant
+			return base, nil
+		}
+	}
+	if si.so.ro != nil {
+		replace, err := si.so.ro.Replace(base, si.att)
+		if err != nil {
+			return nil, err
+		}
+		return ReplaceSignatures(replace)
+	}
+	return AppendSignatures(base, si.att)
+}
+
+// Attachment implements oci.SignedEntity
+func (si *signedUnknown) Attachment(attName string) (oci.File, error) {
+	if f, ok := si.attachments[attName]; ok {
+		return f, nil
+	}
+	return nil, fmt.Errorf("attachment %q not found", attName)
+}
diff --git a/pkg/oci/remote/remote.go b/pkg/oci/remote/remote.go
index 65057eb3..fab0a765 100644
--- a/pkg/oci/remote/remote.go
+++ b/pkg/oci/remote/remote.go
@@ -36,6 +36,10 @@ var (
 	remoteIndex = remote.Index
 	remoteGet   = remote.Get
 	remoteWrite = remote.Write
+
+	// ErrEntityNotFound is the error that SignedEntity returns when the
+	// provided ref does not exist.
+	ErrEntityNotFound = errors.New("entity not found in registry")
 )
 
 // SignedEntity provides access to a remote reference, and its signatures.
@@ -46,7 +50,7 @@ func SignedEntity(ref name.Reference, options ...Option) (oci.SignedEntity, erro
 	got, err := remoteGet(ref, o.ROpt...)
 	var te *transport.Error
 	if errors.As(err, &te) && te.StatusCode == http.StatusNotFound {
-		return nil, errors.New("entity not found in registry")
+		return nil, ErrEntityNotFound
 	} else if err != nil {
 		return nil, err
 	}
diff --git a/pkg/oci/remote/unknown.go b/pkg/oci/remote/unknown.go
new file mode 100644
index 00000000..90a0fc9a
--- /dev/null
+++ b/pkg/oci/remote/unknown.go
@@ -0,0 +1,60 @@
+//
+// Copyright 2023 The Sigstore 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 remote
+
+import (
+	"github.com/google/go-containerregistry/pkg/name"
+	v1 "github.com/google/go-containerregistry/pkg/v1"
+	"github.com/sigstore/cosign/v2/pkg/oci"
+)
+
+// SignedUnknown provides access to signed metadata without directly accessing
+// the underlying entity.  This can be used to access signature metadata for
+// digests that have not been published (yet).
+func SignedUnknown(digest name.Digest, options ...Option) oci.SignedEntity {
+	o := makeOptions(digest.Context(), options...)
+	return &unknown{
+		digest: digest,
+		opt:    o,
+	}
+}
+
+type unknown struct {
+	digest name.Digest
+	opt    *options
+}
+
+var _ oci.SignedEntity = (*unknown)(nil)
+
+// Digest implements digestable
+func (i *unknown) Digest() (v1.Hash, error) {
+	return v1.NewHash(i.digest.DigestStr())
+}
+
+// Signatures implements oci.SignedEntity
+func (i *unknown) Signatures() (oci.Signatures, error) {
+	return signatures(i, i.opt)
+}
+
+// Attestations implements oci.SignedEntity
+func (i *unknown) Attestations() (oci.Signatures, error) {
+	return attestations(i, i.opt)
+}
+
+// Attachment implements oci.SignedEntity
+func (i *unknown) Attachment(name string) (oci.File, error) {
+	return attachment(i, name, i.opt)
+}


Test patch:
diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml
index f21c01b4..17b7e5df 100644
--- a/.github/workflows/tests.yaml
+++ b/.github/workflows/tests.yaml
@@ -175,7 +175,7 @@ jobs:
           go-version: 1.20.x
           check-latest: true
       - name: golangci-lint
-        uses: golangci/golangci-lint-action@08e2f20817b15149a52b5b3ebe7de50aff2ba8c5 # v3.4.0
+        uses: golangci/golangci-lint-action@5f1fec7010f6ae3b84ea4f7b2129beb8639b564f # v3.5.0
         with:
           # Required: the version of golangci-lint is required and must be specified without patch version: we always use the latest patch version.
           version: v1.52
diff --git a/cmd/cosign/cli/attest/attest.go b/cmd/cosign/cli/attest/attest.go
index 2a0aab6b..83595bc3 100644
--- a/cmd/cosign/cli/attest/attest.go
+++ b/cmd/cosign/cli/attest/attest.go
@@ -214,10 +214,9 @@ func (c *AttestCommand) Exec(ctx context.Context, imageRef string) error {
 		return err
 	}
 
-	se, err := ociremote.SignedEntity(digest, ociremoteOpts...)
-	if err != nil {
-		return err
-	}
+	// We don't actually need to access the remote entity to attach things to it
+	// so we use a placeholder here.
+	se := ociremote.SignedUnknown(digest)
 
 	signOpts := []mutate.SignOption{
 		mutate.WithDupeDetector(dd),
diff --git a/pkg/oci/mutate/mutate_test.go b/pkg/oci/mutate/mutate_test.go
index 089d5d41..4a315268 100644
--- a/pkg/oci/mutate/mutate_test.go
+++ b/pkg/oci/mutate/mutate_test.go
@@ -163,8 +163,21 @@ func TestSignEntity(t *testing.T) {
 	}
 	sii := signed.ImageIndex(ii)
 
+	// Create an explicitly unknown implementation of oci.SignedEntity, which we
+	// feed through the table tests below.
+	want := make([]byte, 300)
+	rand.Read(want)
+	orig, err := static.NewFile(want)
+	if err != nil {
+		t.Fatalf("static.NewFile() = %v", err)
+	}
+	sunk, err := AttachFileToUnknown(sii, "sbom", orig)
+	if err != nil {
+		t.Fatalf("AttachFileToUnknown() = %v", err)
+	}
+
 	t.Run("attach SBOMs", func(t *testing.T) {
-		for _, se := range []oci.SignedEntity{si, sii} {
+		for _, se := range []oci.SignedEntity{si, sii, sunk} {
 			want := make([]byte, 300)
 			rand.Read(want)
 
@@ -197,7 +210,7 @@ func TestSignEntity(t *testing.T) {
 	})
 
 	t.Run("without duplicate detector (signature)", func(t *testing.T) {
-		for _, se := range []oci.SignedEntity{si, sii} {
+		for _, se := range []oci.SignedEntity{si, sii, sunk} {
 			orig, err := static.NewSignature(nil, "")
 			if err != nil {
 				t.Fatalf("static.NewSignature() = %v", err)
@@ -232,7 +245,7 @@ func TestSignEntity(t *testing.T) {
 	})
 
 	t.Run("without duplicate detector (attestation)", func(t *testing.T) {
-		for _, se := range []oci.SignedEntity{si, sii} {
+		for _, se := range []oci.SignedEntity{si, sii, sunk} {
 			orig, err := static.NewAttestation([]byte("payload"))
 			if err != nil {
 				t.Fatalf("static.NewAttestation() = %v", err)
@@ -267,7 +280,7 @@ func TestSignEntity(t *testing.T) {
 	})
 
 	t.Run("with duplicate detector (signature)", func(t *testing.T) {
-		for _, se := range []oci.SignedEntity{si, sii} {
+		for _, se := range []oci.SignedEntity{si, sii, sunk} {
 			orig, err := static.NewSignature(nil, "")
 			if err != nil {
 				t.Fatalf("static.NewSignature() = %v", err)
@@ -306,7 +319,7 @@ func TestSignEntity(t *testing.T) {
 	})
 
 	t.Run("with duplicate detector (attestation)", func(t *testing.T) {
-		for _, se := range []oci.SignedEntity{si, sii} {
+		for _, se := range []oci.SignedEntity{si, sii, sunk} {
 			orig, err := static.NewAttestation([]byte("blah"))
 			if err != nil {
 				t.Fatalf("static.NewAttestation() = %v", err)
@@ -345,7 +358,7 @@ func TestSignEntity(t *testing.T) {
 	})
 
 	t.Run("with erroring duplicate detector (signature)", func(t *testing.T) {
-		for _, se := range []oci.SignedEntity{si, sii} {
+		for _, se := range []oci.SignedEntity{si, sii, sunk} {
 			orig, err := static.NewSignature(nil, "")
 			if err != nil {
 				t.Fatalf("static.NewSignature() = %v", err)
@@ -379,7 +392,7 @@ func TestSignEntity(t *testing.T) {
 	})
 
 	t.Run("with erroring duplicate detector (attestation)", func(t *testing.T) {
-		for _, se := range []oci.SignedEntity{si, sii} {
+		for _, se := range []oci.SignedEntity{si, sii, sunk} {
 			orig, err := static.NewAttestation([]byte("blah"))
 			if err != nil {
 				t.Fatalf("static.NewAttestation() = %v", err)
diff --git a/pkg/oci/remote/unknown_test.go b/pkg/oci/remote/unknown_test.go
new file mode 100644
index 00000000..384d2973
--- /dev/null
+++ b/pkg/oci/remote/unknown_test.go
@@ -0,0 +1,101 @@
+//
+// Copyright 2023 The Sigstore 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 remote
+
+import (
+	"testing"
+
+	"github.com/google/go-containerregistry/pkg/name"
+	v1 "github.com/google/go-containerregistry/pkg/v1"
+	"github.com/google/go-containerregistry/pkg/v1/random"
+	"github.com/google/go-containerregistry/pkg/v1/remote"
+)
+
+func TestSignedUnknown(t *testing.T) {
+	ri := remote.Image
+	t.Cleanup(func() {
+		remoteImage = ri
+	})
+	wantLayers := int64(7)
+
+	remoteImage = func(ref name.Reference, options ...remote.Option) (v1.Image, error) {
+		// Only called for signature images
+		return random.Image(300 /* byteSize */, wantLayers)
+	}
+
+	// :nonroot as of 2023/05/07
+	digest, err := name.NewDigest("gcr.io/distroless/static@sha256:9ecc53c269509f63c69a266168e4a687c7eb8c0cfd753bd8bfcaa4f58a90876f")
+	if err != nil {
+		t.Fatalf("ParseRef() = %v", err)
+	}
+	si := SignedUnknown(digest)
+
+	sigs, err := si.Signatures()
+	if err != nil {
+		t.Fatalf("Signatures() = %v", err)
+	}
+
+	if sl, err := sigs.Get(); err != nil {
+		t.Errorf("Get() = %v", err)
+	} else if got := int64(len(sl)); got != wantLayers {
+		t.Errorf("len(Get()) = %d, wanted %d", got, wantLayers)
+	}
+
+	atts, err := si.Attestations()
+	if err != nil {
+		t.Fatalf("Signatures() = %v", err)
+	}
+
+	if al, err := atts.Get(); err != nil {
+		t.Errorf("Get() = %v", err)
+	} else if got := int64(len(al)); got != wantLayers {
+		t.Errorf("len(Get()) = %d, wanted %d", got, wantLayers)
+	}
+}
+
+func TestSignedUnknownWithAttachment(t *testing.T) {
+	ri := remote.Image
+	t.Cleanup(func() {
+		remoteImage = ri
+	})
+	wantLayers := int64(1) // File must have a single layer
+
+	remoteImage = func(ref name.Reference, options ...remote.Option) (v1.Image, error) {
+		// Only called for signature images
+		return random.Image(300 /* byteSize */, wantLayers)
+	}
+
+	// :nonroot as of 2023/05/07
+	digest, err := name.NewDigest("gcr.io/distroless/static@sha256:9ecc53c269509f63c69a266168e4a687c7eb8c0cfd753bd8bfcaa4f58a90876f")
+	if err != nil {
+		t.Fatalf("ParseRef() = %v", err)
+	}
+	si := SignedUnknown(digest)
+
+	file, err := si.Attachment("sbom")
+	if err != nil {
+		t.Fatalf("Signatures() = %v", err)
+	}
+
+	payload, err := file.Payload()
+	if err != nil {
+		t.Errorf("Payload() = %v", err)
+	}
+	// We check greater than because it's wrapped in a tarball with `random.Layer`
+	if len(payload) < 300 {
+		t.Errorf("Payload() = %d bytes, wanted %d", len(payload), 300)
+	}
+}
diff --git a/test/e2e_test_secrets.sh b/test/e2e_test_secrets.sh
index 176a226a..f5cd317d 100755
--- a/test/e2e_test_secrets.sh
+++ b/test/e2e_test_secrets.sh
@@ -36,6 +36,7 @@ signing_key=cosign.key
 verification_key=cosign.pub
 img="${TEST_INSTANCE_REPO}/test"
 img2="${TEST_INSTANCE_REPO}/test-2"
+img3="${TEST_INSTANCE_REPO}/test-3"
 legacy_img="${TEST_INSTANCE_REPO}/legacy-test"
 for image in $img $img2 $legacy_img
 do
@@ -73,6 +74,21 @@ do
     ./cosign verify --key ${verification_key} "${multiarch_img}@$(crane digest --platform=$arch ${multiarch_img})"
 done
 
+# sign/attest an image that doesn't exist (yet) in the registry
+# This digest was generated with the following command and
+# does not exist anywhere AFAIK:
+#   head -10 /dev/urandom | sha256sum | cut -d' ' -f 1
+# We don't just run this here because the macos leg doesn't
+# have sha256sum
+./cosign sign --key ${signing_key} "$img3@sha256:17b14220441083f55dfa21e1deb3720457d3c2d571219801d629b43c53b99627"
+PREDICATE_FILE=$(mktemp)
+cat > "${PREDICATE_FILE}" <<EOF
+{
+  "foo": "bar"
+}
+EOF
+./cosign attest --key ${signing_key} --type custom --predicate "${PREDICATE_FILE}" "$img3@sha256:17b14220441083f55dfa21e1deb3720457d3c2d571219801d629b43c53b99627"
+
 ## confirm use of OCI media type in signature image
 crane manifest $(./cosign triangulate $img) | grep -q "application/vnd.oci.image.config.v1+json"