Packages · supply-chain

k2gl/in-toto-attestation

Build and parse in-toto attestation Statements in PHP.

Wrap any predicate (SLSA provenance, SBOM, …) in the in-toto Statement format tools expect.

k2gl/in-toto-attestation version on Packagist k2gl/in-toto-attestation total downloads k2gl/in-toto-attestation license

Install

composer require k2gl/in-toto-attestation
PHP
>=8.1
k2gl dependencies
k2gl/dsse

Reach for it when

  • You’re producing or reading an in-toto Statement around a predicate.
  • You need the subject/predicate structure tools like cosign expect.

Look elsewhere when

  • You want to sign the statement — wrap it in DSSE (dsse) or a Sigstore bundle.

k2gl/in-toto-attestation

Build, sign and verify in-toto attestation Statements in PHP, both the current v1 and the legacy v0.1 that many real-world bundles still carry. Signed and parsed over DSSE.

An in-toto attestation is a signed claim ("predicate") about one or more artifacts ("subjects"). The claim is a Statement, carried inside a DSSE envelope with payload type application/vnd.in-toto+json. This package gives you typed, validated Statement and ResourceDescriptor value objects plus the sign/parse glue to DSSE.

Install

composer require k2gl/in-toto-attestation

Requires PHP 8.1+. Pulls in k2gl/dsse. The example signers use ext-sodium (Ed25519) / ext-openssl (ECDSA), both bundled with PHP.

Usage

Build and sign a statement

use K2gl\InToto\Statement;
use K2gl\InToto\ResourceDescriptor;
use K2gl\Dsse\Ed25519Signer;

$statement = new Statement(
    subject: [
        new ResourceDescriptor(
            name: 'pkg:composer/k2gl/dsse@1.0.0',
            digest: ['sha256' => '…'],
        ),
    ],
    predicateType: 'https://slsa.dev/provenance/v1',
    predicate: ['buildDefinition' => [/* … */], 'runDetails' => [/* … */]],
);

$envelope = $statement->sign($signer);   // a K2gl\Dsse\Envelope
echo $envelope->toJson();

Verify and parse

use K2gl\InToto\PredicateRegistry;
use K2gl\InToto\Statement;
use K2gl\Dsse\Envelope;
use K2gl\Dsse\Ed25519Verifier;

$envelope = Envelope::fromJson($json);

$envelope->verify($verifier);              // DSSE signature check (throws on failure)
$statement = Statement::fromEnvelope($envelope);

$statement->predicateType;                 // 'https://slsa.dev/provenance/v1'
$statement->subject[0]->digest;            // ['sha256' => '…']
$statement->subject[0]->hasDigest('sha256', $expectedHex);    // case-insensitive digest check
$statement->predicate(PredicateRegistry::default());          // typed Predicate when registered, else the raw array

fromEnvelope() checks the envelope's payloadType and decodes the payload — always verify the envelope's signatures (via k2gl/dsse) before trusting the result.

Statement versions

Real-world Sigstore bundles carry in-toto Statements in two schema versions: the current v1 and the legacy v0.1 (often wrapping a SLSA Provenance v0.2 predicate). fromJson() and fromEnvelope() parse both and expose which one was decoded:

use K2gl\InToto\StatementVersion;

$statement = Statement::fromEnvelope($envelope);
$statement->version === StatementVersion::V0_1;   // true for a legacy bundle

New statements default to v1. To build a v0.1 statement, pass the version explicitly:

$statement = new Statement(
    subject: [new ResourceDescriptor(name: 'app', digest: ['sha256' => '…'])],
    predicateType: 'https://slsa.dev/provenance/v0.2',
    predicate: [/* … */],
    version: StatementVersion::V0_1,
);

Scope

This package models the Statement layer (the generic envelope payload). Concrete predicate types — SLSA Provenance, SPDX/CycloneDX, etc. — are intentionally out of scope. They can be read as the raw predicate array, or modelled by companion packages that implement Predicate and register a factory in a PredicateRegistry (e.g. k2gl/slsa-provenance); Statement::predicate() then returns the typed object.

License

MIT — see LICENSE. Independent, clean-room implementation of the in-toto Attestation specification (Apache-2.0).

API

Public classes and methods, generated from the source.

K2gl\InToto\Exception\InTotoException interface

K2gl\InToto\Exception\InvalidStatementException class

K2gl\InToto\Predicate interface

  • predicateType(): string
  • toArray(): array

K2gl\InToto\PredicateRegistry class

  • register(string $predicateType, callable $factory): void
  • has(string $predicateType): bool
  • resolve(string $predicateType, array $predicate): ?Predicate
  • default(): self

K2gl\InToto\ResourceDescriptor class

  • __construct( public readonly ?string $name = null, public readonly ?string $uri = null, public readonly array $digest = [], public readonly ?string $mediaType = null, public readonly ?string $downloadLocation = null, public readonly ?array $annotations = null, public readonly ?string $content = null, )
  • toArray(): array
  • digestFor(string $algorithm): ?string
  • hasDigest(string $algorithm, string $hexValue): bool
  • fromArray(array $data): self

K2gl\InToto\Statement class

  • __construct( public readonly array $subject, public readonly string $predicateType, public readonly array $predicate = [], public readonly StatementVersion $version = StatementVersion::V1, )
  • sign(Signer ...$signers): Envelope
  • predicate(?PredicateRegistry $registry = null): Predicate|array
  • fromEnvelope(Envelope $envelope): self
  • toArray(): array
  • toJson(): string
  • fromJson(string $json): self
  • fromArray(array $data): self

K2gl\InToto\StatementVersion enum