packslip 1.11.2

A vendor-neutral signed release manifest: what shipped, and how to verify it
Documentation
//! packslip: a vendor publishes one signed, machine-readable document per
//! release that says what the artifacts are and how to verify them.
//! Consumers pin one identity and get checksums, platform mapping,
//! executables, provenance links, and a signed manifest without per-vendor
//! logic or a registry entry.
//!
//! The document is a sigstore bundle carrying an in-toto statement. It is
//! signed keylessly with a CI job's OIDC identity or with a long-lived
//! Ed25519 key, and either way logged to Rekor ([`sigstore`]). The same
//! shape carries a project's release list. This crate holds the schema,
//! the verifier, and the generator. See <https://packslip.dev/release/v1/>.
//!
//! Everything is on by default. A consumer that only verifies takes the
//! crate with `default-features = false`, which keeps [`model`], [`verify`],
//! and [`sigstore`] and drops the archive readers, the executable decoder,
//! the signing path, and the CLI.

#![forbid(unsafe_code)]

#[cfg(feature = "archive")]
pub mod archive;
#[cfg(feature = "verify-cli")]
pub mod cli;
#[cfg(feature = "create")]
pub mod create;
#[cfg(feature = "discovery")]
pub mod discovery;
pub mod dsse;
pub mod fingerprint;
pub mod forge;
#[cfg(feature = "install-cli")]
pub mod install;
#[cfg(feature = "install-extract")]
pub mod install_extract;
#[cfg(feature = "install-fs")]
pub mod install_fs;
#[cfg(feature = "install-host")]
pub mod install_host;
#[cfg(feature = "install-launcher")]
pub mod install_launcher;
#[cfg(feature = "install-policy")]
pub mod install_policy;
#[cfg(any(
    all(feature = "install-launcher", windows),
    all(feature = "install-launcher", test)
))]
mod launcher_payload;
#[cfg(feature = "linkage")]
pub mod linkage;
#[cfg(feature = "manifest")]
pub mod manifest;
pub mod minisign;
pub mod model;
pub mod sigstore;
#[cfg(feature = "trust-root")]
pub mod trust_root;
pub mod verify;

pub use fingerprint::Fingerprint;
#[cfg(feature = "manifest")]
pub use manifest::Manifest;
#[cfg(feature = "schema")]
pub use model::verify_report_schema;
pub use model::{
    Artifact, Attestor, Bin, Evidence, Host, Identity, Predicate, ReleaseList,
    ReleaseListStatement, ReleaseRef, ReleaseStatus, Requires, Resource, ResourceIdentity,
    ResourceSource, Scheme, Selection, Source, Statement, Subject, command_name, github_list_path,
    list_url, select_artifact, select_resources, tag_version,
};
#[cfg(feature = "sign")]
pub use sigstore::Signer;
pub use sigstore::{Policy, Trust};
pub use verify::{
    Claimed, ForgeError, ForgeVerified, Options, Verified, VerifiedArtifact, VerifiedList,
    VerifyReport, peek_unverified, verify, verify_forge, verify_forge_release_list,
    verify_release_list,
};

/// The sha256 of a file, lowercase hex, and its size.
pub fn digest_file(path: &std::path::Path) -> std::io::Result<(String, u64)> {
    let all = digest_file_all(path)?;
    Ok((all.sha256, all.size))
}

/// Every digest of a file, in one pass.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Digests {
    /// Lowercase hex.
    pub sha256: String,
    /// Lowercase hex.
    pub sha512: String,
    pub size: u64,
}

/// The sha256 and sha512 of a file, lowercase hex, and its size.
pub fn digest_file_all(path: &std::path::Path) -> std::io::Result<Digests> {
    use sha2::Digest as _;
    use std::io::Read as _;
    let mut file = std::fs::File::open(path)?;
    let mut sha256 = sha2::Sha256::new();
    let mut sha512 = sha2::Sha512::new();
    let mut size = 0u64;
    let mut buf = vec![0u8; 1 << 16];
    loop {
        let n = file.read(&mut buf)?;
        if n == 0 {
            break;
        }
        sha256.update(&buf[..n]);
        sha512.update(&buf[..n]);
        size += n as u64;
    }
    Ok(Digests {
        sha256: hex::encode(sha256.finalize()),
        sha512: hex::encode(sha512.finalize()),
        size,
    })
}