PHPackages                             k2gl/composer-attest - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Security](/categories/security)
4. /
5. k2gl/composer-attest

ActiveComposer-plugin[Security](/categories/security)

k2gl/composer-attest
====================

Composer plugin that verifies GitHub build-provenance attestations for the packages you install

1.3.0(1mo ago)0627↑25.8%3MITPHPPHP &gt;=8.1CI passing

Since Jul 4Pushed 1mo agoCompare

[ Source](https://github.com/k2gl/composer-attest)[ Packagist](https://packagist.org/packages/k2gl/composer-attest)[ Docs](https://github.com/k2gl/composer-attest)[ RSS](/packages/k2gl-composer-attest/feed)WikiDiscussions main Synced 1w ago

READMEChangelog (3)Dependencies (16)Versions (6)Used By (3)

composer-attest
===============

[](#composer-attest)

A Composer plugin that verifies **GitHub build-provenance attestations** for the packages you install. As Composer downloads each package, the plugin hashes the artifact, asks GitHub for any attestation bound to that digest, and verifies the Sigstore bundle — requiring the signing identity to be a GitHub Actions workflow of the package's own repository.

It builds on [`k2gl/sigstore-verify`](https://github.com/k2gl/sigstore-verify) for the cryptographic verification (certificate chain, transparency-log inclusion, DSSE envelope, identity), so a passing check means the artifact really was built by the repository's own CI and recorded in the public transparency log.

> **Status: proof of concept.** The verification path is real and tested end to end (see [Caveat](#caveat-what-gets-attested) for what this does and does not cover today).

Install
-------

[](#install)

```
composer require k2gl/composer-attest
```

Composer will ask to trust the plugin the first time (it runs during install).

Configure
---------

[](#configure)

All configuration lives under `extra.k2gl-attest` in your root `composer.json`:

```
{
  "extra": {
    "k2gl-attest": {
      "mode": "warn",
      "require-attestation": false,
      "issuer": "https://token.actions.githubusercontent.com"
    }
  }
}
```

- **`mode`**
    - `warn` (default) — verify and print the result; a bad attestation is a warning, not a stop.
    - `enforce` — fail the install if an attestation is present but does not verify (and, with `require-attestation`, if one is missing).
    - `off` — do nothing.
- **`require-attestation`** — treat a package that publishes *no* attestation as a failure (respecting `mode`). Off by default, since most packages don't publish one yet.
- **`issuer`** — the OIDC issuer the signing certificate must carry. Defaults to GitHub Actions.

What you'll see
---------------

[](#what-youll-see)

```
  ✓ attestation verified for k2gl/sigstore-verify (k2gl/sigstore-verify)
  · no attestation for some/other-package

```

Under `enforce`, a package whose attestation fails verification aborts the install with a non-zero exit code.

Verify on demand
----------------

[](#verify-on-demand)

The plugin only sees packages Composer downloads during a given install. To audit everything already in `vendor/` at once, run:

```
composer attest
```

It re-fetches each installed GitHub-hosted package's dist, verifies its attestation, and prints a summary — honouring the same `extra.k2gl-attest` policy, and exiting non-zero on a failure under `enforce`.

How it works
------------

[](#how-it-works)

The plugin subscribes to Composer's `POST_FILE_DOWNLOAD` event. For each package dist it:

1. computes the artifact's SHA-256 digest;
2. requests `GET /repos/{owner}/{repo}/attestations/sha256:{digest}` (through Composer's authenticated HTTP client);
3. parses each returned Sigstore bundle and verifies it with `sigstore-verify`, requiring a GitHub Actions identity of `{owner}/{repo}`;
4. confirms the artifact's digest is one of the in-toto statement's subjects.

Cross-checked against GitHub's own tooling
------------------------------------------

[](#cross-checked-against-githubs-own-tooling)

Two independent implementations agreeing is stronger evidence than either one's own tests. The [cross-check workflow](.github/workflows/cross-check.yml) verifies a real attested package with **both** this verifier (pure PHP) and GitHub's official `gh attestation verify` (sigstore-go), and requires them to agree — verified on the clean zipball, rejected on a tampered one. Run it yourself:

```
GITHUB_TOKEN=$(gh auth token) bash scripts/cross-check.sh
```

Caveat: what gets attested
--------------------------

[](#caveat-what-gets-attested)

Composer installs a package's dist as a **GitHub zipball**(`api.github.com/repos/{owner}/{repo}/zipball/{ref}`). For the plugin to verify a package at install time, the repository must publish a build-provenance attestation **for that zipball's digest**.

Most repositories today attest their *release tarball* (a `git archive` output) or other build outputs — a different artifact than the zipball Composer fetches — so the plugin will report "no attestation" for them. This is a property of the current ecosystem, not the plugin: it is exactly why the zipball digest is reproducible yet unattested. As registries and publishers begin attesting the artifacts Composer actually installs, the plugin verifies them with no changes.

The verification logic itself is proven: it verifies a real published attestation end to end (the k2gl release tarballs, whose digests *are* attested, verify against the live GitHub attestations API).

Requirements
------------

[](#requirements)

- PHP 8.1+
- Composer 2 (`composer-plugin-api ^2.0`)

License
-------

[](#license)

MIT

###  Health Score

43

—

FairBetter than 89% of packages

Maintenance91

Actively maintained with recent releases

Popularity17

Limited adoption so far

Community10

Small or concentrated contributor base

Maturity46

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~1 days

Total

5

Last Release

41d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/6bc4aa529c7f13ea593297497f6eae20d5c07f476baa0a551960d7e6ff1e5413?d=identicon)[k2gl](/maintainers/k2gl)

---

Top Contributors

[![k2gl](https://avatars.githubusercontent.com/u/2846079?v=4)](https://github.com/k2gl "k2gl (6 commits)")

---

Tags

attestationcomposer-pluginprovenancesecuritysigstoresupply-chainsecuritygithubcomposer-pluginverificationattestationsupply-chainprovenancesigstore

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Code StyleLaravel Pint

Type Coverage Yes

### Embed Badge

![Health badge](/badges/k2gl-composer-attest/health.svg)

```
[![Health](https://phpackages.com/badges/k2gl-composer-attest/health.svg)](https://phpackages.com/packages/k2gl-composer-attest)
```

###  Alternatives

[drupal/core-composer-scaffold

A flexible Composer project scaffold builder.

5346.5M600](/packages/drupal-core-composer-scaffold)[drupal/core-vendor-hardening

Hardens the vendor directory for when it's in the docroot.

175.0M54](/packages/drupal-core-vendor-hardening)[plan2net/typo3-update-check

A Composer plugin that checks for TYPO3 updates and provides detailed information about breaking changes and security updates

208.3k](/packages/plan2net-typo3-update-check)[swop/github-webhook

Library which deals with incoming GitHub web hooks requests (signature validation &amp; payload parsing)

1120.3k4](/packages/swop-github-webhook)[lorddashme/php-simple-captcha

A simple captcha package that fit to any type of web application built on php.

103.0k](/packages/lorddashme-php-simple-captcha)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
