Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 28 additions & 14 deletions .github/workflows/test-and-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ jobs:
echo "matrix=[ '${{ github.event.client_payload.tag }}' ]" >> $GITHUB_OUTPUT
echo "coverage=${{ github.event.client_payload.tag }}" >> $GITHUB_OUTPUT
else
echo "matrix=[ 'v0.15.2', 'v0.16.2', '' ]" >> $GITHUB_OUTPUT
echo "matrix=[ 'v0.17.1', 'v0.18.1', '' ]" >> $GITHUB_OUTPUT
echo "coverage=$(git remote show https://github.com/rnpgp/rnp | grep HEAD | cut -d' ' -f5)" >> $GITHUB_OUTPUT
fi

Expand All @@ -61,12 +61,12 @@ jobs:
fail-fast: false
matrix:
os: [ 'ubuntu-latest', 'macos-latest' ]
ruby: [ '2.7', '3.0', '3.1', '3.2', 'head' ]
ruby: [ '3.1', '3.2', '3.3', '3.4', 'head' ]
rnp: ${{ fromJson(needs.prepare.outputs.matrix) }}
env: [ { COVERAGE: false } ]
include:
- os: 'ubuntu-latest'
ruby: '3.2'
ruby: '3.4'
rnp: ${{ needs.prepare.outputs.coverage }}
env: { COVERAGE: 'true' }

Expand All @@ -75,24 +75,28 @@ jobs:
steps:
- name: Install packages Ubuntu
if: matrix.os == 'ubuntu-latest'
# Already installed on GHA: build-essential libbz2-dev zlib1g-dev
run: sudo apt-get install cmake libbotan-2-dev libjson-c-dev
# build-essential is preinstalled on GHA; libbz2-dev/zlib1g-dev are not on ubuntu-24.04
run: |
sudo apt-get install cmake libbotan-2-dev libjson-c-dev libbz2-dev zlib1g-dev
echo LD_LIBRARY_PATH="/usr/local/lib:$LD_LIBRARY_PATH" >> $GITHUB_ENV

- name: Install packages MacOS
if: matrix.os == 'macos-latest'
# Already installed on GHA: cmake make
run: brew install botan json-c

- name: Checkout rnp
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
repository: rnpgp/rnp
path: rnp
submodules: true
ref: ${{ matrix.rnp }}

- name: Configure rnp
run: cmake -B rnp/build -DBUILD_TESTING=OFF -DENABLE_DOC=OFF -DBUILD_SHARED_LIBS=ON rnp
# Homebrew's botan is Botan 3, which requires CRYPTO_BACKEND=botan3
# (supported by rnp >= 0.17.1).
run: cmake -B rnp/build -DBUILD_TESTING=OFF -DENABLE_DOC=OFF -DBUILD_SHARED_LIBS=ON ${{ matrix.os == 'macos-latest' && '-DCRYPTO_BACKEND=botan3' || '' }} rnp

- name: Build rnp
run: cmake --build rnp/build
Expand All @@ -101,7 +105,7 @@ jobs:
run: sudo cmake --install rnp/build

- name: Checkout ruby-rnp
uses: actions/checkout@v3
uses: actions/checkout@v4

- name: Setup Ruby and bundle
uses: ruby/setup-ruby@v1
Expand All @@ -112,21 +116,31 @@ jobs:
- name: Test
run: bundle exec rake

- name: Upload coverage to Codecov
if: env.COVERAGE == 'true'
uses: codecov/codecov-action@v5
with:
files: ./coverage/coverage.json
token: ${{ secrets.CODECOV_TOKEN }}
# no CODECOV_TOKEN secret exists yet; don't fail CI until one is added
# (the repo's protected main branch makes uploads require a token)
fail_ci_if_error: false

