diff --git a/.github/workflows/cleanup.yml b/.github/workflows/cleanup.yml new file mode 100644 index 000000000..8f5136657 --- /dev/null +++ b/.github/workflows/cleanup.yml @@ -0,0 +1,44 @@ +name: "Dry-Run Cleanup" +run-name: "Dry Run Cleanup for ${{ github.ref }}" + +on: + workflow_dispatch: + inputs: + confirm: + description: Indicate whether you want this workflow to run (must be "true") + required: true + type: string + tag: + description: The name of the tag (and release) to clean up + required: true + type: string + +jobs: + release: + name: "Dry-Run Cleanup" + environment: release + runs-on: 'ubuntu-latest' + if: ${{ inputs.confirm == 'true' }} + + permissions: + # required for all workflows + security-events: write + + # required to fetch internal or private CodeQL packs + packages: read + + # only required for workflows in private repositories + actions: read + contents: write + + # required by the mongodb-labs/drivers-github-tools/setup@v2 step + # also required by `rubygems/release-gem` + id-token: write + + steps: + - name: "Run the cleanup action" + uses: mongodb-labs/drivers-github-tools/ruby/cleanup@v2 + with: + app_id: ${{ vars.APP_ID }} + app_private_key: ${{ secrets.APP_PRIVATE_KEY }} + tag: ${{ inputs.tag }} diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 000000000..42872cbfa --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,69 @@ +name: "CodeQL" + +on: [ push, pull_request ] + +jobs: + analyze: + name: Analyze (${{ matrix.language }}) + # Runner size impacts CodeQL analysis time. To learn more, please see: + # - https://gh.io/recommended-hardware-resources-for-running-codeql + # - https://gh.io/supported-runners-and-hardware-resources + # - https://gh.io/using-larger-runners (GitHub.com only) + # Consider using larger runners or machines with greater resources for possible analysis time improvements. + runs-on: 'ubuntu-latest' + timeout-minutes: 360 + permissions: + # required for all workflows + security-events: write + + # required to fetch internal or private CodeQL packs + packages: read + + # only required for workflows in private repositories + actions: read + contents: read + + strategy: + fail-fast: false + matrix: + include: + - language: ruby + build-mode: none + - language: c + build-mode: manual + - language: java + build-mode: none + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v3 + with: + languages: ${{ matrix.language }} + build-mode: ${{ matrix.build-mode }} + config: | + paths-ignore: + - .evergreen + - spec + - perf + - vendor + + - name: Setup Ruby + if: matrix.build-mode == 'manual' + uses: ruby/setup-ruby@v1 + with: + ruby-version: '3.2' + bundler-cache: true + + - name: Manually build the native code + if: matrix.build-mode == 'manual' + run: | + bundle exec rake compile + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v3 + with: + category: "/language:${{matrix.language}}" + diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 000000000..e270d54c7 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,170 @@ +name: "BSON Release" +run-name: "BSON Release for ${{ github.ref }}" + +on: + workflow_dispatch: + inputs: + dry_run: + description: Whether this is a dry run or not + required: true + default: true + type: boolean + +env: + SILK_ASSET_GROUP: bson-ruby + RELEASE_MESSAGE_TEMPLATE: | + Version {0} of [BSON for Ruby](https://rubygems.org/gems/bson) is now available. + + **Release Highlights** + + TODO: one or more paragraphs describing important changes in this release + + **Documentation** + + Documentation is available at [MongoDB.com](https://www.mongodb.com/docs/ruby-driver/current/tutorials/bson/). + + **Installation** + + You may install this version via RubyGems, with: + + gem install --version {0} bson + +permissions: + # required for all workflows + security-events: write + + # required to fetch internal or private CodeQL packs + packages: read + + # only required for workflows in private repositories + actions: read + contents: write + + # required by the mongodb-labs/drivers-github-tools/setup@v2 step + # also required by `rubygems/release-gem` + id-token: write + +jobs: + build: + name: "Build Gems" + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + ruby: [ '3.2', jruby ] + steps: + - name: Check out the repository + uses: actions/checkout@v4 + + - name: Setup Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{ matrix.ruby }} + bundler-cache: true + + - name: Set output gem file name + shell: bash + run: | + echo "GEM_FILE_NAME=$(bundle exec rake gem_file_name)" >> "$GITHUB_ENV" + + - name: Build the gem + shell: bash + run: bundle exec rake build + + - name: Save the generated gem file for later + uses: actions/upload-artifact@v4 + with: + name: ${{ env.GEM_FILE_NAME }} + path: ${{ env.GEM_FILE_NAME }} + retention-days: 1 + overwrite: true + + publish: + name: Publish Gems + needs: build + environment: release + runs-on: ubuntu-latest + steps: + - name: Check out the repository + uses: mongodb-labs/drivers-github-tools/secure-checkout@v2 + with: + app_id: ${{ vars.APP_ID }} + private_key: ${{ secrets.APP_PRIVATE_KEY }} + + - name: Setup Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: '3.2' + bundler-cache: true + + - name: Get the release version + shell: bash + run: echo "RELEASE_VERSION=$(bundle exec rake version)" >> "$GITHUB_ENV" + + - name: Setup GitHub tooling for DBX Drivers + uses: mongodb-labs/drivers-github-tools/setup@v2 + with: + aws_role_arn: ${{ secrets.AWS_ROLE_ARN }} + aws_region_name: ${{ vars.AWS_REGION_NAME }} + aws_secret_id: ${{ secrets.AWS_SECRET_ID }} + + - name: Fetch the gem artifacts + uses: actions/download-artifact@v4 + with: + merge-multiple: true + + - name: Sign the gems + uses: mongodb-labs/drivers-github-tools/gpg-sign@v2 + with: + filenames: '*.gem' + + - name: Generate SSDLC Reports + uses: mongodb-labs/drivers-github-tools/full-report@v2 + with: + product_name: BSON for Ruby + release_version: ${{ env.RELEASE_VERSION }} + dist_filenames: '*.gem' + silk_asset_group: bson-ruby + + - name: Create the tag + uses: mongodb-labs/drivers-github-tools/tag-version@v2 + with: + version: ${{ env.RELEASE_VERSION }} + tag_template: "v${VERSION}" + tag_message_template: "Release tag for v${VERSION}" + + - name: Create a new release + shell: bash + run: gh release create v${{ env.RELEASE_VERSION }} --title ${{ env.RELEASE_VERSION }} --generate-notes --draft + + - name: Capture the changelog + shell: bash + run: gh release view v${{ env.RELEASE_VERSION }} --json body --template '{{ .body }}' >> changelog + + - name: Prepare release message + shell: bash + run: | + echo "${{ format(env.RELEASE_MESSAGE_TEMPLATE, env.RELEASE_VERSION) }}" > release-message + cat changelog >> release-message + + - name: Update release information + shell: bash + run: | + echo "RELEASE_URL=$(gh release edit v${{ env.RELEASE_VERSION }} --notes-file release-message)" >> "$GITHUB_ENV" + + - name: Upload release artifacts + shell: bash + run: gh release upload v${{ env.RELEASE_VERSION }} *.gem ${{ env.RELEASE_ASSETS }}/*.sig + + - name: Upload S3 assets + uses: mongodb-labs/drivers-github-tools/upload-s3-assets@v2 + with: + version: ${{ env.RELEASE_VERSION }} + product_name: 'bson-ruby' + dry_run: ${{ inputs.dry_run }} + + - name: Publish the gems + uses: rubygems/release-gem@v1 + if: inputs.dry_run == 'false' + with: + await-release: false diff --git a/Rakefile b/Rakefile index 417a37863..26f4f87cc 100644 --- a/Rakefile +++ b/Rakefile @@ -47,28 +47,37 @@ else end end -require "bson/version" +RSpec::Core::RakeTask.new(:rspec) -def extension - RUBY_PLATFORM =~ /darwin/ ? "bundle" : "so" +desc 'Build the bson gem' +task :build => [ :clean_all, *(jruby? ? :compile : nil) ] do + output = "--output=#{ENV['GEM_FILE_NAME']}" if ENV['GEM_FILE_NAME'] + system "gem build #{output} bson.gemspec" end -require_relative "perf/bench" - -RSpec::Core::RakeTask.new(:rspec) +# `rake version` is used by the deployment system so get the release version +# of the product beng deployed. It must do nothing more than just print the +# product version number. +desc 'Print the current version of the Ruby-BSON library' +task :version do + require 'bson/version' + puts BSON::VERSION +end -if jruby? - task :build => [ :clean_all, :compile ] do - system "gem build bson.gemspec" - end -else - task :build => :clean_all do - system "gem build bson.gemspec" - end +# `rake gem_file_name` is used by the deployment system so get the name of +# the gem file to be generated. It must do nothing more than just print the +# name of the gem file to generate. +desc 'Print the name of the gem file to generate.' +task :gem_file_name do + require 'bson/version' + base = "bson-#{BSON::VERSION}" + base << '-java' if jruby? + puts "#{base}.gem" end task :clean_all => :clean do - FileUtils.rm_f(File.join(File.dirname(__FILE__), 'lib', "bson_native.#{extension}")) + FileUtils.rm_f(File.join(File.dirname(__FILE__), 'lib', "bson_native.bundle")) + FileUtils.rm_f(File.join(File.dirname(__FILE__), 'lib', "bson_native.so")) FileUtils.rm_f(File.join(File.dirname(__FILE__), 'lib', "bson_native.o")) FileUtils.rm_f(File.join(File.dirname(__FILE__), 'lib', "bson-ruby.jar")) end @@ -77,49 +86,63 @@ task :spec => :compile do Rake::Task["rspec"].invoke end -# Run bundle exec rake release with mri and jruby. Ex: -# -# rvm use 2.1.0@bson -# bundle exec rake release -# rvm use jruby@bson -# bundle exec rake release -task :release => :build do - system "git tag -a v#{BSON::VERSION} -m 'Tagging release: #{BSON::VERSION}'" - system "git push --tags" - if jruby? - system "gem push bson-#{BSON::VERSION}-java.gem" - system "rm bson-#{BSON::VERSION}-java.gem" - else - system "gem push bson-#{BSON::VERSION}.gem" - system "rm bson-#{BSON::VERSION}.gem" +# overrides the default Bundler-provided `release` task, which also +# builds the gem. Our release process assumes the gem has already +# been built (and signed via GPG), so we just need `rake release` to +# push the gem to rubygems. +task :release do + require 'bson/version' + + # confirm: there ought to be two gems, one for MRI, and one for Java. These + # will have been previously generated by the 'BSON Release' GitHub action. + gems = Dir['*.gem'] + if gems.length != 2 + abort "Expected two gem files to be ready to release; got #{gems.length}" + end + + if ENV['GITHUB_ACTION'].nil? + abort <<~WARNING + `rake release` must be invoked from the `BSON Release` GitHub action, + and must not be invoked locally. This ensures the gem is properly signed + and distributed by the appropriate user. + + Note that it is the `rubygems/release-gem@v1` step in the `BSON Release` + action that invokes this task. Do not rename or remove this task, or the + release-gem step will fail. Reimplement this task with caution. + + NO GEMS were pushed to RubyGems. + WARNING + end + + gems.each do |gem| + system 'gem', 'push', gem end end namespace :benchmark do - task :ruby => :clean_all do + task :prep do + require_relative "perf/bench" + end + + task ruby: [ :clean_all, 'benchmark:prep' ] do puts "Benchmarking pure Ruby..." - require "bson" benchmark! end - task :native => :compile do + task native: [ :compile, 'benchmark:prep' ] do puts "Benchmarking with native extensions..." - require "bson" benchmark! end namespace :decimal128 do - - task :from_string do + task from_string: 'benchmark:prep' do puts "Benchmarking creating Decimal128 objects from a string" - require 'bson' benchmark_decimal128_from_string! end - task :to_string do + task to_string: 'benchmark:prep' do puts "Benchmarking getting a string representation of a Decimal128" - require 'bson' benchmark_decimal128_to_string! end end @@ -133,6 +156,7 @@ task :docs => 'docs:yard' namespace :docs do desc "Generate yard documention" task :yard do + require 'bson/version' out = File.join('yard-docs', BSON::VERSION) FileUtils.rm_rf(out) system "yardoc -o #{out} --title bson-#{BSON::VERSION}" diff --git a/bson.gemspec b/bson.gemspec index 3031558ac..1c416d240 100644 --- a/bson.gemspec +++ b/bson.gemspec @@ -23,15 +23,8 @@ Gem::Specification.new do |s| 'source_code_uri' => 'https://github.com/mongodb/bson-ruby' } - if File.exist?('gem-private_key.pem') - s.signing_key = 'gem-private_key.pem' - s.cert_chain = ['gem-public_cert.pem'] - else - warn "[#{s.name}] Warning: No private key present, creating unsigned gem." - end - - s.files = %w(CONTRIBUTING.md CHANGELOG.md LICENSE NOTICE README.md Rakefile) - s.files += Dir.glob('lib/**/*') + s.files = %w(CONTRIBUTING.md CHANGELOG.md LICENSE NOTICE README.md Rakefile) + s.files += Dir.glob('lib/**/*') unless RUBY_PLATFORM =~ /java/ s.platform = Gem::Platform::RUBY diff --git a/gem-public_cert.pem b/gem-public_cert.pem deleted file mode 100644 index 68fa1da73..000000000 --- a/gem-public_cert.pem +++ /dev/null @@ -1,26 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIEeDCCAuCgAwIBAgIBATANBgkqhkiG9w0BAQsFADBBMREwDwYDVQQDDAhkYngt -cnVieTEXMBUGCgmSJomT8ixkARkWB21vbmdvZGIxEzARBgoJkiaJk/IsZAEZFgNj -b20wHhcNMjQwMjA5MTc0NzIyWhcNMjUwMjA4MTc0NzIyWjBBMREwDwYDVQQDDAhk -YngtcnVieTEXMBUGCgmSJomT8ixkARkWB21vbmdvZGIxEzARBgoJkiaJk/IsZAEZ -FgNjb20wggGiMA0GCSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQC0/Veq9l47cTfX -tQ+kHq2NOCwJuJGt1iXWQ/vH/yp7pZ/bLej7gPDl2CfIngAXRjM7r1FkR9ya7VAm -IneBFcVU3HhpIXWi4ByXGjBOXFD1Dfbz4C4zedIWRk/hNzXa+rQY4KPwpOwG/hZg -id+rSXWSbNlkyN97XfonweVh7JsIa9X/2JY9ADYjhCfEZF+b0+Wl7+jgwzLWb46I -0WH0bZBIZ0BbKAwUXIgvq5mQf9PzukmMVYCwnkJ/P4wrHO22HuwnbMyvJuGjVwqi -j1NRp/2vjmKBFWxIfhlSXEIiqAmeEVNXzhPvTVeyo+rma+7R3Bo+4WHkcnPpXJJZ -Jd63qXMvTB0GplEcMJPztWhrJOmcxIOVoQyigEPSQT8JpzFVXby4SGioizv2eT7l -VYSiCHuc3yEDyq5M+98WGX2etbj6esYtzI3rDevpIAHPB6HQmtoJIA4dSl3gjFb+ -D+YQSuB2qYu021FI9zeY9sbZyWysEXBxhwrmTk+XUV0qz+OQZkMCAwEAAaN7MHkw -CQYDVR0TBAIwADALBgNVHQ8EBAMCBLAwHQYDVR0OBBYEFH4nnr4tYlatU57RbExW -jG86YM5nMB8GA1UdEQQYMBaBFGRieC1ydWJ5QG1vbmdvZGIuY29tMB8GA1UdEgQY -MBaBFGRieC1ydWJ5QG1vbmdvZGIuY29tMA0GCSqGSIb3DQEBCwUAA4IBgQBKGtHA -fpi3N/BL1J5O4CBsAjtF4jHDiw2r5MwK+66NzMh3uedjgPI7MoosemLy++SB+8BR -SE8bDkb6gfDQQzrI6KSXXyqH2TbQXpY5Tac7/yqXRiu8G2qOrOj4czB/Hq7j09CV -YoH88v6hL11i5jt6jPjFh8hXYG0hDQxhi3atRz5Wwd98tUf2DSbyJXJiRgCBeZjl -rP7AnKsWMu0C+zPlL+nXtQr+nTFtkKXRWfUJMqePpBqtriQvgQ+Y1ItqYVTSLuiM -iwUMcn/rGhdCMBSaKDXdFkIveCHQE2f2WBo2EdErrcTrgEKYYdNfzcb/43j7L1kx -AUwyTtk+HFrviBynQbKN82rjbZE+5gukVea5c7idQPkqacPYsoU37DI+hTlUyJkV -dcTtfEg44lLlfNukBslfiQf54r+uWbyB0m0rDUN/py7/Ghyzt5GLBU91uCO3dGoI -55uFRHMvEcJMTDeImC/nuucPCAiEGMHggr9+NPC0tqpxjGKTo7lS7GzUFjg= ------END CERTIFICATE----- diff --git a/lib/bson/decimal128/builder.rb b/lib/bson/decimal128/builder.rb index 4deac8bf2..e7cf83f87 100644 --- a/lib/bson/decimal128/builder.rb +++ b/lib/bson/decimal128/builder.rb @@ -156,7 +156,7 @@ class FromString # @return [ Regex ] The regex for a valid decimal128 string. # # @since 4.2.0 - VALID_DECIMAL128_STRING_REGEX = /^[\-\+]?(\d+(\.\d*)?|\.\d+)(E[\-\+]?\d+)?$/i + VALID_DECIMAL128_STRING_REGEX = /\A[\-\+]?(\d+(\.\d*)?|\.\d+)(E[\-\+]?\d+)?\Z/i # Initialize the FromString Builder object. # diff --git a/perf/bench.rb b/perf/bench.rb index acba7d222..8bf6d6a2a 100644 --- a/perf/bench.rb +++ b/perf/bench.rb @@ -15,6 +15,7 @@ $:.unshift File.join(File.dirname(__FILE__), "..", "lib") require "benchmark" +require 'bson' def benchmark! count = 1_000_000 diff --git a/release.sh b/release.sh deleted file mode 100755 index 735653c9d..000000000 --- a/release.sh +++ /dev/null @@ -1,67 +0,0 @@ -#!/bin/sh - -set -e - -NAME=bson -RELEASE_NAME=bson-ruby-release -VERSION_REQUIRE=bson/version -VERSION_CONSTANT_NAME=BSON::VERSION -CMD=echo - -if ! test -f gem-private_key.pem; then - echo "gem-private_key.pem missing - cannot release" 1>&2 - exit 1 -fi - -if test -z "$PRODUCTION_RELEASE"; then - echo "PRODUCTION_RELEASE is not set. The script will run in 'dry run'" - echo "mode. The gems will be built, but not actually published. To" - echo "publish the gems, set the PRODUCTION_RELEASE env variable to 1 and" - echo "re-run this script." -else - echo "PRODUCTION_RELEASE is set. Gems will be built and published." - CMD='' -fi - -echo -read -p "-- Press RETURN to continue, or CTRL-C to abort --" - -VERSION=`ruby -Ilib -r$VERSION_REQUIRE -e "puts $VERSION_CONSTANT_NAME"` - -echo "Releasing $NAME $VERSION" -echo - -for variant in mri jruby; do - docker build -f release/$variant/Dockerfile -t $RELEASE_NAME-$variant . - - docker kill $RELEASE_NAME-$variant || true - docker container rm $RELEASE_NAME-$variant || true - - docker run -d --name $RELEASE_NAME-$variant -it $RELEASE_NAME-$variant - - docker exec $RELEASE_NAME-$variant /app/release/$variant/build.sh - - if test $variant = jruby; then - docker cp $RELEASE_NAME-$variant:/app/$NAME-$VERSION-java.gem . - else - docker cp $RELEASE_NAME-$variant:/app/$NAME-$VERSION.gem . - fi - - docker kill $RELEASE_NAME-$variant -done - -echo -echo Built: $NAME-$VERSION.gem -echo Built: $NAME-$VERSION-java.gem -echo - -if test -z "$PRODUCTION_RELEASE"; then - echo "*** SHOWING COMMANDS IN 'DRY RUN' MODE ***" - echo -fi - -$CMD git tag -a v$VERSION -m "Tagging release: $VERSION" -$CMD git push origin v$VERSION - -$CMD gem push $NAME-$VERSION.gem -$CMD gem push $NAME-$VERSION-java.gem diff --git a/release/jruby/Dockerfile b/release/jruby/Dockerfile deleted file mode 100644 index 51c9ccd7b..000000000 --- a/release/jruby/Dockerfile +++ /dev/null @@ -1,18 +0,0 @@ -FROM debian:latest - -ENV DEBIAN_FRONTEND=noninteractive - -# Must use JDK 8 for building release packages to avoid this error: -# java.lang.NoSuchMethodError: java.nio.ByteBuffer.flip()Ljava/nio/ByteBuffer; -# https://github.com/hazelcast/hazelcast/issues/14214 - -RUN apt-get update && \ - apt-get -y install openjdk-17-jdk ruby git curl make g++ - -WORKDIR /rubies -COPY release/jruby/install.sh /rubies/ -RUN /rubies/install.sh - -WORKDIR /app - -COPY . . diff --git a/release/jruby/build.sh b/release/jruby/build.sh deleted file mode 100755 index 43f4df06d..000000000 --- a/release/jruby/build.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/bash - -set -e - -export PATH=/rubies/jruby/bin:$PATH - -gem install bundler --no-document -rm -f *.lock -rm -f *.gem -bundle install --without=test -rake build -/app/release/verify-signature.sh *.gem diff --git a/release/jruby/install.sh b/release/jruby/install.sh deleted file mode 100755 index d8cd2950f..000000000 --- a/release/jruby/install.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/bash - -set -e - -mkdir -p /rubies -cd /rubies - -git clone https://github.com/rbenv/ruby-build.git -PREFIX=/usr ./ruby-build/install.sh - -# JRuby 9.3.9.0 is the most recent version that uses -# JOpenSSL 0.12.2. More recent versions use JOpenSSL 0.14.2, -# which appears to be unable to build signed gems. -# See: https://github.com/jruby/jruby-openssl/issues/292 -ruby-build -v jruby-9.3.9.0 /rubies/jruby diff --git a/release/mri/Dockerfile b/release/mri/Dockerfile deleted file mode 100644 index 6cfee88eb..000000000 --- a/release/mri/Dockerfile +++ /dev/null @@ -1,10 +0,0 @@ -FROM debian:latest - -ENV DEBIAN_FRONTEND=noninteractive - -RUN apt-get update && \ - apt-get -y install git ruby-bundler make gcc ruby-dev - -WORKDIR /app - -COPY . . diff --git a/release/mri/build.sh b/release/mri/build.sh deleted file mode 100755 index 20f8d701b..000000000 --- a/release/mri/build.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash - -set -e - -rm -f *.lock -rm -f *.gem -bundle install --without=test -rake build -/app/release/verify-signature.sh *.gem diff --git a/release/verify-signature.sh b/release/verify-signature.sh deleted file mode 100755 index dbac2100b..000000000 --- a/release/verify-signature.sh +++ /dev/null @@ -1,41 +0,0 @@ -#!/bin/bash - -set -ex - -gem="$1" -if test -z "$gem"; then - echo "Usage: `basename $0` /path/to/built.gem" 1>&2 - exit 1 -fi - -gem cert --add gem-public_cert.pem -gem install -P HighSecurity $gem - -exit - -# The verification below does not work. -# https://github.com/rubygems/rubygems/issues/3680 - -# https://docs.ruby-lang.org/en/2.7.0/Gem/Security.html - -tar xf $gem - -# Grab the public key from the gemspec - -gem spec $gem cert_chain | \ - ruby -ryaml -e 'puts YAML.load(STDIN)' > actual_public_key.crt - -for file in data.tar.gz metadata.tar.gz; do - # Generate a SHA1 hash of the data.tar.gz - - openssl dgst -sha1 < $file > actual.hash - - # Verify the signature - - openssl rsautl -verify -inkey actual_public_key.crt -certin \ - -in $file.sig > signed.hash - - # Compare your hash to the verified hash - - diff -s actual.hash signed.hash -done