Packages · supply-chain

k2gl/sigstore-bundle

Build and read Sigstore bundles (.sigstore.json) in PHP.

Assemble the DSSE/message-signature bundle that carries a signature, its cert, and its log entry.

k2gl/sigstore-bundle version on Packagist k2gl/sigstore-bundle total downloads k2gl/sigstore-bundle license

Install

composer require k2gl/sigstore-bundle
PHP
>=8.1
k2gl dependencies
k2gl/dsse

Reach for it when

  • You’re assembling or parsing a .sigstore.json bundle at a low level.
  • You’re building tooling on top of the bundle format.

Look elsewhere when

  • You want the full sign or verify flow — sigstore-sign / sigstore-verify use this for you.

Build Sigstore bundles in PHP

Assemble a Sigstore bundle — the .sigstore.json that cosign, gitsign and npm/PyPI provenance emit — from PHP. This is the counterpart to verification: hand it the pieces you already have (a signature or DSSE envelope, the Fulcio certificate, the Rekor entry) and it lays them out as the canonical v0.3 JSON that verifiers accept.

It does no signing and no network I/O — it is the format layer. The signature, the certificate and the transparency-log entry come from elsewhere (your signer, Fulcio, Rekor); this package places them in a well-formed bundle.

Requirements

  • PHP 8.1+
  • k2gl/dsse (for the DSSE envelope content)

Installation

composer require k2gl/sigstore-bundle

Usage

A DSSE-attestation bundle

use K2gl\SigstoreBundle\BundleBuilder;
use K2gl\SigstoreBundle\InclusionProof;
use K2gl\SigstoreBundle\TransparencyLogEntry;

$rekorEntry = new TransparencyLogEntry(
    logIndex: 148_384_212,
    logId: $logKeyIdBytes,
    kind: 'dsse',
    version: '0.0.2',
    canonicalizedBody: $canonicalBodyBytes,
    inclusionProof: new InclusionProof(
        logIndex: 148_384_212,
        rootHash: $rootHashBytes,
        treeSize: 148_384_213,
        hashes: $siblingHashBytes,       // list of raw hashes, bottom to top
        checkpoint: $signedCheckpoint,   // the signed note string
    ),
);

$json = BundleBuilder::forDsse($envelope)   // a K2gl\Dsse\Envelope you signed
    ->withCertificate($fulcioLeafDer)       // raw DER of the Fulcio leaf
    ->addTransparencyLogEntry($rekorEntry)
    ->toJson();

file_put_contents('artifact.sigstore.json', $json);

An artifact-signature bundle

use K2gl\SigstoreBundle\BundleBuilder;
use K2gl\SigstoreBundle\HashAlgorithm;
use K2gl\SigstoreBundle\MessageSignature;

$signature = new MessageSignature(
    algorithm: HashAlgorithm::SHA2_256,
    digest: $artifactSha256,   // raw 32-byte digest
    signature: $rawSignature,  // raw signature over the artifact
);

$json = BundleBuilder::forMessageSignature($signature)
    ->withCertificate($fulcioLeafDer)
    ->addTransparencyLogEntry($rekorEntry)
    ->addRfc3161Timestamp($rfc3161TokenDer) // optional trusted timestamp
    ->toJson();

Signing identity

Pick one, matching how the artifact was signed:

  • ->withCertificate($der) — a single Fulcio leaf certificate (the keyless default).
  • ->withCertificateChain([$leaf, $intermediate, $root]) — a full X.509 chain.
  • ->withPublicKey($hint) — a key-based identity; the bundle only names the key by hint.

Compatibility

The output is byte-for-byte the same structure the reference tooling emits: the test suite rebuilds real cosign/GitHub v0.3 bundles (DSSE, message signature, and with an RFC 3161 timestamp) from their components and checks the result is identical. Bundles built here verify with k2gl/sigstore-verify and with cosign.

Pull requests are always welcome

Collaborate with pull requests

API

Public classes and methods, generated from the source.

K2gl\SigstoreBundle\Bundle class

  • forDsse( Envelope $envelope, SigningIdentity $identity, array $tlogEntries, array $rfc3161Timestamps = [], ): self
  • forMessageSignature( MessageSignature $messageSignature, SigningIdentity $identity, array $tlogEntries, array $rfc3161Timestamps = [], ): self
  • toArray(): array
  • toJson(): string

K2gl\SigstoreBundle\BundleBuilder class

  • forDsse(Envelope $envelope): self
  • forMessageSignature(MessageSignature $messageSignature): self
  • withCertificate(string $der): self
  • withCertificateChain(array $ders): self
  • withPublicKey(string $hint): self
  • addTransparencyLogEntry(TransparencyLogEntry $entry): self
  • addRfc3161Timestamp(string $token): self
  • build(): Bundle
  • toArray(): array
  • toJson(): string

K2gl\SigstoreBundle\Exception\InvalidBundleInputException class

K2gl\SigstoreBundle\Exception\SigstoreBundleException interface

K2gl\SigstoreBundle\HashAlgorithm enum

  • digestLength(): int

K2gl\SigstoreBundle\InclusionProof class

  • __construct( public readonly int $logIndex, public readonly string $rootHash, public readonly int $treeSize, public readonly array $hashes, public readonly string $checkpoint, )
  • toArray(): array

K2gl\SigstoreBundle\MessageSignature class

  • __construct( public readonly HashAlgorithm $algorithm, public readonly string $digest, public readonly string $signature, )
  • toArray(): array

K2gl\SigstoreBundle\SigningIdentity class

  • certificate(string $der): self
  • certificateChain(array $ders): self
  • publicKey(string $hint): self
  • toArray(): array

K2gl\SigstoreBundle\TransparencyLogEntry class

  • __construct( public readonly int $logIndex, public readonly string $logId, public readonly string $kind, public readonly string $version, public readonly string $canonicalizedBody, public readonly ?int $integratedTime = null, public readonly ?string $inclusionPromise = null, public readonly ?InclusionProof $inclusionProof = null, )
  • toArray(): array