package-and-release:
runs-on: ubuntu-latest
if: contains(github.ref, 'refs/tags/v')
needs: build-and-test
steps:
- name: Install packages Ubuntu
# Already installed on GHA: build-essential libbz2-dev zlib1g-dev
run: sudo apt-get install cmake libbotan-2-dev libjson-c-dev
# build-essential is preinstalled on GHA; libbz2-dev/zlib1g-dev are not on ubuntu-24.04
run: sudo apt-get install cmake libbotan-2-dev libjson-c-dev libbz2-dev zlib1g-dev

- name: Checkout rnp
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
repository: rnpgp/rnp
path: rnp
ref: master
ref: main
submodules: true

- name: Configure rnp
Expand All @@ -139,12 +153,12 @@ jobs:
run: sudo cmake --install rnp/build

- name: Checkout ruby-rnp
uses: actions/checkout@v3
uses: actions/checkout@v4

- name: Setup Ruby and bundle
uses: ruby/setup-ruby@v1
with:
ruby-version: '3.2'
ruby-version: '3.4'
bundler-cache: true

- name: Package
Expand Down
11 changes: 8 additions & 3 deletions README.adoc
Original file line number Diff line number Diff line change
@@ -1,16 +1,21 @@
= Ruby RNP bindings

image:https://github.com/rnpgp/ruby-rnp/actions/workflows/test-and-release.yml/badge.svg["Build Status", link="https://github.com/rnpgp/ruby-rnp/actions/workflows/test-and-release.yml"]
image:https://codecov.io/github/rnpgp/ruby-rnp/coverage.svg["Code Coverage", link="https://codecov.io/github/rnpgp/ruby-rnp?branch=master"]
image:https://codecov.io/gh/rnpgp/ruby-rnp/branch/main/graph/badge.svg["Code Coverage", link="https://codecov.io/gh/rnpgp/ruby-rnp"]

The `rnp` gem provides Ruby bindings to the
https://github.com/rnpgp/rnp[librnp OpenPGP library].

Documentation is available on https://www.rubydoc.info/github/rnpgp/ruby-rnp/master/[RubyDoc].
Documentation is available on https://www.rubydoc.info/github/rnpgp/ruby-rnp/main/[RubyDoc].

== Requirements

This gem currently requires https://github.com/rnpgp/rnp[librnp] 0.10.0 or newer.
This gem currently requires https://github.com/rnpgp/rnp[librnp] 0.15.2 or newer.

NOTE: librnp 0.18.1 or newer is strongly recommended: librnp 0.18.0 is
affected by https://open.ribose.com/advisories/ra-2025-11-20/[CVE-2025-13470],
where PKESK session keys were generated without cryptographically random
values (older releases are not affected).

== Installation

Expand Down
10 changes: 7 additions & 3 deletions docs/quickstart.adoc
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
= RNP’s Ruby bindings overview

image:https://github.com/rnpgp/ruby-rnp/actions/workflows/tests.yml/badge.svg["Build Status", link="https://github.com/rnpgp/ruby-rnp/actions/workflows/tests.yml"]
image:https://codecov.io/github/rnpgp/ruby-rnp/coverage.svg["Code Coverage", link="https://codecov.io/github/rnpgp/ruby-rnp?branch=master"]
image:https://github.com/rnpgp/ruby-rnp/actions/workflows/test-and-release.yml/badge.svg["Build Status", link="https://github.com/rnpgp/ruby-rnp/actions/workflows/test-and-release.yml"]
image:https://codecov.io/gh/rnpgp/ruby-rnp/branch/main/graph/badge.svg["Code Coverage", link="https://codecov.io/gh/rnpgp/ruby-rnp"]

The `rnp` gem provides Ruby bindings to the
https://www.rnpgp.com/software/rnp/[RNP OpenPGP library] and requires RNP 0.10.0 or newer.
https://www.rnpgp.com/software/rnp/[RNP OpenPGP library] and requires RNP 0.15.2 or newer.

NOTE: RNP 0.18.1 or newer is strongly recommended: RNP 0.18.0 is affected by
CVE-2025-13470, where PKESK session keys were generated without
cryptographically random values (older releases are not affected).

