# Signing and Attestations Across Package Registries

Package signing and attestations are two ways of attaching evidence to a published artifact so that someone downloading it later can check where it came from. A signature binds the bytes to a key, either the registry's or the author's. A provenance attestation is a signed statement about where an artifact came from, usually in-toto and signed through [Sigstore](https://www.sigstore.dev/). SLSA build provenance names the source repository, commit and build workflow, while a publish attestation such as PyPI's records which trusted publisher uploaded the file.

Trusted publishing, which several registries have added alongside attestations, replaces long-lived API tokens with short-lived OIDC credentials from CI. It makes provenance easy to produce because the registry receives a verified workflow identity with each upload. Some registries offer trusted publishing on its own. The workflow's identity becomes the publishing credential, so a compromised workflow can publish a malicious release. [GitHub Actions security in Python packages](/2026/05/25/github-actions-security-in-python-packages.html) audits those workflows for PyPI.

Linux distributions have signed packages for decades. Debian builds binaries from uploaded source on its own [buildd](https://wiki.debian.org/buildd) machines and Fedora builds through [Koji](https://docs.fedoraproject.org/en-US/package-maintainers/Using_the_Koji_Build_System/), and the archive key signs the result, so a package apt or dnf accepts is one the distribution built, from source uploaded by one of a vetted group of packagers.

Language registries accept uploads from anyone with an account, and the wheel, gem, crate or tarball was built wherever its author built it, on a laptop or a CI runner. A registry signature over those bytes shows they match what was uploaded, which protects against a tampered mirror. A release pushed with a stolen token gets the same signature as one from the project's real workflow.

Attestations record the build itself: when [Ultralytics](https://blog.pypi.org/posts/2024-12-11-ultralytics-attack-analysis/) was compromised in December 2024, the first malicious releases came out of the project's release workflow with valid attestations, and a later batch uploaded with a leaked API token carried none, which let investigators separate the token uploads from the workflow releases.

The registries are the same set as the [2FA survey](/2026/08/18/two-factor-authentication-across-package-registries.html) in August, and for each one I looked at what it signs and where it stores the evidence, plus whether the client checks it by default. [Signing is for the bad days](/2026/05/24/signing-is-for-the-bad-days.html) explains the reasons for TUF and in-toto, and for Sigstore. Zach Steindler's [FOSDEM talk](https://archive.fosdem.org/2026/schedule/event/BCFZP7-current-state-programming-language-attestations/) ([written summary](https://coffeehousecoders.org/blog/fosdem_2026.html)) covers npm, PyPI, RubyGems and Maven Central in more detail.

In a [pull request to in-toto/friends](https://github.com/in-toto/friends/pull/118), merged in September 2026, Sivana Hamer at NC State catalogued where in-toto attestations are stored. The pull request adds a producer table covering package registries, Git repositories and releases, OCI image manifests and referrers, GitHub's attestation API, Archivista and Rekor. For each one it records whether attestations are stored alongside the artifact, which format they use, and whether they can be private. Hamer co-authored [a study of 1,523 SLSA-related GitHub issues](https://arxiv.org/abs/2409.05014), whose authors identified complex implementation and unclear communication as the main obstacles to adopting SLSA, and [Research Directions in Software Supply Chain Security](https://doi.org/10.1145/3714464) with Laurie Williams.

## Sigstore

npm [launched provenance](https://github.blog/security/supply-chain-security/introducing-npm-package-provenance/) in April 2023 as an opt-in `--provenance` flag for packages built on GitHub Actions or GitLab CI/CD cloud runners from a public repository whose URL matches the `repository` field in package.json. Since [trusted publishing went GA](https://github.blog/changelog/2025-07-31-npm-trusted-publishing-with-oidc-is-generally-available/) in July 2025, provenance is generated by default when publishing that way. The packument lists it in `dist.attestations`, and the bundles are served from `/-/npm/v1/attestations/<package>@<version>`.

Each version published with provenance has two bundles there: a SLSA v1 provenance statement signed with a Sigstore certificate, and an npm publish attestation signed with a registry key that Sigstore's trust root includes. npm designed its publish predicate before in-toto had a release attestation type, and the later [in-toto release predicate](https://github.com/in-toto/attestation/blob/main/spec/predicates/release.md) records the same claim in another format.

[CircleCI](https://github.blog/changelog/2026-04-06-npm-trusted-publishing-now-supports-circleci/) was added as a trusted publisher in April 2026, with provenance still limited to GitHub Actions and GitLab publishes, and every provider requires cloud-hosted runners. After the [SlugFest](https://workos.com/blog/npm-trusted-publishing-slugfest) report showed trust configurations were bound to a repository's name instead of its ID, npm now [expires unvalidated configurations](https://github.blog/changelog/2026-10-02-unvalidated-npm-trusted-publishing-configurations-now-expire/) after 48 hours and rejects `issue_comment` triggers.

PyPI added [trusted publishing](https://docs.pypi.org/trusted-publishers/) in April 2023, [stopped accepting PGP signatures](https://blog.pypi.org/posts/2023-05-23-removing-pgp/) the following month, and saw [PEP 740](https://peps.python.org/pep-0740/) attestations go [generally available](https://blog.sigstore.dev/pypi-attestations-ga/) in November 2024. `pypa/gh-action-pypi-publish` generates attestations by default for projects using trusted publishing, using PyPI's own [publish predicate](https://docs.pypi.org/attestations/publish/v1/) in place of SLSA build provenance: the provenance object for pip 26.2.2's wheel contains a single publish attestation from GitHub. PyPI accepts GitHub Actions, GitLab CI/CD, Google Cloud and ActiveState as publishers, with a beta for self-managed GitLab since November 2025.

PyPI's attestations are per file, served from the [integrity API](https://docs.pypi.org/api/integrity/) at `/integrity/<project>/<version>/<filename>/provenance` and linked from each file in the Simple JSON API. They use PyPI's own envelope format around the Sigstore material, and PEP 740 permits attestations to be added to a file after upload, so a collector has to re-fetch files it has already processed.

RubyGems added [trusted publishing](https://guides.rubygems.org/trusted-publishing/) for GitHub Actions in December 2023 and [server support for Sigstore attestations](https://github.com/rubygems/rubygems.org/pull/4987) in November 2024. Attestations are uploaded with `gem push --attestation`, or through the `rubygems/release-gem` action, where the input is labelled experimental, and they are served as Sigstore bundles from `/api/v1/attestations/<name>-<version>.json`. [Automatic attestation in `gem push`](https://github.com/ruby/rubygems/pull/9325), limited to GitHub Actions publishing to rubygems.org, was merged in April 2026 and ships in the RubyGems 4.1 line.

RubyGems also has an older [X.509 signing scheme](https://guides.rubygems.org/security/) through `gem cert`, which the guide describes as rarely used, and `gem install` checks those signatures when a trust policy is passed with `-P`.

[JSR](https://jsr.io/docs/trust) has had OIDC publishing from GitHub Actions since its [open beta](https://deno.com/blog/jsr_open_beta) in March 2024, and publishes from Actions get SLSA provenance recorded in Rekor automatically, with `--no-provenance` as the opt-out. [Maven Central](https://central.sonatype.org/news/20250128_sigstore_signature_validation_via_portal/) has validated optional `.sigstore.json` files since January 2025, with an invalid one producing a warning, and Sonatype states that PGP remains the required signature.

conda's [CEP 27](https://github.com/conda/ceps/pull/112), accepted in July 2025, defines a publish predicate in a Sigstore bundle, and [CEP 50](https://github.com/conda/ceps/pull/142), accepted in September 2026, specifies serving attestations as `.sigs` sidecar files next to each package, listed through an `attestations_sha256` field in repodata. [prefix.dev](https://prefix.dev/blog/securing-the-conda-package-supply-chain-with-sigstore) has generated CEP 27 attestations since August 2025 for packages uploaded through trusted publishing from GitHub Actions, GitLab CI/CD or Google Cloud.

conda-forge's own channel uses neither signing nor trusted publishing: builds upload to a staging channel with a per-feedstock token and are copied to `conda-forge` after an [output check](https://conda-forge.org/docs/maintainer/infrastructure/), and the September 2025 core meeting minutes report little progress on signing. The conda client [checks each download](https://github.com/conda/conda/blob/main/conda/gateways/connection/download.py) against the SHA-256 and size in repodata and fails on a mismatch. [rattler](https://github.com/conda/rattler/pull/2795) added opt-in Sigstore verification at install time in September 2026, and conda has [open issues](https://github.com/conda/conda/issues/13965) requesting install-time verification.

In each of these clients verification is a separate step from installing: npm ships [`npm audit signatures`](https://docs.npmjs.com/verifying-registry-signatures), which checks registry signatures and provenance as its own command. For Python, open issues on [pip](https://github.com/pypa/pip/issues/13531) (the `attestation-identities` field in PEP 751 lockfiles) and [uv](https://github.com/astral-sh/uv/issues/9122) (PEP 740) track install-time checks, and PyPI's documentation recommends the [`pypi-attestations`](https://docs.pypi.org/attestations/consuming-attestations/) CLI for manual checks.

## Identity

Checking the signature on an attestation shows that it was signed with a key certified by Sigstore. Checking that the certificate belongs to the repository you expected is a second step, and both `gh` and `pypi-attestations` require the user to supply that repository: [`gh attestation verify`](https://cli.github.com/manual/gh_attestation_verify) takes `--owner` or `--repo` and `pypi-attestations verify pypi` takes `--repository` on every call, and each compares the value with the repository in the signing certificate. [PEP 751](https://peps.python.org/pep-0751/) lockfiles can record the expected identity once per package in `attestation-identities`, which is the field the open pip issue asks installs to be checked against.

## Keys

npm has signed every package with an ECDSA [registry key](https://docs.npmjs.com/about-registry-signatures) since April 2023, when it deprecated its PGP signatures, with signatures in `dist.signatures` and public keys at `/-/npm/v1/keys`. [NuGet.org](https://learn.microsoft.com/en-us/nuget/reference/signed-packages-reference) repository-signs every package and accepts optional author signatures from X.509 certificates issued by a CA in the Windows root store. The dotnet client [checks those signatures during restore](https://learn.microsoft.com/en-us/dotnet/core/tools/nuget-signed-package-verification) by default: always on Windows, and on Linux since the .NET 8 SDK, with macOS left off. NuGet added [trusted publishing](https://devblogs.microsoft.com/dotnet/enhanced-security-is-here-with-the-new-trust-publishing-on-nuget-org/) for GitHub Actions in September 2025, with GitLab supported through the [token API](https://learn.microsoft.com/en-us/nuget/nuget-org/trusted-publishing), and its artifact-level evidence is limited to signatures.

Maven Central [requires](https://central.sonatype.org/publish/requirements/gpg/) a PGP `.asc` signature on every published file, along with MD5 and SHA-1 checksums. Maven checks those signatures during dependency resolution when a plugin such as [pgpverify-maven-plugin](https://www.simplify4u.org/pgpverify-maven-plugin/) is added. A PGP signature identifies the uploader's key and carries no record of the source the file was built from, and Central has no trusted publishing to supply one.

[Clojars](https://github.com/clojars/clojars-web/wiki/Pushing) accepts optional PGP `.asc` or SSH `.sig` files and requires that if any artifact in a deploy is signed, all of them are, but it skips checking the signatures against a key. Leiningen fails on a checksum mismatch by default and checks PGP signatures through `lein deps :verify`, while tools.deps warns on a mismatch and skips signature checks.

The [Terraform Registry](https://developer.hashicorp.com/terraform/registry/providers/publishing) requires providers to publish a GPG signature over a `SHA256SUMS` file, from a key uploaded to the registry, and `terraform init` checks it by default and reports whether the signing key belongs to HashiCorp, a HashiCorp partner, or a community publisher. Terraform modules are published unsigned from git tags through a webhook.

[Open VSX](https://github.com/eclipse-openvsx/openvsx/issues/543) signs every extension with a registry key, and its version API returns the signature, a SHA-256 and the public key URL. `verify` commands were added to the `ovsx` CLI in September 2026. Checking those signatures at install is up to each editor build, and Arch's Code - OSS package has [failed to verify them](https://github.com/eclipse-openvsx/openvsx/issues/1247). Open VSX shipped [trusted publishing](https://github.com/eclipse-openvsx/openvsx/pull/2000) for GitHub Actions and GitLab CI in server v1.2.0 in September 2026, which sets a `publishedWithTrustedPublishing` flag on the version. v1.3.0, still pending deployment on open-vsx.org, [records the CI run](https://github.com/eclipse-openvsx/openvsx/pull/2283) on each upload.

[Hex](https://github.com/hexpm/specifications/blob/main/registry-v2.md) signs all registry resources with the repository's RSA key, and the `hex_core` client verifies those signatures on every fetch. Hex added [Workload Identity](https://hex.pm/docs/workload-identity), its name for trusted publishing, in October 2026. A GitHub Actions job exchanges an OIDC token for a 15-minute key scoped to one package, and the verified claims are stored unsigned on the release and shown on the package page as a "Provenance" card. SLSA provenance and Sigstore are on the [Erlang Ecosystem Foundation's roadmap](https://security.erlef.org/aegis/roadmap/hex-build-provenance) as unfunded work.

CPAN's per-author `CHECKSUMS` files are PGP-signed and include SHA-256 hashes, and authors can sign distributions with Module::Signature. [CPAN.pm](https://fastapi.metacpan.org/v1/pod/CPAN?content-type=text/plain) and [cpanm](https://fastapi.metacpan.org/v1/pod/App::cpanminus?content-type=text/plain) both check signatures only when the user opts in.

Swift's package registry protocol has supported [CMS signing](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0391-package-registry-publish.md) since Swift 5.9. SwiftPM sets [checksum pinning](https://github.com/swiftlang/swift-package-manager/blob/main/Documentation/PackageRegistry/PackageRegistryUsage.md) to `strict` by default and [validates signed archives](https://github.com/swiftlang/swift-package-manager/blob/main/Documentation/PackageRegistry/PackageRegistryUsage.md#validating-signed-packages) against its trust store. The [Swift Package Index](https://swiftpackageindex.com/) lists git repository URLs, and SwiftPM fetches those packages by cloning, so registry signing covers only packages installed from a registry.

[Hackage](https://well-typed.com/blog/2015/07/hackage-security-alpha) signs its index with TUF through hackage-security, and hashes in the signed index cover package tarballs. cabal-install [enables the check](https://github.com/haskell/cabal/blob/master/cabal-install/src/Distribution/Client/Config.hs) by default for hackage.haskell.org.

[Repository Service for TUF](https://github.com/repository-service-tuf) (RSTUF) is software a registry can deploy to sign and republish its index on a schedule. Zach Steindler's FOSDEM talk noted that RSTUF's output is not yet verified in a normal production install workflow.

## Checksums

Go has had the [checksum database](https://go.dev/blog/module-mirror-launch) at sum.golang.org on by default since Go 1.13 in 2019. It is a transparency log of module hashes, so every client gets the same bytes for a given version, and it can be bypassed per path with `GOPRIVATE` or `GONOSUMDB`. A Go module version is a git tag pushed to the source repository, so the checksum database is the only signed record.

crates.io records a SHA-256 of each `.crate` in the [index](https://doc.rust-lang.org/cargo/reference/registry-index.html) and Cargo rejects a download with a different hash, but the index itself is unsigned. A [Sigstore RFC](https://github.com/rust-lang/rfcs/pull/3403) was closed and a [TUF RFC](https://github.com/rust-lang/rfcs/pull/3724) has been open since October 2024. crates.io shipped [trusted publishing](https://blog.rust-lang.org/2025/07/11/crates-io-development-update-2025-07/) for GitHub Actions in July 2025 and [added GitLab](https://blog.rust-lang.org/2026/01/21/crates-io-development-update/) in January 2026, along with a per-crate setting to disable token publishing.

Julia's General registry stores a content-addressed [git tree hash](https://github.com/JuliaLang/Pkg.jl/blob/master/docs/src/protocol.md) per version as its only integrity check. CRAN's `PACKAGES` file lists an MD5 for each package, which `install.packages` ignores when downloading. R 4.6.0, released in April 2026, added optional package signing: a package can ship a `SHA256` file with a detached GnuPG signature, which `R CMD INSTALL` checks when present and requires when `_R_INSTALL_REQUIRE_SIGNED` is set, and otherwise uses the unsigned hash files inside the tarball.

## Caches

Nix, Guix and Spack build packages from source on project infrastructure and sign the binary caches they serve, as Debian and Fedora do. Each client checks those signatures by default. On cache.nixos.org each `.narinfo` carries an Ed25519 signature over the store path, its hash and its references. Nix's [`require-sigs`](https://nix.dev/manual/nix/latest/command-ref/conf-file.html) defaults to true, and the default `trusted-public-keys` includes the cache.nixos.org key.

Guix rejects substitutes that are unsigned or signed by a key outside its ACL, and since 1.2.0 in 2020 `guix pull` authenticates every channel commit against the OpenPGP keys listed in the parent commit's `.guix-authorizations` file, the same check `guix git authenticate` applies to any repository. Spack signs build cache manifests with GPG and verifies them on install by default, with `--no-check-signature` and `--unsigned` as opt-outs, though `spack buildcache keys --install --trust` installs and trusts every key the mirror serves. Nix has an open [Sigstore issue](https://github.com/NixOS/nix/issues/7216) and a [provenance tracking PR](https://github.com/NixOS/nix/pull/11749), the only build provenance proposals across the three.

## Retired

Anaconda's TUF-based [conda-content-trust](https://www.anaconda.com/blog/conda-signature-verification), available since 2021, reached end of support in September 2026. Docker [announced the retirement](https://www.docker.com/blog/retiring-docker-content-trust/) of Docker Content Trust in July 2025, and the Notary v1 server at notary.docker.io [shuts down](https://www.docker.com/blog/docker-content-trust-retirement-and-migration-guidance/) on 8 December 2026, with cosign and Notation named as replacements for publishers. Docker Hardened Images are [signed with cosign](https://docs.docker.com/dhi/core-concepts/signatures/) and carry provenance, SBOM and VEX attestations.

## Unsigned

[pub.dev](https://dart.dev/tools/pub/automated-publishing) has accepted OIDC publishing from GitHub Actions and Google Cloud since January 2023 and its audit log records the CI run that published each version. packagist.org offers neither signing nor trusted publishing, and since July 2026 each stable version has been [fixed to a commit](https://blog.packagist.com/immutable-versions-on-packagist/), though GitHub generates the dist zips on request. A [transparency log](https://blog.packagist.com/strengthening-php-supply-chain-security-with-a-transparency-log-for-packagist-org/) for security events is in progress. The [undated longer-term plan](https://blog.packagist.com/an-update-on-composer-packagist-supply-chain-security/) is hosted artifacts with SLSA provenance and Sigstore attestations that Composer verifies. CocoaPods uses git for integrity, and trunk [stops accepting](https://blog.cocoapods.org/CocoaPods-Specs-Repo/) new podspecs on 2 December 2026.

## Forges

The forge is the identity provider that registries accept for trusted publishing, and for git-based registries like Homebrew it is also where attestations are stored. GitHub [artifact attestations](https://docs.github.com/en/actions/concepts/security/artifact-attestations) went [GA](https://github.blog/changelog/2024-06-25-artifact-attestations-is-generally-available/) in June 2024. Attestations for public repositories are signed through Sigstore's public-good instance and logged in Rekor, while private repositories use GitHub's own instance with no transparency log. A [REST API](https://docs.github.com/en/rest/repos/attestations) lists attestations by subject digest with a `predicate_type` filter.

[Immutable releases](https://github.blog/changelog/2025-10-28-immutable-releases-are-now-generally-available/), GA since October 2025, add a release attestation with its own in-toto predicate, checked with `gh release verify`. Actions themselves are repositories referenced by tag or SHA, with no signature. Immutable Actions, which would have published actions as OCI packages with provenance, was [removed from the roadmap](https://github.com/github/roadmap/issues/592) in December 2025. The [workflow lockfiles](https://github.blog/changelog/2026-10-14-github-actions-workflow-lockfiles-in-public-preview/) that entered public preview in October 2026 pin direct and transitive actions to commits without integrity hashes.

Homebrew has attached GitHub attestations to homebrew-core bottles [since May 2024](https://blog.trailofbits.com/2024/05/14/a-peek-into-build-provenance-for-homebrew/), and verifying them is opt-in with `HOMEBREW_VERIFY_ATTESTATIONS`, which shells out to `gh`. [Who Built This?](/2026/04/07/who-built-this.html) traces an attestation like these from a package back to its commit, and [Reproducible Builds in Language Package Managers](/2026/02/24/reproducible-builds-in-language-package-managers.html) covers checking the artifact by rebuilding it.

GitLab's [SLSA Level 3 provenance](https://docs.gitlab.com/ci/pipeline_security/slsa/level_3/) was introduced as an experiment in GitLab 18.3 and is still marked experimental, available to public projects on GitLab.com Ultimate behind the `slsa_provenance_statement` feature flag. Attestations are listed per project and subject digest through the [attestations API](https://docs.gitlab.com/api/attestations/) and checked with `glab attestation verify`. As an OIDC issuer, GitLab is accepted for trusted publishing by npm, PyPI, crates.io, NuGet, Open VSX and prefix.dev.

Forgejo v15, released in April 2026 and run by Codeberg, added [OIDC ID tokens for Actions](https://forgejo.org/2026-04-release-v15-0), and registries have yet to accept it as a trusted publisher. PyPI has a [discussion thread](https://discuss.python.org/t/new-oidc-providers-for-trusted-publishing/106334) and crates.io has named it as a possibility. Gitea [merged the equivalent](https://github.com/go-gitea/gitea/pull/39052) in October 2026 for its unreleased 29.0 release. Bitbucket Pipelines issues OIDC tokens, and a [request](https://jira.atlassian.com/browse/BCLOUD-23917) for npm trusted publishing from Pipelines is open on Atlassian's Bitbucket Cloud tracker with the status Gathering Interest.

Gitea, Forgejo, Bitbucket Cloud, Gerrit and Tangled have no dedicated attestation endpoint. [fremforge](https://docs.frem.sh/security/immutable-releases/), a Forgejo-based service, has a release attestation endpoint that returns DSSE envelopes and Sigstore bundles.

## Summary

In the "signature checked by default" column, Go's checksum log and Hackage's TUF index sign the metadata that holds the hashes, so the go command and cabal-install authenticate the hashes as well as the downloads. Cargo, Julia's Pkg and conda check downloads against hashes in metadata served over TLS without a signature. That catches corruption, but the hashes are only as trustworthy as the registry serving them.

| | signatures | provenance attestations | trusted publishing | signature checked by default | attestation checked by default |
|---|---|---|---|---|---|
| npm | registry ECDSA | SLSA + npm publish, Sigstore | GitHub, GitLab, CircleCI | no; `npm audit signatures` | no; `npm audit signatures` |
| PyPI | PGP removed 2023 | PEP 740 publish | GitHub, GitLab, Google Cloud, ActiveState | n/a | no; `pypi-attestations` |
| RubyGems | optional X.509 | Sigstore | GitHub | opt-in (`-P`) | no |
| JSR | none | SLSA, Sigstore | GitHub | n/a | no |
| Maven Central | PGP required | optional `.sigstore.json` | no | plugin | no |
| prefix.dev | none | Sigstore (CEP 27) | GitHub, GitLab, Google Cloud | n/a | opt-in (rattler) |
| conda-forge | none | none | no | n/a; repodata checksum | n/a |
| NuGet | repository + optional author | none | GitHub, GitLab | Windows, Linux | n/a |
| Clojars | optional PGP/SSH, not verified | none | no | opt-in (Leiningen); checksum | n/a |
| Terraform Registry | GPG required for providers | none | no | yes, providers | n/a |
| Open VSX | registry key | none | GitHub, GitLab | depends on editor | n/a |
| Hex.pm | registry RSA | planned | GitHub | yes | n/a |
| CPAN | PGP CHECKSUMS, optional author | none | no | opt-in | n/a |
| Swift registries | CMS | none | no | yes; checksum pinning | n/a |
| Hackage | TUF index | none | no | yes, TUF | n/a |
| Go | signed checksum log | none | n/a | yes, checksum DB | n/a |
| crates.io | none | none | GitHub, GitLab | n/a; index checksum | n/a |
| Julia General | none | none | n/a | n/a; tree hash | n/a |
| CRAN | optional GnuPG (R 4.6) | none | no | if present | n/a |
| nixpkgs | Ed25519 cache signatures | none | n/a | yes | n/a |
| Guix | substitutes + signed commits | none | n/a | yes | n/a |
| Spack | GPG build cache | none | n/a | yes | n/a |
| Docker Hub | DCT, retiring Dec 2026 | Hardened Images only | no | no | no |
| pub.dev | none | none | GitHub, Google Cloud | n/a | n/a |
| Packagist | none | planned | planned | n/a | n/a |
| CocoaPods | none | none | no | n/a | n/a |
| GitHub Actions | none | immutable releases only | n/a | n/a | no |
| Homebrew | none | GitHub attestations | n/a | n/a | opt-in |

---

By Andrew Nesbitt (https://nesbitt.io). Markdown version of https://nesbitt.io/2026/10/30/signing-and-attestations-across-package-registries.html
