diff --git a/Gemfile b/Gemfile index c244f36a..7b70db06 100644 --- a/Gemfile +++ b/Gemfile @@ -14,7 +14,7 @@ group :development do gem "rubocop-performance", "~> 1" gem "rubocop-rspec", "~> 3" gem "rubygems-await", "~> 0.5.4" - gem "sigstore-cli", "~> 0.2.1" + gem "sigstore-cli", git: "https://github.com/sigstore/sigstore-ruby", ref: "ce93acf7fa7e26ba81ff21820848d7df2273a557" gem "simplecov", "~> 0.22" gem "simplecov-erb", "~> 1" gem "vcr", "~> 6.3", ">= 6.3.1" diff --git a/Gemfile.lock b/Gemfile.lock index bef934e0..aeead671 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,3 +1,12 @@ +GIT + remote: https://github.com/sigstore/sigstore-ruby + revision: ce93acf7fa7e26ba81ff21820848d7df2273a557 + ref: ce93acf7fa7e26ba81ff21820848d7df2273a557 + specs: + sigstore-cli (0.2.1) + sigstore (= 0.2.1) + thor + PATH remote: . specs: @@ -189,9 +198,6 @@ GEM net-http protobug_sigstore_protos (~> 0.1.0) uri - sigstore-cli (0.2.1) - sigstore (= 0.2.1) - thor simplecov (0.22.0) docile (~> 1.1) simplecov-html (~> 0.11) @@ -232,7 +238,7 @@ DEPENDENCIES rubocop-performance (~> 1) rubocop-rspec (~> 3) rubygems-await (~> 0.5.4) - sigstore-cli (~> 0.2.1) + sigstore-cli! simplecov (~> 0.22) simplecov-erb (~> 1) vcr (~> 6.3, >= 6.3.1) diff --git a/vendor/cache/sigstore-cli-0.2.1.gem b/vendor/cache/sigstore-cli-0.2.1.gem deleted file mode 100644 index 80849a91..00000000 Binary files a/vendor/cache/sigstore-cli-0.2.1.gem and /dev/null differ diff --git a/vendor/cache/sigstore-ruby-ce93acf7fa7e/.bundlecache b/vendor/cache/sigstore-ruby-ce93acf7fa7e/.bundlecache new file mode 100644 index 00000000..e69de29b diff --git a/vendor/cache/sigstore-ruby-ce93acf7fa7e/.github/dependabot.yml b/vendor/cache/sigstore-ruby-ce93acf7fa7e/.github/dependabot.yml new file mode 100644 index 00000000..608ee2bc --- /dev/null +++ b/vendor/cache/sigstore-ruby-ce93acf7fa7e/.github/dependabot.yml @@ -0,0 +1,29 @@ +version: 2 + +updates: + - package-ecosystem: bundler + directory: / + schedule: + interval: daily + + - package-ecosystem: github-actions + directory: / + schedule: + interval: daily + open-pull-requests-limit: 99 + rebase-strategy: "disabled" + groups: + actions: + patterns: + - "*" + + - package-ecosystem: github-actions + directory: .github/actions/upload-coverage/ + schedule: + interval: daily + open-pull-requests-limit: 99 + rebase-strategy: "disabled" + groups: + actions: + patterns: + - "*" diff --git a/vendor/cache/sigstore-ruby-ce93acf7fa7e/.github/workflows/ci.yml b/vendor/cache/sigstore-ruby-ce93acf7fa7e/.github/workflows/ci.yml new file mode 100644 index 00000000..60b59187 --- /dev/null +++ b/vendor/cache/sigstore-ruby-ce93acf7fa7e/.github/workflows/ci.yml @@ -0,0 +1,265 @@ +name: CI + +on: + push: + branches: + - main + pull_request: + schedule: + - cron: "0 12 * * *" + +permissions: {} + +jobs: + ruby-versions: + uses: ruby/actions/.github/workflows/ruby_versions.yml@3fbf038d6f0d8043b914f923764c61bc2a114a77 + with: + engine: all + min_version: 3.2 + + test: + needs: ruby-versions + runs-on: ${{ matrix.os }} + name: Test Ruby ${{ matrix.ruby }} / ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + ruby: ${{ fromJson(needs.ruby-versions.outputs.versions) }} + os: [ubuntu-latest] + # os: [ ubuntu-latest, macos-latest, windows-latest ] + # include: + # - { os: windows-latest, ruby: ucrt } + # - { os: windows-latest, ruby: mingw } + # - { os: windows-latest, ruby: mswin } + steps: + - name: Harden Runner + uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2 + with: + egress-policy: audit + + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + persist-credentials: false + - name: Set up Ruby + uses: ruby/setup-ruby@a4effe49ee8ee5b8b5091268c473a4628afb5651 # v1.245.0 + with: + ruby-version: ${{ matrix.ruby }} + bundler-cache: true + + - name: Run the tests + run: bin/rake test + + - name: Upload coverage reports to Codecov + uses: codecov/codecov-action@13ce06bfc6bbe3ecf90edbbf1bc32fe5978ca1d3 # v5.3.1 + if: ${{ matrix.ruby }} == ${{ fromJson(needs.ruby-versions.outputs.latest) }} && ${{ matrix.os }} == "ubuntu-latest" && always() + with: + token: ${{ secrets.CODECOV_TOKEN }} + slug: sigstore/sigstore-ruby + + sigstore-conformance: + needs: ruby-versions + runs-on: ${{ matrix.os }} + name: Sigstore Ruby ${{ matrix.ruby }} / ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + ruby: ${{ fromJson(needs.ruby-versions.outputs.versions) }} + os: [ubuntu-latest] + # os: [ ubuntu-latest, macos-latest, windows-latest ] + # include: + # - { os: windows-latest, ruby: ucrt } + # - { os: windows-latest, ruby: mingw } + # - { os: windows-latest, ruby: mswin } + steps: + - name: Harden Runner + uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2 + with: + egress-policy: audit + + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + persist-credentials: false + - name: Set up Ruby + uses: ruby/setup-ruby@a4effe49ee8ee5b8b5091268c473a4628afb5651 # v1.245.0 + with: + ruby-version: ${{ matrix.ruby }} + bundler-cache: true + + - name: Run the conformance tests + uses: sigstore/sigstore-conformance@d658ea74a060aeabae78f8a379167f219dc38c38 # v0.0.16 + with: + entrypoint: ${{ github.workspace }}/bin/conformance-entrypoint + xfail: "${{ matrix.ruby != 'head' && matrix.ruby != '3.4' && 'test_verify_rejects_bad_tsa_timestamp' }}" + if: ${{ matrix.os }} == "ubuntu-latest" + - name: Run the conformance tests against staging + uses: sigstore/sigstore-conformance@d658ea74a060aeabae78f8a379167f219dc38c38 # v0.0.16 + with: + entrypoint: ${{ github.workspace }}/bin/conformance-entrypoint + xfail: "${{ matrix.ruby != 'head' && matrix.ruby != '3.4' && 'test_verify_rejects_bad_tsa_timestamp' }}" + environment: staging + if: ${{ matrix.os }} == "ubuntu-latest" + - name: Upload coverage reports to Codecov + uses: codecov/codecov-action@13ce06bfc6bbe3ecf90edbbf1bc32fe5978ca1d3 # v5.3.1 + if: ${{ matrix.ruby }} == ${{ fromJson(needs.ruby-versions.outputs.latest) }} && ${{ matrix.os }} == "ubuntu-latest" && always() + with: + token: ${{ secrets.CODECOV_TOKEN }} + slug: sigstore/sigstore-ruby + + tuf-conformance: + needs: ruby-versions + runs-on: ${{ matrix.os }} + name: TUF Ruby ${{ matrix.ruby }} / ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + ruby: ${{ fromJson(needs.ruby-versions.outputs.versions) }} + os: [ubuntu-latest] + # os: [ ubuntu-latest, macos-latest, windows-latest ] + # include: + # - { os: windows-latest, ruby: ucrt } + # - { os: windows-latest, ruby: mingw } + # - { os: windows-latest, ruby: mswin } + steps: + - name: Harden Runner + uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2 + with: + egress-policy: audit + + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + persist-credentials: false + - name: Set up Ruby + uses: ruby/setup-ruby@a4effe49ee8ee5b8b5091268c473a4628afb5651 # v1.245.0 + with: + ruby-version: ${{ matrix.ruby }} + bundler-cache: true + + - name: Touch requirements.txt + run: touch requirements.txt + + - name: Write xfails + run: bin/rake bin/tuf-conformance-entrypoint.xfails + + - name: Run the TUF conformance tests + uses: theupdateframework/tuf-conformance@9bfc222a371e30ad5511eb17449f68f855fb9d8f # v2.3.0 + with: + entrypoint: ${{ github.workspace }}/bin/tuf-conformance-entrypoint + artifact-name: "test repositories ${{ matrix.ruby }} ${{ matrix.os }}" + if: | + ${{ matrix.os }} == "ubuntu-latest" + + - name: Upload coverage reports to Codecov + uses: codecov/codecov-action@13ce06bfc6bbe3ecf90edbbf1bc32fe5978ca1d3 # v5.3.1 + if: ${{ matrix.ruby }} == ${{ fromJson(needs.ruby-versions.outputs.latest) }} && ${{ matrix.os }} == "ubuntu-latest" && always() + with: + token: ${{ secrets.CODECOV_TOKEN }} + slug: sigstore/sigstore-ruby + + smoketest: + needs: ruby-versions + runs-on: ubuntu-latest + name: Smoketest + permissions: + id-token: write + strategy: + fail-fast: false + matrix: + ruby: ${{ fromJson(needs.ruby-versions.outputs.versions) }} + os: [ubuntu-latest] + steps: + - name: Harden Runner + uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2 + with: + egress-policy: audit + + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + persist-credentials: false + - name: Set up Ruby + uses: ruby/setup-ruby@a4effe49ee8ee5b8b5091268c473a4628afb5651 # v1.245.0 + with: + ruby-version: ${{ fromJson(needs.ruby-versions.outputs.latest) }} + bundler-cache: true + - name: Build the gem + run: bin/rake build + - name: List built gems + id: list-gems + run: | + echo "gems=$(find pkg -type f -name '*.gem' -print0 | xargs -0 jq --compact-output --null-input --args '[$ARGS.positional[]]')" >> $GITHUB_OUTPUT + - name: Run the smoketest + run: | + ./bin/smoketest ${BUILT_GEMS} + env: + BUILT_GEMS: ${{ join(fromJson(steps.list-gems.outputs.gems), ' ') }} + WORKFLOW_NAME: ci + + all-tests-pass: + if: always() + + needs: + - test + - sigstore-conformance + - tuf-conformance + + runs-on: ubuntu-latest + + steps: + - name: Harden Runner + uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2 + with: + egress-policy: audit + + - name: check test jobs + uses: re-actors/alls-green@05ac9388f0aebcb5727afa17fcccfecd6f8ec5fe # v1.2.2 + with: + jobs: ${{ toJSON(needs) }} + + lint: + needs: ruby-versions + runs-on: ubuntu-latest + name: Lint + steps: + - name: Harden Runner + uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2 + with: + egress-policy: audit + + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + persist-credentials: false + - name: Set up Ruby + uses: ruby/setup-ruby@a4effe49ee8ee5b8b5091268c473a4628afb5651 # v1.245.0 + with: + ruby-version: ${{ fromJson(needs.ruby-versions.outputs.latest) }} + bundler-cache: true + - name: Run the linter + run: bin/rubocop + + zizmor: + name: zizmor + runs-on: ubuntu-latest + permissions: + security-events: write + # required for workflows in private repositories + contents: read + actions: read + steps: + - name: Checkout repository + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + persist-credentials: false + + - name: Install the latest version of uv + uses: astral-sh/setup-uv@180f8b44399608a850e1db031fa65c77746566d3 # v5.0.1 + + - name: Run zizmor 🌈 + run: uvx zizmor --format sarif . > results.sarif + + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Upload SARIF file + uses: github/codeql-action/upload-sarif@9e8d0789d4a0fa9ceb6b1738f7e269594bdd67f0 # v3.28.9 + with: + sarif_file: results.sarif + category: zizmor diff --git a/vendor/cache/sigstore-ruby-ce93acf7fa7e/.github/workflows/codeql.yml b/vendor/cache/sigstore-ruby-ce93acf7fa7e/.github/workflows/codeql.yml new file mode 100644 index 00000000..1ad42ecc --- /dev/null +++ b/vendor/cache/sigstore-ruby-ce93acf7fa7e/.github/workflows/codeql.yml @@ -0,0 +1,80 @@ +# For most projects, this workflow file will not need changing; you simply need +# to commit it to your repository. +# +# You may wish to alter this file to override the set of languages analyzed, +# or to provide custom queries or build logic. +# +# ******** NOTE ******** +# We have attempted to detect the languages in your repository. Please check +# the `language` matrix defined below to confirm you have the correct set of +# supported CodeQL languages. +# +name: "CodeQL" + +on: + push: + branches: ["main"] + pull_request: + # The branches below must be a subset of the branches above + branches: ["main"] + schedule: + - cron: "0 0 * * 1" + +permissions: + contents: read + +jobs: + analyze: + name: Analyze + runs-on: ubuntu-latest + permissions: + actions: read + contents: read + security-events: write + + strategy: + fail-fast: false + matrix: + language: ["ruby"] + # CodeQL supports [ $supported-codeql-languages ] + # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support + + steps: + - name: Harden Runner + uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2 + with: + egress-policy: audit + + - name: Checkout repository + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + persist-credentials: false + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@f6091c0113d1dcf9b98e269ee48e8a7e51b7bdd4 # v3.28.5 + with: + languages: ${{ matrix.language }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + + # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). + # If this step fails, then you should remove it and run the build manually (see below) + - name: Autobuild + uses: github/codeql-action/autobuild@f6091c0113d1dcf9b98e269ee48e8a7e51b7bdd4 # v3.28.5 + + # â„šī¸ Command-line programs to run using the OS shell. + # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun + + # If the Autobuild fails above, remove it and uncomment the following three lines. + # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance. + + # - run: | + # echo "Run, Build Application using script" + # ./location_of_script_within_repo/buildscript.sh + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@f6091c0113d1dcf9b98e269ee48e8a7e51b7bdd4 # v3.28.5 + with: + category: "/language:${{matrix.language}}" diff --git a/vendor/cache/sigstore-ruby-ce93acf7fa7e/.github/workflows/dependency-review.yml b/vendor/cache/sigstore-ruby-ce93acf7fa7e/.github/workflows/dependency-review.yml new file mode 100644 index 00000000..9c9bc9f9 --- /dev/null +++ b/vendor/cache/sigstore-ruby-ce93acf7fa7e/.github/workflows/dependency-review.yml @@ -0,0 +1,29 @@ +# Dependency Review Action +# +# This Action will scan dependency manifest files that change as part of a Pull Request, +# surfacing known-vulnerable versions of the packages declared or updated in the PR. +# Once installed, if the workflow run is marked as required, +# PRs introducing known-vulnerable packages will be blocked from merging. +# +# Source repository: https://github.com/actions/dependency-review-action +name: "Dependency Review" +on: [pull_request] + +permissions: + contents: read + +jobs: + dependency-review: + runs-on: ubuntu-latest + steps: + - name: Harden Runner + uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2 + with: + egress-policy: audit + + - name: "Checkout Repository" + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + persist-credentials: false + - name: "Dependency Review" + uses: actions/dependency-review-action@3b139cfc5fae8b618d3eae3675e383bb1769c019 # v4.5.0 diff --git a/vendor/cache/sigstore-ruby-ce93acf7fa7e/.github/workflows/depsreview.yml b/vendor/cache/sigstore-ruby-ce93acf7fa7e/.github/workflows/depsreview.yml new file mode 100644 index 00000000..54a8a72f --- /dev/null +++ b/vendor/cache/sigstore-ruby-ce93acf7fa7e/.github/workflows/depsreview.yml @@ -0,0 +1,24 @@ +# +# Copyright 2022 The Sigstore Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +name: 'Dependency Review' +on: [pull_request] + +permissions: + contents: read + +jobs: + dependency-review: + name: License and Vulnerability Scan + uses: sigstore/community/.github/workflows/reusable-dependency-review.yml@9b1b5aca605f92ec5b1bf3681b1e61b3dbc420cc diff --git a/vendor/cache/sigstore-ruby-ce93acf7fa7e/.github/workflows/release.yml b/vendor/cache/sigstore-ruby-ce93acf7fa7e/.github/workflows/release.yml new file mode 100644 index 00000000..91389431 --- /dev/null +++ b/vendor/cache/sigstore-ruby-ce93acf7fa7e/.github/workflows/release.yml @@ -0,0 +1,177 @@ +name: Release + +on: + release: + types: + - published + +permissions: + contents: read + +jobs: + build: + name: Build and sign artifacts + runs-on: ubuntu-latest + permissions: + id-token: write + outputs: + hashes: ${{ steps.hash.outputs.hashes }} + built-gems: ${{ steps.list-gems.outputs.gems }} + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + persist-credentials: false + + - uses: ruby/setup-ruby@a4effe49ee8ee5b8b5091268c473a4628afb5651 # v1.245.0 + with: + # NOTE: We intentionally don't use a cache in the release step, + # to reduce the risk of cache poisoning. + ruby-version: "3.3" + bundler-cache: false + + - name: deps + run: bundle install --jobs 4 --retry 3 + + - name: Set source date epoch + run: | + # Set SOURCE_DATE_EPOCH to the commit date of the last commit. + export SOURCE_DATE_EPOCH=$(git log -1 --pretty=%ct) + echo "SOURCE_DATE_EPOCH=$SOURCE_DATE_EPOCH" >> $GITHUB_ENV + + - name: build + run: bin/rake build + + - name: List built gems + id: list-gems + run: | + echo "gems=$(find pkg -type f -name '*.gem' -print0 | xargs -0 jq --compact-output --null-input --args '[$ARGS.positional[]]')" >> $GITHUB_OUTPUT + + - name: Check release and tag name match built version + run: | + for gem in ${BUILT_GEMS}; do + gemspec_version=$(gem spec ${gem} version | ruby -ryaml -e 'puts YAML.safe_load(ARGF.read, permitted_classes: [Gem::Version])') + if [ "${RELEASE_TAG_NAME}" != "v${gemspec_version}" ]; then + echo "Release tag name '${RELEASE_TAG_NAME}' does not match gemspec version 'v${gemspec_version}'" + exit 1 + fi + done + env: + RELEASE_TAG_NAME: ${{ github.event.release.tag_name }} + BUILT_GEMS: ${{ join(fromJson(steps.list-gems.outputs.gems), ' ') }} + + - name: sign + run: | + ./bin/smoketest ${BUILT_GEMS} + env: + BUILT_GEMS: ${{ join(fromJson(steps.list-gems.outputs.gems), ' ') }} + + - name: Generate hashes for provenance + shell: bash + id: hash + working-directory: pkg + run: | + # sha256sum generates sha256 hash for all artifacts. + # base64 -w0 encodes to base64 and outputs on a single line. + # sha256sum artifact1 artifact2 ... | base64 -w0 + echo "hashes=$(sha256sum * | base64 -w0)" >> $GITHUB_OUTPUT + + - name: Save hashes + run: echo "$HASHES" | base64 -d > pkg/sha256sum.txt + env: + HASHES: ${{ steps.hash.outputs.hashes }} + + - name: Upload built packages + uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0 + with: + name: built-packages + path: ./pkg/ + if-no-files-found: warn + + - name: Upload smoketest-artifacts + uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0 + with: + name: smoketest-artifacts + path: smoketest-artifacts/ + if-no-files-found: warn + + generate-provenance: + needs: [build] + name: Generate build provenance + permissions: + actions: read # To read the workflow path. + id-token: write # To sign the provenance. + contents: write # To add assets to a release. + # Currently this action needs to be referred by tag. More details at: + # https://github.com/slsa-framework/slsa-github-generator#verification-of-provenance + uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v2.0.0 + with: + provenance-name: provenance-sigstore-${{ github.event.release.tag_name }}.intoto.jsonl + base64-subjects: "${{ needs.build.outputs.hashes }}" + upload-assets: true + + release-rubygems: + needs: [build, generate-provenance] + runs-on: ubuntu-latest + permissions: + # Used to authenticate to RubyGems.org via OIDC. + id-token: write + strategy: + matrix: + built-gem: ${{ fromJson(needs.build.outputs.built-gems) }} + concurrency: + group: release-rubygems + name: Publish ${{ matrix.built-gem }} to RubyGems + steps: + - name: Download artifacts directories # goes to current working directory + uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 + + - name: Set up Ruby + uses: ruby/setup-ruby@a4effe49ee8ee5b8b5091268c473a4628afb5651 # v1.245.0 + with: + ruby-version: "3.3" + bundler-cache: false + + - name: Clone rubygems HEAD + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + repository: rubygems/rubygems + persist-credentials: false + fetch-depth: 0 + ref: a5412d9a0e358893e20ac69a4c6c0c2bac59d888 + path: rubygems + + - name: Install rubygems HEAD + run: ruby setup.rb + working-directory: rubygems + + - name: Configure RubyGems credentials + uses: rubygems/configure-rubygems-credentials@f456a002d58f0de60b44383d10ae82316b18a166 # main + with: + trusted-publisher: true + + - name: publish + run: | + gem push "built-packages/$(basename $BUILT_GEM)" --attestation "smoketest-artifacts/$(basename $BUILT_GEM).sigstore.json" + env: + BUILT_GEM: ${{ matrix.built-gem }} + + release-github: + needs: [build, generate-provenance] + runs-on: ubuntu-latest + permissions: + # Needed to upload release assets. + contents: write + steps: + - name: Download artifacts directories # goes to current working directory + uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 + + - name: Upload artifacts to github + # Confusingly, this action also supports updating releases, not + # just creating them. This is what we want here, since we've manually + # created the release that triggered the action. + uses: softprops/action-gh-release@c95fe1489396fe8a9eb87c0abf8aa5b2ef267fda # v2.2.1 + with: + # smoketest-artifacts/ contains the signatures and certificates. + files: | + built-packages/* + smoketest-artifacts/* diff --git a/vendor/cache/sigstore-ruby-ce93acf7fa7e/.github/workflows/scorecard.yml b/vendor/cache/sigstore-ruby-ce93acf7fa7e/.github/workflows/scorecard.yml new file mode 100644 index 00000000..96064d58 --- /dev/null +++ b/vendor/cache/sigstore-ruby-ce93acf7fa7e/.github/workflows/scorecard.yml @@ -0,0 +1,81 @@ +# This workflow uses actions that are not certified by GitHub. They are provided +# by a third-party and are governed by separate terms of service, privacy +# policy, and support documentation. + +name: Scorecard supply-chain security +on: + # For Branch-Protection check. Only the default branch is supported. See + # https://github.com/ossf/scorecard/blob/main/docs/checks.md#branch-protection + branch_protection_rule: + # To guarantee Maintained check is occasionally updated. See + # https://github.com/ossf/scorecard/blob/main/docs/checks.md#maintained + schedule: + - cron: "37 2 * * 0" + push: + branches: ["main"] + +# Declare default permissions as read only. +permissions: + contents: read + security-events: read + actions: read + +jobs: + analysis: + name: Scorecard analysis + runs-on: ubuntu-latest + permissions: + # Needed to upload the results to code-scanning dashboard. + security-events: write + # Needed to publish results and get a badge (see publish_results below). + id-token: write + # Uncomment the permissions below if installing in a private repository. + # contents: read + # actions: read + + steps: + - name: Harden Runner + uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2 + with: + egress-policy: audit + + - name: "Checkout code" + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + persist-credentials: false + + - name: "Run analysis" + uses: ossf/scorecard-action@62b2cac7ed8198b15735ed49ab1e5cf35480ba46 # v2.4.0 + with: + results_file: results.sarif + results_format: sarif + # (Optional) "write" PAT token. Uncomment the `repo_token` line below if: + # - you want to enable the Branch-Protection check on a *public* repository, or + # - you are installing Scorecard on a *private* repository + # To create the PAT, follow the steps in https://github.com/ossf/scorecard-action?tab=readme-ov-file#authentication-with-fine-grained-pat-optional. + # repo_token: ${{ secrets.SCORECARD_TOKEN }} + + # Public repositories: + # - Publish results to OpenSSF REST API for easy access by consumers + # - Allows the repository to include the Scorecard badge. + # - See https://github.com/ossf/scorecard-action#publishing-results. + # For private repositories: + # - `publish_results` will always be set to `false`, regardless + # of the value entered here. + publish_results: true + + # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF + # format to the repository Actions tab. + - name: "Upload artifact" + uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0 + with: + name: SARIF file + path: results.sarif + retention-days: 5 + + # Upload the results to GitHub's code scanning dashboard (optional). + # Commenting out will disable upload of results to your repo's Code Scanning dashboard + - name: "Upload to code-scanning" + uses: github/codeql-action/upload-sarif@f6091c0113d1dcf9b98e269ee48e8a7e51b7bdd4 # v3.28.5 + with: + sarif_file: results.sarif diff --git a/vendor/cache/sigstore-ruby-ce93acf7fa7e/.gitignore b/vendor/cache/sigstore-ruby-ce93acf7fa7e/.gitignore new file mode 100644 index 00000000..0c792a19 --- /dev/null +++ b/vendor/cache/sigstore-ruby-ce93acf7fa7e/.gitignore @@ -0,0 +1,9 @@ +/.bundle/ +/.yardoc +/_yardoc/ +/coverage/ +/doc/ +/pkg/ +/spec/reports/ +/tmp/ +/bin/tuf-conformance-entrypoint.xfails diff --git a/vendor/cache/sigstore-ruby-ce93acf7fa7e/.gitleaksignore b/vendor/cache/sigstore-ruby-ce93acf7fa7e/.gitleaksignore new file mode 100644 index 00000000..be5a8576 --- /dev/null +++ b/vendor/cache/sigstore-ruby-ce93acf7fa7e/.gitleaksignore @@ -0,0 +1,21 @@ +fixtures/vcr_cassettes/conformance/verify_bundle_success.yml:generic-api-key:115 +fixtures/vcr_cassettes/production.yml:generic-api-key:115 +fixtures/vcr_cassettes/conformance/verify_bundle_success.yml:generic-api-key:200 +fixtures/vcr_cassettes/production.yml:generic-api-key:200 +fixtures/vcr_cassettes/conformance/verify_signature_invalid.yml:generic-api-key:115 +fixtures/vcr_cassettes/conformance/verify_signature_invalid.yml:generic-api-key:200 +fixtures/vcr_cassettes/conformance/verify_signature_invalid.yml:generic-api-key:320 +fixtures/vcr_cassettes/conformance/verify_signature_invalid.yml:generic-api-key:324 +fixtures/vcr_cassettes/conformance/verify_signature_invalid.yml:generic-api-key:328 +fixtures/vcr_cassettes/conformance/verify_signature_invalid.yml:generic-api-key:332 +fixtures/vcr_cassettes/conformance/verify_signature_invalid.yml:generic-api-key:336 +fixtures/vcr_cassettes/production.yml:generic-api-key:320 +fixtures/vcr_cassettes/production.yml:generic-api-key:324 +fixtures/vcr_cassettes/production.yml:generic-api-key:328 +fixtures/vcr_cassettes/production.yml:generic-api-key:332 +fixtures/vcr_cassettes/production.yml:generic-api-key:336 +fixtures/vcr_cassettes/conformance/verify_bundle_success.yml:generic-api-key:320 +fixtures/vcr_cassettes/conformance/verify_bundle_success.yml:generic-api-key:324 +fixtures/vcr_cassettes/conformance/verify_bundle_success.yml:generic-api-key:328 +fixtures/vcr_cassettes/conformance/verify_bundle_success.yml:generic-api-key:332 +fixtures/vcr_cassettes/conformance/verify_bundle_success.yml:generic-api-key:336 diff --git a/vendor/cache/sigstore-ruby-ce93acf7fa7e/.pre-commit-config.yaml b/vendor/cache/sigstore-ruby-ce93acf7fa7e/.pre-commit-config.yaml new file mode 100644 index 00000000..a5dc7fd0 --- /dev/null +++ b/vendor/cache/sigstore-ruby-ce93acf7fa7e/.pre-commit-config.yaml @@ -0,0 +1,17 @@ +repos: + - repo: https://github.com/gitleaks/gitleaks + rev: v8.18.4 + hooks: + - id: gitleaks + - repo: https://github.com/jumanjihouse/pre-commit-hooks + rev: 3.0.0 + hooks: + - id: bundler-audit + - id: rubocop + - id: shellcheck + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.6.0 + hooks: + - id: end-of-file-fixer + - id: trailing-whitespace +exclude: ^(data/|test/sigstore/data/) diff --git a/vendor/cache/sigstore-ruby-ce93acf7fa7e/.rubocop.yml b/vendor/cache/sigstore-ruby-ce93acf7fa7e/.rubocop.yml new file mode 100644 index 00000000..e10e5c23 --- /dev/null +++ b/vendor/cache/sigstore-ruby-ce93acf7fa7e/.rubocop.yml @@ -0,0 +1,37 @@ +AllCops: + TargetRubyVersion: 3.2 + NewCops: enable + Exclude: + - "test/sigstore-conformance/**/*" + - "test/tuf-conformance/**/*" + - "node_modules/**/*" + - "tmp/**/*" + - "vendor/**/*" + - ".git/**/*" + +require: + - rubocop-performance + - rubocop-rake + +Style/StringLiterals: + Enabled: true + EnforcedStyle: double_quotes + +Style/StringLiteralsInInterpolation: + Enabled: true + EnforcedStyle: double_quotes + +Layout/LineLength: + Max: 120 + +Metrics: + Enabled: false + +Style/Documentation: + Enabled: false + +Style/ClassAndModuleChildren: + Enabled: false + +Style/ImplicitRuntimeError: + Enabled: true diff --git a/vendor/cache/sigstore-ruby-ce93acf7fa7e/.ruby-version b/vendor/cache/sigstore-ruby-ce93acf7fa7e/.ruby-version new file mode 100644 index 00000000..4d9d11cf --- /dev/null +++ b/vendor/cache/sigstore-ruby-ce93acf7fa7e/.ruby-version @@ -0,0 +1 @@ +3.4.2 diff --git a/vendor/cache/sigstore-ruby-ce93acf7fa7e/.simplecov b/vendor/cache/sigstore-ruby-ce93acf7fa7e/.simplecov new file mode 100644 index 00000000..475dfeb6 --- /dev/null +++ b/vendor/cache/sigstore-ruby-ce93acf7fa7e/.simplecov @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +SimpleCov.root(__dir__) + +if ENV["COVERAGE"] + SimpleCov.start do + enable_coverage :branch unless RUBY_ENGINE == "truffleruby" + end +end diff --git a/vendor/cache/sigstore-ruby-ce93acf7fa7e/CHANGELOG.md b/vendor/cache/sigstore-ruby-ce93acf7fa7e/CHANGELOG.md new file mode 100644 index 00000000..81463de5 --- /dev/null +++ b/vendor/cache/sigstore-ruby-ce93acf7fa7e/CHANGELOG.md @@ -0,0 +1,7 @@ +## [0.1.1] - 2024-10-18 + +- Fix release automation + +## [0.1.0] - 2024-10-18 + +- Initial release diff --git a/vendor/cache/sigstore-ruby-ce93acf7fa7e/CODEOWNERS b/vendor/cache/sigstore-ruby-ce93acf7fa7e/CODEOWNERS new file mode 100644 index 00000000..a629f750 --- /dev/null +++ b/vendor/cache/sigstore-ruby-ce93acf7fa7e/CODEOWNERS @@ -0,0 +1,6 @@ +@sigstore/codeowners-sigstore-ruby + +# The CODEOWNERS are managed via a GitHub team, but the current list is (in alphabetical order): + +# segiddins +# woodruffw diff --git a/vendor/cache/sigstore-ruby-ce93acf7fa7e/Gemfile b/vendor/cache/sigstore-ruby-ce93acf7fa7e/Gemfile new file mode 100644 index 00000000..02fab6f8 --- /dev/null +++ b/vendor/cache/sigstore-ruby-ce93acf7fa7e/Gemfile @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +source "https://rubygems.org" + +# Specify your gem's dependencies in sigstore.gemspec +gemspec +gemspec path: "cli" + +gem "cgi", "~> 0.5.0" # Used by webmock +gem "rake", "~> 13.2" +gem "rubocop", "~> 1.67" +gem "rubocop-performance", "~> 1.23" +gem "rubocop-rake", "~> 0.6.0" +gem "simplecov", "~> 0.22.0" +gem "test-unit", "~> 3.7" +gem "thor", "~> 1.3" +gem "timecop", "~> 0.9.10" +gem "vcr", "~> 6.3" +gem "webmock", "~> 3.25" diff --git a/vendor/cache/sigstore-ruby-ce93acf7fa7e/Gemfile.lock b/vendor/cache/sigstore-ruby-ce93acf7fa7e/Gemfile.lock new file mode 100644 index 00000000..442662a9 --- /dev/null +++ b/vendor/cache/sigstore-ruby-ce93acf7fa7e/Gemfile.lock @@ -0,0 +1,172 @@ +PATH + remote: . + specs: + sigstore (0.2.1) + logger + net-http + protobug_sigstore_protos (~> 0.1.0) + uri + +PATH + remote: cli + specs: + sigstore-cli (0.2.1) + sigstore (= 0.2.1) + thor + +GEM + remote: https://rubygems.org/ + specs: + addressable (2.8.7) + public_suffix (>= 2.0.2, < 7.0) + ast (2.4.2) + base64 (0.3.0) + bigdecimal (3.1.9) + bigdecimal (3.1.9-java) + cgi (0.5.0) + cgi (0.5.0-java) + crack (1.0.0) + bigdecimal + rexml + docile (1.4.0) + hashdiff (1.1.2) + json (2.10.2) + json (2.10.2-java) + language_server-protocol (3.17.0.4) + logger (1.6.6) + net-http (0.6.0) + uri + parallel (1.26.3) + parser (3.3.7.1) + ast (~> 2.4.1) + racc + power_assert (2.0.5) + protobug (0.1.0) + protobug_googleapis_field_behavior_protos (0.1.0) + protobug (= 0.1.0) + protobug_well_known_protos (= 0.1.0) + protobug_sigstore_protos (0.1.0) + protobug (= 0.1.0) + protobug_googleapis_field_behavior_protos (= 0.1.0) + protobug_well_known_protos (= 0.1.0) + protobug_well_known_protos (0.1.0) + protobug (= 0.1.0) + public_suffix (6.0.1) + racc (1.8.1) + racc (1.8.1-java) + rainbow (3.1.1) + rake (13.2.1) + regexp_parser (2.10.0) + rexml (3.4.2) + rubocop (1.67.0) + json (~> 2.3) + language_server-protocol (>= 3.17.0) + parallel (~> 1.10) + parser (>= 3.3.0.2) + rainbow (>= 2.2.2, < 4.0) + regexp_parser (>= 2.4, < 3.0) + rubocop-ast (>= 1.32.2, < 2.0) + ruby-progressbar (~> 1.7) + unicode-display_width (>= 2.4.0, < 3.0) + rubocop-ast (1.38.0) + parser (>= 3.3.1.0) + rubocop-performance (1.23.1) + rubocop (>= 1.48.1, < 2.0) + rubocop-ast (>= 1.31.1, < 2.0) + rubocop-rake (0.6.0) + rubocop (~> 1.0) + ruby-progressbar (1.13.0) + simplecov (0.22.0) + docile (~> 1.1) + simplecov-html (~> 0.11) + simplecov_json_formatter (~> 0.1) + simplecov-html (0.12.3) + simplecov_json_formatter (0.1.4) + test-unit (3.7.0) + power_assert + thor (1.3.2) + timecop (0.9.10) + unicode-display_width (2.6.0) + uri (1.0.3) + vcr (6.3.1) + base64 + webmock (3.25.1) + addressable (>= 2.8.0) + crack (>= 0.3.2) + hashdiff (>= 0.4.0, < 2.0.0) + +PLATFORMS + arm64-darwin + arm64-linux + java + ruby + universal-java-1.8 + universal-java-19 + universal-java-24 + x86_64-linux + +DEPENDENCIES + cgi (~> 0.5.0) + rake (~> 13.2) + rubocop (~> 1.67) + rubocop-performance (~> 1.23) + rubocop-rake (~> 0.6.0) + sigstore! + sigstore-cli! + simplecov (~> 0.22.0) + test-unit (~> 3.7) + thor (~> 1.3) + timecop (~> 0.9.10) + vcr (~> 6.3) + webmock (~> 3.25) + +CHECKSUMS + addressable (2.8.7) sha256=462986537cf3735ab5f3c0f557f14155d778f4b43ea4f485a9deb9c8f7c58232 + ast (2.4.2) sha256=1e280232e6a33754cde542bc5ef85520b74db2aac73ec14acef453784447cc12 + base64 (0.3.0) sha256=27337aeabad6ffae05c265c450490628ef3ebd4b67be58257393227588f5a97b + bigdecimal (3.1.9) sha256=2ffc742031521ad69c2dfc815a98e426a230a3d22aeac1995826a75dabfad8cc + bigdecimal (3.1.9-java) sha256=dd9b8f7c870664cd9538a1325ce385ba57a6627969177258c4f0e661a7be4456 + cgi (0.5.0) sha256=fe99f65bb2c146e294372ebb27602adbc3b4c008e9ea7038c6bd48c1ec9759da + cgi (0.5.0-java) sha256=e39b3e7d74961e5474bb18d9bbfd7308f01cc7e9f1cfe7f379281c5d0c26f90d + crack (1.0.0) sha256=c83aefdb428cdc7b66c7f287e488c796f055c0839e6e545fec2c7047743c4a49 + docile (1.4.0) sha256=5f1734bde23721245c20c3d723e76c104208e1aa01277a69901ce770f0ebb8d3 + hashdiff (1.1.2) sha256=2c30eeded6ed3dce8401d2b5b99e6963fe5f14ed85e60dd9e33c545a44b71a77 + json (2.10.2) sha256=34e0eada93022b2a0a3345bb0b5efddb6e9ff5be7c48e409cfb54ff8a36a8b06 + json (2.10.2-java) sha256=fe31faac61ea21ea1448c35450183f84e85c2b94cc6522c241959ba9d1362006 + language_server-protocol (3.17.0.4) sha256=c484626478664fd13482d8180947c50a8590484b1258b99b7aedb3b69df89669 + logger (1.6.6) sha256=dd618d24e637715472732e7eed02e33cfbdf56deaad225edd0f1f89d38024017 + net-http (0.6.0) sha256=9621b20c137898af9d890556848c93603716cab516dc2c89b01a38b894e259fb + parallel (1.26.3) sha256=d86babb7a2b814be9f4b81587bf0b6ce2da7d45969fab24d8ae4bf2bb4d4c7ef + parser (3.3.7.1) sha256=7dbe61618025519024ac72402a6677ead02099587a5538e84371b76659e6aca1 + power_assert (2.0.5) sha256=63b511b85bb8ea57336d25156864498644f5bbf028699ceda27949e0125bc323 + protobug (0.1.0) sha256=5bf1356cedf99dcf311890743b78f5e602f62ca703e574764337f1996b746bf2 + protobug_googleapis_field_behavior_protos (0.1.0) sha256=db48ef6a5913b2355b4a6931ab400a9e3e995fb48499977a3ad0be6365f9e265 + protobug_sigstore_protos (0.1.0) sha256=4ad1eebaf6454131b6f432dda50ad0e513773613474b92470847614a5acacce1 + protobug_well_known_protos (0.1.0) sha256=356757f562453bb34a28f12e8e9fa357346cca35a6807a549837c3fe256bb5b3 + public_suffix (6.0.1) sha256=61d44e1cab5cbbbe5b31068481cf16976dd0dc1b6b07bd95617ef8c5e3e00c6f + racc (1.8.1) sha256=4a7f6929691dbec8b5209a0b373bc2614882b55fc5d2e447a21aaa691303d62f + racc (1.8.1-java) sha256=54f2e6d1e1b91c154013277d986f52a90e5ececbe91465d29172e49342732b98 + rainbow (3.1.1) sha256=039491aa3a89f42efa1d6dec2fc4e62ede96eb6acd95e52f1ad581182b79bc6a + rake (13.2.1) sha256=46cb38dae65d7d74b6020a4ac9d48afed8eb8149c040eccf0523bec91907059d + regexp_parser (2.10.0) sha256=cb6f0ddde88772cd64bff1dbbf68df66d376043fe2e66a9ef77fcb1b0c548c61 + rexml (3.4.2) sha256=1384268554a37af5da5279431ca3f2f37d46f09ffdd6c95e17cc84c83ea7c417 + rubocop (1.67.0) sha256=8ccca7226e76d0a9974af960ea446d1fb38adf0c491214294e2fed75a85c378c + rubocop-ast (1.38.0) sha256=4fdf6792fe443a9a18acb12dbc8225d0d64cd1654e41fedb30e79c18edbb26ae + rubocop-performance (1.23.1) sha256=f22f86a795f5e6a6180aac2c6fc172534b173a068d6ed3396d6460523e051b82 + rubocop-rake (0.6.0) sha256=56b6f22189af4b33d4f4e490a555c09f1281b02f4d48c3a61f6e8fe5f401d8db + ruby-progressbar (1.13.0) sha256=80fc9c47a9b640d6834e0dc7b3c94c9df37f08cb072b7761e4a71e22cff29b33 + sigstore (0.2.1) + sigstore-cli (0.2.1) + simplecov (0.22.0) sha256=fe2622c7834ff23b98066bb0a854284b2729a569ac659f82621fc22ef36213a5 + simplecov-html (0.12.3) sha256=4b1aad33259ffba8b29c6876c12db70e5750cb9df829486e4c6e5da4fa0aa07b + simplecov_json_formatter (0.1.4) sha256=529418fbe8de1713ac2b2d612aa3daa56d316975d307244399fa4838c601b428 + test-unit (3.7.0) sha256=2b5745498c848768e1774acb63e3806d3bb47e2943bd91cc9bf559b4c6d4faa1 + thor (1.3.2) sha256=eef0293b9e24158ccad7ab383ae83534b7ad4ed99c09f96f1a6b036550abbeda + timecop (0.9.10) sha256=12ba45ce57cdcf6b1043cb6cdffa6381fd89ce10d369c28a7f6f04dc1b0cd8eb + unicode-display_width (2.6.0) sha256=12279874bba6d5e4d2728cef814b19197dbb10d7a7837a869bab65da943b7f5a + uri (1.0.3) sha256=e9f2244608eea2f7bc357d954c65c910ce0399ca5e18a7a29207ac22d8767011 + vcr (6.3.1) sha256=37b56e157e720446a3f4d2d39919cabef8cb7b6c45936acffd2ef8229fec03ed + webmock (3.25.1) sha256=ab9d5d9353bcbe6322c83e1c60a7103988efc7b67cd72ffb9012629c3d396323 + +BUNDLED WITH + 2.6.9 diff --git a/vendor/cache/sigstore-ruby-ce93acf7fa7e/LICENSE b/vendor/cache/sigstore-ruby-ce93acf7fa7e/LICENSE new file mode 100644 index 00000000..a72c7b13 --- /dev/null +++ b/vendor/cache/sigstore-ruby-ce93acf7fa7e/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright 2024 The Sigstore Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/vendor/cache/sigstore-ruby-ce93acf7fa7e/README.md b/vendor/cache/sigstore-ruby-ce93acf7fa7e/README.md new file mode 100644 index 00000000..b1058dfd --- /dev/null +++ b/vendor/cache/sigstore-ruby-ce93acf7fa7e/README.md @@ -0,0 +1,26 @@ +# Sigstore + +This is a pure Ruby implementation of the `sigstore verify` command from the [sigstore/cosign](https://sigstore.dev/projects/cosign) project. It is intended to be used as a library in other Ruby projects, in additional to a `gem` subcommand. The project also contains a TUF client implementation, given TUF is a part of the sigstore verification flow. + +## Usage + +```shell +$ gem sigstore_cosign_verify_bundle --bundle a.txt.sigstore \ + --certificate-identity https://github.com/sigstore-conformance/extremely-dangerous-public-oidc-beacon/.github/workflows/extremely-dangerous-oidc-beacon.yml@refs/heads/main \ + --certificate-oidc-issuer https://token.actions.githubusercontent.com \ + a.txt +``` + +## Development + +After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test-unit` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment. + +To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org). + +## Contributing + +Bug reports and pull requests are welcome on GitHub at . + +## License + +The gem is available as open source under the terms of the [Apache 2](https://opensource.org/licenses/Apache-2.0). diff --git a/vendor/cache/sigstore-ruby-ce93acf7fa7e/Rakefile b/vendor/cache/sigstore-ruby-ce93acf7fa7e/Rakefile new file mode 100644 index 00000000..7cfa53fd --- /dev/null +++ b/vendor/cache/sigstore-ruby-ce93acf7fa7e/Rakefile @@ -0,0 +1,186 @@ +# frozen_string_literal: true + +require "bundler/gem_tasks" +require "rake/testtask" + +directory "pkg" +namespace "cli" do + Bundler::GemHelper.install_tasks(dir: "cli") + task build: "pkg" do # rubocop:disable Rake/Desc + FileUtils.cp_r FileList["cli/pkg/*"], "pkg" + end +end +task "build" => "cli:build" # rubocop:disable Rake/Desc + +Rake::TestTask.new(:test) do |t| + t.libs << "test" + t.test_files = FileList["test/**/*_test.rb"] +end + +require "rubocop/rake_task" + +RuboCop::RakeTask.new + +task default: %i[test conformance_staging conformance conformance_tuf rubocop] + +require "openssl" +# Checks for https://github.com/ruby/openssl/pull/770 +xfail = OpenSSL::X509::Store.new.instance_variable_defined?(:@time) ? "test_verify_rejects_bad_tsa_timestamp" : "" + +desc "Run the conformance tests" +task conformance: %w[conformance:setup] do + sh({ "GHA_SIGSTORE_CONFORMANCE_XFAIL" => xfail }, + File.expand_path("test/sigstore-conformance/env/bin/pytest"), "test", + "--entrypoint=#{File.join(__dir__, "bin", "conformance-entrypoint")}", + chdir: "test/sigstore-conformance") +end + +desc "Run the conformance tests against staging" +task conformance_staging: %w[conformance:setup] do + sh({ "GHA_SIGSTORE_CONFORMANCE_XFAIL" => xfail }, + File.expand_path("test/sigstore-conformance/env/bin/pytest"), "test", + "--entrypoint=#{File.join(__dir__, "bin", "conformance-entrypoint")}", + "--staging", + chdir: "test/sigstore-conformance") +end + +desc "Run the TUF conformance tests" +task conformance_tuf: %w[tuf_conformance:setup] do + sh("env/bin/pytest", "tuf_conformance", "--entrypoint", File.expand_path("bin/tuf-conformance-entrypoint"), + chdir: "test/tuf-conformance") +end + +namespace :conformance do + file "test/sigstore-conformance/env/pyvenv.cfg" => :sigstore_conformance do + sh "make", "dev", chdir: "test/sigstore-conformance" + end + task setup: "test/sigstore-conformance/env/pyvenv.cfg" # rubocop:disable Rake/Desc +end + +task :find_action_versions do # rubocop:disable Rake/Desc + require "yaml" + gh = YAML.load_file(".github/workflows/ci.yml") + actions = gh.fetch("jobs").flat_map { |_, job| job.fetch("steps", []).filter_map { |step| step.fetch("uses", nil) } } + .uniq.map { |x| x.split("@", 2) } + .group_by(&:first).transform_values { |v| v.map(&:last) } + if actions.any? { |_, v| v.size > 1 } + raise StandardError, "conflicts: #{actions.select { |_, v| v.size > 1 }.inspect}" + end + + @action_versions = actions.transform_values(&:first) +end + +task test: %w[sigstore_conformance] + +desc "Update the vendored data files" +task :update_data do + require "sigstore" + require "sigstore/trusted_root" + { + prod: Sigstore::TUF::DEFAULT_TUF_URL, + staging: Sigstore::TUF::STAGING_TUF_URL + }.each do |name, url| + Dir.mktmpdir do |dir| + updater = Sigstore::TUF::TrustUpdater.new(url, false, metadata_dir: dir, targets_dir: dir).updater + updater.refresh + updater.download_target(updater.get_targetinfo("trusted_root.json")) + cp File.join(dir, "trusted_root.json"), "data/_store/#{name}/trusted_root.json" + cp File.join(dir, "root.json"), "data/_store/#{name}/root.json" + end + end +end + +require "open3" + +class GitRepo < Rake::Task + attr_accessor :path, :url + attr_writer :commit + + include FileUtils + + def initialize(*) + super + + @actions << method(:clone_repo) + @actions << method(:checkout) + end + + def needed? + !correct_remote? || !correct_commit? + end + + def correct_remote? + return false unless File.directory?(@path) + + out, status = Open3.capture2(*%w[git remote get-url origin], chdir: path) + status.success? && out.strip == url + end + + def correct_commit? + head, status = Open3.capture2(*%w[git rev-parse HEAD], chdir: path) + head.strip! + return true if status.success? && head == commit + + desired, status = Open3.capture2(*%w[git rev-parse], "#{commit}^{commit}", "--", chdir: path) + desired.strip! + status.success? && desired == head + end + + def clone_repo(_, _) + return if correct_remote? + + rm_rf path + sh "git", "clone", url, path + end + + def checkout(_, _) + return if correct_commit? + + sh "git", "-C", path, "switch", "--detach", commit do |ok, _| + unless ok + sh "git", "-C", path, "fetch", "origin", "#{commit}:#{commit}" + sh "git", "-C", path, "switch", "--detach", commit + end + end + end + + def commit + case @commit + when String + @commit + when ->(c) { c.respond_to?(:call) } + @commit.call + else + raise StandardError, "unexpected commit type: #{@commit.inspect}" + end + end +end + +GitRepo.define_task(sigstore_conformance: %w[find_action_versions]).tap do |task| + task.path = "test/sigstore-conformance" + task.url = "https://github.com/sigstore/sigstore-conformance.git" + task.commit = -> { @action_versions.fetch("sigstore/sigstore-conformance") } +end + +GitRepo.define_task(tuf_conformance: %w[find_action_versions]).tap do |task| + task.path = "test/tuf-conformance" + task.url = "https://github.com/theupdateframework/tuf-conformance.git" + task.commit = -> { @action_versions.fetch("theupdateframework/tuf-conformance") } +end + +namespace :tuf_conformance do + file "bin/tuf-conformance-entrypoint.xfails" do |t| + if RUBY_ENGINE == "jruby" + File.write(t.name, <<~TXT) + test_keytype_and_scheme[rsa/rsassa-pss-sha256] + test_keytype_and_scheme[ed25519/ed25519] + TXT + else + File.write(t.name, "") + end + end + file "test/tuf-conformance/env/pyvenv.cfg" => :tuf_conformance do + sh "make", "dev", chdir: "test/tuf-conformance" + end + task setup: %w[test/tuf-conformance/env/pyvenv.cfg bin/tuf-conformance-entrypoint.xfails] +end diff --git a/vendor/cache/sigstore-ruby-ce93acf7fa7e/bin/conformance-entrypoint b/vendor/cache/sigstore-ruby-ce93acf7fa7e/bin/conformance-entrypoint new file mode 100755 index 00000000..fb94aa9b --- /dev/null +++ b/vendor/cache/sigstore-ruby-ce93acf7fa7e/bin/conformance-entrypoint @@ -0,0 +1,27 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +ENV["BUNDLE_GEMFILE"] = File.expand_path("../Gemfile", __dir__) +require "bundler/setup" + +require "tmpdir" + +tmp = Dir.mktmpdir + +require "simplecov" +SimpleCov.command_name "conformance:#{Digest::SHA256.hexdigest ARGV.join(" ")}" +load File.expand_path("../.simplecov", __dir__) +SimpleCov::Formatter::HTMLFormatter.module_eval do + def puts(...) + # Suppress output + end +end + +ENV.update( + "HOME" => tmp, + "XDG_DATA_HOME" => nil, + "XDG_CACHE_HOME" => nil +) + +require "sigstore/cli" +Sigstore::CLI.start(ARGV << "--no-update-trusted-root") diff --git a/vendor/cache/sigstore-ruby-ce93acf7fa7e/bin/console b/vendor/cache/sigstore-ruby-ce93acf7fa7e/bin/console new file mode 100755 index 00000000..f50c2aa1 --- /dev/null +++ b/vendor/cache/sigstore-ruby-ce93acf7fa7e/bin/console @@ -0,0 +1,11 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +require "bundler/setup" +require "sigstore" + +# You can add fixtures and/or initialization code here to make experimenting +# with your gem easier. You can also use a different console, if you like. + +require "irb" +IRB.start(__FILE__) diff --git a/vendor/cache/sigstore-ruby-ce93acf7fa7e/bin/rake b/vendor/cache/sigstore-ruby-ce93acf7fa7e/bin/rake new file mode 100755 index 00000000..4eb7d7bf --- /dev/null +++ b/vendor/cache/sigstore-ruby-ce93acf7fa7e/bin/rake @@ -0,0 +1,27 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +# +# This file was generated by Bundler. +# +# The application 'rake' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) + +bundle_binstub = File.expand_path("bundle", __dir__) + +if File.file?(bundle_binstub) + if File.read(bundle_binstub, 300).include?("This file was generated by Bundler") + load(bundle_binstub) + else + abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. +Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") + end +end + +require "rubygems" +require "bundler/setup" + +load Gem.bin_path("rake", "rake") diff --git a/vendor/cache/sigstore-ruby-ce93acf7fa7e/bin/rubocop b/vendor/cache/sigstore-ruby-ce93acf7fa7e/bin/rubocop new file mode 100755 index 00000000..369a05be --- /dev/null +++ b/vendor/cache/sigstore-ruby-ce93acf7fa7e/bin/rubocop @@ -0,0 +1,27 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +# +# This file was generated by Bundler. +# +# The application 'rubocop' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) + +bundle_binstub = File.expand_path("bundle", __dir__) + +if File.file?(bundle_binstub) + if File.read(bundle_binstub, 300).include?("This file was generated by Bundler") + load(bundle_binstub) + else + abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. +Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") + end +end + +require "rubygems" +require "bundler/setup" + +load Gem.bin_path("rubocop", "rubocop") diff --git a/vendor/cache/sigstore-ruby-ce93acf7fa7e/bin/setup b/vendor/cache/sigstore-ruby-ce93acf7fa7e/bin/setup new file mode 100755 index 00000000..dce67d86 --- /dev/null +++ b/vendor/cache/sigstore-ruby-ce93acf7fa7e/bin/setup @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -euo pipefail +IFS=$'\n\t' +set -vx + +bundle install + +# Do any other automated setup that you need to do here diff --git a/vendor/cache/sigstore-ruby-ce93acf7fa7e/bin/sigstore-cli b/vendor/cache/sigstore-ruby-ce93acf7fa7e/bin/sigstore-cli new file mode 100755 index 00000000..9d1bef7c --- /dev/null +++ b/vendor/cache/sigstore-ruby-ce93acf7fa7e/bin/sigstore-cli @@ -0,0 +1,27 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +# +# This file was generated by Bundler. +# +# The application 'sigstore-cli' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) + +bundle_binstub = File.expand_path("bundle", __dir__) + +if File.file?(bundle_binstub) + if File.read(bundle_binstub, 300).include?("This file was generated by Bundler") + load(bundle_binstub) + else + abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. +Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") + end +end + +require "rubygems" +require "bundler/setup" + +load Gem.bin_path("sigstore-cli", "sigstore-cli") diff --git a/vendor/cache/sigstore-ruby-ce93acf7fa7e/bin/smoketest b/vendor/cache/sigstore-ruby-ce93acf7fa7e/bin/smoketest new file mode 100755 index 00000000..e6aefea3 --- /dev/null +++ b/vendor/cache/sigstore-ruby-ce93acf7fa7e/bin/smoketest @@ -0,0 +1,57 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +require "fileutils" +require "rake" +require "net/http" +require "json" + +include FileUtils # rubocop:disable Style/MixinUsage + +raise(StandardError, "Usage: #{$PROGRAM_NAME} ") if ARGV.empty? + +dists = ARGV +mkdir_p %w[smoketest-gem-home smoketest-artifacts] + +at_exit { rm_rf "smoketest-gem-home" } + +env = { + "PATH" => "smoketest-gem-home/bin:#{ENV.fetch("PATH")}", + "GEM_HOME" => "smoketest-gem-home", + "GEM_PATH" => "smoketest-gem-home", + "BUNDLE_GEMFILE" => "smoketest-gem-home/Gemfile" +} + +cert_identity = "#{ENV.fetch("GITHUB_SERVER_URL")}/#{ENV.fetch("GITHUB_REPOSITORY")}" \ + "/.github/workflows/#{ENV.fetch("WORKFLOW_NAME", "release")}.yml@#{ENV.fetch("GITHUB_REF")}" + +sh(env, "gem", "install", *dists, "--no-document", exception: true) + +File.write("smoketest-gem-home/Gemfile", <<~RUBY) + gem "sigstore-cli" +RUBY + +dists.each do |dist| + sh(env, File.expand_path("sigstore-cli", __dir__), + "sign", dist, + "--signature=smoketest-artifacts/#{File.basename(dist)}.sig", + "--certificate=smoketest-artifacts/#{File.basename(dist)}.crt", + "--bundle=smoketest-artifacts/#{File.basename(dist)}.sigstore.json", + exception: true) + + sh(env, File.expand_path("sigstore-cli", __dir__), + "verify", + "--signature=smoketest-artifacts/#{File.basename(dist)}.sig", + "--certificate=smoketest-artifacts/#{File.basename(dist)}.crt", + "--certificate-oidc-issuer=https://token.actions.githubusercontent.com", + "--certificate-identity=#{cert_identity}", + dist, + exception: true) + sh(env, File.expand_path("sigstore-cli", __dir__), + "verify", + "--bundle=smoketest-artifacts/#{File.basename(dist)}.sigstore.json", + "--certificate-oidc-issuer=https://token.actions.githubusercontent.com", + "--certificate-identity=#{cert_identity}", + dist, + exception: true) +end diff --git a/vendor/cache/sigstore-ruby-ce93acf7fa7e/bin/tuf-conformance-entrypoint b/vendor/cache/sigstore-ruby-ce93acf7fa7e/bin/tuf-conformance-entrypoint new file mode 100755 index 00000000..45a0d2da --- /dev/null +++ b/vendor/cache/sigstore-ruby-ce93acf7fa7e/bin/tuf-conformance-entrypoint @@ -0,0 +1,57 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +ENV["BUNDLE_GEMFILE"] = File.expand_path("../Gemfile", __dir__) +require "bundler/setup" + +require "optparse" + +args = [] +tmp = nil +OptionParser.new do |parser| + parser.on("--metadata-url U") do |v| + args << "--metadata-url" << v + end + parser.on("--metadata-dir D") do |v| + tmp = v + args << "--metadata-dir" << v + end + parser.on("--targets-dir D") do |v| + args << "--targets-dir" << v + end + parser.on("--cached") do |_v| + args << "--cached" + end + parser.on("--target-base-url U") do |v| + args << "--target-base-url" << v + end + parser.on("--target-name N") do |v| + args << v + end +end.parse! + +require "simplecov" +SimpleCov.command_name "tuf-conformance:#{Digest::SHA256.hexdigest ARGV.map { |a| + a.sub(tmp, "$TMPDIR") +}.join(" ")}" +load File.expand_path("../.simplecov", __dir__) +SimpleCov::Formatter::HTMLFormatter.module_eval do + def puts(...) + # Suppress output + end +end + +ARGV.prepend("tuf") +ARGV[2, 0] = args + +if ENV.fetch("FAKETIME", nil) && + !ENV["DYLD_INSERT_LIBRARIES"].to_s.include?("libfaketime") && !ENV["LD_PRELOAD"].to_s.include?("libfaketime") + Time.singleton_class.prepend(Module.new do + def now + super + ENV["FAKETIME"].to_f + end + end) +end + +require "sigstore/cli" +Sigstore::CLI.start(ARGV) diff --git a/vendor/cache/sigstore-ruby-ce93acf7fa7e/cli/.gitignore b/vendor/cache/sigstore-ruby-ce93acf7fa7e/cli/.gitignore new file mode 100644 index 00000000..e7c57088 --- /dev/null +++ b/vendor/cache/sigstore-ruby-ce93acf7fa7e/cli/.gitignore @@ -0,0 +1,2 @@ +pkg/ +*.gem diff --git a/vendor/cache/sigstore-ruby-ce93acf7fa7e/cli/exe/sigstore-cli b/vendor/cache/sigstore-ruby-ce93acf7fa7e/cli/exe/sigstore-cli new file mode 100755 index 00000000..ceb5964f --- /dev/null +++ b/vendor/cache/sigstore-ruby-ce93acf7fa7e/cli/exe/sigstore-cli @@ -0,0 +1,5 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +require "sigstore/cli" +Sigstore::CLI.start diff --git a/vendor/cache/sigstore-ruby-ce93acf7fa7e/cli/lib/sigstore/cli.rb b/vendor/cache/sigstore-ruby-ce93acf7fa7e/cli/lib/sigstore/cli.rb new file mode 100644 index 00000000..ef3c1b3b --- /dev/null +++ b/vendor/cache/sigstore-ruby-ce93acf7fa7e/cli/lib/sigstore/cli.rb @@ -0,0 +1,270 @@ +# frozen_string_literal: true + +require "thor" +require "sigstore" + +module Sigstore + class CLI < Thor + def self.exit_on_failure? + true + end + + def self.start(given_args = ARGV, config = {}) + super + rescue Sigstore::Error => e + raise if config[:debug] || ENV["THOR_DEBUG"] == "1" + + detailed_message = e.respond_to?(:detailed_message) ? e.detailed_message : e.message + config[:shell].error(detailed_message) + + exit(false) + end + + class ShellWrapper + def initialize(shell) + @shell = shell + end + + def close + @shell.close + end + + def write(...) + @shell.say(...) + end + end + + def initialize(*) + super + Sigstore.logger.reopen ShellWrapper.new(shell) + Sigstore.logger.level = options[:debug] ? Logger::DEBUG : Logger::INFO + end + + package_name "sigstore-cli" + + desc "verify FILE", "Verify a signature" + option :staging, type: :boolean, desc: "Use the staging trusted root" + option :signature, type: :string, desc: "Path to the signature file" + option :certificate, type: :string, desc: "Path to the public certificate" + option :certificate_identity, type: :string, desc: "The identity of the certificate" + option :certificate_oidc_issuer, type: :string, desc: "The OIDC issuer of the certificate" + option :offline, type: :boolean, desc: "Do not fetch the latest timestamp from the Rekor server" + option :bundle, type: :string, desc: "Path to the signed bundle" + option :trusted_root, type: :string, desc: "Path to the trusted root" + option :update_trusted_root, type: :boolean, desc: "Update the trusted root", default: true + exclusive :bundle, :signature + exclusive :bundle, :certificate + def verify(*files) + verifier, files_with_materials = collect_verification_state(files) + policy = Sigstore::Policy::Identity.new( + identity: options[:certificate_identity], + issuer: options[:certificate_oidc_issuer] + ) + + verified = files_with_materials.all? do |file, input| + result = verifier.verify(input:, policy:, offline: options[:offline]) + + if result.verified? + say "OK: #{file}" + true + else + say "FAIL: #{file}" + say "\t#{result.reason}" + false + end + end + exit(false) unless verified + end + map "verify-bundle" => :verify + + desc "sign ARTIFACT", "Sign a file" + option :staging, type: :boolean, desc: "Use the staging trusted root" + option :identity_token, type: :string, desc: "Identity token to use for signing" + option :bundle, type: :string, desc: "Path to write the signed bundle to" + option :signature, type: :string, desc: "Path to write the signature to" + option :certificate, type: :string, desc: "Path to the public certificate" + option :trusted_root, type: :string, desc: "Path to the trusted root" + option :update_trusted_root, type: :boolean, desc: "Update the trusted root", default: true + def sign(file) + self.options = options.merge(identity_token: IdToken.detect_credential).freeze if options[:identity_token].nil? + unless options[:identity_token] + raise Error::InvalidIdentityToken, + "Failed to detect an ambient identity token, please provide one via --identity-token" + end + + contents = File.binread(file) + bundle = Sigstore::Signer.new( + jwt: options[:identity_token], + trusted_root: + ).sign(contents) + + File.binwrite(options[:bundle], bundle.to_json) if options[:bundle] + if options[:signature] + File.binwrite(options[:signature], Internal::Util.base64_encode(bundle.message_signature.signature)) + end + File.binwrite(options[:certificate], bundle.verification_material.certificate.raw_bytes) if options[:certificate] + end + map "sign-bundle" => :sign + + desc "display", "Display sigstore bundle(s)" + def display(*files) + files.each do |file| + bundle_bytes = Gem.read_binary(file) + bundle = SBundle.new Bundle::V1::Bundle.decode_json(bundle_bytes, registry: Sigstore::REGISTRY) + + say "--- Bundle #{file} ---" + say "Media Type: #{bundle.media_type}" + say bundle.leaf_certificate.to_text + + case bundle.content + when :message_signature + say "Signature over: #{bundle.message_signature.message_digest.algorithm} " \ + "#{Internal::Util.hex_encode bundle.message_signature.message_digest.digest}" + when :dsse_envelope + say bundle.dsse_envelope.payloadType + say bundle.dsse_envelope.payload + else raise Error::InvalidBundle, "expected either message_signature or dsse_envelope" + end + end + end + + class TUF < Thor + def self.exit_on_failure? + true + end + + desc "download-target TARGET...", "Download a target from a TUP repo" + option :metadata_url, type: :string, desc: "URL to the metadata", required: true + option :metadata_dir, type: :string, desc: "Directory to store the metadata", required: true + option :targets_dir, type: :string, desc: "Directory to store the targets", required: true + option :cached, type: :boolean, desc: "Return cached targets only" + option :target_base_url, type: :string, desc: "Base URL for the targets" + def download_target(*targets) + trust_updater = Sigstore::TUF::TrustUpdater.new( + options[:metadata_url], false, + metadata_dir: options[:metadata_dir], targets_dir: options[:targets_dir], + target_base_url: options[:target_base_url] + ) + trust_updater.refresh + + targets.each do |target| + target_info = trust_updater.updater.get_targetinfo(target) + raise Sigstore::TUF::Error, "No such target: #{target}" unless target_info + + path = if @cached + trust_updater.updater.find_cached_target(target_info) + else + trust_updater.updater.download_target(target_info) + end + say "Downloaded #{target} to #{path}" + end + end + + desc "init ROOT", "Initialize a TUF repo" + option :metadata_dir, type: :string, desc: "Directory to store the metadata", required: true + def init(root) + FileUtils.mkdir_p(options[:metadata_dir]) + FileUtils.cp(root, File.join(options[:metadata_dir], "root.json")) + end + + desc "refresh", "Refresh the metadata" + option :metadata_url, type: :string, desc: "URL to the metadata", required: true + option :metadata_dir, type: :string, desc: "Directory to store the metadata", required: true + def refresh + Sigstore::TUF::TrustUpdater.new( + options[:metadata_url], false, + metadata_dir: options[:metadata_dir] + ).refresh + end + end + + register TUF, "tuf", "tuf SUBCOMMAND", "TUF commands" + + private + + def trusted_root + return Sigstore::TrustedRoot.from_file(options[:trusted_root]) if options[:trusted_root] + + if options[:staging] + Sigstore::TrustedRoot.staging(offline: !options[:update_trusted_root]) + else + Sigstore::TrustedRoot.production(offline: !options[:update_trusted_root]) + end + end + + def collect_verification_state(files) + if (options[:certificate] || options[:signature] || options[:bundle]) && files.size > 1 + raise Thor::InvocationError, "Too many files specified: #{files.inspect}" + end + + if options[:bundle] && (options[:certificate] || options[:signature]) + raise Thor::InvocationError, "Cannot specify both --bundle and --certificate or --signature" + end + + input_map = {} + + verifier = Sigstore::Verifier.for_trust_root(trust_root: trusted_root) + + all_materials = [] + + files.each do |file| + raise Thor::InvocationError, "File not found: #{file}" unless File.exist?(file) || file.start_with?("sha256:") + + sig = options[:signature] + cert = options[:certificate] + bundle = options[:bundle] + + directory = File.dirname(file) + + sig ||= File.join(directory, "#{file}.sig") + cert ||= File.join(directory, "#{file}.cert") + bundle = File.join(directory, "#{file}.sigstore.json") if bundle.nil? + + missing = [] + + if options[:signature] || options[:certificate] + missing << sig unless File.exist?(sig) + missing << cert unless File.exist?(cert) + input_map[file] = { cert:, sig: } + else + missing << bundle unless File.exist?(bundle) + input_map[file] = { bundle: } + end + + raise Thor::InvocationError, "Missing files: #{missing.join(", ")}" if missing.any? + end + + input_map.each do |file, inputs| + artifact = Sigstore::Verification::V1::Artifact.new + case file + when /\Asha256:/ + artifact.artifact_uri = file + else + artifact.artifact = File.binread(file) + end + + verification_input = Sigstore::Verification::V1::Input.new + verification_input.artifact = artifact + + if inputs[:bundle] + bundle_bytes = Gem.read_binary(inputs[:bundle]) + verification_input.bundle = Sigstore::Bundle::V1::Bundle.decode_json(bundle_bytes, + registry: Sigstore::REGISTRY) + else + cert_pem = Gem.read_binary(inputs[:cert]) + b64_sig = Gem.read_binary(inputs[:sig]) + signature = b64_sig.unpack1("m") + + verification_input.bundle = Sigstore::SBundle.for_cert_bytes_and_signature(cert_pem, signature).__getobj__ + end + + say "Verifying #{file}..." + all_materials << [file, Sigstore::VerificationInput.new(verification_input)] + end + + [verifier, all_materials] + end + end +end + +require "sigstore/cli/id_token" diff --git a/vendor/cache/sigstore-ruby-ce93acf7fa7e/cli/lib/sigstore/cli/id_token.rb b/vendor/cache/sigstore-ruby-ce93acf7fa7e/cli/lib/sigstore/cli/id_token.rb new file mode 100644 index 00000000..6877c446 --- /dev/null +++ b/vendor/cache/sigstore-ruby-ce93acf7fa7e/cli/lib/sigstore/cli/id_token.rb @@ -0,0 +1,89 @@ +# frozen_string_literal: true + +class Sigstore::CLI + class IdToken + include Sigstore::Loggable + + class AmbientCredentialError < Sigstore::Error + end + + def self.detect_credential + [ + GitHub + # detect_gcp, + # detect_buildkite, + # detect_gitlab, + # detect_circleci + ].each do |detector| + credential = detector.call("sigstore") + return credential if credential + end + + logger.debug { "failed to find ambient OIDC credential" } + + nil + end + + def self.call(audience) + new(audience).call + end + + def initialize(audience) + @audience = audience + end + + def call + raise NotImplementedError, "#{self.class}#call" + end + + class GitHub < IdToken + class PermissionCredentialError < Sigstore::Error + end + + def call + logger.debug { "looking for OIDC credentials" } + unless ENV["GITHUB_ACTIONS"] + logger.debug { "environment doesn't look like a GH action; giving up" } + return + end + + req_token = ENV.fetch("ACTIONS_ID_TOKEN_REQUEST_TOKEN", nil) + unless req_token + raise PermissionCredentialError, + "missing or insufficient OIDC token permissions, " \ + "the ACTIONS_ID_TOKEN_REQUEST_TOKEN environment variable was unset" + end + + req_url = ENV.fetch("ACTIONS_ID_TOKEN_REQUEST_URL", nil) + unless req_url + raise PermissionCredentialError, + "missing or insufficient OIDC token permissions, " \ + "the ACTIONS_ID_TOKEN_REQUEST_URL environment variable was unset" + end + req_url = URI.parse(req_url) + req_url.query = "audience=#{URI.encode_uri_component(@audience)}" + + logger.debug { "requesting OIDC token" } + resp = Net::HTTP.get_response( + req_url, { "Authorization" => "bearer #{req_token}" } + ) + + begin + resp.value + rescue Net::HTTPExceptions + raise AmbientCredentialError, "OIDC token request failed (code=#{resp.code}, body=#{resp.body})" + rescue Timeout::Error + raise AmbientCredentialError, "OIDC token request timed out" + end + + begin + body = JSON.parse resp.body + rescue StandardError + raise AmbientCredentialError, "malformed or incomplete json" + else + body.fetch("value") + end + end + end + end +end diff --git a/vendor/cache/sigstore-ruby-ce93acf7fa7e/cli/sigstore-cli.gemspec b/vendor/cache/sigstore-ruby-ce93acf7fa7e/cli/sigstore-cli.gemspec new file mode 100644 index 00000000..be4f754b --- /dev/null +++ b/vendor/cache/sigstore-ruby-ce93acf7fa7e/cli/sigstore-cli.gemspec @@ -0,0 +1,29 @@ +# -*- encoding: utf-8 -*- +# stub: sigstore-cli 0.2.1 ruby lib + +Gem::Specification.new do |s| + s.name = "sigstore-cli".freeze + s.version = "0.2.1".freeze + + s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= + s.metadata = { "allowed_push_host" => "https://rubygems.org", "homepage_uri" => "https://github.com/sigstore/sigstore-ruby", "rubygems_mfa_required" => "true" } if s.respond_to? :metadata= + s.require_paths = ["lib".freeze] + s.authors = ["The Sigstore Authors".freeze, "Samuel Giddins".freeze] + s.bindir = "exe".freeze + s.date = "1980-01-02" + s.email = [nil, "segiddins@segiddins.me".freeze] + s.executables = ["sigstore-cli".freeze] + s.files = ["exe/sigstore-cli".freeze, "lib/sigstore/cli.rb".freeze, "lib/sigstore/cli/id_token.rb".freeze] + s.homepage = "https://github.com/sigstore/sigstore-ruby".freeze + s.licenses = ["Apache-2.0".freeze] + s.required_ruby_version = Gem::Requirement.new(">= 3.2.0".freeze) + s.rubygems_version = "3.6.7".freeze + s.summary = "A CLI interface to the sigstore ruby client".freeze + + s.installed_by_version = "3.6.7".freeze + + s.specification_version = 4 + + s.add_runtime_dependency(%q.freeze, ["= 0.2.1".freeze]) + s.add_runtime_dependency(%q.freeze, [">= 0".freeze]) +end diff --git a/vendor/cache/sigstore-ruby-ce93acf7fa7e/data/_store/prod/root.json b/vendor/cache/sigstore-ruby-ce93acf7fa7e/data/_store/prod/root.json new file mode 100644 index 00000000..3f18ee74 --- /dev/null +++ b/vendor/cache/sigstore-ruby-ce93acf7fa7e/data/_store/prod/root.json @@ -0,0 +1,165 @@ +{ + "signatures": [ + { + "keyid": "6f260089d5923daf20166ca657c543af618346ab971884a99962b01988bbe0c3", + "sig": "30460221008ab1f6f17d4f9e6d7dcf1c88912b6b53cc10388644ae1f09bc37a082cd06003e022100e145ef4c7b782d4e8107b53437e669d0476892ce999903ae33d14448366996e7" + }, + { + "keyid": "e71a54d543835ba86adad9460379c7641fb8726d164ea766801a1c522aba7ea2", + "sig": "3045022100c768b2f86da99569019c160a081da54ae36c34c0a3120d3cb69b53b7d113758e02204f671518f617b20d46537fae6c3b63bae8913f4f1962156105cc4f019ac35c6a" + }, + { + "keyid": "22f4caec6d8e6f9555af66b3d4c3cb06a3bb23fdc7e39c916c61f462e6f52b06", + "sig": "3045022100b4434e6995d368d23e74759acd0cb9013c83a5d3511f0f997ec54c456ae4350a022015b0e265d182d2b61dc74e155d98b3c3fbe564ba05286aa14c8df02c9b756516" + }, + { + "keyid": "61643838125b440b40db6942f5cb5a31c0dc04368316eb2aaa58b95904a58222", + "sig": "304502210082c58411d989eb9f861410857d42381590ec9424dbdaa51e78ed13515431904e0220118185da6a6c2947131c17797e2bb7620ce26e5f301d1ceac5f2a7e58f9dcf2e" + }, + { + "keyid": "a687e5bf4fab82b0ee58d46e05c9535145a2c9afb458f43d42b45ca0fdce2a70", + "sig": "3046022100c78513854cae9c32eaa6b88e18912f48006c2757a258f917312caba75948eb9e022100d9e1b4ce0adfe9fd2e2148d7fa27a2f40ba1122bd69da7612d8d1776b013c91d" + }, + { + "keyid": "fdfa83a07b5a83589b87ded41f77f39d232ad91f7cce52868dacd06ba089849f", + "sig": "3045022056483a2d5d9ea9cec6e11eadfb33c484b614298faca15acf1c431b11ed7f734c022100d0c1d726af92a87e4e66459ca5adf38a05b44e1f94318423f954bae8bca5bb2e" + }, + { + "keyid": "e2f59acb9488519407e18cbfc9329510be03c04aca9929d2f0301343fec85523", + "sig": "3046022100d004de88024c32dc5653a9f4843cfc5215427048ad9600d2cf9c969e6edff3d2022100d9ebb798f5fc66af10899dece014a8628ccf3c5402cd4a4270207472f8f6e712" + }, + { + "keyid": "3c344aa068fd4cc4e87dc50b612c02431fbc771e95003993683a2b0bf260cf0e", + "sig": "3046022100b7b09996c45ca2d4b05603e56baefa29718a0b71147cf8c6e66349baa61477df022100c4da80c717b4fa7bba0fd5c72da8a0499358b01358b2309f41d1456ea1e7e1d9" + }, + { + "keyid": "ec81669734e017996c5b85f3d02c3de1dd4637a152019fe1af125d2f9368b95e", + "sig": "3046022100be9782c30744e411a82fa85b5138d601ce148bc19258aec64e7ec24478f38812022100caef63dcaf1a4b9a500d3bd0e3f164ec18f1b63d7a9460d9acab1066db0f016d" + }, + { + "keyid": "1e1d65ce98b10addad4764febf7dda2d0436b3d3a3893579c0dddaea20e54849", + "sig": "30450220746ec3f8534ce55531d0d01ff64964ef440d1e7d2c4c142409b8e9769f1ada6f022100e3b929fcd93ea18feaa0825887a7210489879a66780c07a83f4bd46e2f09ab3b" + } + ], + "signed": { + "_type": "root", + "consistent_snapshot": true, + "expires": "2025-02-19T08:04:32Z", + "keys": { + "22f4caec6d8e6f9555af66b3d4c3cb06a3bb23fdc7e39c916c61f462e6f52b06": { + "keyid_hash_algorithms": [ + "sha256", + "sha512" + ], + "keytype": "ecdsa", + "keyval": { + "public": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEzBzVOmHCPojMVLSI364WiiV8NPrD\n6IgRxVliskz/v+y3JER5mcVGcONliDcWMC5J2lfHmjPNPhb4H7xm8LzfSA==\n-----END PUBLIC KEY-----\n" + }, + "scheme": "ecdsa-sha2-nistp256", + "x-tuf-on-ci-keyowner": "@santiagotorres" + }, + "61643838125b440b40db6942f5cb5a31c0dc04368316eb2aaa58b95904a58222": { + "keyid_hash_algorithms": [ + "sha256", + "sha512" + ], + "keytype": "ecdsa", + "keyval": { + "public": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEinikSsAQmYkNeH5eYq/CnIzLaacO\nxlSaawQDOwqKy/tCqxq5xxPSJc21K4WIhs9GyOkKfzueY3GILzcMJZ4cWw==\n-----END PUBLIC KEY-----\n" + }, + "scheme": "ecdsa-sha2-nistp256", + "x-tuf-on-ci-keyowner": "@bobcallaway" + }, + "6f260089d5923daf20166ca657c543af618346ab971884a99962b01988bbe0c3": { + "keyid_hash_algorithms": [ + "sha256", + "sha512" + ], + "keytype": "ecdsa", + "keyval": { + "public": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEy8XKsmhBYDI8Jc0GwzBxeKax0cm5\nSTKEU65HPFunUn41sT8pi0FjM4IkHz/YUmwmLUO0Wt7lxhj6BkLIK4qYAw==\n-----END PUBLIC KEY-----\n" + }, + "scheme": "ecdsa-sha2-nistp256", + "x-tuf-on-ci-keyowner": "@dlorenc" + }, + "7247f0dbad85b147e1863bade761243cc785dcb7aa410e7105dd3d2b61a36d2c": { + "keyid_hash_algorithms": [ + "sha256", + "sha512" + ], + "keytype": "ecdsa", + "keyval": { + "public": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEWRiGr5+j+3J5SsH+Ztr5nE2H2wO7\nBV+nO3s93gLca18qTOzHY1oWyAGDykMSsGTUBSt9D+An0KfKsD2mfSM42Q==\n-----END PUBLIC KEY-----\n" + }, + "scheme": "ecdsa-sha2-nistp256", + "x-tuf-on-ci-online-uri": "gcpkms://projects/sigstore-root-signing/locations/global/keyRings/root/cryptoKeys/timestamp" + }, + "a687e5bf4fab82b0ee58d46e05c9535145a2c9afb458f43d42b45ca0fdce2a70": { + "keyid_hash_algorithms": [ + "sha256", + "sha512" + ], + "keytype": "ecdsa", + "keyval": { + "public": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE0ghrh92Lw1Yr3idGV5WqCtMDB8Cx\n+D8hdC4w2ZLNIplVRoVGLskYa3gheMyOjiJ8kPi15aQ2//7P+oj7UvJPGw==\n-----END PUBLIC KEY-----\n" + }, + "scheme": "ecdsa-sha2-nistp256", + "x-tuf-on-ci-keyowner": "@joshuagl" + }, + "e71a54d543835ba86adad9460379c7641fb8726d164ea766801a1c522aba7ea2": { + "keyid_hash_algorithms": [ + "sha256", + "sha512" + ], + "keytype": "ecdsa", + "keyval": { + "public": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEEXsz3SZXFb8jMV42j6pJlyjbjR8K\nN3Bwocexq6LMIb5qsWKOQvLN16NUefLc4HswOoumRsVVaajSpQS6fobkRw==\n-----END PUBLIC KEY-----\n" + }, + "scheme": "ecdsa-sha2-nistp256", + "x-tuf-on-ci-keyowner": "@mnm678" + } + }, + "roles": { + "root": { + "keyids": [ + "6f260089d5923daf20166ca657c543af618346ab971884a99962b01988bbe0c3", + "e71a54d543835ba86adad9460379c7641fb8726d164ea766801a1c522aba7ea2", + "22f4caec6d8e6f9555af66b3d4c3cb06a3bb23fdc7e39c916c61f462e6f52b06", + "61643838125b440b40db6942f5cb5a31c0dc04368316eb2aaa58b95904a58222", + "a687e5bf4fab82b0ee58d46e05c9535145a2c9afb458f43d42b45ca0fdce2a70" + ], + "threshold": 3 + }, + "snapshot": { + "keyids": [ + "7247f0dbad85b147e1863bade761243cc785dcb7aa410e7105dd3d2b61a36d2c" + ], + "threshold": 1, + "x-tuf-on-ci-expiry-period": 3650, + "x-tuf-on-ci-signing-period": 365 + }, + "targets": { + "keyids": [ + "6f260089d5923daf20166ca657c543af618346ab971884a99962b01988bbe0c3", + "e71a54d543835ba86adad9460379c7641fb8726d164ea766801a1c522aba7ea2", + "22f4caec6d8e6f9555af66b3d4c3cb06a3bb23fdc7e39c916c61f462e6f52b06", + "61643838125b440b40db6942f5cb5a31c0dc04368316eb2aaa58b95904a58222", + "a687e5bf4fab82b0ee58d46e05c9535145a2c9afb458f43d42b45ca0fdce2a70" + ], + "threshold": 3 + }, + "timestamp": { + "keyids": [ + "7247f0dbad85b147e1863bade761243cc785dcb7aa410e7105dd3d2b61a36d2c" + ], + "threshold": 1, + "x-tuf-on-ci-expiry-period": 7, + "x-tuf-on-ci-signing-period": 4 + } + }, + "spec_version": "1.0", + "version": 10, + "x-tuf-on-ci-expiry-period": 182, + "x-tuf-on-ci-signing-period": 31 + } +} \ No newline at end of file diff --git a/vendor/cache/sigstore-ruby-ce93acf7fa7e/data/_store/prod/trusted_root.json b/vendor/cache/sigstore-ruby-ce93acf7fa7e/data/_store/prod/trusted_root.json new file mode 100644 index 00000000..5ed62811 --- /dev/null +++ b/vendor/cache/sigstore-ruby-ce93acf7fa7e/data/_store/prod/trusted_root.json @@ -0,0 +1,114 @@ +{ + "mediaType": "application/vnd.dev.sigstore.trustedroot+json;version=0.1", + "tlogs": [ + { + "baseUrl": "https://rekor.sigstore.dev", + "hashAlgorithm": "SHA2_256", + "publicKey": { + "rawBytes": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE2G2Y+2tabdTV5BcGiBIx0a9fAFwrkBbmLSGtks4L3qX6yYY0zufBnhC8Ur/iy55GhWP/9A/bY2LhC30M9+RYtw==", + "keyDetails": "PKIX_ECDSA_P256_SHA_256", + "validFor": { + "start": "2021-01-12T11:53:27.000Z" + } + }, + "logId": { + "keyId": "wNI9atQGlz+VWfO6LRygH4QUfY/8W4RFwiT5i5WRgB0=" + } + } + ], + "certificateAuthorities": [ + { + "subject": { + "organization": "sigstore.dev", + "commonName": "sigstore" + }, + "uri": "https://fulcio.sigstore.dev", + "certChain": { + "certificates": [ + { + "rawBytes": "MIIB+DCCAX6gAwIBAgITNVkDZoCiofPDsy7dfm6geLbuhzAKBggqhkjOPQQDAzAqMRUwEwYDVQQKEwxzaWdzdG9yZS5kZXYxETAPBgNVBAMTCHNpZ3N0b3JlMB4XDTIxMDMwNzAzMjAyOVoXDTMxMDIyMzAzMjAyOVowKjEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MREwDwYDVQQDEwhzaWdzdG9yZTB2MBAGByqGSM49AgEGBSuBBAAiA2IABLSyA7Ii5k+pNO8ZEWY0ylemWDowOkNa3kL+GZE5Z5GWehL9/A9bRNA3RbrsZ5i0JcastaRL7Sp5fp/jD5dxqc/UdTVnlvS16an+2Yfswe/QuLolRUCrcOE2+2iA5+tzd6NmMGQwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYEFMjFHQBBmiQpMlEk6w2uSu1KBtPsMB8GA1UdIwQYMBaAFMjFHQBBmiQpMlEk6w2uSu1KBtPsMAoGCCqGSM49BAMDA2gAMGUCMH8liWJfMui6vXXBhjDgY4MwslmN/TJxVe/83WrFomwmNf056y1X48F9c4m3a3ozXAIxAKjRay5/aj/jsKKGIkmQatjI8uupHr/+CxFvaJWmpYqNkLDGRU+9orzh5hI2RrcuaQ==" + } + ] + }, + "validFor": { + "start": "2021-03-07T03:20:29.000Z", + "end": "2022-12-31T23:59:59.999Z" + } + }, + { + "subject": { + "organization": "sigstore.dev", + "commonName": "sigstore" + }, + "uri": "https://fulcio.sigstore.dev", + "certChain": { + "certificates": [ + { + "rawBytes": "MIICGjCCAaGgAwIBAgIUALnViVfnU0brJasmRkHrn/UnfaQwCgYIKoZIzj0EAwMwKjEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MREwDwYDVQQDEwhzaWdzdG9yZTAeFw0yMjA0MTMyMDA2MTVaFw0zMTEwMDUxMzU2NThaMDcxFTATBgNVBAoTDHNpZ3N0b3JlLmRldjEeMBwGA1UEAxMVc2lnc3RvcmUtaW50ZXJtZWRpYXRlMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE8RVS/ysH+NOvuDZyPIZtilgUF9NlarYpAd9HP1vBBH1U5CV77LSS7s0ZiH4nE7Hv7ptS6LvvR/STk798LVgMzLlJ4HeIfF3tHSaexLcYpSASr1kS0N/RgBJz/9jWCiXno3sweTAOBgNVHQ8BAf8EBAMCAQYwEwYDVR0lBAwwCgYIKwYBBQUHAwMwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQU39Ppz1YkEZb5qNjpKFWixi4YZD8wHwYDVR0jBBgwFoAUWMAeX5FFpWapesyQoZMi0CrFxfowCgYIKoZIzj0EAwMDZwAwZAIwPCsQK4DYiZYDPIaDi5HFKnfxXx6ASSVmERfsynYBiX2X6SJRnZU84/9DZdnFvvxmAjBOt6QpBlc4J/0DxvkTCqpclvziL6BCCPnjdlIB3Pu3BxsPmygUY7Ii2zbdCdliiow=" + }, + { + "rawBytes": "MIIB9zCCAXygAwIBAgIUALZNAPFdxHPwjeDloDwyYChAO/4wCgYIKoZIzj0EAwMwKjEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MREwDwYDVQQDEwhzaWdzdG9yZTAeFw0yMTEwMDcxMzU2NTlaFw0zMTEwMDUxMzU2NThaMCoxFTATBgNVBAoTDHNpZ3N0b3JlLmRldjERMA8GA1UEAxMIc2lnc3RvcmUwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAT7XeFT4rb3PQGwS4IajtLk3/OlnpgangaBclYpsYBr5i+4ynB07ceb3LP0OIOZdxexX69c5iVuyJRQ+Hz05yi+UF3uBWAlHpiS5sh0+H2GHE7SXrk1EC5m1Tr19L9gg92jYzBhMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRYwB5fkUWlZql6zJChkyLQKsXF+jAfBgNVHSMEGDAWgBRYwB5fkUWlZql6zJChkyLQKsXF+jAKBggqhkjOPQQDAwNpADBmAjEAj1nHeXZp+13NWBNa+EDsDP8G1WWg1tCMWP/WHPqpaVo0jhsweNFZgSs0eE7wYI4qAjEA2WB9ot98sIkoF3vZYdd3/VtWB5b9TNMea7Ix/stJ5TfcLLeABLE4BNJOsQ4vnBHJ" + } + ] + }, + "validFor": { + "start": "2022-04-13T20:06:15.000Z" + } + } + ], + "ctlogs": [ + { + "baseUrl": "https://ctfe.sigstore.dev/test", + "hashAlgorithm": "SHA2_256", + "publicKey": { + "rawBytes": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEbfwR+RJudXscgRBRpKX1XFDy3PyudDxz/SfnRi1fT8ekpfBd2O1uoz7jr3Z8nKzxA69EUQ+eFCFI3zeubPWU7w==", + "keyDetails": "PKIX_ECDSA_P256_SHA_256", + "validFor": { + "start": "2021-03-14T00:00:00.000Z", + "end": "2022-10-31T23:59:59.999Z" + } + }, + "logId": { + "keyId": "CGCS8ChS/2hF0dFrJ4ScRWcYrBY9wzjSbea8IgY2b3I=" + } + }, + { + "baseUrl": "https://ctfe.sigstore.dev/2022", + "hashAlgorithm": "SHA2_256", + "publicKey": { + "rawBytes": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEiPSlFi0CmFTfEjCUqF9HuCEcYXNKAaYalIJmBZ8yyezPjTqhxrKBpMnaocVtLJBI1eM3uXnQzQGAJdJ4gs9Fyw==", + "keyDetails": "PKIX_ECDSA_P256_SHA_256", + "validFor": { + "start": "2022-10-20T00:00:00.000Z" + } + }, + "logId": { + "keyId": "3T0wasbHETJjGR4cmWc3AqJKXrjePK3/h4pygC8p7o4=" + } + } + ], + "timestampAuthorities": [ + { + "subject": { + "organization": "GitHub, Inc.", + "commonName": "Internal Services Root" + }, + "certChain": { + "certificates": [ + { + "rawBytes": "MIIB3DCCAWKgAwIBAgIUchkNsH36Xa04b1LqIc+qr9DVecMwCgYIKoZIzj0EAwMwMjEVMBMGA1UEChMMR2l0SHViLCBJbmMuMRkwFwYDVQQDExBUU0EgaW50ZXJtZWRpYXRlMB4XDTIzMDQxNDAwMDAwMFoXDTI0MDQxMzAwMDAwMFowMjEVMBMGA1UEChMMR2l0SHViLCBJbmMuMRkwFwYDVQQDExBUU0EgVGltZXN0YW1waW5nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEUD5ZNbSqYMd6r8qpOOEX9ibGnZT9GsuXOhr/f8U9FJugBGExKYp40OULS0erjZW7xV9xV52NnJf5OeDq4e5ZKqNWMFQwDgYDVR0PAQH/BAQDAgeAMBMGA1UdJQQMMAoGCCsGAQUFBwMIMAwGA1UdEwEB/wQCMAAwHwYDVR0jBBgwFoAUaW1RudOgVt0leqY0WKYbuPr47wAwCgYIKoZIzj0EAwMDaAAwZQIwbUH9HvD4ejCZJOWQnqAlkqURllvu9M8+VqLbiRK+zSfZCZwsiljRn8MQQRSkXEE5AjEAg+VxqtojfVfu8DhzzhCx9GKETbJHb19iV72mMKUbDAFmzZ6bQ8b54Zb8tidy5aWe" + }, + { + "rawBytes": "MIICEDCCAZWgAwIBAgIUX8ZO5QXP7vN4dMQ5e9sU3nub8OgwCgYIKoZIzj0EAwMwODEVMBMGA1UEChMMR2l0SHViLCBJbmMuMR8wHQYDVQQDExZJbnRlcm5hbCBTZXJ2aWNlcyBSb290MB4XDTIzMDQxNDAwMDAwMFoXDTI4MDQxMjAwMDAwMFowMjEVMBMGA1UEChMMR2l0SHViLCBJbmMuMRkwFwYDVQQDExBUU0EgaW50ZXJtZWRpYXRlMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEvMLY/dTVbvIJYANAuszEwJnQE1llftynyMKIMhh48HmqbVr5ygybzsLRLVKbBWOdZ21aeJz+gZiytZetqcyF9WlER5NEMf6JV7ZNojQpxHq4RHGoGSceQv/qvTiZxEDKo2YwZDAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUaW1RudOgVt0leqY0WKYbuPr47wAwHwYDVR0jBBgwFoAU9NYYlobnAG4c0/qjxyH/lq/wz+QwCgYIKoZIzj0EAwMDaQAwZgIxAK1B185ygCrIYFlIs3GjswjnwSMG6LY8woLVdakKDZxVa8f8cqMs1DhcxJ0+09w95QIxAO+tBzZk7vjUJ9iJgD4R6ZWTxQWKqNm74jO99o+o9sv4FI/SZTZTFyMn0IJEHdNmyA==" + }, + { + "rawBytes": "MIIB9DCCAXqgAwIBAgIUa/JAkdUjK4JUwsqtaiRJGWhqLSowCgYIKoZIzj0EAwMwODEVMBMGA1UEChMMR2l0SHViLCBJbmMuMR8wHQYDVQQDExZJbnRlcm5hbCBTZXJ2aWNlcyBSb290MB4XDTIzMDQxNDAwMDAwMFoXDTMzMDQxMTAwMDAwMFowODEVMBMGA1UEChMMR2l0SHViLCBJbmMuMR8wHQYDVQQDExZJbnRlcm5hbCBTZXJ2aWNlcyBSb290MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEf9jFAXxz4kx68AHRMOkFBhflDcMTvzaXz4x/FCcXjJ/1qEKon/qPIGnaURskDtyNbNDOpeJTDDFqt48iMPrnzpx6IZwqemfUJN4xBEZfza+pYt/iyod+9tZr20RRWSv/o0UwQzAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBAjAdBgNVHQ4EFgQU9NYYlobnAG4c0/qjxyH/lq/wz+QwCgYIKoZIzj0EAwMDaAAwZQIxALZLZ8BgRXzKxLMMN9VIlO+e4hrBnNBgF7tz7Hnrowv2NetZErIACKFymBlvWDvtMAIwZO+ki6ssQ1bsZo98O8mEAf2NZ7iiCgDDU0Vwjeco6zyeh0zBTs9/7gV6AHNQ53xD" + } + ] + }, + "validFor": { + "start": "2023-04-14T00:00:00.000Z" + } + } + ] +} diff --git a/vendor/cache/sigstore-ruby-ce93acf7fa7e/data/_store/staging/root.json b/vendor/cache/sigstore-ruby-ce93acf7fa7e/data/_store/staging/root.json new file mode 100644 index 00000000..f00afe8b --- /dev/null +++ b/vendor/cache/sigstore-ruby-ce93acf7fa7e/data/_store/staging/root.json @@ -0,0 +1,107 @@ +{ + "signatures": [ + { + "keyid": "aa61e09f6af7662ac686cf0c6364079f63d3e7a86836684eeced93eace3acd81", + "sig": "304502204d5d01c2ae4b846cc6d29d7c5676f5d99ea464a69bd464fef16a5d0cdd4a616d022100bf73b2b11b68bf7a7047480bf0d5961a3a40c524f64a82e2c90f59d4083e498e" + }, + { + "keyid": "61f9609d2655b346fcebccd66b509d5828168d5e447110e261f0bcc8553624bc", + "sig": "3044022005a8e904d484b7f4c3bac53ed6babeee303f6308f81f9ea29a7a1f6ad51068c20220641303f1e5ab14b151525c63ca95b35df64ffc905c8883f96cbee703ed45a2df" + }, + { + "keyid": "9471fbda95411d10109e467ad526082d15f14a38de54ea2ada9687ab39d8e237", + "sig": "" + }, + { + "keyid": "0374a9e18a20a2103736cb4277e2fdd7f8453642c7d9eaf4ad8aee9cf2d47bb5", + "sig": "" + } + ], + "signed": { + "_type": "root", + "consistent_snapshot": true, + "expires": "2025-03-07T07:44:40Z", + "keys": { + "0374a9e18a20a2103736cb4277e2fdd7f8453642c7d9eaf4ad8aee9cf2d47bb5": { + "keytype": "ecdsa", + "keyval": { + "public": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEoxkvDOmtGEknB3M+ZkPts8joDM0X\nIH5JZwPlgC2CXs/eqOuNF8AcEWwGYRiDhV/IMlQw5bg8PLICQcgsbrDiKg==\n-----END PUBLIC KEY-----\n" + }, + "scheme": "ecdsa-sha2-nistp256", + "x-tuf-on-ci-keyowner": "@mnm678" + }, + "61f9609d2655b346fcebccd66b509d5828168d5e447110e261f0bcc8553624bc": { + "keytype": "ecdsa", + "keyval": { + "public": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE++Wv+DcLRk+mfkmlpCwl1GUi9EMh\npBUTz8K0fH7bE4mQuViGSyWA/eyMc0HvzZi6Xr0diHw0/lUPBvok214YQw==\n-----END PUBLIC KEY-----\n" + }, + "scheme": "ecdsa-sha2-nistp256", + "x-tuf-on-ci-keyowner": "@kommendorkapten" + }, + "9471fbda95411d10109e467ad526082d15f14a38de54ea2ada9687ab39d8e237": { + "keytype": "ecdsa", + "keyval": { + "public": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEFHDb85JH+JYR1LQmxiz4UMokVMnP\nxKoWpaEnFCKXH8W4Fc/DfIxMnkpjCuvWUBdJXkO0aDIxwsij8TOFh2R7dw==\n-----END PUBLIC KEY-----\n" + }, + "scheme": "ecdsa-sha2-nistp256", + "x-tuf-on-ci-keyowner": "@joshuagl" + }, + "aa61e09f6af7662ac686cf0c6364079f63d3e7a86836684eeced93eace3acd81": { + "keytype": "ecdsa", + "keyval": { + "public": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEohqIdE+yTl4OxpX8ZxNUPrg3SL9H\nBDnhZuceKkxy2oMhUOxhWweZeG3bfM1T4ZLnJimC6CAYVU5+F5jZCoftRw==\n-----END PUBLIC KEY-----\n" + }, + "scheme": "ecdsa-sha2-nistp256", + "x-tuf-on-ci-keyowner": "@jku" + }, + "c3479007e861445ce5dc109d9661ed77b35bbc0e3f161852c46114266fc2daa4": { + "keytype": "ecdsa", + "keyval": { + "public": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAExxmEtmhF5U+i+v/6he4BcSLzCgMx\n/0qSrvDg6bUWwUrkSKS2vDpcJrhGy5fmmhRrGawjPp1ALpC3y1kqFTpXDg==\n-----END PUBLIC KEY-----\n" + }, + "scheme": "ecdsa-sha2-nistp256", + "x-tuf-on-ci-online-uri": "gcpkms:projects/projectsigstore-staging/locations/global/keyRings/tuf-keyring/cryptoKeys/tuf-key/cryptoKeyVersions/2" + } + }, + "roles": { + "root": { + "keyids": [ + "aa61e09f6af7662ac686cf0c6364079f63d3e7a86836684eeced93eace3acd81", + "61f9609d2655b346fcebccd66b509d5828168d5e447110e261f0bcc8553624bc", + "9471fbda95411d10109e467ad526082d15f14a38de54ea2ada9687ab39d8e237", + "0374a9e18a20a2103736cb4277e2fdd7f8453642c7d9eaf4ad8aee9cf2d47bb5" + ], + "threshold": 2 + }, + "snapshot": { + "keyids": [ + "c3479007e861445ce5dc109d9661ed77b35bbc0e3f161852c46114266fc2daa4" + ], + "threshold": 1, + "x-tuf-on-ci-expiry-period": 3650, + "x-tuf-on-ci-signing-period": 365 + }, + "targets": { + "keyids": [ + "aa61e09f6af7662ac686cf0c6364079f63d3e7a86836684eeced93eace3acd81", + "61f9609d2655b346fcebccd66b509d5828168d5e447110e261f0bcc8553624bc", + "9471fbda95411d10109e467ad526082d15f14a38de54ea2ada9687ab39d8e237", + "0374a9e18a20a2103736cb4277e2fdd7f8453642c7d9eaf4ad8aee9cf2d47bb5" + ], + "threshold": 1 + }, + "timestamp": { + "keyids": [ + "c3479007e861445ce5dc109d9661ed77b35bbc0e3f161852c46114266fc2daa4" + ], + "threshold": 1, + "x-tuf-on-ci-expiry-period": 7, + "x-tuf-on-ci-signing-period": 6 + } + }, + "spec_version": "1.0", + "version": 10, + "x-tuf-on-ci-expiry-period": 182, + "x-tuf-on-ci-signing-period": 35 + } +} \ No newline at end of file diff --git a/vendor/cache/sigstore-ruby-ce93acf7fa7e/data/_store/staging/trusted_root.json b/vendor/cache/sigstore-ruby-ce93acf7fa7e/data/_store/staging/trusted_root.json new file mode 100644 index 00000000..35b9ba3e --- /dev/null +++ b/vendor/cache/sigstore-ruby-ce93acf7fa7e/data/_store/staging/trusted_root.json @@ -0,0 +1,87 @@ +{ + "mediaType": "application/vnd.dev.sigstore.trustedroot+json;version=0.1", + "tlogs": [ + { + "baseUrl": "https://rekor.sigstage.dev", + "hashAlgorithm": "SHA2_256", + "publicKey": { + "rawBytes": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEDODRU688UYGuy54mNUlaEBiQdTE9nYLr0lg6RXowI/QV/RE1azBn4Eg5/2uTOMbhB1/gfcHzijzFi9Tk+g1Prg==", + "keyDetails": "PKIX_ECDSA_P256_SHA_256", + "validFor": { + "start": "2021-01-12T11:53:27.000Z" + } + }, + "logId": { + "keyId": "0y8wo8MtY5wrdiIFohx7sHeI5oKDpK5vQhGHI6G+pJY=" + } + } + ], + "certificateAuthorities": [ + { + "subject": { + "organization": "sigstore.dev", + "commonName": "sigstore" + }, + "uri": "https://fulcio.sigstage.dev", + "certChain": { + "certificates": [ + { + "rawBytes": "MIICGTCCAaCgAwIBAgITJta/okfgHvjabGm1BOzuhrwA1TAKBggqhkjOPQQDAzAqMRUwEwYDVQQKEwxzaWdzdG9yZS5kZXYxETAPBgNVBAMTCHNpZ3N0b3JlMB4XDTIyMDQxNDIxMzg0MFoXDTMyMDMyMjE2NTA0NVowNzEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MR4wHAYDVQQDExVzaWdzdG9yZS1pbnRlcm1lZGlhdGUwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAASosAySWJQ/tK5r8T5aHqavk0oI+BKQbnLLdmOMRXHQF/4Hx9KtNfpcdjH9hNKQSBxSlLFFN3tvFCco0qFBzWYwZtsYsBe1l91qYn/9VHFTaEVwYQWIJEEvrs0fvPuAqjajezB5MA4GA1UdDwEB/wQEAwIBBjATBgNVHSUEDDAKBggrBgEFBQcDAzASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQWBBRxhjCmFHxib/n31vQFGn9f/+tvrDAfBgNVHSMEGDAWgBT/QjK6aH2rOnCv3AzUGuI+h49mZTAKBggqhkjOPQQDAwNnADBkAjAM1lbKkcqQlE/UspMTbWNo1y2TaJ44tx3l/FJFceTSdDZ+0W1OHHeU4twie/lq8XgCMHQxgEv26xNNiAGyPXbkYgrDPvbOqp0UeWX4mJnLSrBr3aN/KX1SBrKQu220FmVL0Q==" + }, + { + "rawBytes": "MIIB9jCCAXugAwIBAgITDdEJvluliE0AzYaIE4jTMdnFTzAKBggqhkjOPQQDAzAqMRUwEwYDVQQKEwxzaWdzdG9yZS5kZXYxETAPBgNVBAMTCHNpZ3N0b3JlMB4XDTIyMDMyNTE2NTA0NloXDTMyMDMyMjE2NTA0NVowKjEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MREwDwYDVQQDEwhzaWdzdG9yZTB2MBAGByqGSM49AgEGBSuBBAAiA2IABMo9BUNk9QIYisYysC24+2OytoV72YiLonYcqR3yeVnYziPt7Xv++CYE8yoCTiwedUECCWKOcvQKRCJZb9ht4Hzy+VvBx36hK+C6sECCSR0x6pPSiz+cTk1f788ZjBlUZaNjMGEwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFP9CMrpofas6cK/cDNQa4j6Hj2ZlMB8GA1UdIwQYMBaAFP9CMrpofas6cK/cDNQa4j6Hj2ZlMAoGCCqGSM49BAMDA2kAMGYCMQD+kojuzMwztNay9Ibzjuk//ZL5m6T2OCsm45l1lY004pcb984L926BowodoirFMcMCMQDIJtFHhP/1D3a+M3dAGomOb6O4CmTry3TTPbPsAFnv22YA0Y+P21NVoxKDjdu0tkw=" + } + ] + }, + "validFor": { + "start": "2022-04-14T21:38:40.000Z" + } + } + ], + "ctlogs": [ + { + "baseUrl": "https://ctfe.sigstage.dev/test", + "hashAlgorithm": "SHA2_256", + "publicKey": { + "rawBytes": "MIICCgKCAgEA27A2MPQXm0I0v7/Ly5BIauDjRZF5Jor9vU+QheoE2UIIsZHcyYq3slHzSSHy2lLj1ZD2d91CtJ492ZXqnBmsr4TwZ9jQ05tW2mGIRI8u2DqN8LpuNYZGz/f9SZrjhQQmUttqWmtu3UoLfKz6NbNXUnoo+NhZFcFRLXJ8VporVhuiAmL7zqT53cXR3yQfFPCUDeGnRksnlhVIAJc3AHZZSHQJ8DEXMhh35TVv2nYhTI3rID7GwjXXw4ocz7RGDD37ky6p39Tl5NB71gT1eSqhZhGHEYHIPXraEBd5+3w9qIuLWlp5Ej/K6Mu4ELioXKCUimCbwy+Cs8UhHFlqcyg4AysOHJwIadXIa8LsY51jnVSGrGOEBZevopmQPNPtyfFY3dmXSS+6Z3RD2Gd6oDnNGJzpSyEk410Ag5uvNDfYzJLCWX9tU8lIxNwdFYmIwpd89HijyRyoGnoJ3entd63cvKfuuix5r+GHyKp1Xm1L5j5AWM6P+z0xigwkiXnt+adexAl1J9wdDxv/pUFEESRF4DG8DFGVtbdH6aR1A5/vD4krO4tC1QYUSeyL5Mvsw8WRqIFHcXtgybtxylljvNcGMV1KXQC8UFDmpGZVDSHx6v3e/BHMrZ7gjoCCfVMZ/cFcQi0W2AIHPYEMH/C95J2r4XbHMRdYXpovpOoT5Ca78gsCAwEAAQ==", + "keyDetails": "PKCS1_RSA_PKCS1V5", + "validFor": { + "start": "2021-03-14T00:00:00.000Z", + "end": "2022-07-31T00:00:00.000Z" + } + }, + "logId": { + "keyId": "G3wUKk6ZK6ffHh/FdCRUE2wVekyzHEEIpSG4savnv0w=" + } + }, + { + "baseUrl": "https://ctfe.sigstage.dev/2022", + "hashAlgorithm": "SHA2_256", + "publicKey": { + "rawBytes": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEh99xuRi6slBFd8VUJoK/rLigy4bYeSYWO/fE6Br7r0D8NpMI94+A63LR/WvLxpUUGBpY8IJA3iU2telag5CRpA==", + "keyDetails": "PKIX_ECDSA_P256_SHA_256", + "validFor": { + "start": "2022-07-01T00:00:00.000Z", + "end": "2022-07-31T00:00:00.000Z" + } + }, + "logId": { + "keyId": "++JKOMQt7SJ3ynUHnCfnDhcKP8/58J4TueMqXuk3HmA=" + } + }, + { + "baseUrl": "https://ctfe.sigstage.dev/2022-2", + "hashAlgorithm": "SHA2_256", + "publicKey": { + "rawBytes": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE8gEDKNme8AnXuPBgHjrtXdS6miHqc24CRblNEOFpiJRngeq8Ko73Y+K18yRYVf1DXD4AVLwvKyzdNdl5n0jUSQ==", + "keyDetails": "PKIX_ECDSA_P256_SHA_256", + "validFor": { + "start": "2022-07-01T00:00:00.000Z" + } + }, + "logId": { + "keyId": "KzC83GiIyeLh2CYpXnQfSDkxlgLynDPLXkNA/rKshno=" + } + } + ] +} diff --git a/vendor/cache/sigstore-ruby-ce93acf7fa7e/fixtures/vcr_cassettes/conformance/verify_bundle_success.yml b/vendor/cache/sigstore-ruby-ce93acf7fa7e/fixtures/vcr_cassettes/conformance/verify_bundle_success.yml new file mode 100644 index 00000000..d2224451 --- /dev/null +++ b/vendor/cache/sigstore-ruby-ce93acf7fa7e/fixtures/vcr_cassettes/conformance/verify_bundle_success.yml @@ -0,0 +1,482 @@ +--- +http_interactions: + - request: + method: get + uri: https://tuf-repo-cdn.sigstore.dev/11.root.json + body: + encoding: US-ASCII + string: "" + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + - RubyGems/3.4.19 arm64-darwin-23 Ruby/3.2.3 (2024-01-18 patchlevel 157) + Connection: + - keep-alive + Keep-Alive: + - "30" + response: + status: + code: 404 + message: Not Found + headers: + Content-Type: + - application/xml; charset=UTF-8 + Content-Length: + - "127" + X-Guploader-Uploadid: + - AD-8ljsMeSQlrns1XqnvGLPDw0bdbnPzG1d7m7rFS_7pQk05crb9sK120IY3YOkR96u2Fbr2L2lPlVvXCQ + Date: + - Tue, 24 Sep 2024 19:32:14 GMT + Expires: + - Tue, 24 Sep 2024 19:32:14 GMT + Cache-Control: + - private, max-age=0 + Server: + - UploadServer + Via: + - 1.1 google + Alt-Svc: + - h3=":443"; ma=2592000,h3-29=":443"; ma=2592000 + body: + encoding: UTF-8 + string: + "NoSuchKeyThe + specified key does not exist." + recorded_at: Tue, 24 Sep 2024 19:32:14 GMT + - request: + method: get + uri: https://tuf-repo-cdn.sigstore.dev/timestamp.json + body: + encoding: US-ASCII + string: "" + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + - RubyGems/3.4.19 arm64-darwin-23 Ruby/3.2.3 (2024-01-18 patchlevel 157) + Connection: + - keep-alive + Keep-Alive: + - "30" + response: + status: + code: 200 + message: OK + headers: + Date: + - Tue, 24 Sep 2024 19:32:14 GMT + Cache-Control: + - no-store + Expires: + - Wed, 24 Sep 2025 19:32:14 GMT + Last-Modified: + - Tue, 24 Sep 2024 13:30:21 GMT + Etag: + - '"7c6cbda4330af48fd1e23db82286e7ab"' + X-Goog-Generation: + - "1727184620932794" + X-Goog-Metageneration: + - "1" + X-Goog-Stored-Content-Encoding: + - identity + X-Goog-Stored-Content-Length: + - "449" + Content-Type: + - application/json + X-Goog-Hash: + - crc32c=709eSg== + - md5=fGy9pDMK9I/R4j24Iobnqw== + X-Goog-Storage-Class: + - STANDARD + Accept-Ranges: + - bytes + Content-Length: + - "449" + X-Guploader-Uploadid: + - AD-8ljt9mMrXUS90bR_niI8SdX3YNzqcD5ymdrSp4aX0DfcfrSfE3-54IZL4DqDd-XoXPXyPjDv4zOG5bg + Server: + - UploadServer + Via: + - 1.1 google + Alt-Svc: + - h3=":443"; ma=2592000,h3-29=":443"; ma=2592000 + body: + encoding: UTF-8 + string: |- + { + "signatures": [ + { + "keyid": "7247f0dbad85b147e1863bade761243cc785dcb7aa410e7105dd3d2b61a36d2c", + "sig": "304502204cbf8eedddcb8cd1f4d274ad202aad9162d85fb4c79ee4dff5ec1d08948e8191022100abe1569a87d13d40d4b563806c1694017332b7101fbaea377d4a0991a29a9065" + } + ], + "signed": { + "_type": "timestamp", + "expires": "2024-10-01T13:26:15Z", + "meta": { + "snapshot.json": { + "version": 156 + } + }, + "spec_version": "1.0", + "version": 224 + } + } + recorded_at: Tue, 24 Sep 2024 19:32:14 GMT + - request: + method: get + uri: https://tuf-repo-cdn.sigstore.dev/156.snapshot.json + body: + encoding: US-ASCII + string: "" + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + - RubyGems/3.4.19 arm64-darwin-23 Ruby/3.2.3 (2024-01-18 patchlevel 157) + Connection: + - keep-alive + Keep-Alive: + - "30" + response: + status: + code: 200 + message: OK + headers: + X-Goog-Generation: + - "1725380115625190" + X-Goog-Metageneration: + - "1" + X-Goog-Stored-Content-Encoding: + - identity + X-Goog-Stored-Content-Length: + - "1758" + X-Goog-Meta-Goog-Reserved-File-Mtime: + - "1725379916" + X-Goog-Hash: + - crc32c=KP+kcQ== + - md5=xVm/fgX6HzD6P9pEzgZ51Q== + X-Goog-Storage-Class: + - STANDARD + Accept-Ranges: + - bytes + Content-Length: + - "1758" + X-Guploader-Uploadid: + - AD-8ljuVnlyofdHPsb9q0-aPa9byMEep5AY_466v8T3dOT8LZfF_maLHZbnl8f8h1MWSvT32vv77slsFAQ + Server: + - UploadServer + Via: + - 1.1 google + Date: + - Tue, 24 Sep 2024 16:21:05 GMT + Cache-Control: + - public,max-age=86400 + Age: + - "11470" + Last-Modified: + - Tue, 24 Sep 2024 13:30:19 GMT + Etag: + - '"c559bf7e05fa1f30fa3fda44ce0679d5"' + Content-Type: + - application/json + Alt-Svc: + - h3=":443"; ma=2592000,h3-29=":443"; ma=2592000 + body: + encoding: UTF-8 + string: |- + { + "signatures": [ + { + "keyid": "7247f0dbad85b147e1863bade761243cc785dcb7aa410e7105dd3d2b61a36d2c", + "sig": "304402206566fd1ac98aae6c76e88d477201f8d6793d1df8655d5585f70cdfea16dfc46a022060fdeaafc754530606b4b78e2c273a8f6bed629345b8505e0380e722a8900450" + } + ], + "signed": { + "_type": "snapshot", + "expires": "2034-08-31T13:31:34Z", + "meta": { + "registry.npmjs.org.json": { + "version": 4 + }, + "rekor.json": { + "hashes": { + "sha256": "9d2e1a5842937d8e0d3e3759170b0ad15c56c5df36afc5cf73583ddd283a463b", + "sha512": "176e9e710ddddd1b357a7d7970831bae59763395a0c18976110cbd35b25e5412dc50f356ec421a7a30265670cf7aec9ed84ee944ba700ec2394b9c876645b960" + }, + "length": 797, + "version": 3 + }, + "revocation.json": { + "hashes": { + "sha256": "6f60848ba8fb0955a02abfd1232fb3845dc9ee9f418bf03521a7ddb48217e040", + "sha512": "a965dddd0d0edef6c59e84cf02ecf5a53299f633fd339b2b61814a4219ab4df672a6390f265b8b29e1c8cea9368ea3440df013790759d50231a30df1c1f02551" + }, + "length": 800, + "version": 2 + }, + "root.json": { + "hashes": { + "sha256": "f5ad897c9414cca99629f400ac3585e41bd8ebb44c5af07fb08dd636a9eced9c", + "sha512": "7445ddfdd338ef786c324fc3d68f75be28cb95b7fb581d2a383e3e5dde18aa17029a5636ec0a22e9631931bbcb34057788311718ea41e21e7cdd3c0de13ede42" + }, + "length": 5297, + "version": 2 + }, + "staging.json": { + "hashes": { + "sha256": "cda57759abac5375397eea3531d7ca51e3a67da9a2dc93f2cdab749e2ae73149", + "sha512": "e9e59587bde453144c7079884a880c706f1d43f26e8bb23fac2b96a99569a2a30ae6cf51ec51c2454f760ce83d4c20915e062aede7f319b3da6a6ed1d26ca281" + }, + "length": 401, + "version": 2 + }, + "targets.json": { + "version": 10 + } + }, + "spec_version": "1.0", + "version": 156 + } + } + recorded_at: Tue, 24 Sep 2024 19:32:14 GMT + - request: + method: get + uri: https://tuf-repo-cdn.sigstore.dev/10.targets.json + body: + encoding: US-ASCII + string: "" + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + - RubyGems/3.4.19 arm64-darwin-23 Ruby/3.2.3 (2024-01-18 patchlevel 157) + Connection: + - keep-alive + Keep-Alive: + - "30" + response: + status: + code: 200 + message: OK + headers: + X-Goog-Generation: + - "1725380115569153" + X-Goog-Metageneration: + - "1" + X-Goog-Stored-Content-Encoding: + - identity + X-Goog-Stored-Content-Length: + - "5624" + X-Goog-Meta-Goog-Reserved-File-Mtime: + - "1725379916" + X-Goog-Hash: + - crc32c=uBDWLw== + - md5=HDgoh6x8PE4twwByxqk9eg== + X-Goog-Storage-Class: + - STANDARD + Accept-Ranges: + - bytes + Content-Length: + - "5624" + X-Guploader-Uploadid: + - AD-8ljuqI0TCFNPAhR460l5rdARrrRdHJzvtdI_Iqshy_FcPX3swUKm4oT7MPCWUP8Fok9QUA3QcQ6YLiQ + Server: + - UploadServer + Via: + - 1.1 google + Date: + - Tue, 24 Sep 2024 16:21:05 GMT + Cache-Control: + - public,max-age=86400 + Age: + - "11470" + Last-Modified: + - Tue, 24 Sep 2024 13:30:19 GMT + Etag: + - '"1c382887ac7c3c4e2dc30072c6a93d7a"' + Content-Type: + - application/json + Alt-Svc: + - h3=":443"; ma=2592000,h3-29=":443"; ma=2592000 + body: + encoding: UTF-8 + string: |- + { + "signatures": [ + { + "keyid": "6f260089d5923daf20166ca657c543af618346ab971884a99962b01988bbe0c3", + "sig": "3045022100cffdd70aff94fab0127ac749c64449d5f644c7195971bfdca57879d5f645ab960220129ed6aeb07a57d9554af28941543bbb58f28c4c60d28a819f2294d290ff6cd9" + }, + { + "keyid": "e71a54d543835ba86adad9460379c7641fb8726d164ea766801a1c522aba7ea2", + "sig": "30450220208c663d230a0ebb3a2b964020d019394112e216d4964c743ad2e61cebc43b52022100c2964f3fa7e77cd3abe13640d91b53d1a294470b65211a42f3f7764064c28ce4" + }, + { + "keyid": "22f4caec6d8e6f9555af66b3d4c3cb06a3bb23fdc7e39c916c61f462e6f52b06", + "sig": "304502210093afa3a6d28f67f6aace8c6c5258282ec0784ce82da93589e2870b522c1b685502205374c8871e12e07f856f83e780b626dd5a00a032285d4436f615cdb9d637c3c3" + }, + { + "keyid": "61643838125b440b40db6942f5cb5a31c0dc04368316eb2aaa58b95904a58222", + "sig": "3044022006b5eae637d0b66f4f72759f86e86840f6a9a580b3baf7303a046d8fac1c0872022053c1b8a6fbce7e37a7e46501019a160f4d833efb48e7ca5bd274df54b2bbce3f" + }, + { + "keyid": "a687e5bf4fab82b0ee58d46e05c9535145a2c9afb458f43d42b45ca0fdce2a70", + "sig": "304502203d51eac2b34f6f06178e86e484d192f7a40b53df47e2ba0540d2e5a397d1e92b0221009833e3bb41c3bd28bc1adc06a74e5e7c73a6c9d9a1648ab558cfbdd380a2c4e2" + } + ], + "signed": { + "_type": "targets", + "delegations": { + "keys": { + "5e3a4021b11a425fd0a444f1670457ce5b15bbe036144f2417426f7f4b9721da": { + "keytype": "ecdsa", + "keyval": { + "public": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEVfei1dXQRVeArCMcTDgxJtYg+Fs7\nV87DjhQbGlRJPyC7SW5TbNNkmvpmi4LeTv6moLVZ7T2nVqiRZbSkD+cf8w==\n-----END PUBLIC KEY-----\n" + }, + "scheme": "ecdsa-sha2-nistp256", + "x-tuf-on-ci-online-uri": "azurekms://npm-tuf-delegate.vault.azure.net/keys/npm-tuf-delegate-2024-08/e2772c1d01ca400da571096889f1660e" + } + }, + "roles": [ + { + "keyids": [ + "5e3a4021b11a425fd0a444f1670457ce5b15bbe036144f2417426f7f4b9721da" + ], + "name": "registry.npmjs.org", + "paths": [ + "registry.npmjs.org/*" + ], + "terminating": true, + "threshold": 1 + } + ] + }, + "expires": "2034-08-24T07:16:33Z", + "spec_version": "1.0", + "targets": { + "artifact.pub": { + "custom": { + "sigstore": { + "status": "Active", + "usage": "Unknown" + } + }, + "hashes": { + "sha256": "59ebf97a9850aecec4bc39c1f5c1dc46e6490a6b5fd2a6cacdcac0c3a6fc4cbf", + "sha512": "308fd1d1d95d7f80aa33b837795251cc3e886792982275e062409e13e4e236ffc34d676682aa96fdc751414de99c864bf132dde71581fa651c6343905e3bf988" + }, + "length": 177 + }, + "ctfe.pub": { + "custom": { + "sigstore": { + "status": "Active", + "uri": "https://ctfe.sigstore.dev/test", + "usage": "CTFE" + } + }, + "hashes": { + "sha256": "7fcb94a5d0ed541260473b990b99a6c39864c1fb16f3f3e594a5a3cebbfe138a", + "sha512": "4b20747d1afe2544238ad38cc0cc3010921b177d60ac743767e0ef675b915489bd01a36606c0ff83c06448622d7160f0d866c83d20f0c0f44653dcc3f9aa0bd4" + }, + "length": 177 + }, + "ctfe_2022.pub": { + "custom": { + "sigstore": { + "status": "Active", + "uri": "https://ctfe.sigstore.dev/2022", + "usage": "CTFE" + } + }, + "hashes": { + "sha256": "270488a309d22e804eeb245493e87c667658d749006b9fee9cc614572d4fbbdc", + "sha512": "e83fa4f427b24ee7728637fad1b4aa45ebde2ba02751fa860694b1bb16059a490328f9985e51cc70e4d237545315a1bc866dc4fdeef2f6248d99cc7a6077bf85" + }, + "length": 178 + }, + "fulcio.crt.pem": { + "custom": { + "sigstore": { + "status": "Expired", + "uri": "https://fulcio.sigstore.dev", + "usage": "Fulcio" + } + }, + "hashes": { + "sha256": "f360c53b2e13495a628b9b8096455badcb6d375b185c4816d95a5d746ff29908", + "sha512": "0713252a7fd17f7f3ab12f88a64accf2eb14b8ad40ca711d7fe8b4ecba3b24db9e9dffadb997b196d3867b8f9ff217faf930d80e4dab4e235c7fc3f07be69224" + }, + "length": 744 + }, + "fulcio_intermediate_v1.crt.pem": { + "custom": { + "sigstore": { + "status": "Active", + "uri": "https://fulcio.sigstore.dev", + "usage": "Fulcio" + } + }, + "hashes": { + "sha256": "f8cbecf186db7714624a5f4e99da31a917cbef70a94dd6921f5c3ca969dfe30a", + "sha512": "0f99f47dbc26c5f1e3cba0bfd9af4245a26e5cb735d6ef005792ec7e603f66fdb897de985973a6e50940ca7eff5e1849719e967b5ad2dac74a29115a41cf6f21" + }, + "length": 789 + }, + "fulcio_v1.crt.pem": { + "custom": { + "sigstore": { + "status": "Active", + "uri": "https://fulcio.sigstore.dev", + "usage": "Fulcio" + } + }, + "hashes": { + "sha256": "f989aa23def87c549404eadba767768d2a3c8d6d30a8b793f9f518a8eafd2cf5", + "sha512": "f2e33a6dc208cee1f51d33bbea675ab0f0ced269617497985f9a0680689ee7073e4b6f8fef64c91bda590d30c129b3070dddce824c05bc165ac9802f0705cab6" + }, + "length": 740 + }, + "rekor.pub": { + "custom": { + "sigstore": { + "status": "Active", + "uri": "https://rekor.sigstore.dev", + "usage": "Rekor" + } + }, + "hashes": { + "sha256": "dce5ef715502ec9f3cdfd11f8cc384b31a6141023d3e7595e9908a81cb6241bd", + "sha512": "0ae7705e02db33e814329746a4a0e5603c5bdcd91c96d072158d71011a2695788866565a2fec0fe363eb72cbcaeda39e54c5fe8d416daf9f3101fdba4217ef35" + }, + "length": 178 + }, + "trusted_root.json": { + "hashes": { + "sha256": "4364d7724c04cc912ce2a6c45ed2610e8d8d1c4dc857fb500292738d4d9c8d2c", + "sha512": "fdebade075c4840d40f1806a14d0660ae1d22f47c0516abc4141e09f4ddf6ee6f4dbfbf08a7025bea10a4b8794658a4cd8ebb1024b963f239a9bfe02c2057fc6" + }, + "length": 7014 + } + }, + "version": 10, + "x-tuf-on-ci-expiry-period": 3650, + "x-tuf-on-ci-signing-period": 31 + } + } + recorded_at: Tue, 24 Sep 2024 19:32:14 GMT +recorded_with: VCR 6.3.1 diff --git a/vendor/cache/sigstore-ruby-ce93acf7fa7e/fixtures/vcr_cassettes/conformance/verify_signature_invalid.yml b/vendor/cache/sigstore-ruby-ce93acf7fa7e/fixtures/vcr_cassettes/conformance/verify_signature_invalid.yml new file mode 100644 index 00000000..64dd2853 --- /dev/null +++ b/vendor/cache/sigstore-ruby-ce93acf7fa7e/fixtures/vcr_cassettes/conformance/verify_signature_invalid.yml @@ -0,0 +1,518 @@ +--- +http_interactions: + - request: + method: get + uri: https://tuf-repo-cdn.sigstore.dev/11.root.json + body: + encoding: US-ASCII + string: "" + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + - RubyGems/3.4.19 arm64-darwin-23 Ruby/3.2.3 (2024-01-18 patchlevel 157) + Connection: + - keep-alive + Keep-Alive: + - "30" + response: + status: + code: 404 + message: Not Found + headers: + Content-Type: + - application/xml; charset=UTF-8 + Content-Length: + - "127" + X-Guploader-Uploadid: + - AD-8ljsftnYd4GzY6zZrYaP95G04zCNoQN0VU5Gz9f-kyOUmB3jyma18GuHaWLZrgi4yNWdGTt6kBUzAPA + Date: + - Tue, 24 Sep 2024 19:32:15 GMT + Expires: + - Tue, 24 Sep 2024 19:32:15 GMT + Cache-Control: + - private, max-age=0 + Server: + - UploadServer + Via: + - 1.1 google + Alt-Svc: + - h3=":443"; ma=2592000,h3-29=":443"; ma=2592000 + body: + encoding: UTF-8 + string: + "NoSuchKeyThe + specified key does not exist." + recorded_at: Tue, 24 Sep 2024 19:32:14 GMT + - request: + method: get + uri: https://tuf-repo-cdn.sigstore.dev/timestamp.json + body: + encoding: US-ASCII + string: "" + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + - RubyGems/3.4.19 arm64-darwin-23 Ruby/3.2.3 (2024-01-18 patchlevel 157) + Connection: + - keep-alive + Keep-Alive: + - "30" + response: + status: + code: 200 + message: OK + headers: + Date: + - Tue, 24 Sep 2024 19:32:15 GMT + Cache-Control: + - no-store + Expires: + - Wed, 24 Sep 2025 19:32:15 GMT + Last-Modified: + - Tue, 24 Sep 2024 13:30:21 GMT + Etag: + - '"7c6cbda4330af48fd1e23db82286e7ab"' + X-Goog-Generation: + - "1727184620932794" + X-Goog-Metageneration: + - "1" + X-Goog-Stored-Content-Encoding: + - identity + X-Goog-Stored-Content-Length: + - "449" + Content-Type: + - application/json + X-Goog-Hash: + - crc32c=709eSg== + - md5=fGy9pDMK9I/R4j24Iobnqw== + X-Goog-Storage-Class: + - STANDARD + Accept-Ranges: + - bytes + Content-Length: + - "449" + X-Guploader-Uploadid: + - AD-8ljs6ZeY1sAGOueTKElDsYifj7zyIn1vbjknJ60eCOOFu5P-zezhR0N8D4nFM9-qlPow7llNFDilZxw + Server: + - UploadServer + Via: + - 1.1 google + Alt-Svc: + - h3=":443"; ma=2592000,h3-29=":443"; ma=2592000 + body: + encoding: UTF-8 + string: |- + { + "signatures": [ + { + "keyid": "7247f0dbad85b147e1863bade761243cc785dcb7aa410e7105dd3d2b61a36d2c", + "sig": "304502204cbf8eedddcb8cd1f4d274ad202aad9162d85fb4c79ee4dff5ec1d08948e8191022100abe1569a87d13d40d4b563806c1694017332b7101fbaea377d4a0991a29a9065" + } + ], + "signed": { + "_type": "timestamp", + "expires": "2024-10-01T13:26:15Z", + "meta": { + "snapshot.json": { + "version": 156 + } + }, + "spec_version": "1.0", + "version": 224 + } + } + recorded_at: Tue, 24 Sep 2024 19:32:14 GMT + - request: + method: get + uri: https://tuf-repo-cdn.sigstore.dev/156.snapshot.json + body: + encoding: US-ASCII + string: "" + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + - RubyGems/3.4.19 arm64-darwin-23 Ruby/3.2.3 (2024-01-18 patchlevel 157) + Connection: + - keep-alive + Keep-Alive: + - "30" + response: + status: + code: 200 + message: OK + headers: + X-Goog-Generation: + - "1725380115625190" + X-Goog-Metageneration: + - "1" + X-Goog-Stored-Content-Encoding: + - identity + X-Goog-Stored-Content-Length: + - "1758" + X-Goog-Meta-Goog-Reserved-File-Mtime: + - "1725379916" + X-Goog-Hash: + - crc32c=KP+kcQ== + - md5=xVm/fgX6HzD6P9pEzgZ51Q== + X-Goog-Storage-Class: + - STANDARD + Accept-Ranges: + - bytes + Content-Length: + - "1758" + X-Guploader-Uploadid: + - AD-8ljuVnlyofdHPsb9q0-aPa9byMEep5AY_466v8T3dOT8LZfF_maLHZbnl8f8h1MWSvT32vv77slsFAQ + Server: + - UploadServer + Via: + - 1.1 google + Date: + - Tue, 24 Sep 2024 16:21:05 GMT + Cache-Control: + - public,max-age=86400 + Age: + - "11470" + Last-Modified: + - Tue, 24 Sep 2024 13:30:19 GMT + Etag: + - '"c559bf7e05fa1f30fa3fda44ce0679d5"' + Content-Type: + - application/json + Alt-Svc: + - h3=":443"; ma=2592000,h3-29=":443"; ma=2592000 + body: + encoding: UTF-8 + string: |- + { + "signatures": [ + { + "keyid": "7247f0dbad85b147e1863bade761243cc785dcb7aa410e7105dd3d2b61a36d2c", + "sig": "304402206566fd1ac98aae6c76e88d477201f8d6793d1df8655d5585f70cdfea16dfc46a022060fdeaafc754530606b4b78e2c273a8f6bed629345b8505e0380e722a8900450" + } + ], + "signed": { + "_type": "snapshot", + "expires": "2034-08-31T13:31:34Z", + "meta": { + "registry.npmjs.org.json": { + "version": 4 + }, + "rekor.json": { + "hashes": { + "sha256": "9d2e1a5842937d8e0d3e3759170b0ad15c56c5df36afc5cf73583ddd283a463b", + "sha512": "176e9e710ddddd1b357a7d7970831bae59763395a0c18976110cbd35b25e5412dc50f356ec421a7a30265670cf7aec9ed84ee944ba700ec2394b9c876645b960" + }, + "length": 797, + "version": 3 + }, + "revocation.json": { + "hashes": { + "sha256": "6f60848ba8fb0955a02abfd1232fb3845dc9ee9f418bf03521a7ddb48217e040", + "sha512": "a965dddd0d0edef6c59e84cf02ecf5a53299f633fd339b2b61814a4219ab4df672a6390f265b8b29e1c8cea9368ea3440df013790759d50231a30df1c1f02551" + }, + "length": 800, + "version": 2 + }, + "root.json": { + "hashes": { + "sha256": "f5ad897c9414cca99629f400ac3585e41bd8ebb44c5af07fb08dd636a9eced9c", + "sha512": "7445ddfdd338ef786c324fc3d68f75be28cb95b7fb581d2a383e3e5dde18aa17029a5636ec0a22e9631931bbcb34057788311718ea41e21e7cdd3c0de13ede42" + }, + "length": 5297, + "version": 2 + }, + "staging.json": { + "hashes": { + "sha256": "cda57759abac5375397eea3531d7ca51e3a67da9a2dc93f2cdab749e2ae73149", + "sha512": "e9e59587bde453144c7079884a880c706f1d43f26e8bb23fac2b96a99569a2a30ae6cf51ec51c2454f760ce83d4c20915e062aede7f319b3da6a6ed1d26ca281" + }, + "length": 401, + "version": 2 + }, + "targets.json": { + "version": 10 + } + }, + "spec_version": "1.0", + "version": 156 + } + } + recorded_at: Tue, 24 Sep 2024 19:32:14 GMT + - request: + method: get + uri: https://tuf-repo-cdn.sigstore.dev/10.targets.json + body: + encoding: US-ASCII + string: "" + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + - RubyGems/3.4.19 arm64-darwin-23 Ruby/3.2.3 (2024-01-18 patchlevel 157) + Connection: + - keep-alive + Keep-Alive: + - "30" + response: + status: + code: 200 + message: OK + headers: + X-Goog-Generation: + - "1725380115569153" + X-Goog-Metageneration: + - "1" + X-Goog-Stored-Content-Encoding: + - identity + X-Goog-Stored-Content-Length: + - "5624" + X-Goog-Meta-Goog-Reserved-File-Mtime: + - "1725379916" + X-Goog-Hash: + - crc32c=uBDWLw== + - md5=HDgoh6x8PE4twwByxqk9eg== + X-Goog-Storage-Class: + - STANDARD + Accept-Ranges: + - bytes + Content-Length: + - "5624" + X-Guploader-Uploadid: + - AD-8ljuqI0TCFNPAhR460l5rdARrrRdHJzvtdI_Iqshy_FcPX3swUKm4oT7MPCWUP8Fok9QUA3QcQ6YLiQ + Server: + - UploadServer + Via: + - 1.1 google + Date: + - Tue, 24 Sep 2024 16:21:05 GMT + Cache-Control: + - public,max-age=86400 + Age: + - "11470" + Last-Modified: + - Tue, 24 Sep 2024 13:30:19 GMT + Etag: + - '"1c382887ac7c3c4e2dc30072c6a93d7a"' + Content-Type: + - application/json + Alt-Svc: + - h3=":443"; ma=2592000,h3-29=":443"; ma=2592000 + body: + encoding: UTF-8 + string: |- + { + "signatures": [ + { + "keyid": "6f260089d5923daf20166ca657c543af618346ab971884a99962b01988bbe0c3", + "sig": "3045022100cffdd70aff94fab0127ac749c64449d5f644c7195971bfdca57879d5f645ab960220129ed6aeb07a57d9554af28941543bbb58f28c4c60d28a819f2294d290ff6cd9" + }, + { + "keyid": "e71a54d543835ba86adad9460379c7641fb8726d164ea766801a1c522aba7ea2", + "sig": "30450220208c663d230a0ebb3a2b964020d019394112e216d4964c743ad2e61cebc43b52022100c2964f3fa7e77cd3abe13640d91b53d1a294470b65211a42f3f7764064c28ce4" + }, + { + "keyid": "22f4caec6d8e6f9555af66b3d4c3cb06a3bb23fdc7e39c916c61f462e6f52b06", + "sig": "304502210093afa3a6d28f67f6aace8c6c5258282ec0784ce82da93589e2870b522c1b685502205374c8871e12e07f856f83e780b626dd5a00a032285d4436f615cdb9d637c3c3" + }, + { + "keyid": "61643838125b440b40db6942f5cb5a31c0dc04368316eb2aaa58b95904a58222", + "sig": "3044022006b5eae637d0b66f4f72759f86e86840f6a9a580b3baf7303a046d8fac1c0872022053c1b8a6fbce7e37a7e46501019a160f4d833efb48e7ca5bd274df54b2bbce3f" + }, + { + "keyid": "a687e5bf4fab82b0ee58d46e05c9535145a2c9afb458f43d42b45ca0fdce2a70", + "sig": "304502203d51eac2b34f6f06178e86e484d192f7a40b53df47e2ba0540d2e5a397d1e92b0221009833e3bb41c3bd28bc1adc06a74e5e7c73a6c9d9a1648ab558cfbdd380a2c4e2" + } + ], + "signed": { + "_type": "targets", + "delegations": { + "keys": { + "5e3a4021b11a425fd0a444f1670457ce5b15bbe036144f2417426f7f4b9721da": { + "keytype": "ecdsa", + "keyval": { + "public": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEVfei1dXQRVeArCMcTDgxJtYg+Fs7\nV87DjhQbGlRJPyC7SW5TbNNkmvpmi4LeTv6moLVZ7T2nVqiRZbSkD+cf8w==\n-----END PUBLIC KEY-----\n" + }, + "scheme": "ecdsa-sha2-nistp256", + "x-tuf-on-ci-online-uri": "azurekms://npm-tuf-delegate.vault.azure.net/keys/npm-tuf-delegate-2024-08/e2772c1d01ca400da571096889f1660e" + } + }, + "roles": [ + { + "keyids": [ + "5e3a4021b11a425fd0a444f1670457ce5b15bbe036144f2417426f7f4b9721da" + ], + "name": "registry.npmjs.org", + "paths": [ + "registry.npmjs.org/*" + ], + "terminating": true, + "threshold": 1 + } + ] + }, + "expires": "2034-08-24T07:16:33Z", + "spec_version": "1.0", + "targets": { + "artifact.pub": { + "custom": { + "sigstore": { + "status": "Active", + "usage": "Unknown" + } + }, + "hashes": { + "sha256": "59ebf97a9850aecec4bc39c1f5c1dc46e6490a6b5fd2a6cacdcac0c3a6fc4cbf", + "sha512": "308fd1d1d95d7f80aa33b837795251cc3e886792982275e062409e13e4e236ffc34d676682aa96fdc751414de99c864bf132dde71581fa651c6343905e3bf988" + }, + "length": 177 + }, + "ctfe.pub": { + "custom": { + "sigstore": { + "status": "Active", + "uri": "https://ctfe.sigstore.dev/test", + "usage": "CTFE" + } + }, + "hashes": { + "sha256": "7fcb94a5d0ed541260473b990b99a6c39864c1fb16f3f3e594a5a3cebbfe138a", + "sha512": "4b20747d1afe2544238ad38cc0cc3010921b177d60ac743767e0ef675b915489bd01a36606c0ff83c06448622d7160f0d866c83d20f0c0f44653dcc3f9aa0bd4" + }, + "length": 177 + }, + "ctfe_2022.pub": { + "custom": { + "sigstore": { + "status": "Active", + "uri": "https://ctfe.sigstore.dev/2022", + "usage": "CTFE" + } + }, + "hashes": { + "sha256": "270488a309d22e804eeb245493e87c667658d749006b9fee9cc614572d4fbbdc", + "sha512": "e83fa4f427b24ee7728637fad1b4aa45ebde2ba02751fa860694b1bb16059a490328f9985e51cc70e4d237545315a1bc866dc4fdeef2f6248d99cc7a6077bf85" + }, + "length": 178 + }, + "fulcio.crt.pem": { + "custom": { + "sigstore": { + "status": "Expired", + "uri": "https://fulcio.sigstore.dev", + "usage": "Fulcio" + } + }, + "hashes": { + "sha256": "f360c53b2e13495a628b9b8096455badcb6d375b185c4816d95a5d746ff29908", + "sha512": "0713252a7fd17f7f3ab12f88a64accf2eb14b8ad40ca711d7fe8b4ecba3b24db9e9dffadb997b196d3867b8f9ff217faf930d80e4dab4e235c7fc3f07be69224" + }, + "length": 744 + }, + "fulcio_intermediate_v1.crt.pem": { + "custom": { + "sigstore": { + "status": "Active", + "uri": "https://fulcio.sigstore.dev", + "usage": "Fulcio" + } + }, + "hashes": { + "sha256": "f8cbecf186db7714624a5f4e99da31a917cbef70a94dd6921f5c3ca969dfe30a", + "sha512": "0f99f47dbc26c5f1e3cba0bfd9af4245a26e5cb735d6ef005792ec7e603f66fdb897de985973a6e50940ca7eff5e1849719e967b5ad2dac74a29115a41cf6f21" + }, + "length": 789 + }, + "fulcio_v1.crt.pem": { + "custom": { + "sigstore": { + "status": "Active", + "uri": "https://fulcio.sigstore.dev", + "usage": "Fulcio" + } + }, + "hashes": { + "sha256": "f989aa23def87c549404eadba767768d2a3c8d6d30a8b793f9f518a8eafd2cf5", + "sha512": "f2e33a6dc208cee1f51d33bbea675ab0f0ced269617497985f9a0680689ee7073e4b6f8fef64c91bda590d30c129b3070dddce824c05bc165ac9802f0705cab6" + }, + "length": 740 + }, + "rekor.pub": { + "custom": { + "sigstore": { + "status": "Active", + "uri": "https://rekor.sigstore.dev", + "usage": "Rekor" + } + }, + "hashes": { + "sha256": "dce5ef715502ec9f3cdfd11f8cc384b31a6141023d3e7595e9908a81cb6241bd", + "sha512": "0ae7705e02db33e814329746a4a0e5603c5bdcd91c96d072158d71011a2695788866565a2fec0fe363eb72cbcaeda39e54c5fe8d416daf9f3101fdba4217ef35" + }, + "length": 178 + }, + "trusted_root.json": { + "hashes": { + "sha256": "4364d7724c04cc912ce2a6c45ed2610e8d8d1c4dc857fb500292738d4d9c8d2c", + "sha512": "fdebade075c4840d40f1806a14d0660ae1d22f47c0516abc4141e09f4ddf6ee6f4dbfbf08a7025bea10a4b8794658a4cd8ebb1024b963f239a9bfe02c2057fc6" + }, + "length": 7014 + } + }, + "version": 10, + "x-tuf-on-ci-expiry-period": 3650, + "x-tuf-on-ci-signing-period": 31 + } + } + recorded_at: Tue, 24 Sep 2024 19:32:14 GMT + - request: + method: post + uri: https://rekor.sigstore.dev/api/v1/log/entries/retrieve/ + body: + encoding: UTF-8 + string: '{"entries":[{"spec":{"signature":{"content":"MGYCMQC4JASdu7Gx4GHFMauOoAQTb5gUYIO1d8ruB2yDemDA66KJcaMrEqBdSMKjl86c4cwCMQCOs2PROY/qEwg/Wsra+taofoTE3y31FD4Ef2TAIb2uAvXCp0U1JQdc1qCteRS/veM=","publicKey":{"content":"LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUN4akNDQWt1Z0F3SUJBZ0lVRjQ3MHR4ZDFZOGErRE8vZ2ErTHdLMnBJeTJNd0NnWUlLb1pJemowRUF3TXcKTnpFVk1CTUdBMVVFQ2hNTWMybG5jM1J2Y21VdVpHVjJNUjR3SEFZRFZRUURFeFZ6YVdkemRHOXlaUzFwYm5SbApjbTFsWkdsaGRHVXdIaGNOTWpJeE1UQTRNRFV5TkRJeVdoY05Nakl4TVRBNE1EVXpOREl5V2pBQU1IWXdFQVlICktvWkl6ajBDQVFZRks0RUVBQ0lEWWdBRWN5cC8wUUZJbkNZaWlod2d5ZUtHUlhhbEdmMmZWSzZTQlk0eDhTcmcKQy9EZE5XMHdxUjRTVkNIREpSU2pHR1JuRWtOaGpWUk82NGxZK3pCRWVBSkFialNoNkRkdVJ6QnNJQVRFRWdlaQpFSFJKVFB3enFaTEU1ejNYRnJHREtyeTNvNElCVFRDQ0FVa3dEZ1lEVlIwUEFRSC9CQVFEQWdlQU1CTUdBMVVkCkpRUU1NQW9HQ0NzR0FRVUZCd01ETUIwR0ExVWREZ1FXQkJTOFRKbzIzd3BmRVVaaFlDLzhtT3N6V1JRSzB6QWYKQmdOVkhTTUVHREFXZ0JSeGhqQ21GSHhpYi9uMzF2UUZHbjlmLyt0dnJEQXFCZ05WSFJFQkFmOEVJREFlZ1J4aApiR1Y0TG1OaGJXVnliMjVBZEhKaGFXeHZabUpwZEhNdVkyOXRNQ2tHQ2lzR0FRUUJnNzh3QVFFRUcyaDBkSEJ6Ck9pOHZZV05qYjNWdWRITXVaMjl2WjJ4bExtTnZiVENCaWdZS0t3WUJCQUhXZVFJRUFnUjhCSG9BZUFCMkFDc3cKdk54b2lNbmk0ZGdtS1Y1MEgwZzVNWllDOHB3enkxNURRUDZ5cklaNkFBQUJoRld5V0tRQUFBUURBRWN3UlFJZwpWUzdvN1BmSXRHbHh4Y1Zwd2swa3lkMVBhUThhYW5PcEk3dE9ra0VnSDNBQ0lRRFN6bFhnY0NuQWlXRnVEZ3NmClpTR1FCWHFnaEFFWFRuaWxQZThFTTlZMVREQUtCZ2dxaGtqT1BRUURBd05wQURCbUFqRUE1dU4zZkRhN3BrUTYKZFRNS29yd2ZHMk9wcXdaRHZOVzNFKytUM3FWd3pNNVh3aEhVYWoxVytaQ25WdjU0TUkwOEFqRUE2aXJoY2gxSgplRWZ4VkMzV3RWZmtYbUNHQ3UxQU1mUkdFT08wdUpBYllsNE9HQ2NwRlVtV0hEZW1HZlVwYlJFVgotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg=="}},"data":{"hash":{"algorithm":"sha256","value":"a0cfc71271d6e278e57cd332ff957c3f7043fdda354c4cbb190a30d56efa01bf"}}},"kind":"hashedrekord","apiVersion":"0.0.1"}]}' + headers: + Content-Type: + - application/json + Accept: + - application/json + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + User-Agent: + - Ruby + response: + status: + code: 200 + message: OK + headers: + Content-Type: + - application/json + Vary: + - Origin + Date: + - Tue, 24 Sep 2024 19:32:15 GMT + Content-Length: + - "3" + Via: + - 1.1 google + Alt-Svc: + - h3=":443"; ma=2592000,h3-29=":443"; ma=2592000 + body: + encoding: UTF-8 + string: "[]\n" + recorded_at: Tue, 24 Sep 2024 19:32:14 GMT +recorded_with: VCR 6.3.1 diff --git a/vendor/cache/sigstore-ruby-ce93acf7fa7e/fixtures/vcr_cassettes/conformance/verify_signature_success.yml b/vendor/cache/sigstore-ruby-ce93acf7fa7e/fixtures/vcr_cassettes/conformance/verify_signature_success.yml new file mode 100644 index 00000000..96a9b1c9 --- /dev/null +++ b/vendor/cache/sigstore-ruby-ce93acf7fa7e/fixtures/vcr_cassettes/conformance/verify_signature_success.yml @@ -0,0 +1,40 @@ +--- +http_interactions: +- request: + method: post + uri: https://rekor.sigstore.dev/api/v1/log/entries/retrieve/ + body: + encoding: UTF-8 + string: '{"entries":[{"spec":{"signature":{"content":"MEUCIBlwAPA5TYC4gUIsHMX2HFLZvTmBkOBASBZ+mHIZaVnnAiEA5DU7iwJfF/qC/y7z0h1Olpz2HWnqCWnNhZ3NFdYmUI0=","publicKey":{"content":"LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUlNRENDQjdhZ0F3SUJBZ0lVYVVIWGowUzRaTkVFakR4YVhselB3L1ZZUVE0d0NnWUlLb1pJemowRUF3TXcKTnpFVk1CTUdBMVVFQ2hNTWMybG5jM1J2Y21VdVpHVjJNUjR3SEFZRFZRUURFeFZ6YVdkemRHOXlaUzFwYm5SbApjbTFsWkdsaGRHVXdIaGNOTWpNd09USTNNVFl3TkRRd1doY05Nak13T1RJM01UWXhORFF3V2pBQU1Ga3dFd1lICktvWkl6ajBDQVFZSUtvWkl6ajBEQVFjRFFnQUVhZDBVaDZ0d0UzeDhZQWJmQm1lMFQvRzBWMnh4SWwwcncvdVkKOEdmYW1QclFrM0F6VzliL1R3UU10aXB5VFkyR0FQREM3U1ZiWlR4R0JkNkJ0VFdVbXFPQ0J0VXdnZ2JSTUE0RwpBMVVkRHdFQi93UUVBd0lIZ0RBVEJnTlZIU1VFRERBS0JnZ3JCZ0VGQlFjREF6QWRCZ05WSFE0RUZnUVVPaXpVCmRVUHZtV0RTQjhMdE9qcGp5TE5LZ00wd0h3WURWUjBqQkJnd0ZvQVUzOVBwejFZa0VaYjVxTmpwS0ZXaXhpNFkKWkQ4d2dhVUdBMVVkRVFFQi93U0JtakNCbDRhQmxHaDBkSEJ6T2k4dloybDBhSFZpTG1OdmJTOXphV2R6ZEc5eQpaUzFqYjI1bWIzSnRZVzVqWlM5bGVIUnlaVzFsYkhrdFpHRnVaMlZ5YjNWekxYQjFZbXhwWXkxdmFXUmpMV0psCllXTnZiaTh1WjJsMGFIVmlMM2R2Y210bWJHOTNjeTlsZUhSeVpXMWxiSGt0WkdGdVoyVnliM1Z6TFc5cFpHTXQKWW1WaFkyOXVMbmx0YkVCeVpXWnpMMmhsWVdSekwyMWhhVzR3T1FZS0t3WUJCQUdEdnpBQkFRUXJhSFIwY0hNNgpMeTkwYjJ0bGJpNWhZM1JwYjI1ekxtZHBkR2gxWW5WelpYSmpiMjUwWlc1MExtTnZiVEFmQmdvckJnRUVBWU8vCk1BRUNCQkYzYjNKclpteHZkMTlrYVhOd1lYUmphREEyQmdvckJnRUVBWU8vTUFFREJDaG1aVGRoWkdVNU1XWTAKWXpSa05EWmpaVGM1T0RnMlptRTRNR1JtT0RBd05tRXpabUZsT1dVeU1DMEdDaXNHQVFRQmc3OHdBUVFFSDBWNApkSEpsYldWc2VTQmtZVzVuWlhKdmRYTWdUMGxFUXlCaVpXRmpiMjR3U1FZS0t3WUJCQUdEdnpBQkJRUTdjMmxuCmMzUnZjbVV0WTI5dVptOXliV0Z1WTJVdlpYaDBjbVZ0Wld4NUxXUmhibWRsY205MWN5MXdkV0pzYVdNdGIybGsKWXkxaVpXRmpiMjR3SFFZS0t3WUJCQUdEdnpBQkJnUVBjbVZtY3k5b1pXRmtjeTl0WVdsdU1Ec0dDaXNHQVFRQgpnNzh3QVFnRUxRd3JhSFIwY0hNNkx5OTBiMnRsYmk1aFkzUnBiMjV6TG1kcGRHaDFZblZ6WlhKamIyNTBaVzUwCkxtTnZiVENCcGdZS0t3WUJCQUdEdnpBQkNRU0Jsd3lCbEdoMGRIQnpPaTh2WjJsMGFIVmlMbU52YlM5emFXZHoKZEc5eVpTMWpiMjVtYjNKdFlXNWpaUzlsZUhSeVpXMWxiSGt0WkdGdVoyVnliM1Z6TFhCMVlteHBZeTF2YVdSagpMV0psWVdOdmJpOHVaMmwwYUhWaUwzZHZjbXRtYkc5M2N5OWxlSFJ5WlcxbGJIa3RaR0Z1WjJWeWIzVnpMVzlwClpHTXRZbVZoWTI5dUxubHRiRUJ5WldaekwyaGxZV1J6TDIxaGFXNHdPQVlLS3dZQkJBR0R2ekFCQ2dRcURDaG0KWlRkaFpHVTVNV1kwWXpSa05EWmpaVGM1T0RnMlptRTRNR1JtT0RBd05tRXpabUZsT1dVeU1CMEdDaXNHQVFRQgpnNzh3QVFzRUR3d05aMmwwYUhWaUxXaHZjM1JsWkRCZUJnb3JCZ0VFQVlPL01BRU1CRkFNVG1oMGRIQnpPaTh2CloybDBhSFZpTG1OdmJTOXphV2R6ZEc5eVpTMWpiMjVtYjNKdFlXNWpaUzlsZUhSeVpXMWxiSGt0WkdGdVoyVnkKYjNWekxYQjFZbXhwWXkxdmFXUmpMV0psWVdOdmJqQTRCZ29yQmdFRUFZTy9NQUVOQkNvTUtHWmxOMkZrWlRreApaalJqTkdRME5tTmxOems0T0RabVlUZ3daR1k0TURBMllUTm1ZV1U1WlRJd0h3WUtLd1lCQkFHRHZ6QUJEZ1FSCkRBOXlaV1p6TDJobFlXUnpMMjFoYVc0d0dRWUtLd1lCQkFHRHZ6QUJEd1FMREFrMk16STFPVFk0T1Rjd053WUsKS3dZQkJBR0R2ekFCRUFRcERDZG9kSFJ3Y3pvdkwyZHBkR2gxWWk1amIyMHZjMmxuYzNSdmNtVXRZMjl1Wm05eQpiV0Z1WTJVd0dRWUtLd1lCQkFHRHZ6QUJFUVFMREFreE16RTRNRFExTmpNd2dhWUdDaXNHQVFRQmc3OHdBUklFCmdaY01nWlJvZEhSd2N6b3ZMMmRwZEdoMVlpNWpiMjB2YzJsbmMzUnZjbVV0WTI5dVptOXliV0Z1WTJVdlpYaDAKY21WdFpXeDVMV1JoYm1kbGNtOTFjeTF3ZFdKc2FXTXRiMmxrWXkxaVpXRmpiMjR2TG1kcGRHaDFZaTkzYjNKcgpabXh2ZDNNdlpYaDBjbVZ0Wld4NUxXUmhibWRsY205MWN5MXZhV1JqTFdKbFlXTnZiaTU1Yld4QWNtVm1jeTlvClpXRmtjeTl0WVdsdU1EZ0dDaXNHQVFRQmc3OHdBUk1FS2d3b1ptVTNZV1JsT1RGbU5HTTBaRFEyWTJVM09UZzQKTm1aaE9EQmtaamd3TURaaE0yWmhaVGxsTWpBaEJnb3JCZ0VFQVlPL01BRVVCQk1NRVhkdmNtdG1iRzkzWDJScApjM0JoZEdOb01JR0JCZ29yQmdFRUFZTy9NQUVWQkhNTWNXaDBkSEJ6T2k4dloybDBhSFZpTG1OdmJTOXphV2R6CmRHOXlaUzFqYjI1bWIzSnRZVzVqWlM5bGVIUnlaVzFsYkhrdFpHRnVaMlZ5YjNWekxYQjFZbXhwWXkxdmFXUmoKTFdKbFlXTnZiaTloWTNScGIyNXpMM0oxYm5Ndk5qTXlPRFE1T1RJMk15OWhkSFJsYlhCMGN5OHhNQllHQ2lzRwpBUVFCZzc4d0FSWUVDQXdHY0hWaWJHbGpNSUdKQmdvckJnRUVBZFo1QWdRQ0JIc0VlUUIzQUhVQTNUMHdhc2JICkVUSmpHUjRjbVdjM0FxSktYcmplUEszL2g0cHlnQzhwN280QUFBR0sxMktrc2dBQUJBTUFSakJFQWlCLzczR0sKdjlhM0NkVzR1QmtXaE53MVcwWUNlTHVCTFJpL1B2NnlyQVNWcHdJZ09ySzhMMnViYUxuWFNXQWlLNzZvRG1tSgoxTWFIS0dhblN1aDEzcHhXNGZnd0NnWUlLb1pJemowRUF3TURhQUF3WlFJd2FHMThEZndDaFRYOWhQQS9XQURhCmk5V2g5aTNoRVNvNU5peG9mZi83MUF0TXdFVGZCRHUyTVZOM2xxbzhvNzNOQWpFQXhlZDhoTHhpSmR4bVozWkEKWFBPYXJ6bUZUWkxQQzc5NCtpMTVpN1JxSW5zWjQ5RnRVVkxqSHV2Y2NJTlpMNjNZCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K"}},"data":{"hash":{"algorithm":"sha256","value":"a0cfc71271d6e278e57cd332ff957c3f7043fdda354c4cbb190a30d56efa01bf"}}},"kind":"hashedrekord","apiVersion":"0.0.1"}]}' + headers: + Content-Type: + - application/json + Accept: + - application/json + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + User-Agent: + - Ruby + response: + status: + code: 200 + message: OK + headers: + Content-Type: + - application/json + Vary: + - Origin + Date: + - Tue, 24 Sep 2024 19:32:15 GMT + Via: + - 1.1 google + Alt-Svc: + - h3=":443"; ma=2592000,h3-29=":443"; ma=2592000 + Transfer-Encoding: + - chunked + body: + encoding: ASCII-8BIT + string: !binary |- + W3siMjQyOTZmYjI0YjhhZDc3YTUxNDgwNGFkMDM5MDA3ZDg2NmRjNzJiMzY3ZjJhYWI2Mzc4YTM1ZjFiNTNjNDVkMTk4OGQ1ZWI2NTBhNzk1MGIiOnsiYm9keSI6ImV5SmhjR2xXWlhKemFXOXVJam9pTUM0d0xqRWlMQ0pyYVc1a0lqb2lhR0Z6YUdWa2NtVnJiM0prSWl3aWMzQmxZeUk2ZXlKa1lYUmhJanA3SW1oaGMyZ2lPbnNpWVd4bmIzSnBkR2h0SWpvaWMyaGhNalUySWl3aWRtRnNkV1VpT2lKaE1HTm1ZemN4TWpjeFpEWmxNamM0WlRVM1kyUXpNekptWmprMU4yTXpaamN3TkRObVpHUmhNelUwWXpSalltSXhPVEJoTXpCa05UWmxabUV3TVdKbUluMTlMQ0p6YVdkdVlYUjFjbVVpT25zaVkyOXVkR1Z1ZENJNklrMUZWVU5KUW14M1FWQkJOVlJaUXpSblZVbHpTRTFZTWtoR1RGcDJWRzFDYTA5Q1FWTkNXaXR0U0VsYVlWWnVia0ZwUlVFMVJGVTNhWGRLWmtZdmNVTXZlVGQ2TUdneFQyeHdlakpJVjI1eFExZHVUbWhhTTA1R1pGbHRWVWt3UFNJc0luQjFZbXhwWTB0bGVTSTZleUpqYjI1MFpXNTBJam9pVEZNd2RFeFRNVU5TVldSS1ZHbENSRkpXU2xWVFZWcEtVVEJHVlZKVE1IUk1VekIwUTJzeFNsTlZiRTVTUlU1RVVXcGthRm93UmpOVFZVcENXakJzVmxsV1ZrbFhSMjkzVlhwU1lWUnJWa1poYTFJMFdWWm9jMlZzUWpOTU1WcGFWVlpGTUdRd1RtNVhWV3hNWWpGd1NtVnRiM2RTVlVZelZGaGpTMVJ1Y0VaV2F6RkRWRlZrUWsxV1ZrWlJNbWhPVkZkTmVXSkhOV3BOTVVveVdUSXhWbVJXY0VoV2FrcE9WV3BTTTFORlJscFNSbHBTVlZWU1JtVkdXalpaVm1SclpXMVNTRTlZYkdGVmVrWjNXVzAxVTJKQmNHcGlWRVp6VjJ0a2MyRkhVa2hXV0dSSllVZE9UMVJYY0U1a01EbFZVMVJPVGxaR2JETlVhMUpTWkRGa2Ixa3dOVTVoYXpFelZERlNTazB3TVZWWFdHaFBVa1pHTTFZeWNFSlJWVEZIWVROa1JtUXhiRWxEYTNSMlYydHNObUZxUWtSUlZrWmFVMVYwZGxkcmJEWmhha0pGVVZaR2FsSkdSbTVSVlZab1drUkNWbUZFV2pCa01GVjZaVVJvV2xGWFNtMVJiVEZzVFVaUmRsSjZRbGROYm1nMFUxZDNkMk51WTNaa1ZtdExUMFZrYlZsWE1WRmpiRVp5VFRCR05sWjZiR2xNTVZJelZWVXhNR0ZZUWpWV1JtdDVVakJHVVZKRlRUTlZNVnBwVjJ4U05GSXdTbXRPYTBvd1ZrWmtWbUpZUmxCUk1Fb3dWbGhrYmxveVNsTlVWVVV3VW5kd1FrMVdWbXRTU0dSR1VXazVNMVZWVmtKa01HeEpXakJTUWxaRlNtNVViRnBKVlRGV1JsSkZVa0pUTUVwdVdqTktRMW93VmtkUmJFWnFVa1ZHTmxGWFVrTmFNRFZYVTBaRk1GSlZXbTVWVmxaUVlWaHdWa050VWxaVlNGcDBWakJTVkZGcWFFMWtSVGx4WTBkd05WUkZOVXhhTURCM1pEQm9NMWRWVWxkVmFrSnhVV3RLYm1Rd1duWlJWbFY2VDFaQ2QyVnFSbHBoTUZaaFdXcFdlRlJ0Y0hkVE1GcFlZVmhvY0U1R2EwdFhhMUUwWkRKa2FGWlZaRUpOVmxaclVsWkdSbEZwT1ROVk1FcDBZV3RPUTJKRVVtaFJiWGhJWVVSQ2ExTkZTalpVTW1zMFpHeHZlV0pFUW1oVFJscHdWRWN4VDJSdFNsUlBXSEJvVmpKU05scEZZelZsVVhCaFZYcEdjVmxxU1RGaVYwbDZVMjVTV2xaNlZuRlhiRTAxWWtkV1NWVnViR0ZXZWtaeldXdG9jbVJHY0VoU2JsWmhUV3hhTlZscVRsZGxhM2haVVdwR1dtSllhSGRYV0d0NFpHMUdXRlZ0Y0UxV01IQnpRMnhzV0ZSdVdtbGhWR2d4VjJwS2MwMUhSa2xXYld4TlRUSlNNbGt5TVRCaVYwcElUMVJPYW1WVWJITmFWV2hUWlZad1dFMVhlR2xUUjNRd1YydGtSMlJXYjNsV2JteHBUVEZhTmxSR1l6VmpSbkJJVkZoUlMxZFhNVmRoUm10NVQxaFdUV0p0ZURCWmExWkRaVlp3V0ZkdWNFMU5iV2h6VjFaa1UyVnJkM2xOVjJob1ZucFNNMVF4UmxwVE1IUXpWMVZLUTFGVlpFVmtibkJDVVd0R1VsVllTbWhUUmtsM1dUQm9UazVuY0UxbFZHdDNXV3BLTUdKSFNuQk9WMmhhVFRGS2QxbHFTVEZsYTNoMFdraENhMUl5WjNoWFZ6VlhaV3h3V1ZOdGNHbE5hbFYzVjJ4ak1VMUZlSFJVYmxwcFZrVkdiVkZ0WkhaamEwcHVVbFZXUWxkVk9IWkRhekZDVWxWT1ExRnJXWHBaYWs1TFkyeHdkR1ZJV210TlZHeHlXVlpvVDJReGJGbFZiWEJvVWtWRmVWRnRaSFpqYTBwdVVsVldRbGRWT0haVVZVWkdVa1ZLUkdGSE1XRldSMUp2VjJ0a1ZrNVZNVmhYVkVGTFYxaHdVMkV3TlVWWGJYQmhWa2ROTVZRd1VtNU5iSEIwVWxSU1RsSXhTblJVTUZKQ1pEQTFkRkpZY0dGaVZWcHpWREZrVm1WVk1VUk5SV1JFWVZoT1NGRldSbEpSYldNelQwaGtRbFZXUmtaVFJFSlhUa0Z3YTFORmNITlpiR1JYWXpKV1ZGRnRkRnBXZWxaMVYyeG9TMlJ0VWxsVVYyUlZUVWQ0UmxWWWJFTmhWbkJZVW0xd2FVMXFVak5WTVVaYVV6QjBNMWRWU2tOUlZXUkZaRzV3UWxGclNsSlZWR1JxVFcxNGRVTnRUWHBWYmxwcVlsWldNRmRVU1RWa1ZuQjBUMWhzYVZZd1dqRlhWRXBXWkd4d1dXRkVRbXBpVmxvd1YyeGtORTVWZUZoVmJXaHBZbGRTYzFreU1EVk5WMDQxVFZoa2ExWXdjSHBaVm1ST1pFZEplV0pIYzB0WFdHdDRZVlp3V0ZKdGNHbE5hbEl6VTBaR1dsTXdkRE5YVlVwRFVWVmtSV1J1Y0VKUmEwcHVWVlpDYW1KV1duUlpNMnMxWWpGd1dGSnRkR3BsVkd3d1YxWmtjMlJWTVVWak1HUkVZVmhPU0ZGV1JsSlJaM0J1VG5wb00xRldSbTVTVlhoU1pETkthRk5HU1hkWk1HaE9UbXQ0TlU5VVFtbE5ibEp6V1cxck1XRkdhM3BWYmtKcFRXcFdObFJITVd0alIxSklZVVJHV21Kc1dqWlhiR2hMWVcxSmVVNVVRbUZXZWxWM1EydDRkRlJ1V21sV1JVNURZMGRrV2xNd2RETlhWVXBEVVZWa1JXUnVjRUpSYTA1U1ZUQktjMlF6YkVOaVJXUnZUVWRTU1ZGdWNGQmhWR2d5VjJwS2MwMUhSa2xXYld4TllsVTFNbGxzVFRWbGJVWllXa2h2UzFwRll6VmxWbkJVVFZkd2FVMXFWblJaYWs1TFpFWnNXRTVYY0dGVmVteHpXbFZvVTJWV2NGaE5WM2hwVTBkME1GZHJaRWRrVm05NVZtNXNhVTB4V2paVVJtaERUVlpzZEdWSVFscGxWRVl5V1Zaa1UyRm5jRTFXTUhCelYxWmtUMlJ0U25CUFNGWmhUVzEzZDFsVmFGZGhWWGQ2V2toYWFtSllVblJaYTJNMVRUSk9OVTlYZUd4VFJrbzFWMnhqZUdKSFNrbGhNMUpoVWpCYU1WZHFTbGRsVjBsNlZtNXdUVlo2YkhkRGJIQklWRmhTV21KV1dtOVhWRWsxWkZWNGRXSklVbWxTVlVvMVYyeGtZV1ZyZDNsaFIzaGFWakZLTmxSRVNYaGhSMFpZVGtoa1VGRldiRXhUTTJSYVVXdEtRbEl3VWpKbGEwWkRVVEprVW1OVlVrUmhSekJMVjJ4U2EyRkdjRWhXVkZaT1ZqRnJkMWRZY0ZOaE1EVkZWMjF3WVZaSFRURlVNRkp1VFd4d2RGSlVVazVTTVVwMFZEQlNRbVF3TlhSU1dIQmhZbFZhYzFReFpGWmxWVEZEVFVWa1JHRllUa2hSVmtaU1VXZHdiazU2YUROUlZrWjZVbFZTTTJRd05XRk5iWGQzV1ZWb1YyRlZlRmhoU0ZwcVRURktjMWRyVWtOYVZVcHVZak5LUTFvd1ZrWlJWbXhRVERBeFFsSlZNVU5TYTBaT1ZrY3hiMDFIVWtsUmJuQlFZVlJvTWtOc2IzbGlSRUpvVTBaYWNGUkhNVTlrYlVwVVQxaHdhRll5VWpaYVJXTTFaVlp3VkUxWGNHbE5hbFowV1dwT1MyUkdiRmhPVjNCaFZYcHNjMXBWYUZObFZuQllUVmQ0YVZOSGREQlhhMlJIWkZadmVWWnVhMHRaYWs1WFpXdDRXVkZxUmxwaVdHaDNWMWhyZUdSdFJsaFZiWEJOVmpCd2MxZFdaRTlrYlVweFVWUlNRMW95T1hsUmJXUkdVbFZHV2xSNU9VNVJWVlpQVVd0T2RsUlZkRWhYYlhoUFRXdGFjbGRzVW5KbFFYQmhZV3hLY1ZSclpGSk5SVFYwVkcxNFQyVnRjekJVTUZKaFlsWnNWVm96WkdGU01Xc3dWRlZTUWsxc2JGVlViVEZhVmpGVk1WZHNVa3BrTUdnelYxVjBUR1F4YkVOUmEwWklVa2hhTmxGVlNrVmFNVVpUUTJ0U1FrOVliR0ZXTVhBMlZFUktiMkpHYkZoVmJuQk5UV3BHYjFsV1l6QmtNR1JTVjFWMFRHUXhiRU5SYTBaSVVraGFObEZWU2tWa01VWk5Va1ZHY2sxck1UWlRWRVpRVmtack1GUXhVbXBrTURVelYxVnpTMU16WkZwUmEwcENVakJTTW1WclJrTlNWVVpTWTBWU1JGcEhPV3RUUmtveldUTndkbVJyZDNsYVNFSnJVakpuZUZkWGF6RmhiVWw1VFVoYWFrMXRlSFZaZWs1VFpHMU9kRlpZVWxwTmFtd3hWMjB3TldWUmNHbFdNRm94VjFSS1ZtUXdaRkpYVlhSTVpERnNRMUZyUmtoU1NGbzJVVlZLUmxWV1JrMVNSVVp5WlVVeE5sSlVVazVTUmtWNFZHMXdUbVF5WkdoWFZXUkVZVmhPU0ZGV1JsSlJiV016VDBoa1FsVnJiRVpEYldSaFdUQXhibGRzU25aYVJXaFRaREpPTm1JeldrMU5iVkozV2tWa2IwMVdiSEJPVjNCcFRXcENNbGw2U25OaWJVMTZWVzVhYW1KV1ZqQlhWRWsxWkZad2RFOVliR2xXTUZveFYxUktWbVJzY0ZsaFJFRkxXVEl4VjJSR2NGaGxSRlpOVmpGS2IxbHRNV3RpUjA1MFQxUkdhbVZVUmpOYVJtUkxZekpHV0ZSWVVtbE5iWGh5VjFocmVHRldjRmhTYlhCcFRXcFNNbFJITVd0alIxSklZVVJHV21GVWEzcFphazVMWTJkd1lXSllhREphUkU1T1pHeHdXV0ZFUW1waVZsb3dWMnhrTkU1VmVGaFZiV2hwWWxkU2Mxa3lNRFZOVjA0MVRWaGFhRll4U25GVVJtUkxZa1pzV0ZSdVdtbGhWRlV4V1d4a05GRlhUblJXYlRGcVpWUnNka05zY0ZoU2JYUnFaVlJzTUZkV1pITmtWVEZGV2pCa1JHRllUa2hSVmtaU1VXMWpNMDlJWkVKVmF6RkdVekprTTJJeGNIUldWRTVhVmpGS2MxUXhVa2RpVlRWSVZGUkNZVkpHUlhsWFZFcFdUVEE1VlZwNlVVdFViVEZoWVVVNVJWRnRkR0ZoYldRelZGVlNZV0ZGTUhsWGJXaGhWa2Q0YzFSWGNFSmhSVXB1WWpOS1Exb3dWa1pSVm14UVREQXhRbEpXVmtOUmF6Rk9VbFpvYTJSdFRuUmtSekZwVW5wcmVsZEVTbE5qUVhCcVRUQktiMXBGWkU5aU1ERktVakJLUTFveU9YbFJiV1JHVWxWR1dsUjVPVTVSVlZaWFVXdG9UbFJYVGxoaFJFSnJVMFZLTmxReWF6UmtiRzk1WWtSQ2FGTkdXbkJVUnpGUFpHMUtWRTlZY0doV01sSTJRMjFTU0U5WWJHRlZla1p4V1dwSk1XSlhTWHBUYmxKYVZucFdjVmRzVFRWaVIxWkpWVzVzWVZaNlJuTlphMmh5WkVad1NGSnVWbUZOYkZvMVdXcE9WMlZyZUZsUmFrWmFZbGhvZDFkWWEzaGtiVVpZVlcxdlMxUkdaRXRpUm14WVZHNWFhV0ZVYkc5WFZFNVRZMGRKZVU1WWNFMU5NRzk0V1cwMVRtUnJOWEZVV0d4UVVrWkZNVlF4VWtwTmF6RTFUMWRvYTFOR1NuTlpiR2hEVFVkT05VOUlhRTVSYkd4SVVUSnNlbEozY0VKVlZrWkRXbnBqTkdRd1JsTlhWVlpFVVZoa1NGa3dhRmRoVjBwSVlrZHdUbE5WWkV0UmJXUjJZMnRLYmxKVlZrSmFSbTh4VVZka1VsRXdTa2xqTUZac1ZWVkplbEZWYUZaUlZFNVZUVWhrYUdNeVNrbERhMVpWVTIxd1NGVnFVbXBpVm1ScVRUQkdlRk5yZEZsamJYQnNWVVZ6ZWt3eVp6QmpTR3h1VVhwb2QwNHlPREJSVlVaQ1VqQnplRTFyZEhKak1tUkNVVlZLUWxSVlJsTmhhMHBHVVZkc1EweDZZM3BTTUhOTFpHcHNhRTB3VG10V2VsSXhVVzEwV0dGRk5UTk5WbU4zVjFWT2JGUklWa05VUmtwd1RERkNNazV1YkhsUlZrNVhZMGhrU2xvd09YbFRlbWhOVFc1V2FWbFZlSFZYUms1WVVWZHNURTU2V25aU1J6RjBVMmR2ZUZSWFJrbFRNR1JvWW14T01XRkVSWHBqU0doWVRrZGFibVF3VG01WFZXeE1ZakZ3U21WdGIzZFNWVVl6VkZWU2FGRlZSak5YYkVaS1pESkdTRTFVYUVWYWJtUkVZVVpTV1U5WGFGRlJVemxZVVZWU2FFTnRhelZXTW1jMVlWUk9iMUpXVG5aT1ZUVndaVWM1YlZwcE9ETk5WVVl3VkZoa1JsWkhXa05TU0ZWNVZGWmFUMDB5ZUhoaWVtaDJUbnBPVDFGWGNFWlJXR2hzV2tSb2IxUklhSEJUYlZJMFlsWnZlbGRyUlV0WFJrSlFXVmhLTm1KVldsVlhhM2hSVVhwak5VNURkSEJOVkZad1RqRktlRk5YTlhwWGFsRTFVbTVTVmxacmVIRlRTRll5V1RKT1NsUnNjRTFPYWs1YVEya3dkRXhUTUhSU1ZUVkZTVVZPUmxWc1VrcFNhMnhFVVZaU1JreFRNSFJNVXpCTEluMTlmWDA9IiwiaW50ZWdyYXRlZFRpbWUiOjE2OTU4MzA2ODEsImxvZ0lEIjoiYzBkMjNkNmFkNDA2OTczZjk1NTlmM2JhMmQxY2EwMWY4NDE0N2Q4ZmZjNWI4NDQ1YzIyNGY5OGI5NTkxODAxZCIsImxvZ0luZGV4IjozODk2NjEyNCwidmVyaWZpY2F0aW9uIjp7ImluY2x1c2lvblByb29mIjp7ImNoZWNrcG9pbnQiOiJyZWtvci5zaWdzdG9yZS5kZXYgLSAyNjA1NzM2NjcwOTcyNzk0NzQ2XG4xMTc3NDA4MzFcbks1eFhnSEhoSUtxRXlZV0hnOXFtY1ZaZVFXWHpwOStobWFyWUdVQXBuWTQ9XG5cbuKAlCByZWtvci5zaWdzdG9yZS5kZXYgd05JOWFqQkZBaUF4UXhZZnROMCtrcVAwazBGMHIrdWNSelpTQlA5K3ZjL002Z3ZRUTkxdlpnSWhBSzRrbmpOTzZCZFJ3ZUQ1bFNITU0vRlhHbmhHVEEzcHg2MEhUc28rSjlnTlxuIiwiaGFzaGVzIjpbImYzNzAyYmJlNWFjZTYxOTZlZTM2NzMxNjNhMjNlNzM3YmZkZDRlODg4NjZhMjgyOTEwNzg1MzU3M2ViNzQwYjQiLCI0MzQ4ZWViZmJmNjdiMWFlYzU2MzY1MWUzOTljY2RjODQ4MTI3Nzc4NjdkNGU0MjRlZDgwNmE2Njc5OTg3NmJkIiwiZjAzNzM4YWI2M2Q2MDBkOTg5YWY5NTZkZTE2MjdkYTZlNzQwOTY5M2U2OGZkMDRhMjU3OWYwZWQ0MWJkZjE5OSIsIjk5NmJlYWI3ZWVkNzhkY2MyOWMxNjI1ODk4ZGEzZjgyZDExZTYyNDQ0OWRlY2ZlMDMxYmRiNWRjNGZjMGQ4MWQiLCJkM2M5MTU5NDA4ODEwNTBmNWJjOWU0MGNjMDQyNTZjMTRmYjE3NjJjODE3OTEzYTVjNzdlOWU4MTM2OWIxODI1IiwiZGEzMzBlYzgxOTI2OThhMzUzMWVjMDJiNWM0ZjA5MmUzODZkNTBiNTAwYmI3MDcwMThlMzg5NjRiMDIzNTE3MCIsImIzZGQ4MDZlOGJlN2IyMmJiMzMyNDdiOWUzMmYzY2JlYWNlOTAxMmJlYTg2ZGM0ZTIwN2MzYTdjZTk2ZmNmMmQiLCIxYjJmZGYxZTkzODZmODAyZDMyYjUzZWNlOTA1NTI5ZGM4NGUwZjY4YWVhZjEyYjU4NzM1MTVkMjJhYTYyNTY2IiwiNTA1Yjg1MDY2ODRiMzdiYzgyN2EwNzUxNDRmZWZiYTI4YjNmYTczNjIwNzZlMDg5ZWZkYmNiNmQ4OTBkMDQwNSIsIjhhZDI2OGE3N2QyZTZiMzRkZGE5OThjMzQ3OTI2MzU0MWYzYzY0ZmEzODdiOGQyYTczYTNjOTAzMWJjYWFiMmEiLCI1YzkzMjE0NjMyOWZiOWFjOTFiMDVjZjQ5YTc3NmRlNjQwZGQyNTRkNzQwZTMzN2VlZWZjYjMwNWE3MTA4ZTk3IiwiNDhlODZhYWZjNjE2MjIwNjQ3M2I2Yjc1MDE4ZWI4ZDA5MDIzYmQ1ZWRiZjM3ZTg0NDc3YmIyYWIzZmFhNmZmYiIsIjg0ZjY3ZTdkMGI5YmEzYTA4MTM1YzQxNDc2ZWY3ZmViYTI5YzdmMWFkYWJlZTRkMTlhODlmNDU1MzI2NDEzNGIiLCJjYThlOWRjNDA2ODBkN2IzNGE4YzAwN2QxNDA0NzViOTBmYjRjMWUxMWFiM2ZhZGM5YjZhZWMyN2RjNzAxNmE5IiwiNzQ2MTc0NTcwYjhjMGUwNDQzOTY0NDYwZWE3OGU3NzYzNzk2NjlkYWMxNWNhMWZmMWMzODJiNzQzYTBjODU4NiIsIjRjZmExNGNmOGIzNWY4M2IyYTYxNzdmMmJlODQzYjAxMWQyODkzYmRjNzcyYTkyMDZhZmNhOTdjNDJjMGNiMmMiLCIxNzkxNmY1Njk5ZTUyYTc1ZGQ1ODA5YTE3MTZhMjA4MjkxMWY0Y2ZlNWM0MGE1NWFkMDExNGIxYjNlYjA2MzI2IiwiMzcyYTg2OWIyNDU0NTVlZWM0ZWIwMTE3ZWE1NmJjMTllN2IzZGVjMmRhZjYzNzkzNWI2YzI2Yjk1YzEzMDA4YiIsIjMxNjE1MTM1YTE1ZGM2NjkzZmE5NDZhMmU1M2JjMzMzODViZGJhM2Y5ODY0YzQ3OGNiOWUzNTdhMjFlMDhkNjgiLCI4NWMzODQ0OTE0NjAyMDE1OTVmY2JkNTAyNzZmZTlkNmU3Yjk0ZWY2ZGY0N2FiMWQ3ZGQxN2M3ZDE0NDEyNDZlIiwiMjg0NjFlZDQ4NTAzY2JmNWYyZmNlMDNlYjUyOGY2OWEyNzljYjY2YjBjZjQ3NjU1Yjc4NDgyZDY5YzBlMTk5NSIsIjFkNWZjN2JhYWZkZWMzNmZmY2M0ODFmNWQ0NmIyODE3MWZmNjdjOTQ2MjQ0OTNhNTczZTRlYzUyOGI2MmY2OTYiLCIxYjI0YzFjODVlM2ZlYzI1MWY5YzZjYmNmMzQ2ZGJmNTNhZDhiMGM2N2I0NzZkNTVmOTYxMTRkZWMxNWJmZDIxIiwiYmRkMDI3Yzg0N2U0ODRhZWRmZDY4OTRmYjliZTkyMTdkN2E1NTUzZGYwOWIwMmQyODhhZDI4OTQxZTA1ODg5NiIsImY4MWZlMmIxODgzYmU3OWNlZWMwZmE4ZGFlNmRlM2ViY2QwYTZjMTMwZGE2OTg5Njk4Mjk2YzM2YzAzNDdlYjMiLCI2OTY5YzQ5YmQ3M2YxOWJmMjhhNWVhZWFiZDMzMWRkZDYwNTAyZGVmYjJjZDNkOTZlMTdiNzQxYzgwYWRlYzZjIiwiNWQxODMyNjUyMWYxNTY4ZmNmZGRlOGIwNzFiZmU5MDQ2NmU3MGI0ZDVlNzFiZjIxOWJmMDA5MDY1MDM4ODNmOSJdLCJsb2dJbmRleCI6MzQ4MDI2OTMsInJvb3RIYXNoIjoiMmI5YzU3ODA3MWUxMjBhYTg0Yzk4NTg3ODNkYWE2NzE1NjVlNDE2NWYzYTdkZmExOTlhYWQ4MTk0MDI5OWQ4ZSIsInRyZWVTaXplIjoxMTc3NDA4MzF9LCJzaWduZWRFbnRyeVRpbWVzdGFtcCI6Ik1FUUNJRU84aFBZMWJNbmtOckJLY1JFNlV3LzFFTURBanMyV0RZUlRPd2tvMGFjbkFpQkdLY1VxZHNZMFd0c1Q5MENoTEF0N0VNZEljdXpxdm5tREk0V3JsRkgxOWc9PSJ9fX1dCg== + recorded_at: Tue, 24 Sep 2024 19:32:15 GMT +recorded_with: VCR 6.3.1 diff --git a/vendor/cache/sigstore-ruby-ce93acf7fa7e/fixtures/vcr_cassettes/production.yml b/vendor/cache/sigstore-ruby-ce93acf7fa7e/fixtures/vcr_cassettes/production.yml new file mode 100644 index 00000000..4c03814b --- /dev/null +++ b/vendor/cache/sigstore-ruby-ce93acf7fa7e/fixtures/vcr_cassettes/production.yml @@ -0,0 +1,482 @@ +--- +http_interactions: + - request: + method: get + uri: https://tuf-repo-cdn.sigstore.dev/11.root.json + body: + encoding: US-ASCII + string: "" + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + - RubyGems/3.4.19 arm64-darwin-23 Ruby/3.2.3 (2024-01-18 patchlevel 157) + Connection: + - keep-alive + Keep-Alive: + - "30" + response: + status: + code: 404 + message: Not Found + headers: + Content-Type: + - application/xml; charset=UTF-8 + Content-Length: + - "127" + X-Guploader-Uploadid: + - AD-8ljtTzbzTSTi82QIhiVa2EFp1ZT6wkfTcGfV5_3thgnW13kudJIC8cNsMjKUn103ju6bRfko + Date: + - Tue, 24 Sep 2024 19:32:15 GMT + Expires: + - Tue, 24 Sep 2024 19:32:15 GMT + Cache-Control: + - private, max-age=0 + Server: + - UploadServer + Via: + - 1.1 google + Alt-Svc: + - h3=":443"; ma=2592000,h3-29=":443"; ma=2592000 + body: + encoding: UTF-8 + string: + "NoSuchKeyThe + specified key does not exist." + recorded_at: Tue, 24 Sep 2024 19:32:15 GMT + - request: + method: get + uri: https://tuf-repo-cdn.sigstore.dev/timestamp.json + body: + encoding: US-ASCII + string: "" + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + - RubyGems/3.4.19 arm64-darwin-23 Ruby/3.2.3 (2024-01-18 patchlevel 157) + Connection: + - keep-alive + Keep-Alive: + - "30" + response: + status: + code: 200 + message: OK + headers: + Date: + - Tue, 24 Sep 2024 19:32:15 GMT + Cache-Control: + - no-store + Expires: + - Wed, 24 Sep 2025 19:32:15 GMT + Last-Modified: + - Tue, 24 Sep 2024 13:30:21 GMT + Etag: + - '"7c6cbda4330af48fd1e23db82286e7ab"' + X-Goog-Generation: + - "1727184620932794" + X-Goog-Metageneration: + - "1" + X-Goog-Stored-Content-Encoding: + - identity + X-Goog-Stored-Content-Length: + - "449" + Content-Type: + - application/json + X-Goog-Hash: + - crc32c=709eSg== + - md5=fGy9pDMK9I/R4j24Iobnqw== + X-Goog-Storage-Class: + - STANDARD + Accept-Ranges: + - bytes + Content-Length: + - "449" + X-Guploader-Uploadid: + - AD-8ljsfxSjK3qA0HnndOGcCWE-MY1qCDD-zRyNpBkywc8vsMtE70feehDZ3JKGq5wmJITPA5PoEizFyyQ + Server: + - UploadServer + Via: + - 1.1 google + Alt-Svc: + - h3=":443"; ma=2592000,h3-29=":443"; ma=2592000 + body: + encoding: UTF-8 + string: |- + { + "signatures": [ + { + "keyid": "7247f0dbad85b147e1863bade761243cc785dcb7aa410e7105dd3d2b61a36d2c", + "sig": "304502204cbf8eedddcb8cd1f4d274ad202aad9162d85fb4c79ee4dff5ec1d08948e8191022100abe1569a87d13d40d4b563806c1694017332b7101fbaea377d4a0991a29a9065" + } + ], + "signed": { + "_type": "timestamp", + "expires": "2024-10-01T13:26:15Z", + "meta": { + "snapshot.json": { + "version": 156 + } + }, + "spec_version": "1.0", + "version": 224 + } + } + recorded_at: Tue, 24 Sep 2024 19:32:15 GMT + - request: + method: get + uri: https://tuf-repo-cdn.sigstore.dev/156.snapshot.json + body: + encoding: US-ASCII + string: "" + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + - RubyGems/3.4.19 arm64-darwin-23 Ruby/3.2.3 (2024-01-18 patchlevel 157) + Connection: + - keep-alive + Keep-Alive: + - "30" + response: + status: + code: 200 + message: OK + headers: + X-Goog-Generation: + - "1725380115625190" + X-Goog-Metageneration: + - "1" + X-Goog-Stored-Content-Encoding: + - identity + X-Goog-Stored-Content-Length: + - "1758" + X-Goog-Meta-Goog-Reserved-File-Mtime: + - "1725379916" + X-Goog-Hash: + - crc32c=KP+kcQ== + - md5=xVm/fgX6HzD6P9pEzgZ51Q== + X-Goog-Storage-Class: + - STANDARD + Accept-Ranges: + - bytes + Content-Length: + - "1758" + X-Guploader-Uploadid: + - AD-8ljuVnlyofdHPsb9q0-aPa9byMEep5AY_466v8T3dOT8LZfF_maLHZbnl8f8h1MWSvT32vv77slsFAQ + Server: + - UploadServer + Via: + - 1.1 google + Date: + - Tue, 24 Sep 2024 16:21:05 GMT + Cache-Control: + - public,max-age=86400 + Age: + - "11470" + Last-Modified: + - Tue, 24 Sep 2024 13:30:19 GMT + Etag: + - '"c559bf7e05fa1f30fa3fda44ce0679d5"' + Content-Type: + - application/json + Alt-Svc: + - h3=":443"; ma=2592000,h3-29=":443"; ma=2592000 + body: + encoding: UTF-8 + string: |- + { + "signatures": [ + { + "keyid": "7247f0dbad85b147e1863bade761243cc785dcb7aa410e7105dd3d2b61a36d2c", + "sig": "304402206566fd1ac98aae6c76e88d477201f8d6793d1df8655d5585f70cdfea16dfc46a022060fdeaafc754530606b4b78e2c273a8f6bed629345b8505e0380e722a8900450" + } + ], + "signed": { + "_type": "snapshot", + "expires": "2034-08-31T13:31:34Z", + "meta": { + "registry.npmjs.org.json": { + "version": 4 + }, + "rekor.json": { + "hashes": { + "sha256": "9d2e1a5842937d8e0d3e3759170b0ad15c56c5df36afc5cf73583ddd283a463b", + "sha512": "176e9e710ddddd1b357a7d7970831bae59763395a0c18976110cbd35b25e5412dc50f356ec421a7a30265670cf7aec9ed84ee944ba700ec2394b9c876645b960" + }, + "length": 797, + "version": 3 + }, + "revocation.json": { + "hashes": { + "sha256": "6f60848ba8fb0955a02abfd1232fb3845dc9ee9f418bf03521a7ddb48217e040", + "sha512": "a965dddd0d0edef6c59e84cf02ecf5a53299f633fd339b2b61814a4219ab4df672a6390f265b8b29e1c8cea9368ea3440df013790759d50231a30df1c1f02551" + }, + "length": 800, + "version": 2 + }, + "root.json": { + "hashes": { + "sha256": "f5ad897c9414cca99629f400ac3585e41bd8ebb44c5af07fb08dd636a9eced9c", + "sha512": "7445ddfdd338ef786c324fc3d68f75be28cb95b7fb581d2a383e3e5dde18aa17029a5636ec0a22e9631931bbcb34057788311718ea41e21e7cdd3c0de13ede42" + }, + "length": 5297, + "version": 2 + }, + "staging.json": { + "hashes": { + "sha256": "cda57759abac5375397eea3531d7ca51e3a67da9a2dc93f2cdab749e2ae73149", + "sha512": "e9e59587bde453144c7079884a880c706f1d43f26e8bb23fac2b96a99569a2a30ae6cf51ec51c2454f760ce83d4c20915e062aede7f319b3da6a6ed1d26ca281" + }, + "length": 401, + "version": 2 + }, + "targets.json": { + "version": 10 + } + }, + "spec_version": "1.0", + "version": 156 + } + } + recorded_at: Tue, 24 Sep 2024 19:32:15 GMT + - request: + method: get + uri: https://tuf-repo-cdn.sigstore.dev/10.targets.json + body: + encoding: US-ASCII + string: "" + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + - RubyGems/3.4.19 arm64-darwin-23 Ruby/3.2.3 (2024-01-18 patchlevel 157) + Connection: + - keep-alive + Keep-Alive: + - "30" + response: + status: + code: 200 + message: OK + headers: + X-Goog-Generation: + - "1725380115569153" + X-Goog-Metageneration: + - "1" + X-Goog-Stored-Content-Encoding: + - identity + X-Goog-Stored-Content-Length: + - "5624" + X-Goog-Meta-Goog-Reserved-File-Mtime: + - "1725379916" + X-Goog-Hash: + - crc32c=uBDWLw== + - md5=HDgoh6x8PE4twwByxqk9eg== + X-Goog-Storage-Class: + - STANDARD + Accept-Ranges: + - bytes + Content-Length: + - "5624" + X-Guploader-Uploadid: + - AD-8ljuqI0TCFNPAhR460l5rdARrrRdHJzvtdI_Iqshy_FcPX3swUKm4oT7MPCWUP8Fok9QUA3QcQ6YLiQ + Server: + - UploadServer + Via: + - 1.1 google + Date: + - Tue, 24 Sep 2024 16:21:05 GMT + Cache-Control: + - public,max-age=86400 + Age: + - "11470" + Last-Modified: + - Tue, 24 Sep 2024 13:30:19 GMT + Etag: + - '"1c382887ac7c3c4e2dc30072c6a93d7a"' + Content-Type: + - application/json + Alt-Svc: + - h3=":443"; ma=2592000,h3-29=":443"; ma=2592000 + body: + encoding: UTF-8 + string: |- + { + "signatures": [ + { + "keyid": "6f260089d5923daf20166ca657c543af618346ab971884a99962b01988bbe0c3", + "sig": "3045022100cffdd70aff94fab0127ac749c64449d5f644c7195971bfdca57879d5f645ab960220129ed6aeb07a57d9554af28941543bbb58f28c4c60d28a819f2294d290ff6cd9" + }, + { + "keyid": "e71a54d543835ba86adad9460379c7641fb8726d164ea766801a1c522aba7ea2", + "sig": "30450220208c663d230a0ebb3a2b964020d019394112e216d4964c743ad2e61cebc43b52022100c2964f3fa7e77cd3abe13640d91b53d1a294470b65211a42f3f7764064c28ce4" + }, + { + "keyid": "22f4caec6d8e6f9555af66b3d4c3cb06a3bb23fdc7e39c916c61f462e6f52b06", + "sig": "304502210093afa3a6d28f67f6aace8c6c5258282ec0784ce82da93589e2870b522c1b685502205374c8871e12e07f856f83e780b626dd5a00a032285d4436f615cdb9d637c3c3" + }, + { + "keyid": "61643838125b440b40db6942f5cb5a31c0dc04368316eb2aaa58b95904a58222", + "sig": "3044022006b5eae637d0b66f4f72759f86e86840f6a9a580b3baf7303a046d8fac1c0872022053c1b8a6fbce7e37a7e46501019a160f4d833efb48e7ca5bd274df54b2bbce3f" + }, + { + "keyid": "a687e5bf4fab82b0ee58d46e05c9535145a2c9afb458f43d42b45ca0fdce2a70", + "sig": "304502203d51eac2b34f6f06178e86e484d192f7a40b53df47e2ba0540d2e5a397d1e92b0221009833e3bb41c3bd28bc1adc06a74e5e7c73a6c9d9a1648ab558cfbdd380a2c4e2" + } + ], + "signed": { + "_type": "targets", + "delegations": { + "keys": { + "5e3a4021b11a425fd0a444f1670457ce5b15bbe036144f2417426f7f4b9721da": { + "keytype": "ecdsa", + "keyval": { + "public": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEVfei1dXQRVeArCMcTDgxJtYg+Fs7\nV87DjhQbGlRJPyC7SW5TbNNkmvpmi4LeTv6moLVZ7T2nVqiRZbSkD+cf8w==\n-----END PUBLIC KEY-----\n" + }, + "scheme": "ecdsa-sha2-nistp256", + "x-tuf-on-ci-online-uri": "azurekms://npm-tuf-delegate.vault.azure.net/keys/npm-tuf-delegate-2024-08/e2772c1d01ca400da571096889f1660e" + } + }, + "roles": [ + { + "keyids": [ + "5e3a4021b11a425fd0a444f1670457ce5b15bbe036144f2417426f7f4b9721da" + ], + "name": "registry.npmjs.org", + "paths": [ + "registry.npmjs.org/*" + ], + "terminating": true, + "threshold": 1 + } + ] + }, + "expires": "2034-08-24T07:16:33Z", + "spec_version": "1.0", + "targets": { + "artifact.pub": { + "custom": { + "sigstore": { + "status": "Active", + "usage": "Unknown" + } + }, + "hashes": { + "sha256": "59ebf97a9850aecec4bc39c1f5c1dc46e6490a6b5fd2a6cacdcac0c3a6fc4cbf", + "sha512": "308fd1d1d95d7f80aa33b837795251cc3e886792982275e062409e13e4e236ffc34d676682aa96fdc751414de99c864bf132dde71581fa651c6343905e3bf988" + }, + "length": 177 + }, + "ctfe.pub": { + "custom": { + "sigstore": { + "status": "Active", + "uri": "https://ctfe.sigstore.dev/test", + "usage": "CTFE" + } + }, + "hashes": { + "sha256": "7fcb94a5d0ed541260473b990b99a6c39864c1fb16f3f3e594a5a3cebbfe138a", + "sha512": "4b20747d1afe2544238ad38cc0cc3010921b177d60ac743767e0ef675b915489bd01a36606c0ff83c06448622d7160f0d866c83d20f0c0f44653dcc3f9aa0bd4" + }, + "length": 177 + }, + "ctfe_2022.pub": { + "custom": { + "sigstore": { + "status": "Active", + "uri": "https://ctfe.sigstore.dev/2022", + "usage": "CTFE" + } + }, + "hashes": { + "sha256": "270488a309d22e804eeb245493e87c667658d749006b9fee9cc614572d4fbbdc", + "sha512": "e83fa4f427b24ee7728637fad1b4aa45ebde2ba02751fa860694b1bb16059a490328f9985e51cc70e4d237545315a1bc866dc4fdeef2f6248d99cc7a6077bf85" + }, + "length": 178 + }, + "fulcio.crt.pem": { + "custom": { + "sigstore": { + "status": "Expired", + "uri": "https://fulcio.sigstore.dev", + "usage": "Fulcio" + } + }, + "hashes": { + "sha256": "f360c53b2e13495a628b9b8096455badcb6d375b185c4816d95a5d746ff29908", + "sha512": "0713252a7fd17f7f3ab12f88a64accf2eb14b8ad40ca711d7fe8b4ecba3b24db9e9dffadb997b196d3867b8f9ff217faf930d80e4dab4e235c7fc3f07be69224" + }, + "length": 744 + }, + "fulcio_intermediate_v1.crt.pem": { + "custom": { + "sigstore": { + "status": "Active", + "uri": "https://fulcio.sigstore.dev", + "usage": "Fulcio" + } + }, + "hashes": { + "sha256": "f8cbecf186db7714624a5f4e99da31a917cbef70a94dd6921f5c3ca969dfe30a", + "sha512": "0f99f47dbc26c5f1e3cba0bfd9af4245a26e5cb735d6ef005792ec7e603f66fdb897de985973a6e50940ca7eff5e1849719e967b5ad2dac74a29115a41cf6f21" + }, + "length": 789 + }, + "fulcio_v1.crt.pem": { + "custom": { + "sigstore": { + "status": "Active", + "uri": "https://fulcio.sigstore.dev", + "usage": "Fulcio" + } + }, + "hashes": { + "sha256": "f989aa23def87c549404eadba767768d2a3c8d6d30a8b793f9f518a8eafd2cf5", + "sha512": "f2e33a6dc208cee1f51d33bbea675ab0f0ced269617497985f9a0680689ee7073e4b6f8fef64c91bda590d30c129b3070dddce824c05bc165ac9802f0705cab6" + }, + "length": 740 + }, + "rekor.pub": { + "custom": { + "sigstore": { + "status": "Active", + "uri": "https://rekor.sigstore.dev", + "usage": "Rekor" + } + }, + "hashes": { + "sha256": "dce5ef715502ec9f3cdfd11f8cc384b31a6141023d3e7595e9908a81cb6241bd", + "sha512": "0ae7705e02db33e814329746a4a0e5603c5bdcd91c96d072158d71011a2695788866565a2fec0fe363eb72cbcaeda39e54c5fe8d416daf9f3101fdba4217ef35" + }, + "length": 178 + }, + "trusted_root.json": { + "hashes": { + "sha256": "4364d7724c04cc912ce2a6c45ed2610e8d8d1c4dc857fb500292738d4d9c8d2c", + "sha512": "fdebade075c4840d40f1806a14d0660ae1d22f47c0516abc4141e09f4ddf6ee6f4dbfbf08a7025bea10a4b8794658a4cd8ebb1024b963f239a9bfe02c2057fc6" + }, + "length": 7014 + } + }, + "version": 10, + "x-tuf-on-ci-expiry-period": 3650, + "x-tuf-on-ci-signing-period": 31 + } + } + recorded_at: Tue, 24 Sep 2024 19:32:15 GMT +recorded_with: VCR 6.3.1 diff --git a/vendor/cache/sigstore-ruby-ce93acf7fa7e/lib/sigstore.rb b/vendor/cache/sigstore-ruby-ce93acf7fa7e/lib/sigstore.rb new file mode 100644 index 00000000..2ab45c84 --- /dev/null +++ b/vendor/cache/sigstore-ruby-ce93acf7fa7e/lib/sigstore.rb @@ -0,0 +1,47 @@ +# frozen_string_literal: true + +# Copyright 2024 The Sigstore Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +module Sigstore + class << self + attr_writer :logger + + def logger + @logger ||= begin + require "logger" + Logger.new($stderr) + end + end + end + + module Loggable + def logger + self.class.logger + end + + def self.included(base) + base.extend(ClassMethods) + end + + module ClassMethods + def logger + Sigstore.logger + end + end + end +end + +require_relative "sigstore/verifier" +require_relative "sigstore/signer" diff --git a/vendor/cache/sigstore-ruby-ce93acf7fa7e/lib/sigstore/error.rb b/vendor/cache/sigstore-ruby-ce93acf7fa7e/lib/sigstore/error.rb new file mode 100644 index 00000000..7f06fc53 --- /dev/null +++ b/vendor/cache/sigstore-ruby-ce93acf7fa7e/lib/sigstore/error.rb @@ -0,0 +1,43 @@ +# frozen_string_literal: true + +# Copyright 2024 The Sigstore Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +module Sigstore + class Error < StandardError + class InvalidSignature < Error; end + class InvalidBundle < Error; end + class InvalidCertificate < Error; end + class NoCertificate < Error; end + class NoTrustedRoot < Error; end + class NoBundle < Error; end + class NoSignature < Error; end + class InvalidKey < Error; end + class InvalidCheckpoint < Error; end + class InvalidVerificationInput < Error; end + + class Signing < Error; end + class InvalidIdentityToken < Error; end + + class MissingRekorEntry < Error; end + class InvalidRekorEntry < Error; end + class FailedRekorLookup < Error; end + class FailedRekorPost < Error; end + + class Unimplemented < Error; end + + class UnsupportedPlatform < Error; end + class UnsupportedKeyType < Error; end + end +end diff --git a/vendor/cache/sigstore-ruby-ce93acf7fa7e/lib/sigstore/internal/json.rb b/vendor/cache/sigstore-ruby-ce93acf7fa7e/lib/sigstore/internal/json.rb new file mode 100644 index 00000000..fdacdc79 --- /dev/null +++ b/vendor/cache/sigstore-ruby-ce93acf7fa7e/lib/sigstore/internal/json.rb @@ -0,0 +1,64 @@ +# frozen_string_literal: true + +# Copyright 2024 The Sigstore Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +module Sigstore::Internal + module JSON + # Implements https://wiki.laptop.org/go/Canonical_JSON + # + def self.canonical_generate(data, buffer = +"") + case data + when NilClass + buffer << "null" + when TrueClass + buffer << "true" + when FalseClass + buffer << "false" + when Integer + buffer << data.to_s + when String + buffer << '"' << data.gsub(/(["\\])/, '\\\\\1') << '"' + when Array + buffer << "[" + data.each_with_index do |v, i| + buffer << "," unless i.zero? + canonical_generate(v, buffer) + end + buffer << "]" + when Hash + contents = data.sort_by do |k, _| + raise ArgumentError, "Non-string key in hash" unless k.is_a?(String) + + k.encode("utf-16").codepoints + end + buffer << "{" + comma = false + contents.each do |k, v| + if comma + buffer << "," + else + comma = true + end + canonical_generate(k, buffer) + buffer << ":" + canonical_generate(v, buffer) + end + buffer << "}" + else + raise ArgumentError, "Unsupported data type: #{data.class}" + end + end + end +end diff --git a/vendor/cache/sigstore-ruby-ce93acf7fa7e/lib/sigstore/internal/key.rb b/vendor/cache/sigstore-ruby-ce93acf7fa7e/lib/sigstore/internal/key.rb new file mode 100644 index 00000000..2c369484 --- /dev/null +++ b/vendor/cache/sigstore-ruby-ce93acf7fa7e/lib/sigstore/internal/key.rb @@ -0,0 +1,183 @@ +# frozen_string_literal: true + +# Copyright 2024 The Sigstore Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +require_relative "util" + +module Sigstore + module Internal + class Key + include Loggable + + def self.from_key_details(key_details, key_bytes) + case key_details + when Common::V1::PublicKeyDetails::PKIX_ECDSA_P256_SHA_256 + key_type = "ecdsa" + key_schema = "ecdsa-sha2-nistp256" + when Common::V1::PublicKeyDetails::PKCS1_RSA_PKCS1V5 + key_type = "rsa" + key_schema = "rsa-pkcs1v15-sha256" + else + # Skip unrecognized key types instead of raising an error. + # This allows the library to work with newer trusted roots that include + # key types we don't yet support (e.g., PKIX_ED25519 for Rekor v2). + logger.warn { "Skipping unrecognized key type: #{key_details}" } + return nil + end + + read(key_type, key_schema, key_bytes, key_id: OpenSSL::Digest::SHA256.hexdigest(key_bytes)) + end + + def self.read(key_type, schema, key_bytes, key_id: nil) + case key_type + when "ecdsa", "ecdsa-sha2-nistp256" + pkey = OpenSSL::PKey::EC.new(key_bytes) + EDCSA.new(key_type, schema, pkey, key_id:) + when "ed25519" + pkey = ED25519.pkey_from_der([key_bytes].pack("H*")) + ED25519.new(key_type, schema, pkey, key_id:) + when "rsa" + pkey = OpenSSL::PKey::RSA.new(key_bytes) + RSA.new(key_type, schema, pkey, key_id:) + else + raise ArgumentError, "Unsupported key type #{key_type}" + end + rescue OpenSSL::PKey::PKeyError => e + raise OpenSSL::PKey::PKeyError, "Invalid key: #{e} for #{key_type} #{schema} #{key_id}" + end + + attr_reader :key_type, :schema, :key_id + + def initialize(key_type, schema, key, key_id: nil) + @key_type = key_type + @key = key + @schema = schema + @key_id = key_id + end + + def to_pem + @key.to_pem + end + + def to_der + @key.to_der + end + + def verify(algo, signature, data) + @key.verify(algo, signature, data) + rescue OpenSSL::PKey::PKeyError => e + logger.debug { "Verification failed: #{e}" } + false + end + + def public_to_der + @key.public_to_der + end + + class EDCSA < Key + def initialize(...) + super + unless @key_type == "ecdsa" || @key_type == "ecdsa-sha2-nistp256" + raise ArgumentError, + "key_type must be edcsa, given #{@key_type}" + end + unless @key.is_a?(OpenSSL::PKey::EC) + raise ArgumentError, + "key must be an OpenSSL::PKey::EC, is #{@key.inspect}" + end + + case @schema + when "ecdsa-sha2-nistp256" + unless @key.group.curve_name == "prime256v1" + raise ArgumentError, "Expected prime256v1 curve, got #{@key.group.curve_name}" + end + else + raise ArgumentError, "Unsupported schema #{schema}" + end + end + end + + class RSA < Key + def initialize(...) + super + raise ArgumentError, "key_type must be rsa, given #{@key_type}" unless @key_type == "rsa" + + unless @key.is_a?(OpenSSL::PKey::RSA) + raise ArgumentError, "key must be an OpenSSL::PKey::RSA, given #{@key.inspect}" + end + + case @schema + when "rsassa-pss-sha256" + raise Error::UnsupportedPlatform, "RSA-PSS verification unsupported" unless @key.respond_to?(:verify_pss) + when "rsa-pkcs1v15-sha256" + # supported + else + raise ArgumentError, "Unsupported schema #{schema}" + end + end + + def verify(_algo, signature, data) + case @schema + when "rsassa-pss-sha256" + @key.verify_pss("sha256", signature, data, salt_length: :auto, mgf1_hash: "SHA256") + when "rsa-pkcs1v15-sha256" + super + else + raise ArgumentError, "Unsupported schema #{schema}" + end + end + end + + class ED25519 < Key + def self.pkey_from_der(raw) + if OpenSSL::PKey.respond_to?(:new_raw_public_key) + OpenSSL::PKey.new_raw_public_key("ed25519", raw) + else + pem = <<~PEM + -----BEGIN PUBLIC KEY----- + MCowBQYDK2VwAyEA#{Internal::Util.base64_encode(raw)} + -----END PUBLIC KEY----- + PEM + OpenSSL::PKey.read(pem) + end + end + + def initialize(...) + super + unless @key_type == "ed25519" + raise ArgumentError, + "key_type must be ed25519, given #{@key_type}" + end + unless @key.is_a?(OpenSSL::PKey::PKey) && @key.oid == "ED25519" + raise ArgumentError, + "key must be an OpenSSL::PKey::PKey with oid ED25519, is #{@key.inspect}" + end + raise ArgumentError, "schema must be #{schema}" unless @schema == schema + + case @schema + when "ed25519" + # supported + else + raise ArgumentError, "Unsupported schema #{schema}" + end + end + + def verify(_algo, signature, data) + super(nil, signature, data) + end + end + end + end +end diff --git a/vendor/cache/sigstore-ruby-ce93acf7fa7e/lib/sigstore/internal/keyring.rb b/vendor/cache/sigstore-ruby-ce93acf7fa7e/lib/sigstore/internal/keyring.rb new file mode 100644 index 00000000..f7f297cf --- /dev/null +++ b/vendor/cache/sigstore-ruby-ce93acf7fa7e/lib/sigstore/internal/keyring.rb @@ -0,0 +1,42 @@ +# frozen_string_literal: true + +# Copyright 2024 The Sigstore Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +module Sigstore + module Internal + class Keyring + def initialize(keys:) + @keyring = {} + keys.each do |key| + raise Error, "Duplicate key id #{key.key_id} in keyring" if @keyring.key?(key.key_id) + + @keyring[key.key_id] = key + end + end + + def verify(key_id:, signature:, data:) + key = @keyring.fetch(key_id) { raise KeyError, "key not found: #{key_id.inspect}, known: #{@keyring.keys}" } + + return true if key.verify("SHA256", signature, data) + + raise(Error::InvalidSignature, + "invalid signature: #{signature.inspect} over #{data.inspect} with key #{key_id.inspect}") + rescue OpenSSL::PKey::PKeyError => e + raise(Error::InvalidSignature, + "#{e}: invalid signature: #{signature.inspect} over #{data.inspect} with key #{key_id.inspect}") + end + end + end +end diff --git a/vendor/cache/sigstore-ruby-ce93acf7fa7e/lib/sigstore/internal/merkle.rb b/vendor/cache/sigstore-ruby-ce93acf7fa7e/lib/sigstore/internal/merkle.rb new file mode 100644 index 00000000..eaceaf48 --- /dev/null +++ b/vendor/cache/sigstore-ruby-ce93acf7fa7e/lib/sigstore/internal/merkle.rb @@ -0,0 +1,117 @@ +# frozen_string_literal: true + +# Copyright 2024 The Sigstore Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +require_relative "util" + +module Sigstore + module Internal + module Merkle + class MissingInclusionProofError < StandardError; end + class MissingHashError < StandardError; end + class InvalidInclusionProofError < StandardError; end + class InclusionProofSizeError < InvalidInclusionProofError; end + + def self.verify_merkle_inclusion(entry) + inclusion_proof = entry.inclusion_proof + raise MissingInclusionProofError, "Rekor entry has no inclusion proof" unless inclusion_proof + + leaf_hash = hash_leaf(entry.canonicalized_body) + verify_inclusion(inclusion_proof.log_index, inclusion_proof.tree_size, + inclusion_proof.hashes, + inclusion_proof.root_hash, leaf_hash) + end + + def self.verify_inclusion(index, tree_size, proof, root, leaf_hash) + calc_hash = root_from_inclusion_proof(index, tree_size, proof, leaf_hash) + + return if calc_hash == root + + raise InvalidInclusionProofError, + "Inclusion proof contains invalid root hash: " \ + "expected #{root.unpack1("H*")}, calculated #{calc_hash.unpack1("H*")}" + end + + def self.root_from_inclusion_proof(log_index, tree_size, proof, leaf_hash) + if log_index >= tree_size + raise InclusionProofSizeError, + "Log index #{log_index} is greater than tree size #{tree_size}" + end + + if leaf_hash.bytesize != 32 + raise InvalidInclusionProofError, + "Leaf hash has wrong size, expected 32 bytes, got #{leaf_hash.size}" + end + + if proof.any? { |i| i.bytesize != 32 } + raise InvalidInclusionProofError, + "Proof hashes have wrong sizes, expected 32 bytes, got #{proof.inspect}" + end + + inner, border = decompose_inclusion_proof(log_index, tree_size) + + if proof.size != inner + border + raise InclusionProofSizeError, + "Inclusion proof has wrong size, expected #{inner + border} hashes, got #{proof.size}" + end + + intermediate_result = chain_inner( + leaf_hash, + (proof[...inner] || raise(MissingHashError, "missing left hashes")), + log_index + ) + + chain_border_right( + intermediate_result, + proof[inner..] || raise(MissingHashError, "missing right hashes") + ) + end + + def self.decompose_inclusion_proof(log_index, tree_size) + inner = (log_index ^ (tree_size - 1)).bit_length + border = (log_index >> inner).to_s(2).count("1") + + [inner, border] + end + + def self.hash_leaf(data) + data = "\u0000#{data}".b + OpenSSL::Digest.new("SHA256").digest(data) + end + + def self.chain_inner(seed, hashes, log_index) + hashes.each_with_index do |hash, i| + seed = if ((log_index >> i) & 1).zero? + hash_children(seed, hash) + else + hash_children(hash, seed) + end + end + seed + end + + def self.chain_border_right(seed, hashes) + hashes.reduce(seed) do |acc, hash| + hash_children(hash, acc) + end + end + + def self.hash_children(left, right) + data = "\u0001#{left}#{right}".b + OpenSSL::Digest.new("SHA256").digest(data) + end + end + end +end diff --git a/vendor/cache/sigstore-ruby-ce93acf7fa7e/lib/sigstore/internal/set.rb b/vendor/cache/sigstore-ruby-ce93acf7fa7e/lib/sigstore/internal/set.rb new file mode 100644 index 00000000..d97ee942 --- /dev/null +++ b/vendor/cache/sigstore-ruby-ce93acf7fa7e/lib/sigstore/internal/set.rb @@ -0,0 +1,42 @@ +# frozen_string_literal: true + +# Copyright 2024 The Sigstore Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +module Sigstore + module Internal + module SET + def self.verify_set(keyring:, entry:) + raise Error, "invalid log entry: no inclusion promise" unless entry.inclusion_promise + + signed_entry_timestamp = entry.inclusion_promise.signed_entry_timestamp + log_id = Util.hex_encode(entry.log_id.key_id) + + # https://www.rfc-editor.org/rfc/rfc8785 + canonical_entry = ::JSON.dump({ + body: Internal::Util.base64_encode(entry.canonicalized_body), + integratedTime: entry.integrated_time, + logID: log_id, + logIndex: entry.log_index + }) + + keyring.verify( + key_id: log_id, + signature: signed_entry_timestamp, + data: canonical_entry + ) + end + end + end +end diff --git a/vendor/cache/sigstore-ruby-ce93acf7fa7e/lib/sigstore/internal/util.rb b/vendor/cache/sigstore-ruby-ce93acf7fa7e/lib/sigstore/internal/util.rb new file mode 100644 index 00000000..f237d52b --- /dev/null +++ b/vendor/cache/sigstore-ruby-ce93acf7fa7e/lib/sigstore/internal/util.rb @@ -0,0 +1,52 @@ +# frozen_string_literal: true + +# Copyright 2024 The Sigstore Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +module Sigstore + module Internal + module Util + module_function + + def hash_algorithm_name(algorithm) + case algorithm + when Common::V1::HashAlgorithm::SHA2_256 + "sha256" + when Common::V1::HashAlgorithm::SHA2_384 + "sha384" + when Common::V1::HashAlgorithm::SHA2_512 + "sha512" + else + raise ArgumentError, "Unrecognized hash algorithm #{algorithm}" + end + end + + def hex_encode(string) + string.unpack1("H*") + end + + def hex_decode(string) + [string].pack("H*") + end + + def base64_encode(string) + [string].pack("m0") + end + + def base64_decode(string) + string.unpack1("m0") + end + end + end +end diff --git a/vendor/cache/sigstore-ruby-ce93acf7fa7e/lib/sigstore/internal/x509.rb b/vendor/cache/sigstore-ruby-ce93acf7fa7e/lib/sigstore/internal/x509.rb new file mode 100644 index 00000000..3f3b370e --- /dev/null +++ b/vendor/cache/sigstore-ruby-ce93acf7fa7e/lib/sigstore/internal/x509.rb @@ -0,0 +1,520 @@ +# frozen_string_literal: true + +# Copyright 2024 The Sigstore Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +require "forwardable" +require "openssl" + +module Sigstore + module Internal + module X509 + if RUBY_ENGINE == "jruby" + unless JOpenSSL::VERSION >= "0.15.3" + raise Error::UnsupportedPlatform, "JRuby support requires jruby-openssl >= 0.15.3, is #{JOpenSSL::VERSION}" + end + + def self.validate_chain(trust_roots, leaf, time) + cert_factory = java.security.cert.CertificateFactory.getInstance("X.509") + cert_factory.generateCertificate(java.io.ByteArrayInputStream.new(leaf.to_der.to_java_bytes)) + target = leaf.openssl.to_java + + trust_anchors = Set.new + intermediate_certs = [] + trust_roots.each do |chain| + root = chain.last + + trust_anchors << java.security.cert.TrustAnchor.new(root.openssl.to_java, nil) + chain[..-2].each do |cert| + intermediate_certs << cert.openssl.to_java + end + end + + cert_store_parameters = java.security.cert.CollectionCertStoreParameters.new(intermediate_certs) + cert_store = java.security.cert.CertStore.getInstance("Collection", cert_store_parameters) + + cert_selector = java.security.cert.X509CertSelector.new + cert_selector.setCertificate(target) + + pkix_builder_parameters = java.security.cert.PKIXBuilderParameters.new(trust_anchors, cert_selector) + pkix_builder_parameters.setDate(time) if time + pkix_builder_parameters.setRevocationEnabled(false) + pkix_builder_parameters.addCertStore(cert_store) + + cert_path_builder = java.security.cert.CertPathBuilder.getInstance("PKIX") + cert_path_result = cert_path_builder.build(pkix_builder_parameters) + chain = cert_path_result.cert_path.getCertificates.map do |cert| + der = String.from_java_bytes(cert.getEncoded).b + Certificate.read(der) + end + chain.shift # remove the cert itself + chain << Certificate.read( + String.from_java_bytes(cert_path_result.get_trust_anchor.getTrustedCert.getEncoded).b + ) + [chain, nil] + end + else + def self.validate_chain(trust_roots, leaf, time) + store = OpenSSL::X509::Store.new + intermediate_certs = [] + trust_roots.each do |chain| + store.add_cert(chain.last.openssl) + chain[..-2].each do |cert| + intermediate_certs << cert.openssl + end + end + store_ctx = OpenSSL::X509::StoreContext.new(store, leaf.openssl, intermediate_certs) + store_ctx.time = time if time + unless store_ctx.verify + return nil, VerificationFailure.new( + "failed to validate certificate from fulcio cert chain: #{store_ctx.error_string}" + ) + end + + chain = store_ctx.chain || raise(Error::InvalidCertificate, "no valid cert chain found") + chain.shift # remove the cert itself + [chain.map! { Certificate.new(_1) }, nil] + end + end + + class Certificate + extend Forwardable + + attr_reader :openssl + + def initialize(x509_certificate) + unless x509_certificate.is_a?(OpenSSL::X509::Certificate) + raise ArgumentError, + "Invalid certificate: #{x509_certificate.inspect}" + end + + @openssl = x509_certificate + + raise Error::InvalidCertificate, "invalid X.509 version: #{version.inspect}" if version != 2 # v3 + end + + def self.read(certificate_bytes) + new(OpenSSL::X509::Certificate.new(certificate_bytes)) + rescue OpenSSL::X509::CertificateError => e + raise Error::InvalidCertificate, e.message + end + + def tbs_certificate_der + if openssl.respond_to?(:tbs_bytes) + cert = openssl.dup + short_name = Extension::PrecertificateSignedCertificateTimestamps.oid.short_name + cert.extensions = cert.extensions.reject! do |ext| + ext.oid == short_name + end || raise(Error::InvalidCertificate, + "No PrecertificateSignedCertificateTimestamps found for the certificate") + return cert.tbs_bytes + end + + extension(Extension::PrecertificateSignedCertificateTimestamps) || + raise(Error::InvalidCertificate, + "No PrecertificateSignedCertificateTimestamps found for the certificate") + + # This uglyness is needed because there is no way to force modifying an X509 certificate + # in a way that it will be serialized with the modifications. + seq = OpenSSL::ASN1.decode(to_der) + unless seq.is_a?(OpenSSL::ASN1::Sequence) && seq.value.size == 3 + raise Error::InvalidCertificate, + "invalid X.509 certificate: #{seq.class} #{seq.value.size}" + end + seq = seq.value[0] + unless seq.is_a?(OpenSSL::ASN1::Sequence) + raise Error::InvalidCertificate, + "invalid X.509 certificate: #{seq.inspect}" + end + + seq.value = seq.value.map! do |v| + next v unless v.tag == 3 + + v.value = v.value.map! do |v2| + v2.value = v2.value.map! do |v3| + next if v3.first.oid == Extension::PrecertificateSignedCertificateTimestamps.oid.oid + + v3 + end.compact! || raise(Error::InvalidCertificate, "no SCTs found") + v2 + end + v + end + + seq.to_der + end + + def extension(cls) + openssl.extensions.each do |ext| + return cls.new(ext) if ext.oid == cls.oid || ext.oid == cls.oid.short_name || ext.oid == cls.oid.oid + end + nil + end + + def_delegators :openssl, :version, :not_after, :not_before, :to_pem, :to_der, + :public_key, :to_text, :subject, :hash + + def ==(other) + openssl == other.openssl + end + + def leaf? + return false if ca? + + key_usage = extension(Extension::KeyUsage) || + raise(Error::InvalidCertificate, + "no keyUsage in #{openssl.extensions.map(&:to_h)}") + + unless key_usage.digital_signature + raise Error::InvalidCertificate, + "invalid certificate for Sigstore purposes: missing digital signature usage: #{key_usage.to_h}" + end + + extended_key_usage = extension(Extension::ExtendedKeyUsage) + return false unless extended_key_usage + + extended_key_usage.code_signing? + end + + def ca? + basic_constraints = extension(Extension::BasicConstraints) + return false unless basic_constraints + + unless basic_constraints.critical? + raise Error::InvalidCertificate, + "invalid X.509 certificate: non-critical BasicConstraints in CA" + end + + key_usage = extension(Extension::KeyUsage) + raise Error::InvalidCertificate, "no keyUsage in #{openssl.inspect}" unless key_usage + + ca = basic_constraints.ca + key_cert_sign = key_usage.key_cert_sign + + return true if ca && key_cert_sign + + return false unless key_cert_sign || ca + + raise Error::InvalidCertificate, + "invalid X.509 certificate: inconsistent CA/KeyCertSign in BasicConstraints/KeyUsage " \ + "(#{ca.inspect}, #{key_cert_sign.inspect}):" \ + "\n#{openssl.extensions.map(&:to_h).pretty_inspect}" \ + "\n#{key_usage.pretty_inspect}" + end + + def preissuer? + extended_key_usage = extension(Extension::ExtendedKeyUsage) + return false unless extended_key_usage + + extended_key_usage.precert? + end + end + + class Extension + class << self + attr_accessor :oid, :schema + end + + def initialize(extension) + @extension = extension + value = shift_value([OpenSSL::ASN1.decode(extension.to_der)], OpenSSL::ASN1::Sequence) + @oid = value.shift + + unless @extension.is_a?(OpenSSL::X509::Extension) && @oid.oid == self.class.oid.oid + raise ArgumentError, + "Invalid extension: #{@extension.inspect} is not a #{@oid.inspect} " \ + "(#{self.class} / #{self.class.oid.inspect})" + end + + @critical = false + @critical = value.shift.value if value.first.is_a?(OpenSSL::ASN1::Boolean) + raise ArgumentError, "Mis-parsed the critical bit" unless @critical == @extension.critical? + + contents = shift_value(value, OpenSSL::ASN1::OctetString) + raise ArgumentError, "Invalid extension: extra fields left in #{self}: #{value}" unless value.empty? + + parse_value(OpenSSL::ASN1.decode(contents)) + rescue OpenSSL::ASN1::ASN1Error => e + raise ArgumentError, "Invalid extension: #{e.message} for #{self.class.oid}\n#{extension.inspect}" + end + + def critical? + @extension.critical? + end + + def shift_value(value, klass) + v = value.shift + raise ArgumentError, "Invalid extension: #{v} is not a #{klass}" unless v.is_a?(klass) + + v.value + end + + def shift_bitstring(value) + raise ArgumentError, "Invalid bit string: #{value.inspect}" unless value.is_a?(OpenSSL::ASN1::BitString) + + value.value.each_byte.flat_map do |byte| + [byte & 0b1000_0000 != 0, byte & 0b0100_0000 != 0, byte & 0b0010_0000 != 0, byte & 0b0001_0000 != 0, + byte & 0b0000_1000 != 0, byte & 0b0000_0100 != 0, byte & 0b0000_0010 != 0, byte & 0b0000_0001 != 0] + end[..-value.unused_bits.succ] + end + + class SubjectKeyIdentifier < Extension + attr_reader :key_identifier + + self.oid = OpenSSL::ASN1::ObjectId.new("2.5.29.14") + + def parse_value(value) + unless value.is_a?(OpenSSL::ASN1::OctetString) + raise ArgumentError, + "Invalid key identifier: #{value.inspect}" + end + + @key_identifier = value.value + end + end + + class KeyUsage < Extension + self.oid = OpenSSL::ASN1::ObjectId.new("2.5.29.15") + + attr_reader :digital_signature, :non_repudiation, :key_encipherment, :data_encipherment, :key_agreement, + :key_cert_sign, :crl_sign, :encipher_only, :decipher_only + + def parse_value(value) + @digital_signature, @non_repudiation, @key_encipherment, @data_encipherment, @key_agreement, @key_cert_sign, + @crl_sign, @encipher_only, @decipher_only = + shift_bitstring(value) + end + end + + class ExtendedKeyUsage < Extension + self.oid = OpenSSL::ASN1::ObjectId.new("2.5.29.37") + + attr_reader :purposes + + def parse_value(value) + unless value.is_a?(OpenSSL::ASN1::Sequence) + raise ArgumentError, + "Invalid extended key usage: #{value.inspect}" + end + + @purposes = value.value + return if @purposes.all?(OpenSSL::ASN1::ObjectId) + + raise ArgumentError, + "Invalid extended key usage: #{value.inspect}" + end + + CODE_SIGNING = OpenSSL::ASN1::ObjectId.new("1.3.6.1.5.5.7.3.3") + PRECERT_PURPOSE = OpenSSL::ASN1::ObjectId.new("1.3.6.1.4.1.11129.2.4.4") + + def code_signing? + purposes.any? { |purpose| purpose.oid == CODE_SIGNING.oid } + end + + def precert? + purposes.any? { |purpose| purpose.oid == PRECERT_PURPOSE.oid } + end + end + + class BasicConstraints < Extension + self.oid = OpenSSL::ASN1::ObjectId.new("2.5.29.19") + + attr_reader :ca, :path_len_constraint + + def parse_value(value) + value = shift_value([value], OpenSSL::ASN1::Sequence) + + @ca = false + @path_len_constraint = nil + + @ca = shift_value(value, OpenSSL::ASN1::Boolean) if value.first.is_a?(OpenSSL::ASN1::Boolean) + + return unless value.first.is_a?(OpenSSL::ASN1::Integer) + + @path_len_constraint = shift_value(value, OpenSSL::ASN1::Integer) + end + end + + class SubjectAlternativeName < Extension + self.oid = OpenSSL::ASN1::ObjectId.new("2.5.29.17") + + attr_reader :general_names + + # id-ce-subjectAltName OBJECT IDENTIFIER ::= { id-ce 17 } + + # SubjectAltName ::= GeneralNames + + # GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName + + # GeneralName ::= CHOICE { + # otherName [0] OtherName, + # rfc822Name [1] IA5String, + # dNSName [2] IA5String, + # x400Address [3] ORAddress, + # directoryName [4] Name, + # ediPartyName [5] EDIPartyName, + # uniformResourceIdentifier [6] IA5String, + # iPAddress [7] OCTET STRING, + # registeredID [8] OBJECT IDENTIFIER } + + # OtherName ::= SEQUENCE { + # type-id OBJECT IDENTIFIER, + # value [0] EXPLICIT ANY DEFINED BY type-id } + + # EDIPartyName ::= SEQUENCE { + # nameAssigner [0] DirectoryString OPTIONAL, + # partyName [1] DirectoryString } + + def parse_value(value) + value = shift_value([value], OpenSSL::ASN1::Sequence) + + @general_names = value.map do |general_name| + tag = general_name.tag + + value = general_name.value + value = value.first if value.is_a?(Array) && value.size == 1 + value = value.value if value.is_a?(OpenSSL::ASN1::OctetString) + + case tag + when 1 + [:otherName, value] + when 6 + [:uniformResourceIdentifier, value] + else + raise Error::Unimplemented, + "Unhandled general name tag: #{tag}" + end + end + end + end + + class PrecertificateSignedCertificateTimestamps < Extension + self.oid = OpenSSL::ASN1::ObjectId.new("1.3.6.1.4.1.11129.2.4.2") + + attr_reader :signed_certificate_timestamps + + def parse_value(value) + unless value.is_a?(OpenSSL::ASN1::OctetString) + raise ArgumentError, + "Invalid SCT extension: #{value.inspect}" + end + + value = value.value + length = value.unpack1("n") + value = value.byteslice(2, length) + + unless value && value.bytesize == length + raise Error::InvalidCertificate, + "decoding #{self.class.oid} extension" + end + + length = value.unpack1("n") + value = value.byteslice(2, length) + + unless value && value.bytesize == length + raise Error::InvalidCertificate, + "decoding #{self.class.oid} extension" + end + + @signed_certificate_timestamps = unpack_sct_list(value) + end + + args = %i[version + log_id + timestamp + extensions_bytes + hash_algorithm + signature_algorithm + entry_type + signature] + Timestamp = defined?(Data.define) ? Data.define(*args) : Struct.new(*args, keyword_init: true) # rubocop:disable Naming/ConstantName + + HASHES = { + 0 => "none", + 1 => "md5", + 2 => "sha1", + 3 => "sha224", + 4 => "sha256", + 5 => "sha384", + 6 => "sha512", + 255 => "unknown" + }.freeze + + SIGNATURE_ALGORITHMS = { + 0 => "anonymous", + 1 => "rsa", + 2 => "dsa", + 3 => "ecdsa", + 255 => "unknown" + }.freeze + + private + + # https://letsencrypt.org/2018/04/04/sct-encoding.html + def unpack_sct_list(string) + offset = 0 + len = string.bytesize + list = [] + while offset < len + sct_version, sct_log_id, sct_timestamp, sct_extensions_len = string.unpack("Ca32Q>n", offset:) + offset += 1 + 32 + 8 + 2 + raise Error::Unimplemented, "expect sct version to be 0, got #{sct_version}" unless sct_version.zero? + + sct_extensions_bytes = string.unpack1("a#{sct_extensions_len}", offset:).b + offset += sct_extensions_len + + unless sct_extensions_len.zero? + raise Error::Unimplemented, + "sct_extensions_len=#{sct_extensions_len} not supported" + end + + sct_signature_alg_hash, sct_signature_alg_sign, sct_signature_len = string.unpack("CCn", offset:) + offset += 1 + 1 + 2 + sct_signature_bytes = string.unpack1("a#{sct_signature_len}", offset:).b + offset += sct_signature_len + list << Timestamp.new( + version: sct_version, + log_id: sct_log_id.unpack1("H*"), + timestamp: sct_timestamp, + hash_algorithm: HASHES.fetch(sct_signature_alg_hash), + signature_algorithm: SIGNATURE_ALGORITHMS.fetch(sct_signature_alg_sign), + signature: sct_signature_bytes, + extensions_bytes: sct_extensions_bytes, + entry_type: 1 # X509LogEntryType::PRECERTIFICATE + ) + end + raise Error::InvalidCertificate, "failed unpacking SCTs: offset=#{offset} len=#{len}" unless offset == len + + list + end + end + + class FulcioIssuer < Extension + self.oid = OpenSSL::ASN1::ObjectId.new("1.3.6.1.4.1.57264.1.8") + + attr_reader :issuer + + def parse_value(value) + unless value.is_a?(OpenSSL::ASN1::UTF8String) + raise ArgumentError, + "Invalid Fulcio issuer: #{value.inspect}" + end + + @issuer = value.value + end + end + end + end + end +end diff --git a/vendor/cache/sigstore-ruby-ce93acf7fa7e/lib/sigstore/models.rb b/vendor/cache/sigstore-ruby-ce93acf7fa7e/lib/sigstore/models.rb new file mode 100644 index 00000000..74cc80c4 --- /dev/null +++ b/vendor/cache/sigstore-ruby-ce93acf7fa7e/lib/sigstore/models.rb @@ -0,0 +1,286 @@ +# frozen_string_literal: true + +# Copyright 2024 The Sigstore Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +require_relative "error" + +require_relative "trusted_root" + +module Sigstore + VerificationResult = Struct.new(:success, keyword_init: true) do + # @implements VerificationResult + + alias_method :verified?, :success + end + + class VerificationSuccess < VerificationResult + # @implements VerificationSuccess + def initialize + super(success: true) + end + end + + class VerificationFailure < VerificationResult + # @implements VerificationFailure + attr_reader :reason + + def initialize(reason) + @reason = reason + super(success: false) + end + end + + class BundleType + include Comparable + + attr_reader :media_type + + def initialize(media_type) + @media_type = media_type + end + + BUNDLE_0_1 = new("application/vnd.dev.sigstore.bundle+json;version=0.1") + BUNDLE_0_2 = new("application/vnd.dev.sigstore.bundle+json;version=0.2") + BUNDLE_0_3 = new("application/vnd.dev.sigstore.bundle.v0.3+json") + + VERSIONS = [BUNDLE_0_1, BUNDLE_0_2, BUNDLE_0_3].freeze + + def self.from_media_type(media_type) + case media_type + when BUNDLE_0_1.media_type + BUNDLE_0_1 + when BUNDLE_0_2.media_type + BUNDLE_0_2 + when BUNDLE_0_3.media_type, "application/vnd.dev.sigstore.bundle+json;version=0.3" + BUNDLE_0_3 + else + raise Error::InvalidBundle, "Unsupported bundle format: #{media_type.inspect}" + end + end + + def <=>(other) + VERSIONS.index(self) <=> VERSIONS.index(other) + end + end + + class VerificationInput < DelegateClass(Verification::V1::Input) + attr_reader :trusted_root, :sbundle, :hashed_input + + def initialize(*) + super + + unless bundle.is_a?(Bundle::V1::Bundle) + raise ArgumentError, + "bundle must be a #{Bundle::V1::Bundle}, is #{bundle.class}" + end + + @trusted_root = TrustedRoot.new(artifact_trust_root) + @sbundle = SBundle.new(bundle) + if sbundle.message_signature? && !artifact + raise Error::InvalidVerificationInput, "bundle with message_signature requires an artifact" + end + + case artifact.data + when :artifact_uri + unless artifact.artifact_uri.start_with?("sha256:") + raise Error::InvalidVerificationInput, + "artifact_uri must be prefixed with 'sha256:'" + end + + @hashed_input = Common::V1::HashOutput.new.tap do |hash_output| + hash_output.algorithm = Common::V1::HashAlgorithm::SHA2_256 + hexdigest = artifact.artifact_uri.split(":", 2).last + hash_output.digest = Internal::Util.hex_decode(hexdigest) + end + when :artifact + @hashed_input = Common::V1::HashOutput.new.tap do |hash_output| + hash_output.algorithm = Common::V1::HashAlgorithm::SHA2_256 + hash_output.digest = OpenSSL::Digest.new("SHA256").update(artifact.artifact).digest + end + else + raise Error::InvalidVerificationInput, "Unsupported artifact data: #{artifact.data}" + end + + freeze + end + end + + class SBundle < DelegateClass(Bundle::V1::Bundle) + attr_reader :bundle_type, :leaf_certificate + + def initialize(*) + super + @bundle_type = BundleType.from_media_type(media_type) + validate_version! + freeze + end + + def self.for_cert_bytes_and_signature(cert_bytes, signature) + bundle = Bundle::V1::Bundle.new + bundle.media_type = BundleType::BUNDLE_0_3.media_type + bundle.verification_material = Bundle::V1::VerificationMaterial.new + bundle.verification_material.certificate = Common::V1::X509Certificate.new + bundle.verification_material.certificate.raw_bytes = cert_bytes + bundle.message_signature = Common::V1::MessageSignature.new + bundle.message_signature.signature = signature + new(bundle) + end + + def expected_tlog_entry(hashed_input) + case content + when :message_signature + expected_hashed_rekord_tlog_entry(hashed_input) + when :dsse_envelope + rekor_entry = verification_material.tlog_entries.first + canonicalized_body = begin + JSON.parse(rekor_entry.canonicalized_body) + rescue JSON::ParserError + raise Error::InvalidBundle, "expected canonicalized_body to be JSON" + end + + case kind_version = canonicalized_body.values_at("kind", "apiVersion") + when %w[dsse 0.0.1] + expected_dsse_0_0_1_tlog_entry + when %w[intoto 0.0.2] + expected_intoto_0_0_2_tlog_entry + else + raise Error::InvalidRekorEntry, "Unhandled rekor entry kind/version: #{kind_version.inspect}" + end + else + raise Error::InvalidBundle, "expected either message_signature or dsse_envelope" + end + end + + private + + def validate_version! + raise Error::InvalidBundle, "bundle requires verification material" unless verification_material + + case bundle_type + when BundleType::BUNDLE_0_1 + unless verification_material.tlog_entries.all?(&:inclusion_promise) + raise Error::InvalidBundle, + "bundle v0.1 requires an inclusion promise" + end + if verification_material.tlog_entries.any? { |t| t.inclusion_proof&.checkpoint.nil? } + raise Error::InvalidBundle, + "0.1 bundle contains an inclusion proof without checkpoint" + end + else + unless verification_material.tlog_entries.all?(&:inclusion_proof) + raise Error::InvalidBundle, + "must contain an inclusion proof" + end + unless verification_material.tlog_entries.all? { |t| t.inclusion_proof.checkpoint&.envelope } + raise Error::InvalidBundle, + "inclusion proof must contain a checkpoint" + end + end + + raise Error::InvalidBundle, "Expected one tlog entry" if verification_material.tlog_entries.size > 1 + + case verification_material.content + when :public_key + raise Error::Unimplemented, "public_key content of bundle" + when :x509_certificate_chain + certs = verification_material.x509_certificate_chain.certificates.map do |cert| + Internal::X509::Certificate.read(cert.raw_bytes) + end + + @leaf_certificate = certs.first + certs.each do |cert| + raise Error::InvalidBundle, "Root CA in chain" if cert.ca? + end + when :certificate + @leaf_certificate = Internal::X509::Certificate.read(verification_material.certificate.raw_bytes) + else + raise Error::InvalidBundle, "Unsupported bundle content: #{content.inspect}" + end + raise Error::InvalidBundle, "expected certificate to be leaf" unless @leaf_certificate.leaf? + end + + def expected_hashed_rekord_tlog_entry(hashed_input) + { + "spec" => { + "signature" => { + "content" => Internal::Util.base64_encode(message_signature.signature), + "publicKey" => { + "content" => Internal::Util.base64_encode(leaf_certificate.to_pem) + } + }, + "data" => { + "hash" => { + "algorithm" => Internal::Util.hash_algorithm_name(hashed_input.algorithm), + "value" => Internal::Util.hex_encode(hashed_input.digest) + } + } + }, + "kind" => "hashedrekord", + "apiVersion" => "0.0.1" + } + end + + def expected_intoto_0_0_2_tlog_entry + { + "apiVersion" => "0.0.2", + "kind" => "intoto", + "spec" => { + "content" => { + "envelope" => { + "payloadType" => dsse_envelope.payloadType, + "payload" => Internal::Util.base64_encode(Internal::Util.base64_encode(dsse_envelope.payload)), + "signatures" => dsse_envelope.signatures.map do |sig| + { + "publicKey" => + # needed because #to_pem packs the key in base64 with m* + Internal::Util.base64_encode( + "-----BEGIN CERTIFICATE-----\n" \ + "#{Internal::Util.base64_encode(leaf_certificate.to_der)}\n" \ + "-----END CERTIFICATE-----\n" + ), + "sig" => Internal::Util.base64_encode(Internal::Util.base64_encode(sig.sig)) + } + end + }, + "payloadHash" => { + "algorithm" => "sha256", + "value" => OpenSSL::Digest::SHA256.hexdigest(dsse_envelope.payload) + } + } + } + } + end + + def expected_dsse_0_0_1_tlog_entry + { + "apiVersion" => "0.0.1", + "kind" => "dsse", + "spec" => { + "payloadHash" => { + "algorithm" => "sha256", + "value" => OpenSSL::Digest::SHA256.hexdigest(dsse_envelope.payload) + }, + "signatures" => + dsse_envelope.signatures.map do |sig| + { + "signature" => Internal::Util.base64_encode(sig.sig), + "verifier" => Internal::Util.base64_encode(leaf_certificate.to_pem) + } + end + } + } + end + end +end diff --git a/vendor/cache/sigstore-ruby-ce93acf7fa7e/lib/sigstore/oidc.rb b/vendor/cache/sigstore-ruby-ce93acf7fa7e/lib/sigstore/oidc.rb new file mode 100644 index 00000000..77918a95 --- /dev/null +++ b/vendor/cache/sigstore-ruby-ce93acf7fa7e/lib/sigstore/oidc.rb @@ -0,0 +1,149 @@ +# frozen_string_literal: true + +# Copyright 2024 The Sigstore Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +module Sigstore + module OIDC + KNOWN_OIDC_ISSUERS = { + "https://accounts.google.com" => "email", + "https://oauth2.sigstore.dev/auth" => "email", + "https://oauth2.sigstage.dev/auth" => "email", + "https://token.actions.githubusercontent.com" => "job_workflow_ref" + }.freeze + private_constant :KNOWN_OIDC_ISSUERS + + DEFAULT_AUDIENCE = "sigstore" + private_constant :DEFAULT_AUDIENCE + + class IdentityToken + attr_reader :raw_token, :identity + + def initialize(raw_token) + @raw_token = raw_token + + @unverified_claims = self.class.decode_jwt(raw_token) + @iss = @unverified_claims["iss"] + @nbf = @unverified_claims["nbf"] + @exp = @unverified_claims["exp"] + + # fail early if this token isn't within its validity period + raise Error::InvalidIdentityToken, "identity token is not within its validity period" unless in_validity_period? + + if (identity_claim = KNOWN_OIDC_ISSUERS[issuer]) + unless @unverified_claims[identity_claim] + raise Error::InvalidIdentityToken, "identity token is missing required claim: #{identity_claim}" + end + + @identity = @unverified_claims[identity_claim] + # https://github.com/sigstore/fulcio/blob/8311f93c01ea5b068a86d37c4bb51573289bfd69/pkg/identity/github/principal.go#L92 + @identity = "https://github.com/#{@identity}" if issuer == "https://token.actions.githubusercontent.com" + else + @identity = @unverified_claims["sub"] + end + end + + def issuer + @iss + end + + def self.decode_jwt(raw_token) + # These claims are required by OpenID Connect, so + # we can strongly enforce their presence. + # See: https://openid.net/specs/openid-connect-basic-1_0.html#IDToken + required = %w[aud sub iat exp iss] + audience = DEFAULT_AUDIENCE + leeway = 5 + + _header, payload, _signature = + raw_token + .split(".", 3) + .tap do |parts| + raise Error::InvalidIdentityToken, "identity token is not a JWT" unless parts.length == 3 + end.map! do |part| # rubocop:disable Style/MultilineBlockChain + part.unpack1("m*") + rescue ArgumentError + raise Error::InvalidIdentityToken, "Invalid base64 in identity token" + end + + begin + payload = JSON.parse(payload) + rescue JSON::ParserError + raise Error::InvalidIdentityToken, "Invalid JSON in identity token" + end + unless payload.is_a?(Hash) + raise Error::InvalidIdentityToken, + "Invalid JSON in identity token: must be a json object" + end + time = Time.now.to_i + validate_required_claims(payload, required) + validate_iat(payload["iat"], time, leeway) + validate_nbf(payload["nbf"], time, leeway) + validate_exp(payload["exp"], time, leeway) + validate_aud(payload["aud"], audience) + + payload + end + + private + + # Returns whether or not this `Identity` is currently within its self-stated validity period. + def in_validity_period? + now = Time.now.utc.to_i + return false if @nbf && @nbf > now + + now < @exp + end + + class << self + private + + def validate_required_claims(payload, required) + required.each do |claim| + next if payload[claim] + + raise Error::InvalidIdentityToken, "Missing required claim in identity token: #{claim}" + end + end + + def validate_iat(iat, now, leeway) + raise Error::InvalidIdentityToken, "iat claim must be an integer" unless iat.is_a?(Integer) + raise Error::InvalidIdentityToken, "iat claim is in the future" if iat > now + leeway + end + + def validate_nbf(nbf, now, leeway) + raise Error::InvalidIdentityToken, "nbf claim must be an integer" unless nbf.is_a?(Integer) + raise Error::InvalidIdentityToken, "nbf claim is in the future" if nbf > now + leeway + end + + def validate_exp(exp, now, leeway) + raise Error::InvalidIdentityToken, "exp claim must be an integer" unless exp.is_a?(Integer) + raise Error::InvalidIdentityToken, "exp claim is in the past" if exp <= now - leeway + end + + def validate_aud(aud, audience) + aud = Array(aud) + + raise Error::InvalidIdentityToken, "aud claim must not be empty" if aud.empty? + raise Error::InvalidIdentityToken, "aud claim must be strings" unless aud.all?(String) + + return if aud.include?(audience) + + raise Error::InvalidIdentityToken, + "aud claim does not contain the expected audience #{audience.inspect}" + end + end + end + end +end diff --git a/vendor/cache/sigstore-ruby-ce93acf7fa7e/lib/sigstore/policy.rb b/vendor/cache/sigstore-ruby-ce93acf7fa7e/lib/sigstore/policy.rb new file mode 100644 index 00000000..f72155de --- /dev/null +++ b/vendor/cache/sigstore-ruby-ce93acf7fa7e/lib/sigstore/policy.rb @@ -0,0 +1,114 @@ +# frozen_string_literal: true + +# Copyright 2024 The Sigstore Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +module Sigstore + module Policy + class SingleX509ExtPolicy + def initialize(value) + @value = value + end + + def verify(cert) + ext = cert.openssl.find_extension(oid) + unless ext + return VerificationFailure.new("Certificate does not contain #{self.class.name&.[](/::([^:]+)$/, 1)} " \ + "(#{oid}) extension") + end + + value = ext_value(ext) + verified = value == @value + unless verified + return VerificationFailure.new("Certificate's #{self.class.name&.[](/::([^:]+)$/, 1)} does not match " \ + "(got #{value}, expected #{@value})") + end + + VerificationSuccess.new + end + + if RUBY_ENGINE == "jruby" + def ext_value(ext) + der = ext.to_der + seq = OpenSSL::ASN1.decode(der) + seq.value.last.value + end + else + def ext_value(ext) + ext.value + end + end + + def oid + self.class::OID # : String + end + end + + class OIDCIssuer < SingleX509ExtPolicy + OID = "1.3.6.1.4.1.57264.1.1" + end + + class SingleX509ExtDerEncodedPolicy < SingleX509ExtPolicy + def ext_value(ext) + OpenSSL::ASN1.decode(ext.value_der).value + end + end + + class OIDCIssuerV2 < SingleX509ExtDerEncodedPolicy + OID = "1.3.6.1.4.1.57264.1.8" + end + + class AnyOf + def initialize(*policies) + @policies = policies + end + + def verify(cert) + failures = [] + @policies.each do |policy| + result = policy.verify(cert) + return result if result.verified? + + failures << result.reason + end + + VerificationFailure.new("No policy matched: #{failures.join(", ")}") + end + end + + class Identity + def initialize(identity:, issuer:) + @identity = identity + @issuer = AnyOf.new(OIDCIssuer.new(issuer), OIDCIssuerV2.new(issuer)) + end + + def verify(cert) + issuer_verified = @issuer.verify(cert) + return issuer_verified unless issuer_verified.verified? + + san_ext = cert.extension(Sigstore::Internal::X509::Extension::SubjectAlternativeName) + raise Error::InvalidCertificate, "Certificate does not contain subjectAltName extension" unless san_ext + + verified = san_ext.general_names.any? { |_, id| id == @identity } + unless verified + return VerificationFailure.new( + "Certificate's SANs do not match #{@identity}; actual SANs: #{san_ext.general_names}" + ) + end + + VerificationSuccess.new + end + end + end +end diff --git a/vendor/cache/sigstore-ruby-ce93acf7fa7e/lib/sigstore/rekor/checkpoint.rb b/vendor/cache/sigstore-ruby-ce93acf7fa7e/lib/sigstore/rekor/checkpoint.rb new file mode 100644 index 00000000..f6c3d2a7 --- /dev/null +++ b/vendor/cache/sigstore-ruby-ce93acf7fa7e/lib/sigstore/rekor/checkpoint.rb @@ -0,0 +1,114 @@ +# frozen_string_literal: true + +# Copyright 2024 The Sigstore Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +module Sigstore + module Rekor + module Checkpoint + Signature = Struct.new(:name, :sig_hash, :signature, keyword_init: true) + + SignedCheckpoint = Struct.new(:signed_note, :checkpoint, keyword_init: true) do + # @implements SignedCheckpoint + + def self.from_text(text) + signed_note = SignedNote.from_text(text) + checkpoint = LogCheckpoint.from_text(signed_note.note) + + new(signed_note:, checkpoint:) + end + end + + SignedNote = Struct.new(:note, :signatures, keyword_init: true) do + # @implements SignedNote + + def self.from_text(text) + separator = "\n\n" + + raise Error::InvalidCheckpoint, "Note must include double newline separator" unless text.include?(separator) + + note, signatures = text.split(separator, 2) + raise Error::InvalidCheckpoint, "must contain at least one signature" if signatures.empty? + raise Error::InvalidCheckpoint, "signatures must end with a newline" unless signatures.end_with?("\n") + + note << "\n" + + sig_parser = %r{^\u2014 (?[^[[:space:]]+]+) (?[0-9A-Za-z+/=-]+)\n} + + signatures = signatures.lines.map! do |line| + raise Error::InvalidCertificate, "Invalid signature line: #{line.inspect}" unless sig_parser =~ line + + name = Regexp.last_match[:name] + signature = Regexp.last_match[:signature] + + signature_bytes = signature.unpack1("m0") + raise Error::InvalidCheckpoint, "too few bytes in signature" if signature_bytes.bytesize < 5 + + sig_hash = signature_bytes.slice!(0, 4).unpack1("a4") + + Signature.new(name:, sig_hash:, signature: signature_bytes) + end + + new(note:, signatures:) + end + + def verify(rekor_keyring, key_id) + data = note.encode("utf-8") + signatures.each do |signature| + sig_hash = key_id[0, 4] + if signature.sig_hash != sig_hash + raise Error::InvalidCheckpoint, + "sig_hash hint #{signature.sig_hash.inspect} does not match key_id #{sig_hash.inspect}" + end + + rekor_keyring.verify(key_id: key_id.unpack1("H*"), signature: signature.signature, data:) + end + end + end + + LogCheckpoint = Struct.new(:origin, :log_size, :log_hash, :other_content, keyword_init: true) do + # @implements LogCheckpoint + + def self.from_text(text) + lines = text.strip.split("\n") + + raise Error::InvalidCheckpoint, "too few items in header" if lines.size < 3 + + origin = lines.shift + log_size = lines.shift.to_i + root_hash = lines.shift.unpack1("m0") + + raise Error::InvalidCheckpoint, "empty origin" if origin.empty? + + new(origin:, log_size:, log_hash: root_hash, other_content: lines) + end + end + + def self.verify_checkpoint(rekor_keyring, entry) + raise Error::InvalidRekorEntry, "Rekor entry has no inclusion proof" unless entry.inclusion_proof + + signed_checkpoint = SignedCheckpoint.from_text(entry.inclusion_proof.checkpoint.envelope) + signed_checkpoint.signed_note.verify(rekor_keyring, entry.log_id.key_id) + + checkpoint_hash = signed_checkpoint.checkpoint.log_hash + root_hash = entry.inclusion_proof.root_hash + + return if checkpoint_hash == root_hash + + raise Error::InvalidRekorEntry, "Inclusion proof contains invalid root hash: " \ + "expected #{checkpoint_hash.inspect}, calculated #{root_hash.inspect}" + end + end + end +end diff --git a/vendor/cache/sigstore-ruby-ce93acf7fa7e/lib/sigstore/rekor/client.rb b/vendor/cache/sigstore-ruby-ce93acf7fa7e/lib/sigstore/rekor/client.rb new file mode 100644 index 00000000..ba0a1b4b --- /dev/null +++ b/vendor/cache/sigstore-ruby-ce93acf7fa7e/lib/sigstore/rekor/client.rb @@ -0,0 +1,141 @@ +# frozen_string_literal: true + +# Copyright 2024 The Sigstore Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +require "net/http" + +module Sigstore + module Rekor + class Client + DEFAULT_REKOR_URL = "https://rekor.sigstore.dev" + STAGING_REKOR_URL = "https://rekor.sigstage.dev" + + def initialize(url:) + @url = URI.join(url, "api/v1/") + + net = defined?(Gem::Net) ? Gem::Net : Net + @session = net::HTTP.new(@url.host, @url.port) + @session.use_ssl = true + end + + def self.production + new(url: DEFAULT_REKOR_URL) + end + + def self.staging + new(url: STAGING_REKOR_URL) + end + + def log + Log.new(URI.join(@url, "log/"), session: @session) + end + end + + class Log + def initialize(url, session:) + @url = url + @session = session + end + + def entries + Entries.new(URI.join(@url, "entries/"), session: @session) + end + end + + class Entries + def initialize(url, session:) + @url = url + @session = session + end + + def retrieve + Retrieve.new(URI.join(@url, "retrieve/"), session: @session) + end + + def post(entry) + resp = @session.post2(@url.path.chomp("/"), entry.to_json, + { "Content-Type" => "application/json", "Accept" => "application/json" }) + + unless resp.code == "201" + raise Error::FailedRekorPost, + "#{resp.code} #{resp.message.inspect}\n#{JSON.pretty_generate(entry)}\n#{resp.body}" + end + unless resp.content_type == "application/json" + raise Error::FailedRekorPost, "Unexpected content type: #{resp.content_type.inspect}" + end + + body = JSON.parse(resp.body) + Entries.decode_transparency_log_entry(body) + end + + class Retrieve + def initialize(url, session:) + @url = url + @session = session + end + + def post(expected_entry) + data = { entries: [expected_entry] } + resp = @session.post2(@url.path, data.to_json, + { "Content-Type" => "application/json", "Accept" => "application/json" }) + + if resp.code != "200" + raise Error::FailedRekorLookup, + "#{resp.code} #{resp.message.inspect}\n#{JSON.pretty_generate(data)}\n#{resp.body}" + end + + results = JSON.parse(resp.body) + + results.map do |result| + Entries.decode_transparency_log_entry(result) + end.min_by(&:integrated_time) + end + end + + def self.decode_transparency_log_entry(response) + raise ArgumentError, "response must be a Hash" unless response.is_a?(Hash) + raise ArgumentError, "Received multiple entries in response" if response.size != 1 + + _, result = response.first + canonicalized_body = Internal::Util.base64_decode(result.fetch("body")) + body = JSON.parse(canonicalized_body) + entry = V1::TransparencyLogEntry.new + entry.log_index = result.fetch("logIndex") + entry.log_id = Common::V1::LogId.new + entry.log_id.key_id = Internal::Util.hex_decode(result.fetch("logID")) + entry.kind_version = V1::KindVersion.new + entry.kind_version.kind = body.fetch("kind") + entry.kind_version.version = body.fetch("apiVersion") + entry.integrated_time = result.fetch("integratedTime") + entry.canonicalized_body = canonicalized_body + if (set = result.dig("verification", "signedEntryTimestamp")) + entry.inclusion_promise = V1::InclusionPromise.new + entry.inclusion_promise.signed_entry_timestamp = Internal::Util.base64_decode(set) + end + if (inclusion_proof = result.dig("verification", "inclusionProof")) + entry.inclusion_proof = V1::InclusionProof.new + entry.inclusion_proof.checkpoint = V1::Checkpoint.new + entry.inclusion_proof.checkpoint.envelope = inclusion_proof.fetch("checkpoint") + entry.inclusion_proof.hashes = inclusion_proof.fetch("hashes").map { |h| Internal::Util.hex_decode(h) } + entry.inclusion_proof.log_index = inclusion_proof.fetch("logIndex") + entry.inclusion_proof.root_hash = Internal::Util.hex_decode(inclusion_proof.fetch("rootHash")) + entry.inclusion_proof.tree_size = inclusion_proof.fetch("treeSize") + end + + entry + end + end + end +end diff --git a/vendor/cache/sigstore-ruby-ce93acf7fa7e/lib/sigstore/signer.rb b/vendor/cache/sigstore-ruby-ce93acf7fa7e/lib/sigstore/signer.rb new file mode 100644 index 00000000..aa88c114 --- /dev/null +++ b/vendor/cache/sigstore-ruby-ce93acf7fa7e/lib/sigstore/signer.rb @@ -0,0 +1,283 @@ +# frozen_string_literal: true + +# Copyright 2024 The Sigstore Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +require_relative "internal/util" +require_relative "internal/x509" +require_relative "models" +require_relative "oidc" +require_relative "policy" +require_relative "verifier" + +module Sigstore + class Signer + include Loggable + + def initialize(jwt:, trusted_root:) + @identity_token = OIDC::IdentityToken.new(jwt) + @trusted_root = trusted_root + + @verifier = Verifier.for_trust_root(trust_root: @trusted_root) + end + + def sign(payload) + # 2) generate a keypair + keypair = generate_keypair + # 3) generate a CreateSigningCertificateRequest + csr = generate_csr(keypair) + # 4) get a cert chain from fulcio + leaf = fetch_cert(csr) + # 5) verify returned cert chain + verify_chain(leaf) + # 6) sign the payload + signature = sign_payload(payload, keypair) + # 7) send hash of signature to timestamping service + timestamp_verification_data = submit_signature_hash_to_timstamping_service(signature) + # 8) submit signed metadata to transparency service + hashed_input = Common::V1::HashOutput.new + hashed_input.algorithm = Common::V1::HashAlgorithm::SHA2_256 + hashed_input.digest = OpenSSL::Digest("SHA256").digest(payload) + tlog_entry = submit_signed_metadata_to_transparency_service(signature, leaf, hashed_input) + # 9) perform verification + + bundle = collect_bundle(leaf, [tlog_entry], timestamp_verification_data, hashed_input, signature) + verify(payload, bundle) + + bundle + end + + private + + def generate_keypair + # maybe allow configuring? + key = OpenSSL::PKey::EC.generate("prime256v1") + logger.debug { "Generated keypair #{key}" } + key + end + + def generate_csr(keypair) + csr = OpenSSL::X509::Request.new + + # The subject is unused, but must be set to avoid an error on JRuby + csr.subject = OpenSSL::X509::Name.new + csr.public_key = keypair + + # The subject in the CertificationRequestInfo is an X.501 RelativeDistinguishedName. + # The value of the RelativeDistinguishedName SHOULD be the subject of the authentication token; + # its type MUST be the type identified in the Fulcio instance’s public configuration. + # NOTE: the subject of the CSR is unused + + extension = OpenSSL::X509::ExtensionFactory.new.create_extension( + "basicConstraints", + "CA:FALSE", + true # critical + ) + csr.add_attribute OpenSSL::X509::Attribute.new( + "extReq", + OpenSSL::ASN1::Set.new( + [OpenSSL::ASN1::Sequence.new([extension])] + ) + ) + + csr.sign keypair, OpenSSL::Digest.new("SHA256") + + logger.debug { "Generated CSR" } + + { + credentials: { + oidcIdentityToken: @identity_token.raw_token + }, + certificateSigningRequest: Internal::Util.base64_encode(csr.to_pem) + } + end + + def fetch_cert(csr) + uri = URI.parse @trusted_root.certificate_authority_for_signing.uri + uri = URI.join(uri, "api/v2/signingCert") + resp = Net::HTTP.post( + uri, + JSON.dump(csr), + { "Content-Type" => "application/json" } + ) + + unless resp.code == "200" + raise Error::Signing, + "#{resp.code} #{resp.message}\n\n#{resp.body}" + end + + resp_body = JSON.parse(resp.body) + + unless resp_body.key?("signedCertificateEmbeddedSct") + raise Error::Signing, "missing signedCertificateEmbeddedSct in response from fulcio" + end + + cert = resp_body.fetch("signedCertificateEmbeddedSct").fetch("chain") + .fetch("certificates").first.then { |pem| Internal::X509::Certificate.read(pem) } + logger.debug { "Fetched cert from fulcio" } + cert + end + + def verify_chain(leaf) + # Perform certification path validation (RFC 5280 §6) of the returned certificate chain with the pre-distributed + # Fulcio root certificate(s) as a trust anchor. + + now = Time.now + if leaf.not_before > now + unless leaf.not_before - now < 60 + raise Error::Signing, "leaf certificate not yet valid: #{leaf.not_before.inspect} vs #{now.inspect}" + end + + logger.warn do + "leaf certificate not yet valid: #{leaf.not_before.inspect} vs #{now.inspect}, sleeping until valid" + end + sleep(leaf.not_before - now) + end + + chain, err = Internal::X509.validate_chain(@trusted_root.fulcio_cert_chains, leaf, nil) + raise Error::Signing, "failed to validate returned certificate chain: #{err.reason}" if err + + logger.debug { "verified chain" } + + # Extract a SignedCertificateTimestamp, which may be embedded as an X.509 extension in the leaf certificate or + # attached separately in the SigningCertificate returned from the Identity Service. + # Verify this SignedCertificateTimestamp as in RFC 9162 §8.1.3, using the root certificate from + # the Certificate Transparency Log. + if (result = @verifier.verify_scts(leaf, chain)) && !result.verified? + raise Error::Signing, "Failed to verify SCTs: #{result.reason}" + end + + # Check that the leaf certificate contains the subject from the certificate signing request and encodes the + # appropriate AuthenticationServiceIdentifier in an extension with OID 1.3.6.1.4.1.57264.1.8. + + fulcio_issuer = leaf.extension(Internal::X509::Extension::FulcioIssuer) + unless fulcio_issuer && fulcio_issuer.issuer == @identity_token.issuer + raise Error::Signing, "certificate does not contain expected Fulcio issuer" + end + + unless leaf.subject.to_a.empty? + raise Error::Signing, + "certificate contains unexpected subject #{leaf.subject.to_a}" + end + + general_names = leaf.extension(Internal::X509::Extension::SubjectAlternativeName).general_names + expected_san = [@identity_token.identity] + if general_names.map(&:last) != expected_san + raise Error::Signing, + "certificate does not contain expected SAN #{expected_san}, got #{general_names}" + end + + [leaf, chain.unshift(leaf)] + end + + def sign_payload(payload, key) + # The Signer MAY pre-hash the payload using a hash algorithm from the registry (Spec: Sigstore Registries) for + # compatibility with some signing metadata formats (see §Submission of Signing Metadata to Transparency Service). + key.sign("SHA256", payload) + end + + # TODO: implement + def submit_signature_hash_to_timstamping_service(_signature) + # The Signer sends a hash of the signature as the messageImprint in a TimeStampReq to the Timestamping Service and + # receives a TimeStampResp including a `TimeStampToken`. + # The signer MUST verify the TimeStampToken against the payload and Timestamping Service root certificate. + + nil + end + + def build_proposed_hashed_rekord_entry(signature, cert, hashed_input) + algorithm = case hashed_input.algorithm + when Common::V1::HashAlgorithm::SHA2_256 then "sha256" + when Common::V1::HashAlgorithm::SHA2_384 then "sha384" + when Common::V1::HashAlgorithm::SHA2_512 then "sha512" + else + raise ArgumentError, + "unsupported hash algorithm: #{hashed_input.algorithm.inspect}" + end + { + "spec" => { + "signature" => { + "content" => Internal::Util.base64_encode(signature), + "publicKey" => { + "content" => Internal::Util.base64_encode(cert.to_pem) + } + }, + "data" => { + "hash" => { + "algorithm" => algorithm, + "value" => Internal::Util.hex_encode(hashed_input.digest) + } + } + }, + "kind" => "hashedrekord", + "apiVersion" => "0.0.1" + } + end + + def submit_signed_metadata_to_transparency_service(signature, cert, hashed_input) + # The Signer chooses a format for signing metadata; this format MUST be in the supportedMetadataFormats in the + # Transparency Service configuration. The Signer prepares signing metadata containing at a minimum: + # * The signature. + # * The payload (possibly pre-hashed; if so, the entry also includes the identifier of the hash algorithm). + # * Verification material (signing certificate or verification key). + # * If the verification material is a certificate, the client SHOULD upload only the signing certificate and + # SHOULD NOT upload the CA certificate chain. + # + # The signing metadata might contain additional, application-specific metadata according to the format used. + # The Signer then canonically encodes the metadata (according to the chosen format). + + # TODO: allow configuring the entry kind? + proposed_entry = build_proposed_hashed_rekord_entry(signature, cert, hashed_input) + + ctlog = @trusted_root.tlog_for_signing + logger.info { "Submitting to #{ctlog.base_url}" } + + # The signer MUST verify the log entry as in Spec: Transparency Service. + @verifier.rekor_client.log.entries.post(proposed_entry) + end + + def verify(artifact, bundle) + verification_input = Verification::V1::Input.new + verification_input.bundle = bundle + verification_input.artifact = Verification::V1::Artifact.new + verification_input.artifact.artifact = artifact + + result = @verifier.verify( + input: VerificationInput.new(verification_input), + policy: expected_identity, + offline: false + ) + raise Error::Signing, "Failed to verify: #{result.reason}" unless result.verified? + end + + def expected_identity + Policy::Identity.new(identity: @identity_token.identity, issuer: @identity_token.issuer) + end + + def collect_bundle(leaf_certificate, tlog_entries, timestamp_verification_data, hashed_input, signature) + bundle = Bundle::V1::Bundle.new + bundle.media_type = BundleType::BUNDLE_0_3.media_type + bundle.verification_material = Bundle::V1::VerificationMaterial.new + bundle.verification_material.certificate = Common::V1::X509Certificate.new + bundle.verification_material.certificate.raw_bytes = leaf_certificate.to_der + bundle.verification_material.tlog_entries = tlog_entries + bundle.verification_material.timestamp_verification_data = timestamp_verification_data + bundle.message_signature = Sigstore::Common::V1::MessageSignature.new.tap do |ms| + ms.message_digest = hashed_input + ms.signature = signature + end + bundle + end + end +end diff --git a/vendor/cache/sigstore-ruby-ce93acf7fa7e/lib/sigstore/trusted_root.rb b/vendor/cache/sigstore-ruby-ce93acf7fa7e/lib/sigstore/trusted_root.rb new file mode 100644 index 00000000..a2b569cf --- /dev/null +++ b/vendor/cache/sigstore-ruby-ce93acf7fa7e/lib/sigstore/trusted_root.rb @@ -0,0 +1,115 @@ +# frozen_string_literal: true + +# Copyright 2024 The Sigstore Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +require "delegate" +require "openssl" + +require "protobug_sigstore_protos" + +require_relative "tuf" + +module Sigstore + REGISTRY = Protobug::Registry.new do |registry| + Sigstore::TrustRoot::V1.register_sigstore_trustroot_protos(registry) + Sigstore::Bundle::V1.register_sigstore_bundle_protos(registry) + end + class TrustedRoot < DelegateClass(Sigstore::TrustRoot::V1::TrustedRoot) + def self.production(offline: false) + from_tuf(TUF::DEFAULT_TUF_URL, offline) + end + + def self.staging(offline: false) + from_tuf(TUF::STAGING_TUF_URL, offline) + end + + def self.from_tuf(url, offline) + path = TUF::TrustUpdater.new(url, offline).tap { _1.refresh unless offline }.trusted_root_path + from_file(path) + end + + def self.from_file(path) + contents = Gem.read_binary(path) + new Sigstore::TrustRoot::V1::TrustedRoot.decode_json(contents, registry: REGISTRY) + end + + def rekor_keys + keys = tlog_keys(tlogs).to_a + raise Error::InvalidBundle, "Did not find one Rekor key" if keys.size != 1 + + keys + end + + def ctfe_keys + keys = tlog_keys(ctlogs).to_a + raise Error::InvalidBundle, "Did not find any CTFE keys" if keys.empty? + + keys + end + + def fulcio_cert_chains + chains = ca_keys(certificate_authorities, allow_expired: true).map do |certs| + certs.map { |raw_bytes| Internal::X509::Certificate.read(raw_bytes) } + end + raise Error::InvalidBundle, "Fulcio certificates not found in trusted root" if chains.none?(&:any?) + + chains + end + + def tlog_for_signing + tlogs.find do |ctlog| + timerange_valid?(ctlog.public_key.valid_for, allow_expired: false) + end + end + + def certificate_authority_for_signing + certificate_authorities.find do |ca| + timerange_valid?(ca.valid_for, allow_expired: false) + end + end + + private + + def tlog_keys(tlogs) + return enum_for(__method__, tlogs) unless block_given? + + tlogs.each do |transparency_log_instance| + key = transparency_log_instance.public_key + parsed_key = Internal::Key.from_key_details(key.key_details, key.raw_bytes) + yield parsed_key if parsed_key + end + end + + def ca_keys(certificate_authorities, allow_expired:) + return enum_for(__method__, certificate_authorities, allow_expired:) unless block_given? + + certificate_authorities.each do |ca| + next unless timerange_valid?(ca.valid_for, allow_expired:) + + yield ca.cert_chain.certificates.map(&:raw_bytes) + end + end + + def timerange_valid?(period, allow_expired:) + now = Time.now.utc + return true unless period + return false if now < period.start.to_time + return true if allow_expired + return false if period.end && now > period.end.to_time + + true + end + end +end diff --git a/vendor/cache/sigstore-ruby-ce93acf7fa7e/lib/sigstore/tuf.rb b/vendor/cache/sigstore-ruby-ce93acf7fa7e/lib/sigstore/tuf.rb new file mode 100644 index 00000000..212feb67 --- /dev/null +++ b/vendor/cache/sigstore-ruby-ce93acf7fa7e/lib/sigstore/tuf.rb @@ -0,0 +1,158 @@ +# frozen_string_literal: true + +# Copyright 2024 The Sigstore Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +require_relative "tuf/updater" +require "tempfile" +require "uri" +require "net/http" +require "rubygems/remote_fetcher" + +module Sigstore + module TUF + DEFAULT_TUF_URL = "https://tuf-repo-cdn.sigstore.dev" + STAGING_TUF_URL = "https://tuf-repo-cdn.sigstage.dev" + + class TrustUpdater + include Loggable + + Net = defined?(Gem::Net) ? Gem::Net : Net + + attr_reader :updater + + def initialize(metadata_url, offline, metadata_dir: nil, targets_dir: nil, target_base_url: nil, + config: UpdaterConfig.new) + @repo_url = metadata_url + + default_metadata_dir, default_targets_dir = get_dirs(metadata_url) unless metadata_dir && targets_dir + @metadata_dir = metadata_dir || default_metadata_dir + @targets_dir = targets_dir || default_targets_dir + + @offline = offline + + rsrc_prefix = if @repo_url == DEFAULT_TUF_URL + "prod" + elsif @repo_url == STAGING_TUF_URL + "staging" + end + + FileUtils.mkdir_p @metadata_dir + FileUtils.mkdir_p @targets_dir + + if rsrc_prefix + tuf_root = File.join(@metadata_dir, "root.json") + + unless File.exist?(tuf_root) + File.open(tuf_root, "wb") do |f| + File.open(File.expand_path("../../data/_store/#{rsrc_prefix}/root.json", __dir__), "rb") do |r| + logger.info { "Copying root.json from #{r.path} to #{f.path}" } + IO.copy_stream(r, f) + end + end + end + + trusted_root_target = File.join(@targets_dir, "trusted_root.json") + + unless File.exist?(trusted_root_target) + File.open(trusted_root_target, "wb") do |f| + File.open(File.expand_path("../../data/_store/#{rsrc_prefix}/trusted_root.json", __dir__), + "rb") do |r| + logger.info { "Copying trusted_root.json from #{r.path} to #{f.path}" } + IO.copy_stream(r, f) + end + end + end + end + + return if @offline + + @updater = Updater.new( + metadata_dir: @metadata_dir, + metadata_base_url: @repo_url, + target_base_url: (target_base_url && URI.parse(target_base_url)) || + URI.join("#{@repo_url.to_s.chomp("/")}/", "targets/"), + target_dir: @targets_dir, + fetcher: method(:fetch), + config: + ) + end + + def get_dirs(url) + app_name = "sigstore-ruby" + app_author = "sigstore" + + repo_base = URI.encode_uri_component(url) + home = Dir.home + + data_home = ENV.fetch("XDG_DATA_HOME", File.join(home, ".local", "share")) + cache_home = ENV.fetch("XDG_CACHE_HOME", File.join(home, ".cache")) + tuf_data_dir = File.join(data_home, app_name, app_author, "tuf") + tuf_cache_dir = File.join(cache_home, app_name, app_author, "tuf") + + [File.join(tuf_data_dir, repo_base), File.join(tuf_cache_dir, repo_base)] + end + + def trusted_root_path + unless @updater + logger.info { "Offline mode: using cached trusted root" } + return File.join(@targets_dir, "trusted_root.json") + end + + root_info = @updater.get_targetinfo("trusted_root.json") + raise Error::NoTrustedRoot, "Unsupported TUF configuration: no trusted_root.json" unless root_info + + path = @updater.find_cached_target(root_info) + path ||= @updater.download_target(root_info) + + path + end + + def refresh + raise ArgumentError, "Offline mode: cannot refresh" if @offline || !@updater + + @updater.refresh + end + + private + + def fetch(uri) + uri = Gem::Uri.new uri + raise ArgumentError, "uri scheme is invalid: #{uri.scheme.inspect}" unless %w[http https].include?(uri.scheme) + + fetcher = Gem::RemoteFetcher.fetcher + begin + response = fetcher.request(uri, Net::HTTP::Get, nil) do + nil + end + response.uri = uri + case response + when Net::HTTPOK + nil + when Net::HTTPMovedPermanently, Net::HTTPFound, Net::HTTPSeeOther, + Net::HTTPTemporaryRedirect + raise Error::UnsuccessfulResponse.new("should redirects be supported?", response) + else + raise Error::UnsuccessfulResponse.new("FetchError: #{response.code}", response) + end + response.body + rescue (defined?(Gem::Timeout::Error) ? Gem::Timeout::Error : Timeout::Error), + IOError, SocketError, SystemCallError, + *(OpenSSL::SSL::SSLError if Gem::HAVE_OPENSSL) => e + raise Error::RemoteConnection, e.message + end + end + end + end +end diff --git a/vendor/cache/sigstore-ruby-ce93acf7fa7e/lib/sigstore/tuf/config.rb b/vendor/cache/sigstore-ruby-ce93acf7fa7e/lib/sigstore/tuf/config.rb new file mode 100644 index 00000000..c579cc4c --- /dev/null +++ b/vendor/cache/sigstore-ruby-ce93acf7fa7e/lib/sigstore/tuf/config.rb @@ -0,0 +1,46 @@ +# frozen_string_literal: true + +# Copyright 2024 The Sigstore Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +module Sigstore + module TUF + class UpdaterConfig + attr_reader :max_root_rotations, :max_delegations, :root_max_length, :timestamp_max_length, :snapshot_max_length, + :targets_max_length, :prefix_targets_with_hash, :envelope_type, :app_user_agent + + def initialize( + max_root_rotations: 32, + max_delegations: 32, + root_max_length: 512_000, # bytes + timestamp_max_length: 16_384, # bytes + snapshot_max_length: 2_000_000, # bytes + targets_max_length: 5_000_000, # bytes + prefix_targets_with_hash: true, + envelope_type: :metadata, + app_user_agent: nil + ) + @max_root_rotations = max_root_rotations + @max_delegations = max_delegations + @root_max_length = root_max_length + @timestamp_max_length = timestamp_max_length + @snapshot_max_length = snapshot_max_length + @targets_max_length = targets_max_length + @prefix_targets_with_hash = prefix_targets_with_hash + @envelope_type = envelope_type + @app_user_agent = app_user_agent + end + end + end +end diff --git a/vendor/cache/sigstore-ruby-ce93acf7fa7e/lib/sigstore/tuf/error.rb b/vendor/cache/sigstore-ruby-ce93acf7fa7e/lib/sigstore/tuf/error.rb new file mode 100644 index 00000000..9d191c2b --- /dev/null +++ b/vendor/cache/sigstore-ruby-ce93acf7fa7e/lib/sigstore/tuf/error.rb @@ -0,0 +1,49 @@ +# frozen_string_literal: true + +# Copyright 2024 The Sigstore Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +require_relative "../error" + +module Sigstore::TUF + class Error < ::Sigstore::Error + # An error with a repository's state, such as a missing file. + class RepositoryError < Error; end + + class LengthOrHashMismatch < RepositoryError; end + class ExpiredMetadata < RepositoryError; end + class BadVersionNumber < RepositoryError; end + class EqualVersionNumber < BadVersionNumber; end + class TooFewSignatures < RepositoryError; end + + class BadUpdateOrder < Error; end + class InvalidData < Error; end + class DuplicateKeys < Error; end + + # An error occurred while attempting to download a file. + class DownloadError < Error; end + + class Fetch < Error; end + class RemoteConnection < Fetch; end + + class UnsuccessfulResponse < Fetch + attr_reader :response + + def initialize(message, response) + super(message) + @response = response + end + end + end +end diff --git a/vendor/cache/sigstore-ruby-ce93acf7fa7e/lib/sigstore/tuf/file.rb b/vendor/cache/sigstore-ruby-ce93acf7fa7e/lib/sigstore/tuf/file.rb new file mode 100644 index 00000000..faf80709 --- /dev/null +++ b/vendor/cache/sigstore-ruby-ce93acf7fa7e/lib/sigstore/tuf/file.rb @@ -0,0 +1,96 @@ +# frozen_string_literal: true + +# Copyright 2024 The Sigstore Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +require_relative "error" + +module Sigstore::TUF + module BaseFile + def self.included(base) + base.extend(ClassMethods) + super + end + + module ClassMethods + def verify_hashes(data, expected_hashed) + expected_hashed.each do |algorithm, expected_hash| + actual_hash = Digest(algorithm.upcase).hexdigest(data) + unless actual_hash == expected_hash + raise Error::LengthOrHashMismatch, + "observed hash #{actual_hash} does not match expected hash #{expected_hash}" + end + end + end + + def verify_length(data, expected_length) + actual_length = data.bytesize + return if actual_length == expected_length + + raise Error::LengthOrHashMismatch, + "Observed length #{actual_length} does not match expected length #{expected_length}" + end + + def validate_hashes(hashes) + raise ArgumentError, "hashes must be non-empty" if hashes.empty? + + hashes.each do |algorithm, hash| + raise TypeError, "hashes items must be strings" unless algorithm.is_a?(String) && hash.is_a?(String) + end + end + + def validate_length(length) + return unless length.negative? + + raise ArgumentError, "length must be a non-negative integer, got #{length.inspect}" + end + end + end + + module MetaFile + def self.included(base) + base.include(BaseFile) + base.extend(ClassMethods) + super + end + + def initialize(version: 1, length: nil, hashes: nil, unrecognized_fields: {}) + @version = version + @length = length + @hashes = hashes + @unrecognized_fields = unrecognized_fields + + raise ArgumentError, "Metafile version must be positive, got #{@version}" if @version <= 0 + + self.class.validate_length(@length) unless @length.nil? + self.class.validate_hashes(@hashes) unless @hashes.nil? + end + + def verify_length_and_hashes(data) + self.class.verify_length(data, @length) if @length + self.class.verify_hashes(data, @hashes) if @hashes + end + + module ClassMethods + def from_hash(meta_dict) + version = meta_dict.fetch("version") { raise KeyError, "version is required, given #{meta_dict.inspect}" } + length = meta_dict.fetch("length", nil) + hashes = meta_dict.fetch("hashes", nil) + + new(version:, length:, hashes:, + unrecognized_fields: meta_dict.slice(*(meta_dict.keys - %w[version length hashes]))) + end + end + end +end diff --git a/vendor/cache/sigstore-ruby-ce93acf7fa7e/lib/sigstore/tuf/keys.rb b/vendor/cache/sigstore-ruby-ce93acf7fa7e/lib/sigstore/tuf/keys.rb new file mode 100644 index 00000000..f9621ce5 --- /dev/null +++ b/vendor/cache/sigstore-ruby-ce93acf7fa7e/lib/sigstore/tuf/keys.rb @@ -0,0 +1,42 @@ +# frozen_string_literal: true + +# Copyright 2024 The Sigstore Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +module Sigstore::TUF + class Keys + include Enumerable + + def initialize(keys) + @keys = keys.to_h do |key_id, key_data| + key_type = key_data.fetch("keytype") + scheme = key_data.fetch("scheme") + keyval = key_data.fetch("keyval") + public_key_data = keyval.fetch("public") + + key = Sigstore::Internal::Key.read(key_type, scheme, public_key_data, key_id:) + + [key_id, key] + end + end + + def fetch(key_id) + @keys.fetch(key_id) + end + + def each(&) + @keys.each(&) + end + end +end diff --git a/vendor/cache/sigstore-ruby-ce93acf7fa7e/lib/sigstore/tuf/roles.rb b/vendor/cache/sigstore-ruby-ce93acf7fa7e/lib/sigstore/tuf/roles.rb new file mode 100644 index 00000000..beaa4ffa --- /dev/null +++ b/vendor/cache/sigstore-ruby-ce93acf7fa7e/lib/sigstore/tuf/roles.rb @@ -0,0 +1,106 @@ +# frozen_string_literal: true + +# Copyright 2024 The Sigstore Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +module Sigstore::TUF + class Roles + include Enumerable + + def initialize(data, keys) + @roles = + case data + when Hash # root roles + data.to_h do |role_name, role_data| + role_data = role_data.merge("name" => role_name, "paths" => nil) + role = Role.new(role_data, keys) + [role.name, role] + end + when Array # targets roles + data.to_h do |role_data| + role = Role.new(role_data, keys) + [role.name, role] + end + else + raise ArgumentError, "Unexpected data: #{data.inspect}" + end + end + + def each(&) + @roles.each(&) + end + + def verify_delegate(type, bytes, signatures) + role = fetch(type) + role.verify_delegate(type, bytes, signatures) + end + + def fetch(name) + @roles.fetch(name) + end + + def for_target(target_path) + select do |_, role| + # TODO: this needs to be tested + role.paths.any? { |path| File.fnmatch?(path, target_path, File::FNM_PATHNAME) } + end.to_h + end + end + + class Role + include Sigstore::Loggable + + attr_reader :keys, :name, :paths, :threshold + + def initialize(data, keys) + @name = data.fetch("name") + @paths = data.fetch("paths") + @threshold = data.fetch("threshold") + @keys = data.fetch("keyids").to_h { |key_id| [key_id, keys.fetch(key_id)] } + @terminating = data.fetch("terminating", false) + end + + def terminating? + @terminating + end + + def verify_delegate(type, bytes, signatures) + if (duplicate_keys = signatures.map { |sig| sig.fetch("keyid") }.tally.select { |_, count| count > 1 }).any? + raise Error::DuplicateKeys, "Duplicate keys found in signatures: #{duplicate_keys.inspect}" + end + + count = signatures.count do |signature| + key_id = signature.fetch("keyid") + unless @keys.include?(key_id) + logger.warn "Unknown key_id=#{key_id.inspect} in signatures for #{type}" + next + end + + key = @keys.fetch(key_id) + signature_bytes = [signature.fetch("sig")].pack("H*") + verified = key.verify("sha256", signature_bytes, bytes) + + logger.debug do + "key_id=#{key_id.inspect} type=#{type} verified=#{verified}" + end + verified + end + + return unless count < @threshold + + raise Error::TooFewSignatures, + "Not enough signatures: found #{count} out of threshold=#{@threshold} for #{type}" + end + end +end diff --git a/vendor/cache/sigstore-ruby-ce93acf7fa7e/lib/sigstore/tuf/root.rb b/vendor/cache/sigstore-ruby-ce93acf7fa7e/lib/sigstore/tuf/root.rb new file mode 100644 index 00000000..4057772d --- /dev/null +++ b/vendor/cache/sigstore-ruby-ce93acf7fa7e/lib/sigstore/tuf/root.rb @@ -0,0 +1,53 @@ +# frozen_string_literal: true + +# Copyright 2024 The Sigstore Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +require "time" + +require_relative "keys" +require_relative "roles" +require_relative "../internal/key" + +module Sigstore::TUF + class Root + include Sigstore::Loggable + + TYPE = "root" + attr_reader :version, :consistent_snapshot, :expires + + def initialize(data) + type = data.fetch("_type") + raise Error::InvalidData, "Expected type to be #{TYPE}, got #{type.inspect}" unless type == TYPE + + @spec_version = data.fetch("spec_version") { raise Error::InvalidData, "root missing spec_version" } + @consistent_snapshot = data.fetch("consistent_snapshot") do + raise Error::InvalidData, "root missing consistent_snapshot" + end + @version = data.fetch("version") { raise Error::InvalidData, "root missing version" } + @expires = Time.iso8601(data.fetch("expires") { raise Error::InvalidData, "root missing expires" }) + keys = Keys.new data.fetch("keys") + @roles = Roles.new data.fetch("roles"), keys + @unrecognized_fields = data.fetch("unrecognized_fields", {}) + end + + def verify_delegate(type, bytes, signatures) + @roles.verify_delegate(type, bytes, signatures) + end + + def expired?(reference_time) + @expires < reference_time + end + end +end diff --git a/vendor/cache/sigstore-ruby-ce93acf7fa7e/lib/sigstore/tuf/snapshot.rb b/vendor/cache/sigstore-ruby-ce93acf7fa7e/lib/sigstore/tuf/snapshot.rb new file mode 100644 index 00000000..03be67df --- /dev/null +++ b/vendor/cache/sigstore-ruby-ce93acf7fa7e/lib/sigstore/tuf/snapshot.rb @@ -0,0 +1,45 @@ +# frozen_string_literal: true + +# Copyright 2024 The Sigstore Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +require_relative "file" + +module Sigstore::TUF + # The class for the Snapshot role + class Snapshot + TYPE = "snapshot" + + attr_reader :version, :meta + + def initialize(data) + type = data.fetch("_type") + raise Error::InvalidData, "Expected type to be #{TYPE}, got #{type.inspect}" unless type == TYPE + + @version = data.fetch("version") + @expires = Time.iso8601 data.fetch("expires") + @meta = data.fetch("meta").transform_values { Meta.from_hash(_1) } + end + + def expired?(reference_time) + @expires < reference_time + end + + class Meta + include MetaFile + + attr_reader :version + end + end +end diff --git a/vendor/cache/sigstore-ruby-ce93acf7fa7e/lib/sigstore/tuf/targets.rb b/vendor/cache/sigstore-ruby-ce93acf7fa7e/lib/sigstore/tuf/targets.rb new file mode 100644 index 00000000..4e89f697 --- /dev/null +++ b/vendor/cache/sigstore-ruby-ce93acf7fa7e/lib/sigstore/tuf/targets.rb @@ -0,0 +1,84 @@ +# frozen_string_literal: true + +# Copyright 2024 The Sigstore Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +require_relative "file" +require_relative "keys" +require_relative "roles" + +module Sigstore::TUF + class Targets + TYPE = "targets" + + attr_reader :version, :targets, :delegations + + def initialize(data) + type = data.fetch("_type") + raise Error::InvalidData, "Expected type to be #{TYPE}, got #{type.inspect}" unless type == TYPE + + @version = data.fetch("version") + @expires = Time.iso8601 data.fetch("expires") + @targets = data.fetch("targets").to_h { |k, v| [k, Target.new(v, k)] } + @delegations = Delegations.new(data.fetch("delegations", {})) + + @unrecognized_fields = data.fetch("unrecognized_fields", {}) + end + + def expired?(reference_time) + @expires < reference_time + end + + def verify_delegate(type, bytes, signatures) + role = @delegations.fetch(type) + role.verify_delegate(type, bytes, signatures) + end + + class Target + attr_reader :path, :hashes + + include BaseFile + + def initialize(data, path) + @path = path + @length = data.fetch("length") + @hashes = data.fetch("hashes") + end + + def verify_length_and_hashes(data) + self.class.verify_length(data, @length) + self.class.verify_hashes(data, @hashes) + end + end + + class Delegations + def initialize(data) + keys = Keys.new data.fetch("keys", {}) + @roles = Roles.new data.fetch("roles", []), keys + end + + def roles_for_target(target_path) + @roles.for_target(target_path) + end + + def any? + @roles.any? + end + + def fetch(name) + @roles.fetch(name) + end + end + end +end diff --git a/vendor/cache/sigstore-ruby-ce93acf7fa7e/lib/sigstore/tuf/timestamp.rb b/vendor/cache/sigstore-ruby-ce93acf7fa7e/lib/sigstore/tuf/timestamp.rb new file mode 100644 index 00000000..96a61320 --- /dev/null +++ b/vendor/cache/sigstore-ruby-ce93acf7fa7e/lib/sigstore/tuf/timestamp.rb @@ -0,0 +1,39 @@ +# frozen_string_literal: true + +# Copyright 2024 The Sigstore Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +module Sigstore::TUF + class Timestamp + TYPE = "timestamp" + + attr_reader :version, :spec_version, :expires, :snapshot_meta, :unrecognized_fields + + def initialize(data) + type = data.fetch("_type") + raise Error::InvalidData, "Expected type to be #{TYPE}, got #{type.inspect}" unless type == TYPE + + @version = data.fetch("version") + @spec_version = data.fetch("spec_version") + @expires = Time.iso8601 data.fetch("expires") + meta_dict = data.fetch("meta") + @snapshot_meta = Snapshot::Meta.from_hash(meta_dict["snapshot.json"]) + @unrecognized_fields = data.fetch("unrecognized_fields", {}) + end + + def expired?(reference_time) + @expires < reference_time + end + end +end diff --git a/vendor/cache/sigstore-ruby-ce93acf7fa7e/lib/sigstore/tuf/trusted_metadata_set.rb b/vendor/cache/sigstore-ruby-ce93acf7fa7e/lib/sigstore/tuf/trusted_metadata_set.rb new file mode 100644 index 00000000..92122d5f --- /dev/null +++ b/vendor/cache/sigstore-ruby-ce93acf7fa7e/lib/sigstore/tuf/trusted_metadata_set.rb @@ -0,0 +1,193 @@ +# frozen_string_literal: true + +# Copyright 2024 The Sigstore Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +require_relative "error" +require_relative "root" +require_relative "../internal/json" + +require "json" + +module Sigstore::TUF + class TrustedMetadataSet + include Sigstore::Loggable + + def initialize(root_data, envelope_type, reference_time: Time.now.utc) + @trusted_set = {} + @reference_time = reference_time + @envelope_type = envelope_type + + logger.debug { "Loading trusted root" } + load_trusted_root(root_data) + end + + def root + @trusted_set.fetch("root") { raise Error::InvalidData, "missing root metadata" } + end + + def root=(data) + raise Error::BadUpdateOrder, "cannot update root after timestamp" if @trusted_set.key?("timestamp") + + metadata, canonical_signed, signatures = load_data(Root, data, root) + metadata.verify_delegate("root", canonical_signed, signatures) + raise Error::BadVersionNumber, "root version did not increment by one" if metadata.version != root.version + 1 + + @trusted_set["root"] = metadata + + logger.debug { "Updated root v#{metadata.version}" } + end + + def snapshot + @trusted_set.fetch("snapshot") + end + + def timestamp + @trusted_set.fetch("timestamp") + end + + def timestamp=(data) + raise Error::BadUpdateOrder, "cannot update timestamp after snapshot" if @trusted_set.key?("snapshot") + + if root.expired?(@reference_time) + raise Error::ExpiredMetadata, + "final root.json expired at #{root.expires}, is #{@reference_time}" + end + + metadata, = load_data(Timestamp, data, root) + + if include?(Timestamp::TYPE) + if metadata.version < timestamp.version + raise Error::BadVersionNumber, + "timestamp version less than metadata version" + end + raise Error::EqualVersionNumber if metadata.version == timestamp.version + + snapshot_meta = timestamp.snapshot_meta + new_snapshot_meta = metadata.snapshot_meta + if new_snapshot_meta.version < snapshot_meta.version + raise Error::BadVersionNumber, "snapshot version did not increase" + end + end + + @trusted_set["timestamp"] = metadata + check_final_timestamp + end + + def snapshot=(data, trusted: false) + raise Error::BadUpdateOrder, "cannot update snapshot before timestamp" unless @trusted_set.key?("timestamp") + raise Error::BadUpdateOrder, "cannot update snapshot after targets" if @trusted_set.key?("targets") + + check_final_timestamp + + snapshot_meta = timestamp.snapshot_meta + + snapshot_meta.verify_length_and_hashes(data) unless trusted + + new_snapshot, = load_data(Snapshot, data, root) + + # If an existing trusted snapshot is updated, check for rollback attack + if include?(Snapshot::TYPE) + snapshot.meta.each do |filename, file_info| + new_file_info = new_snapshot.meta[filename] + raise Error::RepositoryError, "new snapshot is missing info for #{filename}" unless new_file_info + + if new_file_info.version < file_info.version + raise Error::BadVersionNumber, "expected #{filename} v#{new_file_info.version}, got v#{file_info.version}" + end + end + end + + @trusted_set["snapshot"] = new_snapshot + logger.debug { "Updated snapshot v#{new_snapshot.version}" } + check_final_snapshot + end + + def include?(type) + @trusted_set.key?(type) + end + + def [](role) + @trusted_set.fetch(role) + end + + def update_delegated_targets(data, role, parent_role) + raise Error::BadUpdateOrder, "cannot update targets before snapshot" unless @trusted_set.key?("snapshot") + + check_final_snapshot + + delegator = @trusted_set[parent_role] + logger.debug { "Updating #{role} delegated by #{parent_role.inspect} to #{delegator.class}" } + raise Error::BadUpdateOrder, "cannot load targets before delegator" unless delegator + + meta = snapshot.meta["#{role}.json"] + raise Error::RepositoryError, "no metadata for role #{role} in snapshot" unless meta + + meta.verify_length_and_hashes(data) + + new_delegate, = load_data(Targets, data, delegator, role) + version = new_delegate.version + raise Error::BadVersionNumber, "expected #{role} v#{meta.version}, got v#{version}" if version != meta.version + + raise Error::ExpiredMetadata, "new #{role} is expired" if new_delegate.expired?(@reference_time) + + @trusted_set[role] = new_delegate + logger.debug { "Updated #{role} v#{version}" } + new_delegate + end + + private + + def load_trusted_root(data) + root, canonical_signed, signatures = load_data(Root, data, nil) + # verify the new root is signed by itself + root.verify_delegate("root", canonical_signed, signatures) + + @trusted_set["root"] = root + end + + def load_data(type, data, delegator, role_name = nil) + metadata = JSON.parse(data) + signed = metadata.fetch("signed") + unless signed["_type"] == type::TYPE + raise Error::InvalidData, + "Expected type to be #{type::TYPE}, got #{signed["_type"].inspect}" + end + + signatures = metadata.fetch("signatures") + metadata = type.new(signed) + canonical_signed = Sigstore::Internal::JSON.canonical_generate(signed) + delegator&.verify_delegate(role_name || type::TYPE, canonical_signed, signatures) + [metadata, canonical_signed, signatures] + rescue JSON::ParserError => e + raise Error::InvalidData, "Failed to parse #{type}: #{e.message}" + end + + def check_final_timestamp + return unless timestamp.expired?(@reference_time) + + raise Error::ExpiredMetadata, + "final timestamp.json is expired (expired at #{timestamp.expires} vs reference time #{@reference_time})" + end + + def check_final_snapshot + raise Error::ExpiredMetadata, "final snapshot.json is expired" if snapshot.expired?(@reference_time) + + snapshot_meta = timestamp.snapshot_meta + return if snapshot.version == snapshot_meta.version + + raise Error::BadVersionNumber, "expected snapshot version #{snapshot_meta.version}, got #{snapshot.version}" + end + end +end diff --git a/vendor/cache/sigstore-ruby-ce93acf7fa7e/lib/sigstore/tuf/updater.rb b/vendor/cache/sigstore-ruby-ce93acf7fa7e/lib/sigstore/tuf/updater.rb new file mode 100644 index 00000000..19a6b436 --- /dev/null +++ b/vendor/cache/sigstore-ruby-ce93acf7fa7e/lib/sigstore/tuf/updater.rb @@ -0,0 +1,271 @@ +# frozen_string_literal: true + +# Copyright 2024 The Sigstore Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +require_relative "config" +require_relative "trusted_metadata_set" +require_relative "root" +require_relative "snapshot" +require_relative "targets" +require_relative "timestamp" + +module Sigstore::TUF + class Updater + include Sigstore::Loggable + + def initialize(metadata_dir:, metadata_base_url:, target_base_url:, target_dir:, fetcher:, + config: UpdaterConfig.new) + @dir = metadata_dir + @metadata_base_url = "#{metadata_base_url.to_s.chomp("/")}/" + @target_dir = target_dir + @target_base_url = target_base_url && "#{target_base_url.to_s.chomp("/")}/" + + @fetcher = fetcher + @config = config + + unless %i[metadata simple].include? @config.envelope_type + raise ArgumentError, "Unsupported envelope type: #{@config[:envelope_type].inspect}" + end + + data = load_local_metadata("root") + @trusted_set = TrustedMetadataSet.new(data, "metadata", reference_time: Time.now) + end + + def refresh + load_root + load_timestamp + load_snapshot + load_targets(Targets::TYPE, Root::TYPE) + end + + def get_targetinfo(target_path) + refresh unless @trusted_set.include? Targets::TYPE + preorder_depth_first_walk(target_path) + end + + def find_cached_target(target_info, filepath = nil) + filepath ||= generate_target_file_path(target_info) + + begin + data = File.binread(filepath) + target_info.verify_length_and_hashes(data) + filepath + rescue Errno::ENOENT, Error::LengthOrHashMismatch => e + logger.debug { "No cached target at #{filepath}: #{e.class} #{e.message}" } + nil + end + end + + def download_target(target_info, filepath = nil, target_base_url = nil) + target_base_url ||= @target_base_url + raise ArgumentError, "No target_base_url set" unless target_base_url + + if (cached_target = find_cached_target(target_info, filepath)) + return cached_target + end + + filepath ||= generate_target_file_path(target_info) + + target_filepath = target_info.path + consistent_snapshot = @trusted_set.root.consistent_snapshot + + if consistent_snapshot && @config.prefix_targets_with_hash + hashes = target_info.hashes.values + dir, sep, basename = target_filepath.rpartition("/") + target_filepath = "#{dir}#{sep}#{hashes.first}.#{basename}" + end + + full_url = URI.join(target_base_url, target_filepath) + begin + resp_body = @fetcher.call(full_url) + target_info.verify_length_and_hashes(resp_body) + + # TODO: atomic write + File.binwrite(filepath, resp_body) + rescue Error::Fetch => e + raise Error::Fetch, + "Failed to download target #{target_info.inspect} #{target_filepath.inspect} from #{e.response.uri}: " \ + "#{e.message}" + end + logger.info { "Downloaded #{target_filepath} to #{filepath}" } + filepath + end + + private + + def load_local_metadata(role_name) + encoded_name = URI.encode_www_form_component(role_name) + + File.binread(File.join(@dir, "#{encoded_name}.json")) + end + + def load_root + lower_bound = @trusted_set.root.version + 1 + upper_bound = lower_bound - 1 + @config.max_root_rotations + + lower_bound.upto(upper_bound) do |version| + data = download_metadata(Root::TYPE, version) + rescue Error::UnsuccessfulResponse => e + logger.debug { "Failed to download root metadata v#{version}: #{e.class} #{e.message}" } + break if %w[403 404].include?(e.response.code) + + raise + else + @trusted_set.root = data + persist_metadata(Root::TYPE, data) + end + end + + def load_timestamp + begin + data = load_local_metadata(Timestamp::TYPE) + @trusted_set.timestamp = data + rescue Errno::ENOENT + logger.debug "No local timestamp found" + rescue Error::RepositoryError => e + logger.debug "Local timestamp not valid as final: #{e.class} #{e.message}" + end + + data = download_metadata(Timestamp::TYPE, nil) + + begin + @trusted_set.timestamp = data + rescue Error::EqualVersionNumber + logger.debug "Timestamp version did not increase" + return + end + + persist_metadata(Timestamp::TYPE, data) + end + + def load_snapshot + data = load_local_metadata(Snapshot::TYPE) + @trusted_set.send(:snapshot=, data, trusted: true) + logger.debug "Loaded snapshot from local metadata" + rescue Errno::ENOENT, Error::RepositoryError => e + logger.debug "Local snapshot not valid as final: #{e.class} #{e.message}" + + snapshot_meta = @trusted_set.timestamp.snapshot_meta + version = snapshot_meta.version if @trusted_set.root.consistent_snapshot + + data = download_metadata(Snapshot::TYPE, version) + @trusted_set.snapshot = data + persist_metadata(Snapshot::TYPE, data) + end + + def load_targets(role, parent_role) + if @trusted_set.include?(role) + logger.debug { "Returning cached targets for #{role}" } + return @trusted_set[role] + end + + begin + data = load_local_metadata(role) + @trusted_set.update_delegated_targets(data, role, parent_role).tap do + logger.debug { "Loaded targets for #{role} from local metadata" } + end + rescue Errno::ENOENT, Error::RepositoryError => e + logger.debug { "No local targets for #{role}, fetching: #{e.class} #{e.message}" } + + snapshot = @trusted_set.snapshot + metainfo = snapshot.meta["#{role}.json"] + raise Error::RepositoryError, "role #{role} was delegated but is not part of snapshot" unless metainfo + + version = metainfo.version if @trusted_set.root.consistent_snapshot + data = download_metadata(role, version) + delegated_targets = @trusted_set.update_delegated_targets(data, role, parent_role) + persist_metadata(role, data) + delegated_targets + end + end + + def download_metadata(role_name, version) + url = metadata_url(role_name, version) + + logger.debug { "Downloading metadata for #{role_name} from #{url}" } + + @fetcher.call(url) + end + + def metadata_url(role_name, version) + encoded_name = URI.encode_www_form_component(role_name) + if version.nil? + URI.join(@metadata_base_url, "#{encoded_name}.json") + else + URI.join(@metadata_base_url, "#{version}.#{encoded_name}.json") + end + end + + def persist_metadata(role_name, data) + logger.debug { "Persisting metadata for #{role_name}" } + + encoded_name = URI.encode_www_form_component(role_name) + filename = File.join(@dir, "#{encoded_name}.json") + Tempfile.create("", @dir) do |f| + f.binmode + f.write(data) + f.close + + File.rename(f.path, filename) + end + end + + def preorder_depth_first_walk(target_path) + logger.debug { "Searching for target #{target_path}" } + + delegations_to_visit = [[Targets::TYPE, Root::TYPE]] + visited_role_names = Set.new + + while delegations_to_visit.any? && visited_role_names.size < @config.max_delegations + role_name, parent_role = delegations_to_visit.pop + next if visited_role_names.include?(role_name) + + targets = load_targets(role_name, parent_role) + target = targets.targets.fetch(target_path, nil) + + return target if target + + visited_role_names.add(role_name) + + next unless targets.delegations.any? + + child_roles_to_visit = [] + + targets.delegations.roles_for_target(target_path).each do |child_name, delegated_role| + child_roles_to_visit << [child_name, role_name] + next unless delegated_role.terminating? + + logger.debug { "Terminating delegation found for #{child_name}" } + delegations_to_visit.clear + break + end + + delegations_to_visit.concat child_roles_to_visit.reverse + end + + logger.warn { "Max delegations reached, stopping search" } if delegations_to_visit.any? + + nil + end + + def generate_target_file_path(target_info) + raise ArgumentError, "target_dir not set" unless @target_dir + raise ArgumentError, "target_info required" unless target_info + + filename = URI.encode_www_form_component(target_info.path) + File.join(@target_dir, filename) + end + end +end diff --git a/vendor/cache/sigstore-ruby-ce93acf7fa7e/lib/sigstore/verifier.rb b/vendor/cache/sigstore-ruby-ce93acf7fa7e/lib/sigstore/verifier.rb new file mode 100644 index 00000000..958db4cb --- /dev/null +++ b/vendor/cache/sigstore-ruby-ce93acf7fa7e/lib/sigstore/verifier.rb @@ -0,0 +1,488 @@ +# frozen_string_literal: true + +# Copyright 2024 The Sigstore Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +require_relative "trusted_root" +require_relative "internal/keyring" +require_relative "internal/merkle" +require_relative "internal/set" +require_relative "rekor/client" +require_relative "rekor/checkpoint" +require_relative "internal/x509" + +module Sigstore + class Verifier + include Loggable + + attr_reader :rekor_client + + def initialize(rekor_client:, fulcio_cert_chains:, timestamp_authorities:, rekor_keyring:, ct_keyring:) + @rekor_client = rekor_client + @fulcio_cert_chains = fulcio_cert_chains + @timestamp_authorities = timestamp_authorities + @rekor_keyring = rekor_keyring + @ct_keyring = ct_keyring + end + + def self.for_trust_root(trust_root:) + new( + rekor_client: Rekor::Client.new(url: trust_root.tlog_for_signing.base_url), + fulcio_cert_chains: trust_root.fulcio_cert_chains, + timestamp_authorities: trust_root.timestamp_authorities, + rekor_keyring: Internal::Keyring.new(keys: trust_root.rekor_keys), + ct_keyring: Internal::Keyring.new(keys: trust_root.ctfe_keys) + ) + end + + def self.production(trust_root: TrustedRoot.production) + for_trust_root(trust_root:) + end + + def self.staging(trust_root: TrustedRoot.staging) + for_trust_root(trust_root:) + end + + def verify(input:, policy:, offline:) + # First, establish a time for the signature. This timestamp is required to validate the certificate chain, + # so this step comes first. + + bundle = input.sbundle + materials = bundle.verification_material + + # 1) + # If the verification policy uses the Timestamping Service, the Verifier MUST verify the timestamping response + # using the Timestamping Service root key material, as described in Spec: Timestamping Service, with the raw bytes + # of the signature as the timestamped data. The Verifier MUST then extract a timestamp from the timestamping + # response. If verification or timestamp parsing fails, the Verifier MUST abort. + + timestamps = extract_timestamp_from_verification_data(materials.timestamp_verification_data) || [] + + # 2) + # If the verification policy uses timestamps from the Transparency Service, the Verifier MUST verify the signature + # on the Transparency Service LogEntry as described in Spec: Transparency Service against the pre-distributed root + # key material from the transparency service. The Verifier SHOULD NOT (yet) attempt to parse the body. + # The Verifier MUST then parse the integratedTime as a Unix timestamp (seconds since January 1, 1970 UTC). + # If verification or timestamp parsing fails, the Verifier MUST abort. + + begin + # TODO: should this instead be an input to the verify method? + # See https://docs.google.com/document/d/1kbhK2qyPPk8SLavHzYSDM8-Ueul9_oxIMVFuWMWKz0E/edit?disco=AAABQVV-gT0 + entry = find_rekor_entry(bundle, input.hashed_input, offline:) + rescue Sigstore::Error::MissingRekorEntry + return VerificationFailure.new("Rekor entry not found") + else + if entry.inclusion_proof&.checkpoint + Internal::Merkle.verify_merkle_inclusion(entry) + Rekor::Checkpoint.verify_checkpoint(@rekor_keyring, entry) + elsif !offline + return VerificationFailure.new("Missing Rekor inclusion proof") + else + logger.warn "inclusion proof not present in bundle: skipping due to offline verification" + end + end + + Internal::SET.verify_set(keyring: @rekor_keyring, entry:) if entry.inclusion_promise + + timestamps << Time.at(entry.integrated_time).utc + + # 3) + # The Verifier MUST perform certification path validation (RFC 5280 §6) of the certificate chain with the + # pre-distributed Fulcio root certificate(s) as a trust anchor, but with a fake “current time.” + # If a timestamp from the timestamping service is available, the Verifier MUST perform path validation using the + # timestamp from the Timestamping Service. If a timestamp from the Transparency Service is available, the Verifier + # MUST perform path validation using the timestamp from the Transparency Service. If both are available, the + # Verifier performs path validation twice. If either fails, verification fails. + + chains = timestamps.map do |ts| + chain, err = Internal::X509.validate_chain(@fulcio_cert_chains, bundle.leaf_certificate, ts) + return err if err + + chain + end + + chains.uniq! { |chain| chain.map(&:to_der) } + unless chains.size == 1 + raise "expected exactly one certificate chain, got #{chains.size} chains:\n" + + chains.map do |chain| + chain.map(&:to_text).join("\n") + end.join("\n\n") + end + + # 4) + # Unless performing online verification (see §Alternative Workflows), the Verifier MUST extract the + # SignedCertificateTimestamp embedded in the leaf certificate, and verify it as in RFC 9162 §8.1.3, + # using the verification key from the Certificate Transparency Log. + chain = chains.first + if (result = verify_scts(bundle.leaf_certificate, chain)) && !result.verified? + return result + end + + # 5) + # The Verifier MUST then check the certificate against the verification policy. + + usage_ext = bundle.leaf_certificate.extension(Internal::X509::Extension::KeyUsage) + return VerificationFailure.new("Key usage is not of type `digital signature`") unless usage_ext.digital_signature + + extended_key_usage = bundle.leaf_certificate.extension(Internal::X509::Extension::ExtendedKeyUsage) + unless extended_key_usage.code_signing? + return VerificationFailure.new("Extended key usage is not of type `code signing`") + end + + policy_check = policy.verify(bundle.leaf_certificate) + return policy_check unless policy_check.verified? + + # 6) + # By this point, the Verifier has already verified the signature by the Transparency Service (§Establishing a Time + # for the Signature). The Verifier MUST parse body: body is a base64-encoded JSON document with keys apiVersion + # and kind. The Verifier implementation contains a list of known Transparency Service formats (by apiVersion and + # kind); if no type is found, abort. The Verifier MUST parse body as the given type. + # + # Then, the Verifier MUST check the following; exactly how to do this will be specified by each type in Spec: + # Sigstore Registries (§Signature Metadata Formats): + # + # * The signature from the parsed body is the same as the provided signature. + # * The key or certificate from the parsed body is the same as in the input certificate. + # * The “subject” of the parsed body matches the artifact. + + signing_key = bundle.leaf_certificate.public_key + + case bundle.content + when :message_signature + verified = verify_raw(signing_key, bundle.message_signature.signature, input.hashed_input.digest) + return VerificationFailure.new("Signature verification failed") unless verified + when :dsse_envelope + verify_dsse(bundle.dsse_envelope, signing_key) or + return VerificationFailure.new("DSSE envelope verification failed") + + case bundle.dsse_envelope.payloadType + when "application/vnd.in-toto+json" + in_toto = begin + JSON.parse(bundle.dsse_envelope.payload) + rescue JSON::ParserError + raise Error::InvalidBundle, "invalid JSON for in-toto statement in DSSE payload" + end + verify_in_toto(input, in_toto) + else + raise Sigstore::Error::Unimplemented, + "unsupported DSSE payload type: #{bundle.dsse_envelope.payloadType.inspect}" + end + else + raise Error::InvalidBundle, "unknown content type: #{bundle.content}" + end + + VerificationSuccess.new + end + + private + + def verify_raw(public_key, signature, data) + if public_key.respond_to?(:verify_raw) + public_key.verify_raw(nil, signature, data) + else + case public_key + when OpenSSL::PKey::EC + public_key.dsa_verify_asn1(data, signature) + else + raise Error::Unimplemented, "unsupported public key type: #{public_key.class} for raw verification" + end + end + end + + def verify_dsse(dsse_envelope, public_key) + payload = dsse_envelope.payload + payload_type = dsse_envelope.payloadType + signatures = dsse_envelope.signatures + + pae = "DSSEv1 #{payload_type.bytesize} #{payload_type} " \ + "#{payload.bytesize} #{payload}".b + + raise Error::InvalidBundle, "DSSEv1 envelope missing signatures" if signatures.empty? + + signatures.all? do |signature| + public_key.verify("SHA256", signature.sig, pae) + end + end + + def verify_in_toto(input, in_toto_payload) + type = in_toto_payload.fetch("_type") + raise Error::InvalidBundle, "Expected in-toto statement, got #{type.inspect}" unless type == "https://in-toto.io/Statement/v1" + + subject = in_toto_payload.fetch("subject") + raise Error::InvalidBundle, "Expected in-toto statement with subject" unless subject && subject.size == 1 + + subject = subject.first + digest = subject.fetch("digest") + raise Error::InvalidBundle, "Expected in-toto statement with digest" if !digest || digest.empty? + + expected_hexdigest = Internal::Util.hex_encode(input.hashed_input.digest) + digest.each do |name, value| + next if expected_hexdigest == value + + return VerificationFailure.new( + "in-toto subject does not match for #{input.hashed_input.algorithm} of #{subject.fetch("name")}: " \ + "expected #{name} to be #{value}, got #{expected_hexdigest}" + ) + end + end + + public + + def verify_scts(leaf_certificate, chain) + sct_list = leaf_certificate + .extension(Internal::X509::Extension::PrecertificateSignedCertificateTimestamps) + .signed_certificate_timestamps + raise Error::InvalidCertificate, "no SCTs found" if sct_list.empty? + + sct_list.each do |sct| + verified = verify_sct( + sct, + leaf_certificate, + chain, + @ct_keyring + ) + return VerificationFailure.new("SCT verification failed") unless verified + end + + nil + end + + private + + def verify_sct(sct, certificate, chain, ct_keyring) + if sct.entry_type == 1 + issuer_cert = find_issuer_cert(chain) + issuer_pubkey = issuer_cert.public_key + unless issuer_cert.ca? + raise Error::InvalidCertificate, "Invalid issuer pubkey basicConstraint (not a CA): #{issuer_cert.to_pem}" + end + + # TODO: use public_to_der when available + issuer_key_id = OpenSSL::Digest::SHA256.digest(issuer_pubkey.to_der) + end + + digitally_signed = pack_digitally_signed(sct, certificate, issuer_key_id).b + + ct_keyring.verify(key_id: sct.log_id, signature: sct.signature, data: digitally_signed) + end + + def pack_digitally_signed(sct, certificate, issuer_key_id = nil) + # https://datatracker.ietf.org/doc/html/rfc6962#section-3.4 + # https://datatracker.ietf.org/doc/html/rfc6962#section-3.5 + # + # digitally-signed struct { + # Version sct_version; + # SignatureType signature_type = certificate_timestamp; + # uint64 timestamp; + # LogEntryType entry_type; + # select(entry_type) { + # case x509_entry: ASN.1Cert; + # case precert_entry: PreCert; + # } signed_entry; + # CtExtensions extensions; + # }; + + signed_entry = + case sct.entry_type + when 0 # x509_entry + cert_der = certificate.to_public_der + cert_len = cert_der.bytesize + unused, len1, len2, len3 = [cert_len].pack("N").unpack("C4") + raise Error::InvalidCertificate, "invalid cert_len #{cert_len} #{cert_der.inspect}" if unused != 0 + + [len1, len2, len3, cert_der].pack("CCC a#{cert_len}") + when 1 # precert_entry + unless issuer_key_id&.bytesize == 32 + raise Error::InvalidCertificate, + "issuer_key_id must be 32 bytes for precert, given #{issuer_key_id.inspect}" + end + + tbs_cert = certificate.tbs_certificate_der + tbs_cert_len = tbs_cert.bytesize + unused, len1, len2, len3 = [tbs_cert_len].pack("N").unpack("C4") + raise Error::InvalidCertificate, "invalid tbs_cert_len #{tbs_cert_len} #{tbs_cert.inspect}" if unused != 0 + + [issuer_key_id, len1, len2, len3, tbs_cert].pack("a32 CCC a#{tbs_cert_len}") + else + raise Error::Unimplemented, "only x509_entry and precert_entry supported, given #{sct.entry_type.inspect}" + end + + [sct.version, 0, sct.timestamp, sct.entry_type, signed_entry, 0].pack(<<~PACK) + C # version + C # signature_type + Q> # timestamp + n # entry_type + a#{signed_entry.bytesize} # signed_entry + n # extensions length + PACK + end + + def find_issuer_cert(chain) + issuer = chain[0] + issuer = chain[1] if issuer.preissuer? + raise Error::InvalidCertificate, "no issuer certificate found" unless issuer + + issuer + end + + def extract_timestamp_from_verification_data(data) + # TODO: allow requiring a verified timestamp + unless data + logger.debug { "no timestamp verification data" } + return nil + end + + # Checks for https://github.com/ruby/openssl/pull/770 + if OpenSSL::X509::Store.new.instance_variable_defined?(:@time) + logger.warn do + "OpenSSL::X509::Store on this version of openssl (#{OpenSSL::VERSION}) does not set time properly, " \ + "this breaks TSA verification" + end + return + end + + authorities = @timestamp_authorities.map do |ta| + store = OpenSSL::X509::Store.new + chain = ta.cert_chain.certificates.map do |cert| + Internal::X509::Certificate.read(cert.raw_bytes).openssl + end + chain.each do |cert| + store.add_cert(cert) + end + [ta, chain, store] + end + + # https://www.rfc-editor.org/rfc/rfc3161.html#section-2.4.2 + data.rfc3161_timestamps.map do |ts| + resp = OpenSSL::Timestamp::Response.new(ts.signed_timestamp) + + req = OpenSSL::Timestamp::Request.new + req.cert_requested = !resp.token.certificates.empty? + # TODO: verify the message imprint against the signature in the bundle + req.message_imprint = resp.token_info.message_imprint + req.algorithm = resp.token_info.algorithm + req.policy_id = resp.token_info.policy_id + req.nonce = resp.token_info.nonce + req.version = resp.token_info.version + + # TODO: verify the hashed message in the message imprint + # against the signature in the bundle + + authorities.any? do |ta, chain, store| + store.time = resp.token_info.gen_time + + resp.verify(req, store, chain) && + (logger.debug do + "timestamp (#{resp.to_text}) verified for #{ta}" + end || true) + rescue OpenSSL::Timestamp::TimestampError => e + logger.error { "timestamp verification failed (#{e})" } + false + end || + raise(OpenSSL::Timestamp::TimestampError, "timestamp verification failed") + resp.token_info.gen_time + end + end + + def find_rekor_entry(bundle, hashed_input, offline:) + raise Error::InvalidBundle, "multiple tlog entries" if bundle.verification_material.tlog_entries.size > 1 + + rekor_entry = bundle.verification_material.tlog_entries&.first + has_inclusion_promise = !rekor_entry.nil? && !rekor_entry.inclusion_promise.nil? + has_inclusion_proof = !rekor_entry.nil? && !rekor_entry.inclusion_proof&.checkpoint.nil? + + logger.debug do + "Looking for rekor entry, " \ + "has_inclusion_promise=#{has_inclusion_promise} has_inclusion_proof=#{has_inclusion_proof}" + end + + expected_entry = bundle.expected_tlog_entry(hashed_input) + + entry = if offline + logger.debug { "Offline verification, skipping rekor" } + rekor_entry + elsif !has_inclusion_proof + logger.debug { "No inclusion proof, searching rekor" } + @rekor_client.log.entries.retrieve.post(expected_entry) + else + logger.debug { "Using rekor entry in sigstore bundle" } + rekor_entry + end + + raise Error::MissingRekorEntry, "Rekor entry not found" unless entry + + logger.debug { "Found rekor entry: #{entry}" } + + actual_body = begin + JSON.parse(entry.canonicalized_body) + rescue JSON::ParserError + raise Error::InvalidRekorEntry, "invalid JSON in rekor entry canonicalized_body" + end + if bundle.dsse_envelope? + # since the hash is over the uncanonicalized envelope, we need to remove it + # + # NOTE(sigstore-python): This is very slightly weaker than the consistency check + # for hashedrekord entries, due to how inclusion is recorded for DSSE: + # the included entry for DSSE includes an envelope hash that we + # *cannot* verify, since the envelope is uncanonicalized JSON. + # Instead, we manually pick apart the entry body below and verify + # the parts we can (namely the payload hash and signature list). + case actual_body["kind"] + when "intoto" + actual_body["spec"]["content"].delete("hash") + when "dsse" + actual_body["spec"].delete("envelopeHash") + else + raise Error::InvalidRekorEntry, "Unknown kind: #{actual_body["kind"]}" + end + end + + if actual_body != expected_entry + require "pp" + raise Error::InvalidRekorEntry, "Invalid rekor entry:\n\n" \ + "Envelope:\n#{bundle.dsse_envelope.pretty_inspect}\n\n" \ + "Diff:\n#{diff_json(expected_entry, actual_body).pretty_inspect}" + end + + entry + end + + def diff_json(a, b) # rubocop:disable Naming/MethodParameterName + return nil if a == b + + return [a, b] if a.class != b.class + + case a + when Hash + (a.keys | b.keys).to_h do |k| + [k, diff_json(a[k], b[k])] + end.compact + when Array + a.zip(b).filter_map { |x, y| diff_json(x, y) } + when String + begin + da = a.unpack1("m0") + db = b.unpack1("m0") + + [{ "decoded" => da, "base64" => a }, + { "decoded" => db, "base64" => b }] + rescue ArgumentError + [a, b] + end + else + [a, b] + end + end + end +end diff --git a/vendor/cache/sigstore-ruby-ce93acf7fa7e/lib/sigstore/version.rb b/vendor/cache/sigstore-ruby-ce93acf7fa7e/lib/sigstore/version.rb new file mode 100644 index 00000000..86a4e980 --- /dev/null +++ b/vendor/cache/sigstore-ruby-ce93acf7fa7e/lib/sigstore/version.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +# Copyright 2024 The Sigstore Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +module Sigstore + VERSION = "0.2.1" +end diff --git a/vendor/cache/sigstore-ruby-ce93acf7fa7e/sigstore.gemspec b/vendor/cache/sigstore-ruby-ce93acf7fa7e/sigstore.gemspec new file mode 100644 index 00000000..8f00b77d --- /dev/null +++ b/vendor/cache/sigstore-ruby-ce93acf7fa7e/sigstore.gemspec @@ -0,0 +1,30 @@ +# -*- encoding: utf-8 -*- +# stub: sigstore 0.2.1 ruby lib + +Gem::Specification.new do |s| + s.name = "sigstore".freeze + s.version = "0.2.1".freeze + + s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= + s.metadata = { "allowed_push_host" => "https://rubygems.org", "homepage_uri" => "https://github.com/sigstore/sigstore-ruby", "rubygems_mfa_required" => "true" } if s.respond_to? :metadata= + s.require_paths = ["lib".freeze] + s.authors = ["The Sigstore Authors".freeze, "Samuel Giddins".freeze] + s.bindir = "exe".freeze + s.date = "1980-01-02" + s.email = [nil, "segiddins@segiddins.me".freeze] + s.files = ["CHANGELOG.md".freeze, "CODEOWNERS".freeze, "LICENSE".freeze, "README.md".freeze, "data/_store/prod/root.json".freeze, "data/_store/prod/trusted_root.json".freeze, "data/_store/staging/root.json".freeze, "data/_store/staging/trusted_root.json".freeze, "lib/sigstore.rb".freeze, "lib/sigstore/error.rb".freeze, "lib/sigstore/internal/json.rb".freeze, "lib/sigstore/internal/key.rb".freeze, "lib/sigstore/internal/keyring.rb".freeze, "lib/sigstore/internal/merkle.rb".freeze, "lib/sigstore/internal/set.rb".freeze, "lib/sigstore/internal/util.rb".freeze, "lib/sigstore/internal/x509.rb".freeze, "lib/sigstore/models.rb".freeze, "lib/sigstore/oidc.rb".freeze, "lib/sigstore/policy.rb".freeze, "lib/sigstore/rekor/checkpoint.rb".freeze, "lib/sigstore/rekor/client.rb".freeze, "lib/sigstore/signer.rb".freeze, "lib/sigstore/trusted_root.rb".freeze, "lib/sigstore/tuf.rb".freeze, "lib/sigstore/tuf/config.rb".freeze, "lib/sigstore/tuf/error.rb".freeze, "lib/sigstore/tuf/file.rb".freeze, "lib/sigstore/tuf/keys.rb".freeze, "lib/sigstore/tuf/roles.rb".freeze, "lib/sigstore/tuf/root.rb".freeze, "lib/sigstore/tuf/snapshot.rb".freeze, "lib/sigstore/tuf/targets.rb".freeze, "lib/sigstore/tuf/timestamp.rb".freeze, "lib/sigstore/tuf/trusted_metadata_set.rb".freeze, "lib/sigstore/tuf/updater.rb".freeze, "lib/sigstore/verifier.rb".freeze, "lib/sigstore/version.rb".freeze] + s.homepage = "https://github.com/sigstore/sigstore-ruby".freeze + s.licenses = ["Apache-2.0".freeze] + s.required_ruby_version = Gem::Requirement.new(">= 3.2.0".freeze) + s.rubygems_version = "3.6.7".freeze + s.summary = "A pure-ruby implementation of sigstore signature verification".freeze + + s.installed_by_version = "3.6.7".freeze + + s.specification_version = 4 + + s.add_runtime_dependency(%q.freeze, [">= 0".freeze]) + s.add_runtime_dependency(%q.freeze, [">= 0".freeze]) + s.add_runtime_dependency(%q.freeze, ["~> 0.1.0".freeze]) + s.add_runtime_dependency(%q.freeze, [">= 0".freeze]) +end diff --git a/vendor/cache/sigstore-ruby-ce93acf7fa7e/test/.gitignore b/vendor/cache/sigstore-ruby-ce93acf7fa7e/test/.gitignore new file mode 100644 index 00000000..e67cc723 --- /dev/null +++ b/vendor/cache/sigstore-ruby-ce93acf7fa7e/test/.gitignore @@ -0,0 +1,3 @@ +/tuf-conformance/ +/sigstore-conformance/ +/conformance_invocations diff --git a/vendor/cache/sigstore-ruby-ce93acf7fa7e/test/sigstore/conformance_test.rb b/vendor/cache/sigstore-ruby-ce93acf7fa7e/test/sigstore/conformance_test.rb new file mode 100644 index 00000000..316f13a6 --- /dev/null +++ b/vendor/cache/sigstore-ruby-ce93acf7fa7e/test/sigstore/conformance_test.rb @@ -0,0 +1,60 @@ +# frozen_string_literal: true + +require "test_helper" +require "sigstore/cli" + +class Sigstore::ConformanceTest < Test::Unit::TestCase + def test_verify_signature_invalid + VCR.use_cassette("conformance/verify_signature_invalid") do |cassette| + Timecop.freeze(cassette.originally_recorded_at || Time.now) do + capture_output do + e = assert_raise SystemExit do + Sigstore::CLI.start([ + "verify", + "--certificate-identity", "https://github.com/sigstore-conformance/extremely-dangerous-public-oidc-beacon/.github/workflows/extremely-dangerous-oidc-beacon.yml@refs/heads/main", + "--certificate-oidc-issuer", "https://token.actions.githubusercontent.com", + "--bundle", + "test/sigstore-conformance/test/assets/a.txt.invalid_signature.sigstore.json", + "test/sigstore-conformance/test/assets/a.txt" + ]) + end + assert_equal 1, e.status + end + end + end + end + + def test_verify_bundle_success + VCR.use_cassette("conformance/verify_bundle_success") do |cassette| + Timecop.freeze(cassette.originally_recorded_at || Time.now) do + capture_output do + assert_nothing_raised do + Sigstore::CLI.start([ + "verify", + "--bundle", "test/sigstore-conformance/test/assets/a.txt.good.sigstore.json", + "--certificate-identity", "https://github.com/sigstore-conformance/extremely-dangerous-public-oidc-beacon/.github/workflows/extremely-dangerous-oidc-beacon.yml@refs/heads/main", + "--certificate-oidc-issuer", "https://token.actions.githubusercontent.com", + "test/sigstore-conformance/test/assets/a.txt" + ]) + end + end + end + end + end + + def test_verify_dsse_bundle_with_trust_root + capture_output do + assert_nothing_raised do + Sigstore::CLI.start([ + "verify", + "--bundle", "test/sigstore-conformance/test/assets/d.txt.good.sigstore.json", + "--certificate-identity", "https://github.com/sigstore-conformance/extremely-dangerous-public-oidc-beacon/.github/workflows/extremely-dangerous-oidc-beacon.yml@refs/heads/main", + "--certificate-oidc-issuer", "https://token.actions.githubusercontent.com", + "--trusted-root", "test/sigstore-conformance/test/assets/trusted_root.d.json", + "--offline", + "test/sigstore-conformance/test/assets/d.txt" + ]) + end + end + end +end diff --git a/vendor/cache/sigstore-ruby-ce93acf7fa7e/test/sigstore/data/transparency/merkle/verify_inclusion.jsonl b/vendor/cache/sigstore-ruby-ce93acf7fa7e/test/sigstore/data/transparency/merkle/verify_inclusion.jsonl new file mode 100644 index 00000000..20bc219b --- /dev/null +++ b/vendor/cache/sigstore-ruby-ce93acf7fa7e/test/sigstore/data/transparency/merkle/verify_inclusion.jsonl @@ -0,0 +1,94 @@ +{"desc":"TestVerifyInclusion/probe:0:0: some leaf hash + empty root","index":0,"size":0,"leaf_hash":"q6yroAAAAAAAAAAAAAAAAAAAAAAAAAAAAGAGHgASNFY=","proof":[],"root":"","expected_error":"index is beyond size: 0 \u003e= 0"} +{"desc":"TestVerifyInclusion/probe:0:0: empty leaf hash + empty tree hash root","index":0,"size":0,"leaf_hash":"","proof":[],"root":"47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=","expected_error":"index is beyond size: 0 \u003e= 0"} +{"desc":"TestVerifyInclusion/probe:0:0: some leaf hash + empty tree hash root","index":0,"size":0,"leaf_hash":"q6yroAAAAAAAAAAAAAAAAAAAAAAAAAAAAGAGHgASNFY=","proof":[],"root":"47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=","expected_error":"index is beyond size: 0 \u003e= 0"} +{"desc":"TestVerifyInclusion/probe:0:1: some leaf hash + empty root","index":0,"size":1,"leaf_hash":"q6yroAAAAAAAAAAAAAAAAAAAAAAAAAAAAGAGHgASNFY=","proof":[],"root":"","expected_error":"calculated root:\n[171 172 171 160 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 96 6 30 0 18 52 86]\n does not match expected root:\n[]"} +{"desc":"TestVerifyInclusion/probe:0:1: empty leaf hash + empty tree hash root","index":0,"size":1,"leaf_hash":"","proof":[],"root":"47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=","expected_error":"leafHash has unexpected size 0, want 32"} +{"desc":"TestVerifyInclusion/probe:0:1: some leaf hash + empty tree hash root","index":0,"size":1,"leaf_hash":"q6yroAAAAAAAAAAAAAAAAAAAAAAAAAAAAGAGHgASNFY=","proof":[],"root":"47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=","expected_error":"calculated root:\n[171 172 171 160 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 96 6 30 0 18 52 86]\n does not match expected root:\n[227 176 196 66 152 252 28 20 154 251 244 200 153 111 185 36 39 174 65 228 100 155 147 76 164 149 153 27 120 82 184 85]"} +{"desc":"TestVerifyInclusion/probe:1:0: some leaf hash + empty root","index":1,"size":0,"leaf_hash":"q6yroAAAAAAAAAAAAAAAAAAAAAAAAAAAAGAGHgASNFY=","proof":[],"root":"","expected_error":"index is beyond size: 1 \u003e= 0"} +{"desc":"TestVerifyInclusion/probe:1:0: empty leaf hash + empty tree hash root","index":1,"size":0,"leaf_hash":"","proof":[],"root":"47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=","expected_error":"index is beyond size: 1 \u003e= 0"} +{"desc":"TestVerifyInclusion/probe:1:0: some leaf hash + empty tree hash root","index":1,"size":0,"leaf_hash":"q6yroAAAAAAAAAAAAAAAAAAAAAAAAAAAAGAGHgASNFY=","proof":[],"root":"47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=","expected_error":"index is beyond size: 1 \u003e= 0"} +{"desc":"TestVerifyInclusion/probe:2:1: some leaf hash + empty root","index":2,"size":1,"leaf_hash":"q6yroAAAAAAAAAAAAAAAAAAAAAAAAAAAAGAGHgASNFY=","proof":[],"root":"","expected_error":"index is beyond size: 2 \u003e= 1"} +{"desc":"TestVerifyInclusion/probe:2:1: empty leaf hash + empty tree hash root","index":2,"size":1,"leaf_hash":"","proof":[],"root":"47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=","expected_error":"index is beyond size: 2 \u003e= 1"} +{"desc":"TestVerifyInclusion/probe:2:1: some leaf hash + empty tree hash root","index":2,"size":1,"leaf_hash":"q6yroAAAAAAAAAAAAAAAAAAAAAAAAAAAAGAGHgASNFY=","proof":[],"root":"47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=","expected_error":"index is beyond size: 2 \u003e= 1"} +{"desc":"TestVerifyInclusion/proof:1","index":0,"size":1,"leaf_hash":"bjQLnP+zepicpUTmu3gKLHiQHT+zNzh2hRGjBhevoB0=","proof":null,"root":"bjQLnP+zepicpUTmu3gKLHiQHT+zNzh2hRGjBhevoB0=","expected_error":null} +{"desc":"TestVerifyInclusion/proof:1: leafIndex - 1","index":18446744073709551615,"size":1,"leaf_hash":"bjQLnP+zepicpUTmu3gKLHiQHT+zNzh2hRGjBhevoB0=","proof":null,"root":"bjQLnP+zepicpUTmu3gKLHiQHT+zNzh2hRGjBhevoB0=","expected_error":"index is beyond size: 18446744073709551615 \u003e= 1"} +{"desc":"TestVerifyInclusion/proof:1: leafIndex + 1","index":1,"size":1,"leaf_hash":"bjQLnP+zepicpUTmu3gKLHiQHT+zNzh2hRGjBhevoB0=","proof":null,"root":"bjQLnP+zepicpUTmu3gKLHiQHT+zNzh2hRGjBhevoB0=","expected_error":"index is beyond size: 1 \u003e= 1"} +{"desc":"TestVerifyInclusion/proof:1: leafIndex ^ 2","index":2,"size":1,"leaf_hash":"bjQLnP+zepicpUTmu3gKLHiQHT+zNzh2hRGjBhevoB0=","proof":null,"root":"bjQLnP+zepicpUTmu3gKLHiQHT+zNzh2hRGjBhevoB0=","expected_error":"index is beyond size: 2 \u003e= 1"} +{"desc":"TestVerifyInclusion/proof:1: treeSize * 2","index":0,"size":2,"leaf_hash":"bjQLnP+zepicpUTmu3gKLHiQHT+zNzh2hRGjBhevoB0=","proof":null,"root":"bjQLnP+zepicpUTmu3gKLHiQHT+zNzh2hRGjBhevoB0=","expected_error":"wrong proof size 0, want 1"} +{"desc":"TestVerifyInclusion/proof:1: treeSize / 2","index":0,"size":0,"leaf_hash":"bjQLnP+zepicpUTmu3gKLHiQHT+zNzh2hRGjBhevoB0=","proof":null,"root":"bjQLnP+zepicpUTmu3gKLHiQHT+zNzh2hRGjBhevoB0=","expected_error":"index is beyond size: 0 \u003e= 0"} +{"desc":"TestVerifyInclusion/proof:1: wrong leaf","index":0,"size":1,"leaf_hash":"V3JvbmdMZWFm","proof":null,"root":"bjQLnP+zepicpUTmu3gKLHiQHT+zNzh2hRGjBhevoB0=","expected_error":"leafHash has unexpected size 9, want 32"} +{"desc":"TestVerifyInclusion/proof:1: empty root","index":0,"size":1,"leaf_hash":"bjQLnP+zepicpUTmu3gKLHiQHT+zNzh2hRGjBhevoB0=","proof":null,"root":"47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=","expected_error":"calculated root:\n[110 52 11 156 255 179 122 152 156 165 68 230 187 120 10 44 120 144 29 63 179 55 56 118 133 17 163 6 23 175 160 29]\n does not match expected root:\n[227 176 196 66 152 252 28 20 154 251 244 200 153 111 185 36 39 174 65 228 100 155 147 76 164 149 153 27 120 82 184 85]"} +{"desc":"TestVerifyInclusion/proof:1: random root","index":0,"size":1,"leaf_hash":"bjQLnP+zepicpUTmu3gKLHiQHT+zNzh2hRGjBhevoB0=","proof":null,"root":"q6yroAAAAAAAAAAAAAAAAAAAAAAAAAAAAGAGHgASNFY=","expected_error":"calculated root:\n[110 52 11 156 255 179 122 152 156 165 68 230 187 120 10 44 120 144 29 63 179 55 56 118 133 17 163 6 23 175 160 29]\n does not match expected root:\n[171 172 171 160 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 96 6 30 0 18 52 86]"} +{"desc":"TestVerifyInclusion/proof:1: trailing garbage","index":0,"size":1,"leaf_hash":"bjQLnP+zepicpUTmu3gKLHiQHT+zNzh2hRGjBhevoB0=","proof":[""],"root":"bjQLnP+zepicpUTmu3gKLHiQHT+zNzh2hRGjBhevoB0=","expected_error":"wrong proof size 1, want 0"} +{"desc":"TestVerifyInclusion/proof:1: trailing root","index":0,"size":1,"leaf_hash":"bjQLnP+zepicpUTmu3gKLHiQHT+zNzh2hRGjBhevoB0=","proof":["bjQLnP+zepicpUTmu3gKLHiQHT+zNzh2hRGjBhevoB0="],"root":"bjQLnP+zepicpUTmu3gKLHiQHT+zNzh2hRGjBhevoB0=","expected_error":"wrong proof size 1, want 0"} +{"desc":"TestVerifyInclusion/proof:1: preceding garbage","index":0,"size":1,"leaf_hash":"bjQLnP+zepicpUTmu3gKLHiQHT+zNzh2hRGjBhevoB0=","proof":[""],"root":"bjQLnP+zepicpUTmu3gKLHiQHT+zNzh2hRGjBhevoB0=","expected_error":"wrong proof size 1, want 0"} +{"desc":"TestVerifyInclusion/proof:1: preceding root","index":0,"size":1,"leaf_hash":"bjQLnP+zepicpUTmu3gKLHiQHT+zNzh2hRGjBhevoB0=","proof":["bjQLnP+zepicpUTmu3gKLHiQHT+zNzh2hRGjBhevoB0="],"root":"bjQLnP+zepicpUTmu3gKLHiQHT+zNzh2hRGjBhevoB0=","expected_error":"wrong proof size 1, want 0"} +{"desc":"TestVerifyInclusion/proof:2","index":0,"size":8,"leaf_hash":"bjQLnP+zepicpUTmu3gKLHiQHT+zNzh2hRGjBhevoB0=","proof":["lqKW0iTyhcZ77pPDD4owkVfw2qNdxbh+QQt4YwoJz8c=","Xwg/ChozygdqlSeYMlgNs+DvRYS9/x9UyKNg9Q3jAx4=","a0eq8p7jwq+a+Im8H7klTavTEXfxYjLdaqsDXKOb9uQ="],"root":"XcnaeacGWamtVZy3Ad7ZoqudgjqtL0lgz+Nw7/RgQyg=","expected_error":null} +{"desc":"TestVerifyInclusion/proof:2: leafIndex - 1","index":18446744073709551615,"size":8,"leaf_hash":"bjQLnP+zepicpUTmu3gKLHiQHT+zNzh2hRGjBhevoB0=","proof":["lqKW0iTyhcZ77pPDD4owkVfw2qNdxbh+QQt4YwoJz8c=","Xwg/ChozygdqlSeYMlgNs+DvRYS9/x9UyKNg9Q3jAx4=","a0eq8p7jwq+a+Im8H7klTavTEXfxYjLdaqsDXKOb9uQ="],"root":"XcnaeacGWamtVZy3Ad7ZoqudgjqtL0lgz+Nw7/RgQyg=","expected_error":"index is beyond size: 18446744073709551615 \u003e= 8"} +{"desc":"TestVerifyInclusion/proof:2: leafIndex + 1","index":1,"size":8,"leaf_hash":"bjQLnP+zepicpUTmu3gKLHiQHT+zNzh2hRGjBhevoB0=","proof":["lqKW0iTyhcZ77pPDD4owkVfw2qNdxbh+QQt4YwoJz8c=","Xwg/ChozygdqlSeYMlgNs+DvRYS9/x9UyKNg9Q3jAx4=","a0eq8p7jwq+a+Im8H7klTavTEXfxYjLdaqsDXKOb9uQ="],"root":"XcnaeacGWamtVZy3Ad7ZoqudgjqtL0lgz+Nw7/RgQyg=","expected_error":"calculated root:\n[142 34 99 10 252 7 196 89 63 196 206 102 180 246 176 52 18 141 190 50 40 247 28 81 158 148 13 224 100 94 194 185]\n does not match expected root:\n[93 201 218 121 167 6 89 169 173 85 156 183 1 222 217 162 171 157 130 58 173 47 73 96 207 227 112 239 244 96 67 40]"} +{"desc":"TestVerifyInclusion/proof:2: leafIndex ^ 2","index":2,"size":8,"leaf_hash":"bjQLnP+zepicpUTmu3gKLHiQHT+zNzh2hRGjBhevoB0=","proof":["lqKW0iTyhcZ77pPDD4owkVfw2qNdxbh+QQt4YwoJz8c=","Xwg/ChozygdqlSeYMlgNs+DvRYS9/x9UyKNg9Q3jAx4=","a0eq8p7jwq+a+Im8H7klTavTEXfxYjLdaqsDXKOb9uQ="],"root":"XcnaeacGWamtVZy3Ad7ZoqudgjqtL0lgz+Nw7/RgQyg=","expected_error":"calculated root:\n[74 61 0 170 105 54 159 242 161 41 40 9 130 202 80 203 87 138 90 52 213 4 81 255 201 233 200 255 17 21 126 246]\n does not match expected root:\n[93 201 218 121 167 6 89 169 173 85 156 183 1 222 217 162 171 157 130 58 173 47 73 96 207 227 112 239 244 96 67 40]"} +{"desc":"TestVerifyInclusion/proof:2: treeSize * 2","index":0,"size":16,"leaf_hash":"bjQLnP+zepicpUTmu3gKLHiQHT+zNzh2hRGjBhevoB0=","proof":["lqKW0iTyhcZ77pPDD4owkVfw2qNdxbh+QQt4YwoJz8c=","Xwg/ChozygdqlSeYMlgNs+DvRYS9/x9UyKNg9Q3jAx4=","a0eq8p7jwq+a+Im8H7klTavTEXfxYjLdaqsDXKOb9uQ="],"root":"XcnaeacGWamtVZy3Ad7ZoqudgjqtL0lgz+Nw7/RgQyg=","expected_error":"wrong proof size 3, want 4"} +{"desc":"TestVerifyInclusion/proof:2: treeSize / 2","index":0,"size":4,"leaf_hash":"bjQLnP+zepicpUTmu3gKLHiQHT+zNzh2hRGjBhevoB0=","proof":["lqKW0iTyhcZ77pPDD4owkVfw2qNdxbh+QQt4YwoJz8c=","Xwg/ChozygdqlSeYMlgNs+DvRYS9/x9UyKNg9Q3jAx4=","a0eq8p7jwq+a+Im8H7klTavTEXfxYjLdaqsDXKOb9uQ="],"root":"XcnaeacGWamtVZy3Ad7ZoqudgjqtL0lgz+Nw7/RgQyg=","expected_error":"wrong proof size 3, want 2"} +{"desc":"TestVerifyInclusion/proof:2: wrong leaf","index":0,"size":8,"leaf_hash":"V3JvbmdMZWFm","proof":["lqKW0iTyhcZ77pPDD4owkVfw2qNdxbh+QQt4YwoJz8c=","Xwg/ChozygdqlSeYMlgNs+DvRYS9/x9UyKNg9Q3jAx4=","a0eq8p7jwq+a+Im8H7klTavTEXfxYjLdaqsDXKOb9uQ="],"root":"XcnaeacGWamtVZy3Ad7ZoqudgjqtL0lgz+Nw7/RgQyg=","expected_error":"leafHash has unexpected size 9, want 32"} +{"desc":"TestVerifyInclusion/proof:2: empty root","index":0,"size":8,"leaf_hash":"bjQLnP+zepicpUTmu3gKLHiQHT+zNzh2hRGjBhevoB0=","proof":["lqKW0iTyhcZ77pPDD4owkVfw2qNdxbh+QQt4YwoJz8c=","Xwg/ChozygdqlSeYMlgNs+DvRYS9/x9UyKNg9Q3jAx4=","a0eq8p7jwq+a+Im8H7klTavTEXfxYjLdaqsDXKOb9uQ="],"root":"47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=","expected_error":"calculated root:\n[93 201 218 121 167 6 89 169 173 85 156 183 1 222 217 162 171 157 130 58 173 47 73 96 207 227 112 239 244 96 67 40]\n does not match expected root:\n[227 176 196 66 152 252 28 20 154 251 244 200 153 111 185 36 39 174 65 228 100 155 147 76 164 149 153 27 120 82 184 85]"} +{"desc":"TestVerifyInclusion/proof:2: random root","index":0,"size":8,"leaf_hash":"bjQLnP+zepicpUTmu3gKLHiQHT+zNzh2hRGjBhevoB0=","proof":["lqKW0iTyhcZ77pPDD4owkVfw2qNdxbh+QQt4YwoJz8c=","Xwg/ChozygdqlSeYMlgNs+DvRYS9/x9UyKNg9Q3jAx4=","a0eq8p7jwq+a+Im8H7klTavTEXfxYjLdaqsDXKOb9uQ="],"root":"q6yroAAAAAAAAAAAAAAAAAAAAAAAAAAAAGAGHgASNFY=","expected_error":"calculated root:\n[93 201 218 121 167 6 89 169 173 85 156 183 1 222 217 162 171 157 130 58 173 47 73 96 207 227 112 239 244 96 67 40]\n does not match expected root:\n[171 172 171 160 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 96 6 30 0 18 52 86]"} +{"desc":"TestVerifyInclusion/proof:2: trailing garbage","index":0,"size":8,"leaf_hash":"bjQLnP+zepicpUTmu3gKLHiQHT+zNzh2hRGjBhevoB0=","proof":["lqKW0iTyhcZ77pPDD4owkVfw2qNdxbh+QQt4YwoJz8c=","Xwg/ChozygdqlSeYMlgNs+DvRYS9/x9UyKNg9Q3jAx4=","a0eq8p7jwq+a+Im8H7klTavTEXfxYjLdaqsDXKOb9uQ=",""],"root":"XcnaeacGWamtVZy3Ad7ZoqudgjqtL0lgz+Nw7/RgQyg=","expected_error":"wrong proof size 4, want 3"} +{"desc":"TestVerifyInclusion/proof:2: trailing root","index":0,"size":8,"leaf_hash":"bjQLnP+zepicpUTmu3gKLHiQHT+zNzh2hRGjBhevoB0=","proof":["lqKW0iTyhcZ77pPDD4owkVfw2qNdxbh+QQt4YwoJz8c=","Xwg/ChozygdqlSeYMlgNs+DvRYS9/x9UyKNg9Q3jAx4=","a0eq8p7jwq+a+Im8H7klTavTEXfxYjLdaqsDXKOb9uQ=","XcnaeacGWamtVZy3Ad7ZoqudgjqtL0lgz+Nw7/RgQyg="],"root":"XcnaeacGWamtVZy3Ad7ZoqudgjqtL0lgz+Nw7/RgQyg=","expected_error":"wrong proof size 4, want 3"} +{"desc":"TestVerifyInclusion/proof:2: preceding garbage","index":0,"size":8,"leaf_hash":"bjQLnP+zepicpUTmu3gKLHiQHT+zNzh2hRGjBhevoB0=","proof":["","lqKW0iTyhcZ77pPDD4owkVfw2qNdxbh+QQt4YwoJz8c=","Xwg/ChozygdqlSeYMlgNs+DvRYS9/x9UyKNg9Q3jAx4=","a0eq8p7jwq+a+Im8H7klTavTEXfxYjLdaqsDXKOb9uQ="],"root":"XcnaeacGWamtVZy3Ad7ZoqudgjqtL0lgz+Nw7/RgQyg=","expected_error":"wrong proof size 4, want 3"} +{"desc":"TestVerifyInclusion/proof:2: preceding root","index":0,"size":8,"leaf_hash":"bjQLnP+zepicpUTmu3gKLHiQHT+zNzh2hRGjBhevoB0=","proof":["XcnaeacGWamtVZy3Ad7ZoqudgjqtL0lgz+Nw7/RgQyg=","lqKW0iTyhcZ77pPDD4owkVfw2qNdxbh+QQt4YwoJz8c=","Xwg/ChozygdqlSeYMlgNs+DvRYS9/x9UyKNg9Q3jAx4=","a0eq8p7jwq+a+Im8H7klTavTEXfxYjLdaqsDXKOb9uQ="],"root":"XcnaeacGWamtVZy3Ad7ZoqudgjqtL0lgz+Nw7/RgQyg=","expected_error":"wrong proof size 4, want 3"} +{"desc":"TestVerifyInclusion/proof:2: modified proof[0] bit 3","index":0,"size":8,"leaf_hash":"bjQLnP+zepicpUTmu3gKLHiQHT+zNzh2hRGjBhevoB0=","proof":["nqKW0iTyhcZ77pPDD4owkVfw2qNdxbh+QQt4YwoJz8c=","Xwg/ChozygdqlSeYMlgNs+DvRYS9/x9UyKNg9Q3jAx4=","a0eq8p7jwq+a+Im8H7klTavTEXfxYjLdaqsDXKOb9uQ="],"root":"XcnaeacGWamtVZy3Ad7ZoqudgjqtL0lgz+Nw7/RgQyg=","expected_error":"calculated root:\n[107 201 161 26 210 5 144 121 127 225 254 149 233 213 172 42 27 249 202 194 65 22 128 237 121 251 34 106 74 64 2 234]\n does not match expected root:\n[93 201 218 121 167 6 89 169 173 85 156 183 1 222 217 162 171 157 130 58 173 47 73 96 207 227 112 239 244 96 67 40]"} +{"desc":"TestVerifyInclusion/proof:2: modified proof[1] bit 3","index":0,"size":8,"leaf_hash":"bjQLnP+zepicpUTmu3gKLHiQHT+zNzh2hRGjBhevoB0=","proof":["lqKW0iTyhcZ77pPDD4owkVfw2qNdxbh+QQt4YwoJz8c=","Vwg/ChozygdqlSeYMlgNs+DvRYS9/x9UyKNg9Q3jAx4=","a0eq8p7jwq+a+Im8H7klTavTEXfxYjLdaqsDXKOb9uQ="],"root":"XcnaeacGWamtVZy3Ad7ZoqudgjqtL0lgz+Nw7/RgQyg=","expected_error":"calculated root:\n[62 22 188 208 161 252 98 25 165 171 73 76 192 145 140 235 252 77 161 12 69 123 59 215 56 136 25 178 233 156 16 83]\n does not match expected root:\n[93 201 218 121 167 6 89 169 173 85 156 183 1 222 217 162 171 157 130 58 173 47 73 96 207 227 112 239 244 96 67 40]"} +{"desc":"TestVerifyInclusion/proof:2: modified proof[2] bit 3","index":0,"size":8,"leaf_hash":"bjQLnP+zepicpUTmu3gKLHiQHT+zNzh2hRGjBhevoB0=","proof":["lqKW0iTyhcZ77pPDD4owkVfw2qNdxbh+QQt4YwoJz8c=","Xwg/ChozygdqlSeYMlgNs+DvRYS9/x9UyKNg9Q3jAx4=","Y0eq8p7jwq+a+Im8H7klTavTEXfxYjLdaqsDXKOb9uQ="],"root":"XcnaeacGWamtVZy3Ad7ZoqudgjqtL0lgz+Nw7/RgQyg=","expected_error":"calculated root:\n[106 127 191 167 189 101 192 110 211 45 125 241 85 157 165 80 205 103 223 91 228 74 158 238 85 213 91 10 145 28 228 163]\n does not match expected root:\n[93 201 218 121 167 6 89 169 173 85 156 183 1 222 217 162 171 157 130 58 173 47 73 96 207 227 112 239 244 96 67 40]"} +{"desc":"TestVerifyInclusion/proof:2: removed component","index":0,"size":8,"leaf_hash":"bjQLnP+zepicpUTmu3gKLHiQHT+zNzh2hRGjBhevoB0=","proof":["lqKW0iTyhcZ77pPDD4owkVfw2qNdxbh+QQt4YwoJz8c=","Xwg/ChozygdqlSeYMlgNs+DvRYS9/x9UyKNg9Q3jAx4="],"root":"XcnaeacGWamtVZy3Ad7ZoqudgjqtL0lgz+Nw7/RgQyg=","expected_error":"wrong proof size 2, want 3"} +{"desc":"TestVerifyInclusion/proof:2: inserted component","index":0,"size":8,"leaf_hash":"bjQLnP+zepicpUTmu3gKLHiQHT+zNzh2hRGjBhevoB0=","proof":["lqKW0iTyhcZ77pPDD4owkVfw2qNdxbh+QQt4YwoJz8c=","q6yroAAAAAAAAAAAAAAAAAAAAAAAAAAAAGAGHgASNFY=","Xwg/ChozygdqlSeYMlgNs+DvRYS9/x9UyKNg9Q3jAx4=","a0eq8p7jwq+a+Im8H7klTavTEXfxYjLdaqsDXKOb9uQ="],"root":"XcnaeacGWamtVZy3Ad7ZoqudgjqtL0lgz+Nw7/RgQyg=","expected_error":"wrong proof size 4, want 3"} +{"desc":"TestVerifyInclusion/proof:3","index":5,"size":8,"leaf_hash":"QnGia+DYqE8L1UyMMC58s6O10fpngKQLzOKHNHfatlg=","proof":["vBoGQ7EuTS18d5GPROD095qDi2z57FtcKD4fTYhZnms=","yoVOoSjtBQtBs1/8G4e46yveRh6eO1WW7Oa51ZdaCuA=","037kGJdt2VdTwcc4Yrk5j6Kiz5tP8P3+izDNlSCWFLc="],"root":"XcnaeacGWamtVZy3Ad7ZoqudgjqtL0lgz+Nw7/RgQyg=","expected_error":null} +{"desc":"TestVerifyInclusion/proof:3: leafIndex - 1","index":4,"size":8,"leaf_hash":"QnGia+DYqE8L1UyMMC58s6O10fpngKQLzOKHNHfatlg=","proof":["vBoGQ7EuTS18d5GPROD095qDi2z57FtcKD4fTYhZnms=","yoVOoSjtBQtBs1/8G4e46yveRh6eO1WW7Oa51ZdaCuA=","037kGJdt2VdTwcc4Yrk5j6Kiz5tP8P3+izDNlSCWFLc="],"root":"XcnaeacGWamtVZy3Ad7ZoqudgjqtL0lgz+Nw7/RgQyg=","expected_error":"calculated root:\n[204 44 19 139 93 214 240 138 20 229 8 193 138 210 204 167 62 13 162 4 122 238 55 103 39 250 11 86 222 45 217 179]\n does not match expected root:\n[93 201 218 121 167 6 89 169 173 85 156 183 1 222 217 162 171 157 130 58 173 47 73 96 207 227 112 239 244 96 67 40]"} +{"desc":"TestVerifyInclusion/proof:3: leafIndex + 1","index":6,"size":8,"leaf_hash":"QnGia+DYqE8L1UyMMC58s6O10fpngKQLzOKHNHfatlg=","proof":["vBoGQ7EuTS18d5GPROD095qDi2z57FtcKD4fTYhZnms=","yoVOoSjtBQtBs1/8G4e46yveRh6eO1WW7Oa51ZdaCuA=","037kGJdt2VdTwcc4Yrk5j6Kiz5tP8P3+izDNlSCWFLc="],"root":"XcnaeacGWamtVZy3Ad7ZoqudgjqtL0lgz+Nw7/RgQyg=","expected_error":"calculated root:\n[110 216 90 230 88 172 109 205 218 171 166 218 244 50 22 246 155 54 211 242 229 190 184 35 242 113 56 85 131 181 169 251]\n does not match expected root:\n[93 201 218 121 167 6 89 169 173 85 156 183 1 222 217 162 171 157 130 58 173 47 73 96 207 227 112 239 244 96 67 40]"} +{"desc":"TestVerifyInclusion/proof:3: leafIndex ^ 2","index":7,"size":8,"leaf_hash":"QnGia+DYqE8L1UyMMC58s6O10fpngKQLzOKHNHfatlg=","proof":["vBoGQ7EuTS18d5GPROD095qDi2z57FtcKD4fTYhZnms=","yoVOoSjtBQtBs1/8G4e46yveRh6eO1WW7Oa51ZdaCuA=","037kGJdt2VdTwcc4Yrk5j6Kiz5tP8P3+izDNlSCWFLc="],"root":"XcnaeacGWamtVZy3Ad7ZoqudgjqtL0lgz+Nw7/RgQyg=","expected_error":"calculated root:\n[189 195 73 103 33 112 144 55 75 112 160 179 176 145 219 68 22 160 255 3 204 28 146 210 52 158 125 104 254 234 50 170]\n does not match expected root:\n[93 201 218 121 167 6 89 169 173 85 156 183 1 222 217 162 171 157 130 58 173 47 73 96 207 227 112 239 244 96 67 40]"} +{"desc":"TestVerifyInclusion/proof:3: treeSize * 2","index":5,"size":16,"leaf_hash":"QnGia+DYqE8L1UyMMC58s6O10fpngKQLzOKHNHfatlg=","proof":["vBoGQ7EuTS18d5GPROD095qDi2z57FtcKD4fTYhZnms=","yoVOoSjtBQtBs1/8G4e46yveRh6eO1WW7Oa51ZdaCuA=","037kGJdt2VdTwcc4Yrk5j6Kiz5tP8P3+izDNlSCWFLc="],"root":"XcnaeacGWamtVZy3Ad7ZoqudgjqtL0lgz+Nw7/RgQyg=","expected_error":"wrong proof size 3, want 4"} +{"desc":"TestVerifyInclusion/proof:3: treeSize / 2","index":5,"size":4,"leaf_hash":"QnGia+DYqE8L1UyMMC58s6O10fpngKQLzOKHNHfatlg=","proof":["vBoGQ7EuTS18d5GPROD095qDi2z57FtcKD4fTYhZnms=","yoVOoSjtBQtBs1/8G4e46yveRh6eO1WW7Oa51ZdaCuA=","037kGJdt2VdTwcc4Yrk5j6Kiz5tP8P3+izDNlSCWFLc="],"root":"XcnaeacGWamtVZy3Ad7ZoqudgjqtL0lgz+Nw7/RgQyg=","expected_error":"index is beyond size: 5 \u003e= 4"} +{"desc":"TestVerifyInclusion/proof:3: wrong leaf","index":5,"size":8,"leaf_hash":"V3JvbmdMZWFm","proof":["vBoGQ7EuTS18d5GPROD095qDi2z57FtcKD4fTYhZnms=","yoVOoSjtBQtBs1/8G4e46yveRh6eO1WW7Oa51ZdaCuA=","037kGJdt2VdTwcc4Yrk5j6Kiz5tP8P3+izDNlSCWFLc="],"root":"XcnaeacGWamtVZy3Ad7ZoqudgjqtL0lgz+Nw7/RgQyg=","expected_error":"leafHash has unexpected size 9, want 32"} +{"desc":"TestVerifyInclusion/proof:3: empty root","index":5,"size":8,"leaf_hash":"QnGia+DYqE8L1UyMMC58s6O10fpngKQLzOKHNHfatlg=","proof":["vBoGQ7EuTS18d5GPROD095qDi2z57FtcKD4fTYhZnms=","yoVOoSjtBQtBs1/8G4e46yveRh6eO1WW7Oa51ZdaCuA=","037kGJdt2VdTwcc4Yrk5j6Kiz5tP8P3+izDNlSCWFLc="],"root":"47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=","expected_error":"calculated root:\n[93 201 218 121 167 6 89 169 173 85 156 183 1 222 217 162 171 157 130 58 173 47 73 96 207 227 112 239 244 96 67 40]\n does not match expected root:\n[227 176 196 66 152 252 28 20 154 251 244 200 153 111 185 36 39 174 65 228 100 155 147 76 164 149 153 27 120 82 184 85]"} +{"desc":"TestVerifyInclusion/proof:3: random root","index":5,"size":8,"leaf_hash":"QnGia+DYqE8L1UyMMC58s6O10fpngKQLzOKHNHfatlg=","proof":["vBoGQ7EuTS18d5GPROD095qDi2z57FtcKD4fTYhZnms=","yoVOoSjtBQtBs1/8G4e46yveRh6eO1WW7Oa51ZdaCuA=","037kGJdt2VdTwcc4Yrk5j6Kiz5tP8P3+izDNlSCWFLc="],"root":"q6yroAAAAAAAAAAAAAAAAAAAAAAAAAAAAGAGHgASNFY=","expected_error":"calculated root:\n[93 201 218 121 167 6 89 169 173 85 156 183 1 222 217 162 171 157 130 58 173 47 73 96 207 227 112 239 244 96 67 40]\n does not match expected root:\n[171 172 171 160 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 96 6 30 0 18 52 86]"} +{"desc":"TestVerifyInclusion/proof:3: trailing garbage","index":5,"size":8,"leaf_hash":"QnGia+DYqE8L1UyMMC58s6O10fpngKQLzOKHNHfatlg=","proof":["vBoGQ7EuTS18d5GPROD095qDi2z57FtcKD4fTYhZnms=","yoVOoSjtBQtBs1/8G4e46yveRh6eO1WW7Oa51ZdaCuA=","037kGJdt2VdTwcc4Yrk5j6Kiz5tP8P3+izDNlSCWFLc=",""],"root":"XcnaeacGWamtVZy3Ad7ZoqudgjqtL0lgz+Nw7/RgQyg=","expected_error":"wrong proof size 4, want 3"} +{"desc":"TestVerifyInclusion/proof:3: trailing root","index":5,"size":8,"leaf_hash":"QnGia+DYqE8L1UyMMC58s6O10fpngKQLzOKHNHfatlg=","proof":["vBoGQ7EuTS18d5GPROD095qDi2z57FtcKD4fTYhZnms=","yoVOoSjtBQtBs1/8G4e46yveRh6eO1WW7Oa51ZdaCuA=","037kGJdt2VdTwcc4Yrk5j6Kiz5tP8P3+izDNlSCWFLc=","XcnaeacGWamtVZy3Ad7ZoqudgjqtL0lgz+Nw7/RgQyg="],"root":"XcnaeacGWamtVZy3Ad7ZoqudgjqtL0lgz+Nw7/RgQyg=","expected_error":"wrong proof size 4, want 3"} +{"desc":"TestVerifyInclusion/proof:3: preceding garbage","index":5,"size":8,"leaf_hash":"QnGia+DYqE8L1UyMMC58s6O10fpngKQLzOKHNHfatlg=","proof":["","vBoGQ7EuTS18d5GPROD095qDi2z57FtcKD4fTYhZnms=","yoVOoSjtBQtBs1/8G4e46yveRh6eO1WW7Oa51ZdaCuA=","037kGJdt2VdTwcc4Yrk5j6Kiz5tP8P3+izDNlSCWFLc="],"root":"XcnaeacGWamtVZy3Ad7ZoqudgjqtL0lgz+Nw7/RgQyg=","expected_error":"wrong proof size 4, want 3"} +{"desc":"TestVerifyInclusion/proof:3: preceding root","index":5,"size":8,"leaf_hash":"QnGia+DYqE8L1UyMMC58s6O10fpngKQLzOKHNHfatlg=","proof":["XcnaeacGWamtVZy3Ad7ZoqudgjqtL0lgz+Nw7/RgQyg=","vBoGQ7EuTS18d5GPROD095qDi2z57FtcKD4fTYhZnms=","yoVOoSjtBQtBs1/8G4e46yveRh6eO1WW7Oa51ZdaCuA=","037kGJdt2VdTwcc4Yrk5j6Kiz5tP8P3+izDNlSCWFLc="],"root":"XcnaeacGWamtVZy3Ad7ZoqudgjqtL0lgz+Nw7/RgQyg=","expected_error":"wrong proof size 4, want 3"} +{"desc":"TestVerifyInclusion/proof:3: modified proof[0] bit 3","index":5,"size":8,"leaf_hash":"QnGia+DYqE8L1UyMMC58s6O10fpngKQLzOKHNHfatlg=","proof":["tBoGQ7EuTS18d5GPROD095qDi2z57FtcKD4fTYhZnms=","yoVOoSjtBQtBs1/8G4e46yveRh6eO1WW7Oa51ZdaCuA=","037kGJdt2VdTwcc4Yrk5j6Kiz5tP8P3+izDNlSCWFLc="],"root":"XcnaeacGWamtVZy3Ad7ZoqudgjqtL0lgz+Nw7/RgQyg=","expected_error":"calculated root:\n[132 255 141 80 168 58 83 173 36 94 212 168 155 14 158 110 45 156 236 35 104 183 216 66 134 251 226 14 249 149 196 134]\n does not match expected root:\n[93 201 218 121 167 6 89 169 173 85 156 183 1 222 217 162 171 157 130 58 173 47 73 96 207 227 112 239 244 96 67 40]"} +{"desc":"TestVerifyInclusion/proof:3: modified proof[1] bit 3","index":5,"size":8,"leaf_hash":"QnGia+DYqE8L1UyMMC58s6O10fpngKQLzOKHNHfatlg=","proof":["vBoGQ7EuTS18d5GPROD095qDi2z57FtcKD4fTYhZnms=","woVOoSjtBQtBs1/8G4e46yveRh6eO1WW7Oa51ZdaCuA=","037kGJdt2VdTwcc4Yrk5j6Kiz5tP8P3+izDNlSCWFLc="],"root":"XcnaeacGWamtVZy3Ad7ZoqudgjqtL0lgz+Nw7/RgQyg=","expected_error":"calculated root:\n[195 18 196 47 177 146 18 11 93 183 32 57 187 47 13 253 201 48 157 112 5 17 17 200 45 171 42 178 126 194 121 238]\n does not match expected root:\n[93 201 218 121 167 6 89 169 173 85 156 183 1 222 217 162 171 157 130 58 173 47 73 96 207 227 112 239 244 96 67 40]"} +{"desc":"TestVerifyInclusion/proof:3: modified proof[2] bit 3","index":5,"size":8,"leaf_hash":"QnGia+DYqE8L1UyMMC58s6O10fpngKQLzOKHNHfatlg=","proof":["vBoGQ7EuTS18d5GPROD095qDi2z57FtcKD4fTYhZnms=","yoVOoSjtBQtBs1/8G4e46yveRh6eO1WW7Oa51ZdaCuA=","237kGJdt2VdTwcc4Yrk5j6Kiz5tP8P3+izDNlSCWFLc="],"root":"XcnaeacGWamtVZy3Ad7ZoqudgjqtL0lgz+Nw7/RgQyg=","expected_error":"calculated root:\n[127 175 4 209 73 87 14 53 242 75 144 255 218 38 204 182 145 156 175 131 13 62 6 121 238 231 140 175 45 210 193 194]\n does not match expected root:\n[93 201 218 121 167 6 89 169 173 85 156 183 1 222 217 162 171 157 130 58 173 47 73 96 207 227 112 239 244 96 67 40]"} +{"desc":"TestVerifyInclusion/proof:3: removed component","index":5,"size":8,"leaf_hash":"QnGia+DYqE8L1UyMMC58s6O10fpngKQLzOKHNHfatlg=","proof":["vBoGQ7EuTS18d5GPROD095qDi2z57FtcKD4fTYhZnms=","yoVOoSjtBQtBs1/8G4e46yveRh6eO1WW7Oa51ZdaCuA="],"root":"XcnaeacGWamtVZy3Ad7ZoqudgjqtL0lgz+Nw7/RgQyg=","expected_error":"wrong proof size 2, want 3"} +{"desc":"TestVerifyInclusion/proof:3: inserted component","index":5,"size":8,"leaf_hash":"QnGia+DYqE8L1UyMMC58s6O10fpngKQLzOKHNHfatlg=","proof":["vBoGQ7EuTS18d5GPROD095qDi2z57FtcKD4fTYhZnms=","q6yroAAAAAAAAAAAAAAAAAAAAAAAAAAAAGAGHgASNFY=","yoVOoSjtBQtBs1/8G4e46yveRh6eO1WW7Oa51ZdaCuA=","037kGJdt2VdTwcc4Yrk5j6Kiz5tP8P3+izDNlSCWFLc="],"root":"XcnaeacGWamtVZy3Ad7ZoqudgjqtL0lgz+Nw7/RgQyg=","expected_error":"wrong proof size 4, want 3"} +{"desc":"TestVerifyInclusion/proof:4","index":2,"size":3,"leaf_hash":"ApjRIpBtz8EIkstTpzmS/FufST6kybrbJ7eRtBJ6f+c=","proof":["+sVCA+fMaWzw38tCySodnbr3CtnmIfS9jZhmLwDjwSU="],"root":"rra8/idLcKFPsGel5VeCZNsPqbUa9eC6FZFY8yngbnc=","expected_error":null} +{"desc":"TestVerifyInclusion/proof:4: leafIndex - 1","index":1,"size":3,"leaf_hash":"ApjRIpBtz8EIkstTpzmS/FufST6kybrbJ7eRtBJ6f+c=","proof":["+sVCA+fMaWzw38tCySodnbr3CtnmIfS9jZhmLwDjwSU="],"root":"rra8/idLcKFPsGel5VeCZNsPqbUa9eC6FZFY8yngbnc=","expected_error":"wrong proof size 1, want 2"} +{"desc":"TestVerifyInclusion/proof:4: leafIndex + 1","index":3,"size":3,"leaf_hash":"ApjRIpBtz8EIkstTpzmS/FufST6kybrbJ7eRtBJ6f+c=","proof":["+sVCA+fMaWzw38tCySodnbr3CtnmIfS9jZhmLwDjwSU="],"root":"rra8/idLcKFPsGel5VeCZNsPqbUa9eC6FZFY8yngbnc=","expected_error":"index is beyond size: 3 \u003e= 3"} +{"desc":"TestVerifyInclusion/proof:4: leafIndex ^ 2","index":0,"size":3,"leaf_hash":"ApjRIpBtz8EIkstTpzmS/FufST6kybrbJ7eRtBJ6f+c=","proof":["+sVCA+fMaWzw38tCySodnbr3CtnmIfS9jZhmLwDjwSU="],"root":"rra8/idLcKFPsGel5VeCZNsPqbUa9eC6FZFY8yngbnc=","expected_error":"wrong proof size 1, want 2"} +{"desc":"TestVerifyInclusion/proof:4: treeSize * 2","index":2,"size":6,"leaf_hash":"ApjRIpBtz8EIkstTpzmS/FufST6kybrbJ7eRtBJ6f+c=","proof":["+sVCA+fMaWzw38tCySodnbr3CtnmIfS9jZhmLwDjwSU="],"root":"rra8/idLcKFPsGel5VeCZNsPqbUa9eC6FZFY8yngbnc=","expected_error":"wrong proof size 1, want 3"} +{"desc":"TestVerifyInclusion/proof:4: treeSize / 2","index":2,"size":1,"leaf_hash":"ApjRIpBtz8EIkstTpzmS/FufST6kybrbJ7eRtBJ6f+c=","proof":["+sVCA+fMaWzw38tCySodnbr3CtnmIfS9jZhmLwDjwSU="],"root":"rra8/idLcKFPsGel5VeCZNsPqbUa9eC6FZFY8yngbnc=","expected_error":"index is beyond size: 2 \u003e= 1"} +{"desc":"TestVerifyInclusion/proof:4: wrong leaf","index":2,"size":3,"leaf_hash":"V3JvbmdMZWFm","proof":["+sVCA+fMaWzw38tCySodnbr3CtnmIfS9jZhmLwDjwSU="],"root":"rra8/idLcKFPsGel5VeCZNsPqbUa9eC6FZFY8yngbnc=","expected_error":"leafHash has unexpected size 9, want 32"} +{"desc":"TestVerifyInclusion/proof:4: empty root","index":2,"size":3,"leaf_hash":"ApjRIpBtz8EIkstTpzmS/FufST6kybrbJ7eRtBJ6f+c=","proof":["+sVCA+fMaWzw38tCySodnbr3CtnmIfS9jZhmLwDjwSU="],"root":"47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=","expected_error":"calculated root:\n[174 182 188 254 39 75 112 161 79 176 103 165 229 87 130 100 219 15 169 181 26 245 224 186 21 145 88 243 41 224 110 119]\n does not match expected root:\n[227 176 196 66 152 252 28 20 154 251 244 200 153 111 185 36 39 174 65 228 100 155 147 76 164 149 153 27 120 82 184 85]"} +{"desc":"TestVerifyInclusion/proof:4: random root","index":2,"size":3,"leaf_hash":"ApjRIpBtz8EIkstTpzmS/FufST6kybrbJ7eRtBJ6f+c=","proof":["+sVCA+fMaWzw38tCySodnbr3CtnmIfS9jZhmLwDjwSU="],"root":"q6yroAAAAAAAAAAAAAAAAAAAAAAAAAAAAGAGHgASNFY=","expected_error":"calculated root:\n[174 182 188 254 39 75 112 161 79 176 103 165 229 87 130 100 219 15 169 181 26 245 224 186 21 145 88 243 41 224 110 119]\n does not match expected root:\n[171 172 171 160 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 96 6 30 0 18 52 86]"} +{"desc":"TestVerifyInclusion/proof:4: trailing garbage","index":2,"size":3,"leaf_hash":"ApjRIpBtz8EIkstTpzmS/FufST6kybrbJ7eRtBJ6f+c=","proof":["+sVCA+fMaWzw38tCySodnbr3CtnmIfS9jZhmLwDjwSU=",""],"root":"rra8/idLcKFPsGel5VeCZNsPqbUa9eC6FZFY8yngbnc=","expected_error":"wrong proof size 2, want 1"} +{"desc":"TestVerifyInclusion/proof:4: trailing root","index":2,"size":3,"leaf_hash":"ApjRIpBtz8EIkstTpzmS/FufST6kybrbJ7eRtBJ6f+c=","proof":["+sVCA+fMaWzw38tCySodnbr3CtnmIfS9jZhmLwDjwSU=","rra8/idLcKFPsGel5VeCZNsPqbUa9eC6FZFY8yngbnc="],"root":"rra8/idLcKFPsGel5VeCZNsPqbUa9eC6FZFY8yngbnc=","expected_error":"wrong proof size 2, want 1"} +{"desc":"TestVerifyInclusion/proof:4: preceding garbage","index":2,"size":3,"leaf_hash":"ApjRIpBtz8EIkstTpzmS/FufST6kybrbJ7eRtBJ6f+c=","proof":["","+sVCA+fMaWzw38tCySodnbr3CtnmIfS9jZhmLwDjwSU="],"root":"rra8/idLcKFPsGel5VeCZNsPqbUa9eC6FZFY8yngbnc=","expected_error":"wrong proof size 2, want 1"} +{"desc":"TestVerifyInclusion/proof:4: preceding root","index":2,"size":3,"leaf_hash":"ApjRIpBtz8EIkstTpzmS/FufST6kybrbJ7eRtBJ6f+c=","proof":["rra8/idLcKFPsGel5VeCZNsPqbUa9eC6FZFY8yngbnc=","+sVCA+fMaWzw38tCySodnbr3CtnmIfS9jZhmLwDjwSU="],"root":"rra8/idLcKFPsGel5VeCZNsPqbUa9eC6FZFY8yngbnc=","expected_error":"wrong proof size 2, want 1"} +{"desc":"TestVerifyInclusion/proof:4: modified proof[0] bit 3","index":2,"size":3,"leaf_hash":"ApjRIpBtz8EIkstTpzmS/FufST6kybrbJ7eRtBJ6f+c=","proof":["8sVCA+fMaWzw38tCySodnbr3CtnmIfS9jZhmLwDjwSU="],"root":"rra8/idLcKFPsGel5VeCZNsPqbUa9eC6FZFY8yngbnc=","expected_error":"calculated root:\n[174 168 92 242 97 166 33 207 200 14 19 21 242 232 236 18 170 162 218 89 111 108 21 115 146 130 255 114 92 219 204 138]\n does not match expected root:\n[174 182 188 254 39 75 112 161 79 176 103 165 229 87 130 100 219 15 169 181 26 245 224 186 21 145 88 243 41 224 110 119]"} +{"desc":"TestVerifyInclusion/proof:4: removed component","index":2,"size":3,"leaf_hash":"ApjRIpBtz8EIkstTpzmS/FufST6kybrbJ7eRtBJ6f+c=","proof":[],"root":"rra8/idLcKFPsGel5VeCZNsPqbUa9eC6FZFY8yngbnc=","expected_error":"wrong proof size 0, want 1"} +{"desc":"TestVerifyInclusion/proof:5","index":1,"size":5,"leaf_hash":"lqKW0iTyhcZ77pPDD4owkVfw2qNdxbh+QQt4YwoJz8c=","proof":["bjQLnP+zepicpUTmu3gKLHiQHT+zNzh2hRGjBhevoB0=","Xwg/ChozygdqlSeYMlgNs+DvRYS9/x9UyKNg9Q3jAx4=","vBoGQ7EuTS18d5GPROD095qDi2z57FtcKD4fTYhZnms="],"root":"Tju7H3tHjc/nH7YxYxUZo7yhLJrvyhYSv85ME6hiZNQ=","expected_error":null} +{"desc":"TestVerifyInclusion/proof:5: leafIndex - 1","index":0,"size":5,"leaf_hash":"lqKW0iTyhcZ77pPDD4owkVfw2qNdxbh+QQt4YwoJz8c=","proof":["bjQLnP+zepicpUTmu3gKLHiQHT+zNzh2hRGjBhevoB0=","Xwg/ChozygdqlSeYMlgNs+DvRYS9/x9UyKNg9Q3jAx4=","vBoGQ7EuTS18d5GPROD095qDi2z57FtcKD4fTYhZnms="],"root":"Tju7H3tHjc/nH7YxYxUZo7yhLJrvyhYSv85ME6hiZNQ=","expected_error":"calculated root:\n[243 218 105 107 209 24 91 246 210 123 44 203 173 236 18 127 139 194 239 231 128 5 220 94 236 90 138 37 84 5 246 96]\n does not match expected root:\n[78 59 187 31 123 71 141 207 231 31 182 49 99 21 25 163 188 161 44 154 239 202 22 18 191 206 76 19 168 98 100 212]"} +{"desc":"TestVerifyInclusion/proof:5: leafIndex + 1","index":2,"size":5,"leaf_hash":"lqKW0iTyhcZ77pPDD4owkVfw2qNdxbh+QQt4YwoJz8c=","proof":["bjQLnP+zepicpUTmu3gKLHiQHT+zNzh2hRGjBhevoB0=","Xwg/ChozygdqlSeYMlgNs+DvRYS9/x9UyKNg9Q3jAx4=","vBoGQ7EuTS18d5GPROD095qDi2z57FtcKD4fTYhZnms="],"root":"Tju7H3tHjc/nH7YxYxUZo7yhLJrvyhYSv85ME6hiZNQ=","expected_error":"calculated root:\n[1 215 240 192 214 107 232 227 4 249 142 25 110 145 232 127 36 78 97 43 187 130 92 164 214 171 228 183 32 229 219 94]\n does not match expected root:\n[78 59 187 31 123 71 141 207 231 31 182 49 99 21 25 163 188 161 44 154 239 202 22 18 191 206 76 19 168 98 100 212]"} +{"desc":"TestVerifyInclusion/proof:5: leafIndex ^ 2","index":3,"size":5,"leaf_hash":"lqKW0iTyhcZ77pPDD4owkVfw2qNdxbh+QQt4YwoJz8c=","proof":["bjQLnP+zepicpUTmu3gKLHiQHT+zNzh2hRGjBhevoB0=","Xwg/ChozygdqlSeYMlgNs+DvRYS9/x9UyKNg9Q3jAx4=","vBoGQ7EuTS18d5GPROD095qDi2z57FtcKD4fTYhZnms="],"root":"Tju7H3tHjc/nH7YxYxUZo7yhLJrvyhYSv85ME6hiZNQ=","expected_error":"calculated root:\n[168 180 216 113 48 163 123 160 15 17 200 28 25 132 95 60 157 139 3 192 214 255 53 16 22 158 62 125 115 81 243 31]\n does not match expected root:\n[78 59 187 31 123 71 141 207 231 31 182 49 99 21 25 163 188 161 44 154 239 202 22 18 191 206 76 19 168 98 100 212]"} +{"desc":"TestVerifyInclusion/proof:5: treeSize * 2","index":1,"size":10,"leaf_hash":"lqKW0iTyhcZ77pPDD4owkVfw2qNdxbh+QQt4YwoJz8c=","proof":["bjQLnP+zepicpUTmu3gKLHiQHT+zNzh2hRGjBhevoB0=","Xwg/ChozygdqlSeYMlgNs+DvRYS9/x9UyKNg9Q3jAx4=","vBoGQ7EuTS18d5GPROD095qDi2z57FtcKD4fTYhZnms="],"root":"Tju7H3tHjc/nH7YxYxUZo7yhLJrvyhYSv85ME6hiZNQ=","expected_error":"wrong proof size 3, want 4"} +{"desc":"TestVerifyInclusion/proof:5: treeSize / 2","index":1,"size":2,"leaf_hash":"lqKW0iTyhcZ77pPDD4owkVfw2qNdxbh+QQt4YwoJz8c=","proof":["bjQLnP+zepicpUTmu3gKLHiQHT+zNzh2hRGjBhevoB0=","Xwg/ChozygdqlSeYMlgNs+DvRYS9/x9UyKNg9Q3jAx4=","vBoGQ7EuTS18d5GPROD095qDi2z57FtcKD4fTYhZnms="],"root":"Tju7H3tHjc/nH7YxYxUZo7yhLJrvyhYSv85ME6hiZNQ=","expected_error":"wrong proof size 3, want 1"} +{"desc":"TestVerifyInclusion/proof:5: wrong leaf","index":1,"size":5,"leaf_hash":"V3JvbmdMZWFm","proof":["bjQLnP+zepicpUTmu3gKLHiQHT+zNzh2hRGjBhevoB0=","Xwg/ChozygdqlSeYMlgNs+DvRYS9/x9UyKNg9Q3jAx4=","vBoGQ7EuTS18d5GPROD095qDi2z57FtcKD4fTYhZnms="],"root":"Tju7H3tHjc/nH7YxYxUZo7yhLJrvyhYSv85ME6hiZNQ=","expected_error":"leafHash has unexpected size 9, want 32"} +{"desc":"TestVerifyInclusion/proof:5: empty root","index":1,"size":5,"leaf_hash":"lqKW0iTyhcZ77pPDD4owkVfw2qNdxbh+QQt4YwoJz8c=","proof":["bjQLnP+zepicpUTmu3gKLHiQHT+zNzh2hRGjBhevoB0=","Xwg/ChozygdqlSeYMlgNs+DvRYS9/x9UyKNg9Q3jAx4=","vBoGQ7EuTS18d5GPROD095qDi2z57FtcKD4fTYhZnms="],"root":"47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=","expected_error":"calculated root:\n[78 59 187 31 123 71 141 207 231 31 182 49 99 21 25 163 188 161 44 154 239 202 22 18 191 206 76 19 168 98 100 212]\n does not match expected root:\n[227 176 196 66 152 252 28 20 154 251 244 200 153 111 185 36 39 174 65 228 100 155 147 76 164 149 153 27 120 82 184 85]"} +{"desc":"TestVerifyInclusion/proof:5: random root","index":1,"size":5,"leaf_hash":"lqKW0iTyhcZ77pPDD4owkVfw2qNdxbh+QQt4YwoJz8c=","proof":["bjQLnP+zepicpUTmu3gKLHiQHT+zNzh2hRGjBhevoB0=","Xwg/ChozygdqlSeYMlgNs+DvRYS9/x9UyKNg9Q3jAx4=","vBoGQ7EuTS18d5GPROD095qDi2z57FtcKD4fTYhZnms="],"root":"q6yroAAAAAAAAAAAAAAAAAAAAAAAAAAAAGAGHgASNFY=","expected_error":"calculated root:\n[78 59 187 31 123 71 141 207 231 31 182 49 99 21 25 163 188 161 44 154 239 202 22 18 191 206 76 19 168 98 100 212]\n does not match expected root:\n[171 172 171 160 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 96 6 30 0 18 52 86]"} +{"desc":"TestVerifyInclusion/proof:5: trailing garbage","index":1,"size":5,"leaf_hash":"lqKW0iTyhcZ77pPDD4owkVfw2qNdxbh+QQt4YwoJz8c=","proof":["bjQLnP+zepicpUTmu3gKLHiQHT+zNzh2hRGjBhevoB0=","Xwg/ChozygdqlSeYMlgNs+DvRYS9/x9UyKNg9Q3jAx4=","vBoGQ7EuTS18d5GPROD095qDi2z57FtcKD4fTYhZnms=",""],"root":"Tju7H3tHjc/nH7YxYxUZo7yhLJrvyhYSv85ME6hiZNQ=","expected_error":"wrong proof size 4, want 3"} +{"desc":"TestVerifyInclusion/proof:5: trailing root","index":1,"size":5,"leaf_hash":"lqKW0iTyhcZ77pPDD4owkVfw2qNdxbh+QQt4YwoJz8c=","proof":["bjQLnP+zepicpUTmu3gKLHiQHT+zNzh2hRGjBhevoB0=","Xwg/ChozygdqlSeYMlgNs+DvRYS9/x9UyKNg9Q3jAx4=","vBoGQ7EuTS18d5GPROD095qDi2z57FtcKD4fTYhZnms=","Tju7H3tHjc/nH7YxYxUZo7yhLJrvyhYSv85ME6hiZNQ="],"root":"Tju7H3tHjc/nH7YxYxUZo7yhLJrvyhYSv85ME6hiZNQ=","expected_error":"wrong proof size 4, want 3"} +{"desc":"TestVerifyInclusion/proof:5: preceding garbage","index":1,"size":5,"leaf_hash":"lqKW0iTyhcZ77pPDD4owkVfw2qNdxbh+QQt4YwoJz8c=","proof":["","bjQLnP+zepicpUTmu3gKLHiQHT+zNzh2hRGjBhevoB0=","Xwg/ChozygdqlSeYMlgNs+DvRYS9/x9UyKNg9Q3jAx4=","vBoGQ7EuTS18d5GPROD095qDi2z57FtcKD4fTYhZnms="],"root":"Tju7H3tHjc/nH7YxYxUZo7yhLJrvyhYSv85ME6hiZNQ=","expected_error":"wrong proof size 4, want 3"} +{"desc":"TestVerifyInclusion/proof:5: preceding root","index":1,"size":5,"leaf_hash":"lqKW0iTyhcZ77pPDD4owkVfw2qNdxbh+QQt4YwoJz8c=","proof":["Tju7H3tHjc/nH7YxYxUZo7yhLJrvyhYSv85ME6hiZNQ=","bjQLnP+zepicpUTmu3gKLHiQHT+zNzh2hRGjBhevoB0=","Xwg/ChozygdqlSeYMlgNs+DvRYS9/x9UyKNg9Q3jAx4=","vBoGQ7EuTS18d5GPROD095qDi2z57FtcKD4fTYhZnms="],"root":"Tju7H3tHjc/nH7YxYxUZo7yhLJrvyhYSv85ME6hiZNQ=","expected_error":"wrong proof size 4, want 3"} +{"desc":"TestVerifyInclusion/proof:5: modified proof[0] bit 3","index":1,"size":5,"leaf_hash":"lqKW0iTyhcZ77pPDD4owkVfw2qNdxbh+QQt4YwoJz8c=","proof":["ZjQLnP+zepicpUTmu3gKLHiQHT+zNzh2hRGjBhevoB0=","Xwg/ChozygdqlSeYMlgNs+DvRYS9/x9UyKNg9Q3jAx4=","vBoGQ7EuTS18d5GPROD095qDi2z57FtcKD4fTYhZnms="],"root":"Tju7H3tHjc/nH7YxYxUZo7yhLJrvyhYSv85ME6hiZNQ=","expected_error":"calculated root:\n[0 137 0 198 215 62 95 128 40 84 210 68 168 179 3 172 115 103 40 223 202 229 172 73 245 162 76 202 130 8 241 110]\n does not match expected root:\n[78 59 187 31 123 71 141 207 231 31 182 49 99 21 25 163 188 161 44 154 239 202 22 18 191 206 76 19 168 98 100 212]"} +{"desc":"TestVerifyInclusion/proof:5: modified proof[1] bit 3","index":1,"size":5,"leaf_hash":"lqKW0iTyhcZ77pPDD4owkVfw2qNdxbh+QQt4YwoJz8c=","proof":["bjQLnP+zepicpUTmu3gKLHiQHT+zNzh2hRGjBhevoB0=","Vwg/ChozygdqlSeYMlgNs+DvRYS9/x9UyKNg9Q3jAx4=","vBoGQ7EuTS18d5GPROD095qDi2z57FtcKD4fTYhZnms="],"root":"Tju7H3tHjc/nH7YxYxUZo7yhLJrvyhYSv85ME6hiZNQ=","expected_error":"calculated root:\n[62 156 245 6 41 4 190 125 80 214 169 189 103 7 224 44 47 100 142 176 78 53 43 74 117 130 72 172 184 17 2 231]\n does not match expected root:\n[78 59 187 31 123 71 141 207 231 31 182 49 99 21 25 163 188 161 44 154 239 202 22 18 191 206 76 19 168 98 100 212]"} +{"desc":"TestVerifyInclusion/proof:5: modified proof[2] bit 3","index":1,"size":5,"leaf_hash":"lqKW0iTyhcZ77pPDD4owkVfw2qNdxbh+QQt4YwoJz8c=","proof":["bjQLnP+zepicpUTmu3gKLHiQHT+zNzh2hRGjBhevoB0=","Xwg/ChozygdqlSeYMlgNs+DvRYS9/x9UyKNg9Q3jAx4=","tBoGQ7EuTS18d5GPROD095qDi2z57FtcKD4fTYhZnms="],"root":"Tju7H3tHjc/nH7YxYxUZo7yhLJrvyhYSv85ME6hiZNQ=","expected_error":"calculated root:\n[122 83 35 175 168 203 5 237 223 19 28 196 125 114 70 223 69 240 88 224 77 29 132 104 146 173 89 252 117 152 219 35]\n does not match expected root:\n[78 59 187 31 123 71 141 207 231 31 182 49 99 21 25 163 188 161 44 154 239 202 22 18 191 206 76 19 168 98 100 212]"} +{"desc":"TestVerifyInclusion/proof:5: removed component","index":1,"size":5,"leaf_hash":"lqKW0iTyhcZ77pPDD4owkVfw2qNdxbh+QQt4YwoJz8c=","proof":["bjQLnP+zepicpUTmu3gKLHiQHT+zNzh2hRGjBhevoB0=","Xwg/ChozygdqlSeYMlgNs+DvRYS9/x9UyKNg9Q3jAx4="],"root":"Tju7H3tHjc/nH7YxYxUZo7yhLJrvyhYSv85ME6hiZNQ=","expected_error":"wrong proof size 2, want 3"} +{"desc":"TestVerifyInclusion/proof:5: inserted component","index":1,"size":5,"leaf_hash":"lqKW0iTyhcZ77pPDD4owkVfw2qNdxbh+QQt4YwoJz8c=","proof":["bjQLnP+zepicpUTmu3gKLHiQHT+zNzh2hRGjBhevoB0=","q6yroAAAAAAAAAAAAAAAAAAAAAAAAAAAAGAGHgASNFY=","Xwg/ChozygdqlSeYMlgNs+DvRYS9/x9UyKNg9Q3jAx4=","vBoGQ7EuTS18d5GPROD095qDi2z57FtcKD4fTYhZnms="],"root":"Tju7H3tHjc/nH7YxYxUZo7yhLJrvyhYSv85ME6hiZNQ=","expected_error":"wrong proof size 4, want 3"} diff --git a/vendor/cache/sigstore-ruby-ce93acf7fa7e/test/sigstore/data/x509/cryptography-scts-tbs-precert.der b/vendor/cache/sigstore-ruby-ce93acf7fa7e/test/sigstore/data/x509/cryptography-scts-tbs-precert.der new file mode 100644 index 00000000..0223ad6f Binary files /dev/null and b/vendor/cache/sigstore-ruby-ce93acf7fa7e/test/sigstore/data/x509/cryptography-scts-tbs-precert.der differ diff --git a/vendor/cache/sigstore-ruby-ce93acf7fa7e/test/sigstore/internal/json_test.rb b/vendor/cache/sigstore-ruby-ce93acf7fa7e/test/sigstore/internal/json_test.rb new file mode 100644 index 00000000..9cc0b6a0 --- /dev/null +++ b/vendor/cache/sigstore-ruby-ce93acf7fa7e/test/sigstore/internal/json_test.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true + +require "test_helper" +require "sigstore/internal/json" + +class Sigstore::Internal::JSONTest < Test::Unit::TestCase + def test_canonical_generate + e = assert_raise(ArgumentError) do + Sigstore::Internal::JSON.canonical_generate({ + "foo" => [1.2] + }) + end + assert_equal "Unsupported data type: Float", e.message + + e = assert_raise(ArgumentError) do + Sigstore::Internal::JSON.canonical_generate({ 1 => [] }) + end + assert_equal "Non-string key in hash", e.message + + hash = { + "empty" => "", + "a" => "b", + "null" => nil, + "true" => true, + "false" => false, + "int" => 1, + "array" => [1, 2, 3, "4"], + "empty_hash" => {}, + "empty_array" => [], + "newline_string" => "a\nb\n", + "quote_string" => "a\"b", + "hash" => { "c" => "d", "e" => "f" } + } + assert_equal <<~JSON.chomp, Sigstore::Internal::JSON.canonical_generate(hash) + {"a":"b","array":[1,2,3,"4"],"empty":"","empty_array":[],"empty_hash":{},"false":false,"hash":{"c":"d","e":"f"},"int":1,"newline_string":"a + b + ","null":null,"quote_string":"a\\"b","true":true} + JSON + end +end diff --git a/vendor/cache/sigstore-ruby-ce93acf7fa7e/test/sigstore/internal/keyring_test.rb b/vendor/cache/sigstore-ruby-ce93acf7fa7e/test/sigstore/internal/keyring_test.rb new file mode 100644 index 00000000..5f0945b5 --- /dev/null +++ b/vendor/cache/sigstore-ruby-ce93acf7fa7e/test/sigstore/internal/keyring_test.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +require "test_helper" + +class Sigstore::Internal::KeyringTest < Test::Unit::TestCase + def test_something; end +end diff --git a/vendor/cache/sigstore-ruby-ce93acf7fa7e/test/sigstore/internal/merkle_test.rb b/vendor/cache/sigstore-ruby-ce93acf7fa7e/test/sigstore/internal/merkle_test.rb new file mode 100644 index 00000000..07a54ef4 --- /dev/null +++ b/vendor/cache/sigstore-ruby-ce93acf7fa7e/test/sigstore/internal/merkle_test.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +require "test_helper" + +class Sigstore::Internal::MerkleTest < Test::Unit::TestCase + test "verify_merkle_inclusion" do + nil + end +end diff --git a/vendor/cache/sigstore-ruby-ce93acf7fa7e/test/sigstore/internal/set_test.rb b/vendor/cache/sigstore-ruby-ce93acf7fa7e/test/sigstore/internal/set_test.rb new file mode 100644 index 00000000..3fc0be45 --- /dev/null +++ b/vendor/cache/sigstore-ruby-ce93acf7fa7e/test/sigstore/internal/set_test.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +require "test_helper" + +class Sigstore::Internal::SETTest < Test::Unit::TestCase + def test_verify_valid; end + def test_verify_invalid; end +end diff --git a/vendor/cache/sigstore-ruby-ce93acf7fa7e/test/sigstore/internal/tuf_test.rb b/vendor/cache/sigstore-ruby-ce93acf7fa7e/test/sigstore/internal/tuf_test.rb new file mode 100644 index 00000000..c7d33eb6 --- /dev/null +++ b/vendor/cache/sigstore-ruby-ce93acf7fa7e/test/sigstore/internal/tuf_test.rb @@ -0,0 +1,58 @@ +# frozen_string_literal: true + +require "test_helper" +require "sigstore/tuf" + +class Sigstore::TUFTest < Test::Unit::TestCase + def test_initialize + updater = Sigstore::TUF::TrustUpdater.new("https://example.com", true) + assert_equal( + File.join( + Dir.home, + ".cache/sigstore-ruby/sigstore/tuf/https%3A%2F%2Fexample.com/trusted_root.json" + ), + updater.trusted_root_path + ) + refute File.file?(updater.trusted_root_path) + end + + def test_production_default_dirs + updater = Sigstore::TUF::TrustUpdater.new("https://tuf-repo-cdn.sigstore.dev", true) + assert_equal( + File.join( + Dir.home, + ".cache/sigstore-ruby/sigstore/tuf/https%3A%2F%2Ftuf-repo-cdn.sigstore.dev/trusted_root.json" + ), + updater.trusted_root_path + ) + + assert File.file?(updater.trusted_root_path) + + assert_equal File.read(updater.trusted_root_path), + File.read(File.expand_path("../../../data/_store/prod/trusted_root.json", __dir__)) + end + + def test_staging_default_dirs + updater = Sigstore::TUF::TrustUpdater.new("https://tuf-repo-cdn.sigstage.dev", true) + assert_equal( + File.join( + Dir.home, + ".cache/sigstore-ruby/sigstore/tuf/https%3A%2F%2Ftuf-repo-cdn.sigstage.dev/trusted_root.json" + ), + updater.trusted_root_path + ) + + assert File.file?(updater.trusted_root_path) + + assert_equal File.read(updater.trusted_root_path), + File.read(File.expand_path("../../../data/_store/staging/trusted_root.json", __dir__)) + end + + def test_initialize_custom_dirs + targets_dir = File.join(Dir.home, "custom-targets") + metadata_dir = File.join(Dir.home, "custom-metadata") + updater = Sigstore::TUF::TrustUpdater.new("https://tuf-repo-cdn.sigstore.dev", true, + metadata_dir:, targets_dir:) + assert_equal(File.join(targets_dir, "trusted_root.json"), updater.trusted_root_path) + end +end diff --git a/vendor/cache/sigstore-ruby-ce93acf7fa7e/test/sigstore/internal/x509_test.rb b/vendor/cache/sigstore-ruby-ce93acf7fa7e/test/sigstore/internal/x509_test.rb new file mode 100644 index 00000000..b2013310 --- /dev/null +++ b/vendor/cache/sigstore-ruby-ce93acf7fa7e/test/sigstore/internal/x509_test.rb @@ -0,0 +1,52 @@ +# frozen_string_literal: true + +require "test_helper" + +require "sigstore/internal/x509" + +class Sigstore::Internal::X509::CertificateTest < Test::Unit::TestCase + def test_cert + cert = Sigstore::Internal::X509::Certificate.new( + OpenSSL::X509::Certificate.new(File.binread(File.join(__dir__, "../data/x509/cryptography-scts.pem"))) + ) + refute_nil(cert) + + refute_nil(ext = cert.extension(Sigstore::Internal::X509::Extension::SubjectKeyIdentifier)) + assert_equal("\x8D\xB7\xB4lMZg\xC1\xE2\xAA\xDC*Q\xF0\x9E\xD7\x96\xC5W\xC5".b, ext.key_identifier) + + refute_nil(ext = cert.extension(Sigstore::Internal::X509::Extension::KeyUsage)) + assert_predicate ext, :digital_signature + refute_predicate ext, :key_cert_sign + + refute_nil(ext = cert.extension(Sigstore::Internal::X509::Extension::ExtendedKeyUsage)) + assert_equal(["1.3.6.1.5.5.7.3.1", "1.3.6.1.5.5.7.3.2"], ext.purposes.map(&:oid)) + + refute_nil(ext = cert.extension(Sigstore::Internal::X509::Extension::BasicConstraints)) + refute_predicate ext, :ca + assert_nil ext.path_len_constraint + + refute_nil(ext = cert.extension(Sigstore::Internal::X509::Extension::PrecertificateSignedCertificateTimestamps)) + assert_equal([ + { entry_type: 1, + extensions_bytes: "", + hash_algorithm: "sha256", + log_id: "293c519654c83965baaa50fc5807d4b76fbf587a2972dca4c30cf4e54547f478", + signature: "0F\x02!\x00\xA5\xCE\xA8|Pnq\x8C&\xE3H\xBB\xF4\v\xC1\x0Eu\xE8M}\xE6:\x8BM\x1E~\x89\n" \ + "r\xDA\xA4@\x02!\x00\xDE\xA9\xF1\xD0\xC3S\xFC\xD37\xE1[q_\x80(\x85u\x80]Kw\x02\xC0'" \ + "\x02\xEE\xD8\xF7\x15N|r".b, + signature_algorithm: "ecdsa", + timestamp: 1_537_995_393_769, + version: 0 } + ], + ext.signed_certificate_timestamps.map(&:to_h)) + end + + def test_tbs_certificate_der + certificate = Sigstore::Internal::X509::Certificate.read( + File.binread(File.join(__dir__, "../data/x509/cryptography-scts.pem")) + ) + expected = File.binread(File.join(__dir__, "../data/x509/cryptography-scts-tbs-precert.der")) + + assert_equal(expected, certificate.tbs_certificate_der) + end +end diff --git a/vendor/cache/sigstore-ruby-ce93acf7fa7e/test/sigstore/models_test.rb b/vendor/cache/sigstore-ruby-ce93acf7fa7e/test/sigstore/models_test.rb new file mode 100644 index 00000000..3dc9848f --- /dev/null +++ b/vendor/cache/sigstore-ruby-ce93acf7fa7e/test/sigstore/models_test.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true + +require "test_helper" +require "sigstore/models" +require "sigstore/trusted_root" + +class Sigstore::BundleTypeTest < Test::Unit::TestCase + def test_from_media_type + assert_equal(Sigstore::BundleType::BUNDLE_0_1, + Sigstore::BundleType.from_media_type("application/vnd.dev.sigstore.bundle+json;version=0.1")) + assert_equal(Sigstore::BundleType::BUNDLE_0_2, + Sigstore::BundleType.from_media_type("application/vnd.dev.sigstore.bundle+json;version=0.2")) + assert_equal(Sigstore::BundleType::BUNDLE_0_3, + Sigstore::BundleType.from_media_type("application/vnd.dev.sigstore.bundle+json;version=0.3")) + + assert_raise(Sigstore::Error::InvalidBundle) do + Sigstore::BundleType.from_media_type("application/vnd.dev.sigstore.bundle+json;version=0.0") + end + end + + def test_verification_input_no_bundle + verification_input = Sigstore::Verification::V1::Input.new + e = assert_raise(ArgumentError) { Sigstore::VerificationInput.new(verification_input) } + assert_equal("bundle must be a Sigstore::Bundle::V1::Bundle, is NilClass", e.message) + end + + def test_verification_input_bundle_missing_media_type + verification_input = Sigstore::Verification::V1::Input.new + verification_input.bundle = Sigstore::Bundle::V1::Bundle.new + e = assert_raise(Sigstore::Error::InvalidBundle) { Sigstore::VerificationInput.new(verification_input) } + assert_equal("Unsupported bundle format: \"\"", e.message) + end + + def test_verification_input_bundle_missing_verification_material + verification_input = Sigstore::Verification::V1::Input.new + verification_input.bundle = Sigstore::Bundle::V1::Bundle.new + verification_input.bundle.media_type = Sigstore::BundleType::BUNDLE_0_3.media_type + e = assert_raise(Sigstore::Error::InvalidBundle) { Sigstore::VerificationInput.new(verification_input) } + assert_equal("bundle requires verification material", e.message) + end +end diff --git a/vendor/cache/sigstore-ruby-ce93acf7fa7e/test/sigstore/oidc_test.rb b/vendor/cache/sigstore-ruby-ce93acf7fa7e/test/sigstore/oidc_test.rb new file mode 100644 index 00000000..f510abed --- /dev/null +++ b/vendor/cache/sigstore-ruby-ce93acf7fa7e/test/sigstore/oidc_test.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +require "test_helper" + +class Sigstore::OIDCTest < Test::Unit::TestCase + def test_something; end +end diff --git a/vendor/cache/sigstore-ruby-ce93acf7fa7e/test/sigstore/policy_test.rb b/vendor/cache/sigstore-ruby-ce93acf7fa7e/test/sigstore/policy_test.rb new file mode 100644 index 00000000..9c766dec --- /dev/null +++ b/vendor/cache/sigstore-ruby-ce93acf7fa7e/test/sigstore/policy_test.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +require "test_helper" + +class Sigstore::PolicyTest < Test::Unit::TestCase + def test_something; end +end diff --git a/vendor/cache/sigstore-ruby-ce93acf7fa7e/test/sigstore/rekor/checkpoint_test.rb b/vendor/cache/sigstore-ruby-ce93acf7fa7e/test/sigstore/rekor/checkpoint_test.rb new file mode 100644 index 00000000..aa0314cc --- /dev/null +++ b/vendor/cache/sigstore-ruby-ce93acf7fa7e/test/sigstore/rekor/checkpoint_test.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +require "test_helper" + +class Sigstore::Rekor::CheckpointTest < Test::Unit::TestCase + def test_something; end +end diff --git a/vendor/cache/sigstore-ruby-ce93acf7fa7e/test/sigstore/rekor/client_test.rb b/vendor/cache/sigstore-ruby-ce93acf7fa7e/test/sigstore/rekor/client_test.rb new file mode 100644 index 00000000..e063e6c8 --- /dev/null +++ b/vendor/cache/sigstore-ruby-ce93acf7fa7e/test/sigstore/rekor/client_test.rb @@ -0,0 +1,6 @@ +# frozen_string_literal: true + +require "test_helper" + +class Sigstore::Rekor::ClientTest < Test::Unit::TestCase +end diff --git a/vendor/cache/sigstore-ruby-ce93acf7fa7e/test/sigstore/transparency_test.rb b/vendor/cache/sigstore-ruby-ce93acf7fa7e/test/sigstore/transparency_test.rb new file mode 100644 index 00000000..4b51e4e0 --- /dev/null +++ b/vendor/cache/sigstore-ruby-ce93acf7fa7e/test/sigstore/transparency_test.rb @@ -0,0 +1,109 @@ +# frozen_string_literal: true + +require "test_helper" + +require "sigstore/internal/merkle" + +class Sigstore::InclusionProofTest < Test::Unit::TestCase + def test_hasher + [ + # ["RFC6962 Empty", "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", ], + ["RFC6962 Empty Leaf", "6e340b9cffb37a989ca544e6bb780a2c78901d3fb33738768511a30617afa01d", + Sigstore::Internal::Merkle.hash_leaf("")], + ["RFC6962 Single Leaf", "395aa064aa4c29f7010acfe3f25db9485bbd4b91897b6ad7ad547639252b4d56", + Sigstore::Internal::Merkle.hash_leaf("L123456")], + ["RFC6962 Node", "aa217fe888e47007fa15edab33c2b492a722cb106c64667fc2b044444de66bbb", + Sigstore::Internal::Merkle.hash_children("N123", "N456")] + ].each do |desc, got, want| + got_hex = [got].pack("H*") + assert_equal got_hex, want, desc + end + end + + def test_hasher_collisions + leaf1 = "Hello" + leaf2 = "World" + + hash1 = Sigstore::Internal::Merkle.hash_leaf(leaf1) + hash2 = Sigstore::Internal::Merkle.hash_leaf(leaf2) + + refute_equal hash1, hash2, "Leaf hashes should differ" + + sub_hash1 = Sigstore::Internal::Merkle.hash_children(hash1, hash2) + preimage = "#{hash1}#{hash2}" + forged_hash = Sigstore::Internal::Merkle.hash_leaf(preimage) + + refute_equal sub_hash1, forged_hash, "Hasher is not second-preimage resistant" + + sub_hash2 = Sigstore::Internal::Merkle.hash_children(hash2, hash1) + + refute_equal sub_hash1, sub_hash2, "Hasher is not order-sensitive" + end + + def test_verify_inclusion_single_entry + data = "data" + # Root and leaf hash for 1-entry tree are the same. + hash = Sigstore::Internal::Merkle.hash_leaf(data) + # The corresponding inclusion proof is empty. + proof = [] + empty_hash = "" + + [ + [hash, hash, false], + [hash, empty_hash, true], + [empty_hash, hash, true], + [empty_hash, empty_hash, true] # wrong hash size + ].each do |root, leaf, want_err| + blk = proc do + Sigstore::Internal::Merkle.verify_inclusion( + 0, 1, proof, root, leaf + ) + end + if want_err + assert_raise(Sigstore::Internal::Merkle::InvalidInclusionProofError, &blk) + else + blk.call + end + end + end + + # dumped from https://github.com/transparency-dev/merkle/blob/main/proof/verify_test.go + File.open(File.expand_path("data/transparency/merkle/verify_inclusion.jsonl", __dir__)) do |f| + f.each_line.map do |l| + c = JSON.parse(l) + + test c["desc"] do + blk = proc { + proof = (c["proof"] || []).map { |h| Sigstore::Internal::Util.base64_decode h } + root = Sigstore::Internal::Util.base64_decode c["root"] + leaf_hash = Sigstore::Internal::Util.base64_decode c["leaf_hash"] + verifier_check( + c["desc"], c["index"], c["size"], proof, root, leaf_hash + ) + } + + if c["expected_error"] + assert_raise(Sigstore::Internal::Merkle::InvalidInclusionProofError, + Sigstore::Internal::Merkle::InclusionProofSizeError, + c.inspect, &blk) + else + assert_nothing_raised(c.inspect, &blk) + end + end + end + end + + def verifier_check(desc, log_index, tree_size, proof, root, leaf_hash) + got = Sigstore::Internal::Merkle.root_from_inclusion_proof( + log_index, tree_size, proof, leaf_hash + ) + + Sigstore::Internal::Merkle.verify_inclusion( + log_index, tree_size, proof, root, leaf_hash + ) + + assert_equal Sigstore::Internal::Util.base64_encode(root), Sigstore::Internal::Util.base64_encode(got), + "#{desc}: got root #{got.inspect}, want #{root.inspect}" + assert_equal root, got, "#{desc}: got root #{got.inspect}, want #{root.inspect}" + end +end diff --git a/vendor/cache/sigstore-ruby-ce93acf7fa7e/test/sigstore/trusted_root_test.rb b/vendor/cache/sigstore-ruby-ce93acf7fa7e/test/sigstore/trusted_root_test.rb new file mode 100644 index 00000000..8060ef63 --- /dev/null +++ b/vendor/cache/sigstore-ruby-ce93acf7fa7e/test/sigstore/trusted_root_test.rb @@ -0,0 +1,73 @@ +# frozen_string_literal: true + +require "test_helper" +require "sigstore/trusted_root" + +class Sigstore::TrustedRootTest < Test::Unit::TestCase + def test_production + VCR.use_cassette("production") do |cassette| + Timecop.freeze(cassette.originally_recorded_at || Time.now) do + production = Sigstore::TrustedRoot.production + assert_equal "application/vnd.dev.sigstore.trustedroot+json;version=0.1", production.media_type + assert_equal ["MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE2G2Y+2tabdTV5BcGiBIx0a9f\n" \ + "AFwrkBbmLSGtks4L3qX6yYY0zufBnhC8Ur/iy55GhWP/9A/bY2LhC30M9+RY\n" \ + "tw==\n"], production.rekor_keys.map { [_1.to_der].pack("m") } + assert_equal ["MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEbfwR+RJudXscgRBRpKX1XFDy\n" \ + "3PyudDxz/SfnRi1fT8ekpfBd2O1uoz7jr3Z8nKzxA69EUQ+eFCFI3zeubPWU\n" \ + "7w==\n", + "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEiPSlFi0CmFTfEjCUqF9HuCEc\n" \ + "YXNKAaYalIJmBZ8yyezPjTqhxrKBpMnaocVtLJBI1eM3uXnQzQGAJdJ4gs9F\n" \ + "yw==\n"], production.ctfe_keys.map { [_1.to_der].pack("m") } + assert_equal "chain 0\n" \ + "-----BEGIN CERTIFICATE-----\n" \ + "MIIB+DCCAX6gAwIBAgITNVkDZoCiofPDsy7dfm6geLbuhzAKBggqhkjOPQQDAzAq\n" \ + "MRUwEwYDVQQKEwxzaWdzdG9yZS5kZXYxETAPBgNVBAMTCHNpZ3N0b3JlMB4XDTIx\n" \ + "MDMwNzAzMjAyOVoXDTMxMDIyMzAzMjAyOVowKjEVMBMGA1UEChMMc2lnc3RvcmUu\n" \ + "ZGV2MREwDwYDVQQDEwhzaWdzdG9yZTB2MBAGByqGSM49AgEGBSuBBAAiA2IABLSy\n" \ + "A7Ii5k+pNO8ZEWY0ylemWDowOkNa3kL+GZE5Z5GWehL9/A9bRNA3RbrsZ5i0Jcas\n" \ + "taRL7Sp5fp/jD5dxqc/UdTVnlvS16an+2Yfswe/QuLolRUCrcOE2+2iA5+tzd6Nm\n" \ + "MGQwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE\n" \ + "FMjFHQBBmiQpMlEk6w2uSu1KBtPsMB8GA1UdIwQYMBaAFMjFHQBBmiQpMlEk6w2u\n" \ + "Su1KBtPsMAoGCCqGSM49BAMDA2gAMGUCMH8liWJfMui6vXXBhjDgY4MwslmN/TJx\n" \ + "Ve/83WrFomwmNf056y1X48F9c4m3a3ozXAIxAKjRay5/aj/jsKKGIkmQatjI8uup\n" \ + "Hr/+CxFvaJWmpYqNkLDGRU+9orzh5hI2RrcuaQ==\n" \ + "-----END CERTIFICATE-----\n" \ + "chain 1\n" \ + "-----BEGIN CERTIFICATE-----\n" \ + "MIICGjCCAaGgAwIBAgIUALnViVfnU0brJasmRkHrn/UnfaQwCgYIKoZIzj0EAwMw\n" \ + "KjEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MREwDwYDVQQDEwhzaWdzdG9yZTAeFw0y\n" \ + "MjA0MTMyMDA2MTVaFw0zMTEwMDUxMzU2NThaMDcxFTATBgNVBAoTDHNpZ3N0b3Jl\n" \ + "LmRldjEeMBwGA1UEAxMVc2lnc3RvcmUtaW50ZXJtZWRpYXRlMHYwEAYHKoZIzj0C\n" \ + "AQYFK4EEACIDYgAE8RVS/ysH+NOvuDZyPIZtilgUF9NlarYpAd9HP1vBBH1U5CV7\n" \ + "7LSS7s0ZiH4nE7Hv7ptS6LvvR/STk798LVgMzLlJ4HeIfF3tHSaexLcYpSASr1kS\n" \ + "0N/RgBJz/9jWCiXno3sweTAOBgNVHQ8BAf8EBAMCAQYwEwYDVR0lBAwwCgYIKwYB\n" \ + "BQUHAwMwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQU39Ppz1YkEZb5qNjp\n" \ + "KFWixi4YZD8wHwYDVR0jBBgwFoAUWMAeX5FFpWapesyQoZMi0CrFxfowCgYIKoZI\n" \ + "zj0EAwMDZwAwZAIwPCsQK4DYiZYDPIaDi5HFKnfxXx6ASSVmERfsynYBiX2X6SJR\n" \ + "nZU84/9DZdnFvvxmAjBOt6QpBlc4J/0DxvkTCqpclvziL6BCCPnjdlIB3Pu3BxsP\n" \ + "mygUY7Ii2zbdCdliiow=\n" \ + "-----END CERTIFICATE-----\n" \ + "-----BEGIN CERTIFICATE-----\n" \ + "MIIB9zCCAXygAwIBAgIUALZNAPFdxHPwjeDloDwyYChAO/4wCgYIKoZIzj0EAwMw\n" \ + "KjEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MREwDwYDVQQDEwhzaWdzdG9yZTAeFw0y\n" \ + "MTEwMDcxMzU2NTlaFw0zMTEwMDUxMzU2NThaMCoxFTATBgNVBAoTDHNpZ3N0b3Jl\n" \ + "LmRldjERMA8GA1UEAxMIc2lnc3RvcmUwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAT7\n" \ + "XeFT4rb3PQGwS4IajtLk3/OlnpgangaBclYpsYBr5i+4ynB07ceb3LP0OIOZdxex\n" \ + "X69c5iVuyJRQ+Hz05yi+UF3uBWAlHpiS5sh0+H2GHE7SXrk1EC5m1Tr19L9gg92j\n" \ + "YzBhMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRY\n" \ + "wB5fkUWlZql6zJChkyLQKsXF+jAfBgNVHSMEGDAWgBRYwB5fkUWlZql6zJChkyLQ\n" \ + "KsXF+jAKBggqhkjOPQQDAwNpADBmAjEAj1nHeXZp+13NWBNa+EDsDP8G1WWg1tCM\n" \ + "WP/WHPqpaVo0jhsweNFZgSs0eE7wYI4qAjEA2WB9ot98sIkoF3vZYdd3/VtWB5b9\n" \ + "TNMea7Ix/stJ5TfcLLeABLE4BNJOsQ4vnBHJ\n" \ + "-----END CERTIFICATE-----\n", production.fulcio_cert_chains.map.with_index { |chain, i| + "chain #{i}\n" + chain.map(&:to_pem).join + }.join + end + end + end + + def test_production_offline + production_offline = Sigstore::TrustedRoot.production(offline: true) + assert_equal "application/vnd.dev.sigstore.trustedroot+json;version=0.1", production_offline.media_type + end +end diff --git a/vendor/cache/sigstore-ruby-ce93acf7fa7e/test/sigstore/tuf/root_test.rb b/vendor/cache/sigstore-ruby-ce93acf7fa7e/test/sigstore/tuf/root_test.rb new file mode 100644 index 00000000..3a96fa70 --- /dev/null +++ b/vendor/cache/sigstore-ruby-ce93acf7fa7e/test/sigstore/tuf/root_test.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +require "test_helper" + +require "sigstore/tuf/root" + +class Sigstore::RootTest < Test::Unit::TestCase + def test_something; end +end diff --git a/vendor/cache/sigstore-ruby-ce93acf7fa7e/test/sigstore/tuf/snapshot_test.rb b/vendor/cache/sigstore-ruby-ce93acf7fa7e/test/sigstore/tuf/snapshot_test.rb new file mode 100644 index 00000000..bcbb5c7d --- /dev/null +++ b/vendor/cache/sigstore-ruby-ce93acf7fa7e/test/sigstore/tuf/snapshot_test.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +require "test_helper" +require "sigstore/tuf/snapshot" + +class Sigstore::TUF::SnapshotTest < Test::Unit::TestCase + def test_something; end +end diff --git a/vendor/cache/sigstore-ruby-ce93acf7fa7e/test/sigstore/tuf/targets_test.rb b/vendor/cache/sigstore-ruby-ce93acf7fa7e/test/sigstore/tuf/targets_test.rb new file mode 100644 index 00000000..cc789e2c --- /dev/null +++ b/vendor/cache/sigstore-ruby-ce93acf7fa7e/test/sigstore/tuf/targets_test.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +require "test_helper" +require "sigstore/tuf/targets" + +class Sigstore::TUF::TargetsTest < Test::Unit::TestCase + def test_something; end +end diff --git a/vendor/cache/sigstore-ruby-ce93acf7fa7e/test/sigstore/tuf/timestamp_test.rb b/vendor/cache/sigstore-ruby-ce93acf7fa7e/test/sigstore/tuf/timestamp_test.rb new file mode 100644 index 00000000..f2f5bfce --- /dev/null +++ b/vendor/cache/sigstore-ruby-ce93acf7fa7e/test/sigstore/tuf/timestamp_test.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +require "test_helper" +require "sigstore/tuf/timestamp" + +class Sigstore::TUF::TimestampTest < Test::Unit::TestCase + def test_something; end +end diff --git a/vendor/cache/sigstore-ruby-ce93acf7fa7e/test/sigstore/tuf/trusted_metadata_set_test.rb b/vendor/cache/sigstore-ruby-ce93acf7fa7e/test/sigstore/tuf/trusted_metadata_set_test.rb new file mode 100644 index 00000000..6dbdb367 --- /dev/null +++ b/vendor/cache/sigstore-ruby-ce93acf7fa7e/test/sigstore/tuf/trusted_metadata_set_test.rb @@ -0,0 +1,106 @@ +# frozen_string_literal: true + +require "test_helper" +require "sigstore/tuf/trusted_metadata_set" + +class Sigstore::TUF::TrustedMetadataSetTest < Test::Unit::TestCase + setup do + @reference_time = Time.utc(12, 42, 2, 7, 3, 2023, 4, 67, false, "UTC") + @priv_key = OpenSSL::PKey::RSA.new(2048) + @root = { + "signed" => { + "_type" => "root", + "spec_version" => "1.0.0", + "consistent_snapshot" => false, + "version" => 1, + "expires" => "2023-07-03T12:42:02Z", + "keys" => {}, + "roles" => { + "root" => { + "keyids" => [], + "threshold" => 0 + }, + "timestamp" => { + "keyids" => [], + "threshold" => 0 + }, + "snapshot" => { + "keyids" => [], + "threshold" => 0 + } + } + }, + "signatures" => [] + } + @timestamp = { + "signed" => { + "_type" => "timestamp", + "version" => 1, + "spec_version" => "1.0.0", + "expires" => "2023-07-03T12:42:02Z", + "meta" => { + "snapshot.json" => { + "version" => 137, + "length" => 104, + "hashes" => { + "sha256" => "5c4853e87c01a1621f410ad55f80bedb6c5b7e55c1f6e59d739769c0b54cf558" + } + } + } + }, + "signatures" => [] + } + @snapshot = { + "signed" => { + "_type" => "snapshot", + "version" => 137, + "expires" => "2023-07-03T12:42:02Z", + "meta" => {} + }, + "signatures" => [] + } + # TODO: need to generate a test root, with keys we can use for signing + @root_data = JSON.dump(@root) + @set = Sigstore::TUF::TrustedMetadataSet.new(@root_data, "json", reference_time: @reference_time) + end + + def test_initialize_known_good + @root_data = File.read(File.expand_path("../../../data/_store/prod/root.json", __dir__)) + Sigstore::TUF::TrustedMetadataSet.new(@root_data, "json", reference_time: @reference_time) + end + + def test_initialize + assert @set.root + + # allows loading expired metadata from the (already truted) root + @reference_time += 60 * 60 * 24 * 365 * 20 + Sigstore::TUF::TrustedMetadataSet.new(@root_data, "json", reference_time: @reference_time) + end + + def test_raises_when_updating_root_after_timestamp + @set.timestamp = JSON.dump(@timestamp) + e = assert_raise(Sigstore::TUF::Error::BadUpdateOrder) do + @set.root = @root_data + end + + assert_equal "cannot update root after timestamp", e.message + end + + def test_raises_when_updating_snapshot_before_timestamp + e = assert_raise(Sigstore::TUF::Error::BadUpdateOrder) do + @set.snapshot = JSON.dump(@snapshot) + end + + assert_equal "cannot update snapshot before timestamp", e.message + end + + def test_raises_when_updating_timestamp_after_snapshot + @set.timestamp = JSON.dump(@timestamp) + @set.snapshot = JSON.dump(@snapshot) + e = assert_raise(Sigstore::TUF::Error::BadUpdateOrder) do + @set.timestamp = JSON.dump(@timestamp) + end + + assert_equal "cannot update timestamp after snapshot", e.message + end +end diff --git a/vendor/cache/sigstore-ruby-ce93acf7fa7e/test/sigstore/verifier_test.rb b/vendor/cache/sigstore-ruby-ce93acf7fa7e/test/sigstore/verifier_test.rb new file mode 100644 index 00000000..5a26a9b6 --- /dev/null +++ b/vendor/cache/sigstore-ruby-ce93acf7fa7e/test/sigstore/verifier_test.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true + +require "test_helper" +require "sigstore/verifier" + +class Sigstore::VerifierTest < Test::Unit::TestCase + def test_pack_digitally_signed_precertificate + verifier = Sigstore::Verifier.allocate + [3, 255, 1024, 16_777_215].each do |precert_bytes_len| + precert_bytes = "x".b * precert_bytes_len + sct = Sigstore::Internal::X509::Extension::PrecertificateSignedCertificateTimestamps::Timestamp.new( + log_id: nil, + extensions_bytes: nil, + hash_algorithm: nil, + signature_algorithm: nil, + signature: nil, + + version: 0, + timestamp: 1234, + entry_type: 1 + ) + issuer_key_id = "iamapublickeyshatwofivesixdigest" + cert = Sigstore::Internal::X509::Certificate.allocate + cert.singleton_class.send(:define_method, :tbs_certificate_der) { precert_bytes } + data = verifier.send(:pack_digitally_signed, sct, cert, issuer_key_id) + _, l1, l2, l3 = [precert_bytes.bytesize].pack("N").unpack("C4") + assert_equal [ + "\x00", # version + "\x00", # signature_type + "\x00\x00\x00\x00\x00\x00\x04\xD2", # timestamp + "\x00\x01", # entry_type + issuer_key_id, + l1.chr, l2.chr, l3.chr, # tbs cert len + precert_bytes, + "\x00\x00", # extensions length + "" # extensions + ].map!(&:b).join, data, "precert_bytes_len=#{precert_bytes_len}" + end + end +end diff --git a/vendor/cache/sigstore-ruby-ce93acf7fa7e/test/sigstore/version_test.rb b/vendor/cache/sigstore-ruby-ce93acf7fa7e/test/sigstore/version_test.rb new file mode 100644 index 00000000..232181e7 --- /dev/null +++ b/vendor/cache/sigstore-ruby-ce93acf7fa7e/test/sigstore/version_test.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +require "test_helper" +require "sigstore/version" + +class Sigstore::VersionTest < Test::Unit::TestCase + def test_version + assert_instance_of String, Sigstore::VERSION + end +end diff --git a/vendor/cache/sigstore-ruby-ce93acf7fa7e/test/test_helper.rb b/vendor/cache/sigstore-ruby-ce93acf7fa7e/test/test_helper.rb new file mode 100644 index 00000000..e53576a3 --- /dev/null +++ b/vendor/cache/sigstore-ruby-ce93acf7fa7e/test/test_helper.rb @@ -0,0 +1,51 @@ +# frozen_string_literal: true + +require "simplecov" +SimpleCov.configure do + add_filter "test/" +end +SimpleCov.start if ENV["COVERAGE"] + +$LOAD_PATH.unshift File.expand_path("../lib", __dir__) +require "sigstore" + +require "test-unit" +require "webmock/test_unit" +require "vcr" +require "json" +require "timecop" +require "tmpdir" + +WebMock.disable_net_connect! + +VCR.configure do |config| + config.cassette_library_dir = "fixtures/vcr_cassettes" + config.hook_into :webmock + config.default_cassette_options = { record: :new_episodes } +end + +class Test::Unit::TestCase + setup + def env_home_setup + @xdg_data_home = ENV.fetch("XDG_DATA_HOME", nil) + @xdg_cache_home = ENV.fetch("XDG_CACHE_HOME", nil) + @home = ENV.fetch("HOME", nil) # rubocop:disable Style/EnvHome + @tmp_home = Dir.mktmpdir + + ENV.update( + "XDG_DATA_HOME" => nil, + "XDG_CACHE_HOME" => nil, + "HOME" => @tmp_home + ) + end + + cleanup + def env_home_cleanup + FileUtils.remove_entry_secure(@tmp_home) + ENV.update( + "XDG_DATA_HOME" => @xdg_data_home, + "XDG_CACHE_HOME" => @xdg_cache_home, + "HOME" => @home + ) + end +end