== Installation

Expand Down
3 changes: 3 additions & 0 deletions lib/rnp/ffi/librnp.rb
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,9 @@ module LibRnp
rnp_signature_packet_to_json: [%i[pointer uint32 pointer], :uint32],
rnp_signature_handle_destroy: [%i[pointer], :uint32],
rnp_op_verify_signature_get_handle: [%i[pointer pointer], :uint32],
# signature validation errors
rnp_signature_error_count: [%i[pointer pointer], :uint32],
rnp_signature_error_at: [%i[pointer size_t pointer], :uint32],
# key uids
rnp_key_get_uid_handle_at: [%i[pointer size_t pointer], :uint32],
rnp_uid_is_revoked: [%i[pointer pointer], :uint32],
Expand Down
13 changes: 13 additions & 0 deletions lib/rnp/op/verify.rb
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@ class Signature

# @api private
def initialize(ptr)
@ptr = ptr

# status
@status = LibRnp.rnp_op_verify_signature_get_status(ptr)
pptr = FFI::MemoryPointer.new(:pointer)
Expand Down Expand Up @@ -133,6 +135,17 @@ def valid?
def expired?
@status == LibRnp::RNP_ERROR_SIGNATURE_EXPIRED
end

# Get the full signature handle, providing access to extended
# information (verification errors, JSON dump, etc).
#
# @see Rnp::Signature
# @return [Rnp::Signature]
def handle
pptr = FFI::MemoryPointer.new(:pointer)
Rnp.call_ffi(:rnp_op_verify_signature_get_handle, @ptr, pptr)
Rnp::Signature.new(pptr.read_pointer)
end
end

private
Expand Down
17 changes: 17 additions & 0 deletions lib/rnp/signature.rb
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,23 @@ def json(mpi: false, raw: false, grip: false)
end
end

# Verification errors recorded for this signature.
#
# @note Requires librnp 0.18.0 or newer.
#
# @return [Array<Integer>] a list of error codes (rnp_result_t values)
# describing why the signature failed verification. An empty array
# means no errors were recorded.
def errors
pcount = FFI::MemoryPointer.new(:size_t)
Rnp.call_ffi(:rnp_signature_error_count, @ptr, pcount)
perror = FFI::MemoryPointer.new(:uint32)
(0...pcount.read(:size_t)).map do |idx|
Rnp.call_ffi(:rnp_signature_error_at, @ptr, idx, perror)
perror.read(:uint32)
end
end

private

def string_property(func)
Expand Down
49 changes: 27 additions & 22 deletions rakelib/platform.rake
Original file line number Diff line number Diff line change
Expand Up @@ -20,22 +20,27 @@ def libname
end
end

def replace_in_file(file, old, new)
content = nil
File.open(file, "r") {|f| content = f.read}
File.open(file, "w") {|f| f.puts content.gsub(old, new)}
end

def apply_workadound_1654
# https://github.com/rnpgp/rnp/issues/1654 workaround
replace_in_file("ci/main.sh", '[ -v "GTEST_SOURCES" ]',
'[ -n "${GTEST_SOURCES:-}" ]')
replace_in_file("ci/main.sh", '[ -v "DOWNLOAD_GTEST" ]',
'[ -n "${DOWNLOAD_GTEST:-}" ]')
replace_in_file("ci/main.sh", '[ -v "DOWNLOAD_RUBYRNP" ]',
'[ -n "${DOWNLOAD_RUBYRNP:-}" ]')
replace_in_file("ci/main.sh", '[ -v "CRYPTO_BACKEND" ]',
'[ -n "${CRYPTO_BACKEND:-}" ]')
# rnp moved its CI shell scripts from ci/ to ci-legacy/ without updating
# their internal references, which still expect to be sourced as ci/...
# from the repository root. Recreate the expected layout with symlinks.
def setup_legacy_ci_scripts
{
"ci/main.sh" => "../ci-legacy/main.sh",
"ci/success.sh" => "../ci-legacy/success.sh",
"ci/env.inc.sh" => "../ci-legacy/env.inc.sh",
"ci/env-common.inc.sh" => "../ci-legacy/env-common.inc.sh",
"ci/env-linux.inc.sh" => "../ci-legacy/env-linux.inc.sh",
"ci/env-freebsd.inc.sh" => "../ci-legacy/env-freebsd.inc.sh",
"ci/utils.inc.sh" => "../ci-legacy/utils.inc.sh",
"ci/lib/install_functions.inc.sh" =>
"../../ci-legacy/lib/install_functions.inc.sh",
"ci/lib/cacheable_install_functions.inc.sh" =>
"../../ci-legacy/lib/cacheable_install_functions.inc.sh",
}.each do |link, target|
next if File.exist?(link)
FileUtils.mkdir_p(File.dirname(link))
FileUtils.ln_s(target, link)
end
end

