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.
Install
composer require k2gl/in-toto-attestation 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(): stringtoArray(): array
K2gl\InToto\PredicateRegistry class
register(string $predicateType, callable $factory): voidhas(string $predicateType): boolresolve(string $predicateType, array $predicate): ?Predicatedefault(): 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(): arraydigestFor(string $algorithm): ?stringhasDigest(string $algorithm, string $hexValue): boolfromArray(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): Envelopepredicate(?PredicateRegistry $registry = null): Predicate|arrayfromEnvelope(Envelope $envelope): selftoArray(): arraytoJson(): stringfromJson(string $json): selffromArray(array $data): self