Skip to content

rpm-rs/rpm

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

451 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

crates.io docs.rs MSRV

RPM-RS

A pure rust library for parsing and creating RPM files.

Goals

  • Easy to use API
  • Pure rust to make it easy to use in larger Projects
  • Independence of Spec files. Pure programmatic interface for Packaging.
  • Compatibility from Enterprise Linux 8 (RHEL, Alma, Rocky, CentOS Stream) to Fedora (I may extend test cases for SUSE)

Non Goals

RPM has a lot of cryptic features. I do not want to re-implement all of them. This library focuses on the ones that I assume as useful. This library does not build software like rpmbuild. It is meant for finished artifacts that need to be packaged as RPM.

Status

  • RPM Creation
  • Basic RPM Reading
  • RPM Signing and Signature Verification
  • High Level API for RPM Reading

Examples

Read package and access metadata

use rpm::signature::pgp::{Signer, Verifier};

let pkg = rpm::Package::open("tests/assets/RPMS/v6/noarch/rpm-basic-2.3.4-5.el9.noarch.rpm")?;

let name = pkg.metadata.get_name()?;
let version = pkg.metadata.get_version()?;
let release = pkg.metadata.get_release()?;
let arch = pkg.metadata.get_arch()?;

println!("{}-{}-{}.{}", name, version, release, arch);

for changelog in pkg.metadata.get_changelog_entries()? {
    println!("{}\n{}\n", changelog.name, changelog.description);
}

Sign existing package and verify package signature

use rpm::signature::pgp::{Signer, Verifier};

let raw_secret_key = std::fs::read("./tests/assets/signing_keys/v6/rpm-testkey-v6-rsa4k.secret")?;
let raw_pub_key = std::fs::read("./tests/assets/signing_keys/v6/rpm-testkey-v6-rsa4k.asc")?;

let mut pkg = rpm::Package::open("./tests/assets/RPMS/v6/signed/rpm-basic-with-rsa4k-2.3.4-5.el9.noarch.rpm")?;
pkg.sign(&raw_secret_key)?;
pkg.write_file("./with_signature.rpm")?;

let pkg = rpm::Package::open("./with_signature.rpm")?;
pkg.verify_signature(Verifier::load_from_asc_bytes(&raw_pub_key)?)?;

Sign with a specific subkey

use rpm::signature::pgp::Signer;

let raw_secret_key = std::fs::read("./tests/assets/signing_keys/v6/rpm-testkey-v6-ed25519.secret")?;
let subkey_fingerprint = hex::decode("1F9A6321E1C5B4600BC2F6D8130FD47580C5CC7701DD8BE59983C1F79325EBF9")?;

let signer = Signer::load_from_asc_bytes(&raw_secret_key)?
    .with_signing_key(&subkey_fingerprint)?;

let mut pkg = rpm::Package::open("./tests/assets/RPMS/v6/noarch/rpm-basic-2.3.4-5.el9.noarch.rpm")?;
pkg.sign(signer)?;

Build new package

use rpm::signature::pgp::Signer;

let build_config = rpm::BuildConfig::default().compression(rpm::CompressionType::Gzip);
let raw_secret_key = std::fs::read("./tests/assets/signing_keys/secret_ed25519.asc")?;
// It's recommended to use timestamp of last commit in your VCS
let source_date = 1_600_000_000;
let pkg = rpm::PackageBuilder::new("test", "1.0.0", "MIT", "x86_64", "some awesome package")
    .using_config(build_config)
    // set default ownership and permissions for files and directories, similar to %defattr
    // in an RPM spec file. Pass None for any field to leave it unchanged (like `-` in %defattr).
    .default_file_attrs(Some(0o644), Some("myuser".into()), Some("mygroup".into()))
    .default_dir_attrs(Some(0o755), Some("myuser".into()), Some("mygroup".into()))
    // add a file with no special options
    // by default, files will be owned by the "root" user and group, and inherit their permissions
    // from the on-disk file.
    .with_file(
        "./tests/assets/SOURCES/multiplication_tables.py",
        rpm::FileOptions::new("/usr/bin/awesome"),
    )?
    // you can set permissions, capabilities and other metadata (user, group, etc.) manually
    .with_file(
        "./tests/assets/SOURCES/example_config.toml",
        rpm::FileOptions::new("/etc/awesome/second.toml")
            .permissions(0o644)
            .caps("cap_sys_admin,cap_net_admin=pe")?
            .user("hugo"),
    )?
    // Add a file - setting flags on it equivalent to `%config(noreplace)`
    .with_file(
        "./tests/assets/SOURCES/example_config.toml",
        rpm::FileOptions::new("/etc/awesome/config.toml")
            .config().noreplace(),
    )?
    // symlinks don't require a source file
    .with_symlink(
        rpm::FileOptions::symlink("/usr/bin/awesome_link", "/usr/bin/awesome"),
    )?
    // directories can be created with explicit ownership and permissions
    // this does not add any directory contents, just declares a directory
    .with_dir_entry(
        rpm::FileOptions::dir("/var/log/awesome").permissions(0o750),
    )?
    // ghost files / directories are not included in the package payload, but their metadata
    // (ownership, permissions, etc.) is tracked by RPM. This is commonly used for files
    // created at runtime (e.g. log files, PID files).
    .with_ghost(
        rpm::FileOptions::ghost("/var/log/awesome/app.log"),
    )?
    .pre_install_script("echo preinst")
    // Alternatively, use scriptlet builder api to specify flags and interpreter/arguments
    .post_trans_script(
        Scriptlet::new("echo posttrans")
            .flags(ScriptletFlags::EXPAND)
            .prog(vec!["/bin/blah/bash", "-c"])
    )
    // If you don't need reproducible builds, you can remove the following line
    .source_date(source_date)
    .build_host(gethostname::gethostname().to_str().unwrap_or("host"))
    .add_changelog_entry(
        "Max Mustermann <max@example.com> - 0.1-29",
        "- was awesome, eh?",
        chrono::DateTime::parse_from_rfc2822("Wed, 19 Apr 2023 23:16:09 GMT")
            .expect("Date 1 is correct. qed"),
    )
    .add_changelog_entry(
        "Charlie Yom <test2@example.com> - 0.1-28",
        "- yeah, it was",
        // Raw timestamp for 1996-08-14 05:20:00
        840_000_000,
    )
    .requires(rpm::Dependency::any("wget"))
    .vendor("corporation or individual")
    .url("www.github.com/repo")
    .vcs("git:repo=example_repo:branch=example_branch:sha=example_sha")
    .build_and_sign(Signer::load_from_asc_bytes(&raw_secret_key)?)?;

pkg.write_file("./awesome.rpm")?;

About

No description, website, or topics provided.

Resources

License

Unknown, MIT licenses found

Licenses found

Unknown
LICENSE-APACHE
MIT
LICENSE-MIT

Stars

Watchers

Forks

Packages

 
 
 

Contributors