workspace = File.dirname(File.dirname(__FILE__))
Expand Down Expand Up @@ -73,7 +78,7 @@ end

desc "Git clone rnp native library"
task :rnp_git do
rev = ENV["RNP_VERSION"] || "master"
rev = ENV["RNP_VERSION"] || "main"
unless Dir.exist?(librnp_path)
system("git clone https://github.com/rnpgp/rnp -b #{rev} #{librnp_path}")
end
Expand All @@ -96,19 +101,19 @@ task compile: [:rnp_git] do
"RNP_INSTALL" => rnp_install,
"USE_STATIC_DEPENDENCIES" => "yes",
"SKIP_TESTS" => "1",
"DOWNLOAD_RUBYRNP" => "OFF",
}

cache_path = File.join(workspace, "tmp", cache_dir)
FileUtils.mkdir_p(cache_path)
FileUtils.ln_s(cache_path, tmp)

Dir.chdir(librnp_path) do
apply_workadound_1654
ci_dir = Dir.exist?("ci-legacy") ? "ci-legacy" : "ci"
setup_legacy_ci_scripts if ci_dir == "ci-legacy"

system(build_env, "ci/install_noncacheable_dependencies.sh")
system(build_env, "ci/install_cacheable_dependencies.sh botan jsonc")
system(build_env, "ci/run.sh")
system(build_env, "#{ci_dir}/install_noncacheable_dependencies.sh")
system(build_env, "#{ci_dir}/install_cacheable_dependencies.sh botan jsonc")
system(build_env, "#{ci_dir}/run.sh")
end

FileUtils.cp(File.join(rnp_install, "lib", libname), "lib/rnp/ffi/")
Expand Down
14 changes: 7 additions & 7 deletions rnp.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,14 @@ Gem::Specification.new do |spec|
spec.metadata['yard.run'] = 'yard'

spec.add_development_dependency 'asciidoctor', '~> 2.0'
spec.add_development_dependency 'bundler', '>= 1.14', '< 3'
spec.add_development_dependency 'codecov', '~> 0.1'
spec.add_development_dependency 'rake', '>= 10', '< 14'
spec.add_development_dependency 'redcarpet', '~> 3.4'
spec.add_development_dependency 'rspec', '~> 3.5'
spec.add_development_dependency 'bundler', '>= 2'
spec.add_development_dependency 'rake', '~> 13.0'
spec.add_development_dependency 'redcarpet', '~> 3.6'
spec.add_development_dependency 'rspec', '~> 3.13'
spec.add_development_dependency 'rubocop', '~> 0.75.0'
spec.add_development_dependency 'simplecov', '~> 0.14'
spec.add_development_dependency 'yard', '~> 0.9.12'
spec.add_development_dependency 'simplecov', '~> 0.22'
spec.add_development_dependency 'simplecov-json', '~> 0.2'
spec.add_development_dependency 'yard', '~> 0.9'

spec.add_runtime_dependency 'ffi', '~> 1.9'
end
Loading
Loading