diff --git a/.github/actions/upload-coverage/action.yml b/.github/actions/upload-coverage/action.yml index 738509401..e1291241b 100644 --- a/.github/actions/upload-coverage/action.yml +++ b/.github/actions/upload-coverage/action.yml @@ -20,7 +20,7 @@ runs: fi id: coverage-uuid shell: bash - - uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4.5.0 + - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: coverage-data-${{ steps.coverage-uuid.outputs.COVERAGE_UUID }} include-hidden-files: 'true' diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 290115783..0f9f75116 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -27,14 +27,3 @@ updates: actions: patterns: - "*" - - - package-ecosystem: gomod - directory: "/.github" - schedule: - interval: daily - open-pull-requests-limit: 1 - rebase-strategy: "disabled" - groups: - actions: - patterns: - - "*" \ No newline at end of file diff --git a/.github/go.mod b/.github/go.mod deleted file mode 100644 index 56f2af9d3..000000000 --- a/.github/go.mod +++ /dev/null @@ -1,11 +0,0 @@ -module sigstore/sigstore-python - -go 1.23 - -require ( - // We don't have a Go module here but this file is picked up by dependabot - // and this will automatically update the dependency when needed. - - github.com/sigstore/timestamp-authority v1.2.3 - -) diff --git a/.github/workflows/check-embedded-root.yml b/.github/workflows/check-embedded-root.yml new file mode 100644 index 000000000..1c47d195a --- /dev/null +++ b/.github/workflows/check-embedded-root.yml @@ -0,0 +1,63 @@ +name: Check embedded root + +on: + workflow_dispatch: + schedule: + - cron: '13 13 * * 3' + +jobs: + check-embedded-root: + runs-on: ubuntu-latest + permissions: + issues: write + + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + persist-credentials: false + + - uses: actions/setup-python@8d9ed9ac5c53483de85588cdf95a591a75ab9f55 # v5.5.0 + with: + python-version: "3.x" + cache: "pip" + cache-dependency-path: pyproject.toml + + - name: Setup environment + run: make dev + + - name: Check if embedded root is up-to-date + run: | + make update-embedded-root + git diff --exit-code + + + - if: failure() + name: Create an issue if embedded root is not up-to-date + uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 + with: + script: | + const repo = context.repo.owner + "/" + context.repo.repo + const body = ` + The Sigstore [TUF repository](https://tuf-repo-cdn.sigstore.dev/) contents have changed: the data embedded + in sigstore-python sources can be updated. This is not urgent but will improve cold-cache performance. + + Run \`make update-embedded-root\` to update the embedded data. + + This issue was filed by _${context.workflow}_ [workflow run](${context.serverUrl}/${repo}/actions/runs/${context.runId}). + ` + + const issues = await github.rest.search.issuesAndPullRequests({ + q: "label:embedded-root-update+state:open+type:issue+repo:" + repo, + }) + if (issues.data.total_count > 0) { + console.log("Issue for embedded root update exists already.") + } else { + github.rest.issues.create({ + owner: context.repo.owner, + repo: context.repo.repo, + title: "Embedded TUF root is not up-to-date", + labels: ["embedded-root-update"], + body: body, + }) + console.log("New issue created.") + } diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index de62ba216..b9d848abc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -33,7 +33,7 @@ jobs: with: persist-credentials: false - - uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0 + - uses: actions/setup-python@8d9ed9ac5c53483de85588cdf95a591a75ab9f55 # v5.5.0 with: python-version: ${{ matrix.conf.py }} allow-prereleases: true @@ -46,31 +46,43 @@ jobs: - name: test (offline) if: matrix.conf.os == 'ubuntu-latest' run: | + # Look at me. I am the captain now. + sudo sysctl -w kernel.unprivileged_userns_clone=1 + sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0 + # We use `unshare` to "un-share" the default networking namespace, # in effect running the tests as if the host is offline. # This in turn effectively exercises the correctness of our # "online-only" test markers, since any test that's online # but not marked as such will fail. - # We also explicitly exclude the intergration tests, since these are + # We also explicitly exclude the integration tests, since these are # always online. unshare --map-root-user --net make test T="test/unit" TEST_ARGS="--skip-online -vv --showlocals" - name: test run: make test TEST_ARGS="-vv --showlocals" + # TODO: Refactor this or remove it entirely once there's + # a suitable staging TSA instance. - name: test (timestamp-authority) if: ${{ matrix.conf.os == 'ubuntu-latest' }} run: | - SIGSTORE_TIMESTAMP_VERSION=$(grep "github.com/sigstore/timestamp-authority" .github/go.mod | awk '{print $2}') + # Fetch the latest sigstore/timestamp-authority build + SIGSTORE_TIMESTAMP_VERSION=$(gh api /repos/sigstore/timestamp-authority/tags --jq '.[0].name') wget https://github.com/sigstore/timestamp-authority/releases/download/${SIGSTORE_TIMESTAMP_VERSION}/timestamp-server-linux-amd64 -O /tmp/timestamp-server chmod +x /tmp/timestamp-server + # Run the TSA in background /tmp/timestamp-server serve --port 3000 --disable-ntp-monitoring & export TEST_SIGSTORE_TIMESTAMP_AUTHORITY_URL="http://localhost:3000/api/v1/timestamp" + # Ensure Timestamp Authority tests are not skipped by # having pytest show skipped tests and verifying ours are running make test TEST_ARGS="-m timestamp_authority -rs" | tee output ! grep -q "skipping test that requires a Timestamp Authority" output || (echo "ERROR: Found skip message" && exit 1) + env: + # Needed for `gh api` above. + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: test (interactive) if: (github.event_name != 'pull_request') || !github.event.pull_request.head.repo.fork @@ -106,14 +118,14 @@ jobs: with: persist-credentials: false - - uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0 + - uses: actions/setup-python@8d9ed9ac5c53483de85588cdf95a591a75ab9f55 # v5.5.0 with: python-version: '3.x' - run: pip install coverage[toml] - name: download coverage data - uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 + uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e # v4.2.1 with: path: all-artifacts/ diff --git a/.github/workflows/conformance.yml b/.github/workflows/conformance.yml index 14addb38c..54022278a 100644 --- a/.github/workflows/conformance.yml +++ b/.github/workflows/conformance.yml @@ -15,7 +15,7 @@ jobs: with: persist-credentials: false - - uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0 + - uses: actions/setup-python@8d9ed9ac5c53483de85588cdf95a591a75ab9f55 # v5.5.0 with: python-version: "3.x" cache: "pip" @@ -24,7 +24,7 @@ jobs: - name: install sigstore-python run: python -m pip install . - - uses: sigstore/sigstore-conformance@b0635d4101f11dbd18a50936568a1f7f55b17760 # v0.0.14 + - uses: sigstore/sigstore-conformance@640e7dfb715518eeeb492910c6d244cedcc6cfea # v0.0.17 with: entrypoint: ${{ github.workspace }}/test/integration/sigstore-python-conformance xfail: "test_verify_with_trust_root test_verify_dsse_bundle_with_trust_root" # see issue 821 diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 3308498a0..76f0bb89c 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -13,7 +13,7 @@ jobs: with: persist-credentials: false - - uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0 + - uses: actions/setup-python@8d9ed9ac5c53483de85588cdf95a591a75ab9f55 # v5.5.0 with: python-version: "3.x" cache: "pip" diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 954564360..40497c5dc 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -14,7 +14,7 @@ jobs: with: persist-credentials: false - - uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0 + - uses: actions/setup-python@8d9ed9ac5c53483de85588cdf95a591a75ab9f55 # v5.5.0 with: python-version: "3.x" cache: "pip" @@ -35,7 +35,7 @@ jobs: # NOTE: We intentionally check `--help` rendering against our minimum Python, # since it changes slightly between Python versions. - - uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0 + - uses: actions/setup-python@8d9ed9ac5c53483de85588cdf95a591a75ab9f55 # v5.5.0 with: python-version: "3.9" cache: "pip" @@ -71,7 +71,7 @@ jobs: persist-credentials: false # NOTE: We intentionally check test certificates against our minimum supported Python. - - uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0 + - uses: actions/setup-python@8d9ed9ac5c53483de85588cdf95a591a75ab9f55 # v5.5.0 with: python-version: "3.9" cache: "pip" diff --git a/.github/workflows/pin-requirements.yml b/.github/workflows/pin-requirements.yml index 960b06531..528e517c0 100644 --- a/.github/workflows/pin-requirements.yml +++ b/.github/workflows/pin-requirements.yml @@ -70,7 +70,7 @@ jobs: git config user.email "41898282+github-actions[bot]@users.noreply.github.com" git config user.name "github-actions[bot]" - - uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0 + - uses: actions/setup-python@8d9ed9ac5c53483de85588cdf95a591a75ab9f55 # v5.5.0 with: python-version-file: install/.python-version cache: "pip" @@ -129,7 +129,7 @@ jobs: git push -f origin "origin/main:${SIGSTORE_PIN_REQUIREMENTS_BRANCH}" - name: Open pull request - uses: peter-evans/create-pull-request@5e914681df9dc83aa4e4905692ca88beb2f9e91f # v7.0.5 + uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # v7.0.8 with: title: | Update pinned requirements for ${{ env.SIGSTORE_RELEASE_TAG }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 2e7ccc20b..b07fddcc8 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -19,7 +19,7 @@ jobs: with: persist-credentials: false - - uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0 + - uses: actions/setup-python@8d9ed9ac5c53483de85588cdf95a591a75ab9f55 # v5.5.0 with: # NOTE: We intentionally don't use a cache in the release step, # to reduce the risk of cache poisoning. @@ -74,14 +74,14 @@ jobs: done - name: Upload built packages - uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4.5.0 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: built-packages path: ./dist/ if-no-files-found: warn - name: Upload smoketest-artifacts - uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4.5.0 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: smoketest-artifacts path: smoketest-artifacts/ @@ -95,7 +95,7 @@ jobs: attestations: write # To persist the attestation files. steps: - name: Download artifacts directories # goes to current working directory - uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 + uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e # v4.2.1 - name: Generate build provenance uses: actions/attest-build-provenance@v2 with: @@ -109,10 +109,10 @@ jobs: id-token: write steps: - name: Download artifacts directories # goes to current working directory - uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 + uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e # v4.2.1 - name: publish - uses: pypa/gh-action-pypi-publish@67339c736fd9354cd4f8cb0b744f2b82a74b5c70 # v1.12.3 + uses: pypa/gh-action-pypi-publish@76f52bc884231f62b9a034ebfe128415bbaabdfc # v1.12.4 with: packages-dir: built-packages/ @@ -124,13 +124,13 @@ jobs: contents: write steps: - name: Download artifacts directories # goes to current working directory - uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 + uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e # v4.2.1 - 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@7b4da11513bf3f43f9999e90eabced41ab8bb048 # v2.2.0 + uses: softprops/action-gh-release@c95fe1489396fe8a9eb87c0abf8aa5b2ef267fda # v2.2.1 with: # smoketest-artifacts/ contains the signatures and certificates. files: | diff --git a/.github/workflows/requirements.yml b/.github/workflows/requirements.yml index 6cf1140ac..4c66d3f30 100644 --- a/.github/workflows/requirements.yml +++ b/.github/workflows/requirements.yml @@ -36,7 +36,7 @@ jobs: ref: ${{ env.SIGSTORE_REF }} persist-credentials: false - - uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0 + - uses: actions/setup-python@8d9ed9ac5c53483de85588cdf95a591a75ab9f55 # v5.5.0 name: Install Python ${{ matrix.python_version }} with: python-version: ${{ matrix.python_version }} diff --git a/.github/workflows/scorecards-analysis.yml b/.github/workflows/scorecards-analysis.yml index b3b5037eb..6c2ea6985 100644 --- a/.github/workflows/scorecards-analysis.yml +++ b/.github/workflows/scorecards-analysis.yml @@ -29,7 +29,7 @@ jobs: persist-credentials: false - name: "Run analysis" - uses: ossf/scorecard-action@62b2cac7ed8198b15735ed49ab1e5cf35480ba46 # v2.4.0 + uses: ossf/scorecard-action@f49aabe0b5af0936a0987cfb85d86b75731b0186 # v2.4.1 with: results_file: results.sarif results_format: sarif @@ -44,7 +44,7 @@ jobs: # Upload the results as artifacts (optional). - name: "Upload artifact" - uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4.5.0 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: SARIF file path: results.sarif @@ -52,6 +52,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@df409f7d9260372bd5f19e5b04e83cb3c43714ae # v3.27.9 + uses: github/codeql-action/upload-sarif@45775bd8235c68ba998cffa5171334d58593da47 # v3.28.15 with: sarif_file: results.sarif diff --git a/.github/workflows/staging-tests.yml b/.github/workflows/staging-tests.yml index 13661a9a8..83ef0cce1 100644 --- a/.github/workflows/staging-tests.yml +++ b/.github/workflows/staging-tests.yml @@ -21,7 +21,7 @@ jobs: with: persist-credentials: false - - uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0 + - uses: actions/setup-python@8d9ed9ac5c53483de85588cdf95a591a75ab9f55 # v5.5.0 with: python-version: "3.x" cache: "pip" diff --git a/CHANGELOG.md b/CHANGELOG.md index 7104a6747..ab9362a33 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,21 @@ All versions prior to 0.9.0 are untracked. ## [Unreleased] +## [3.6.2] + +### Fixed + +* Fixed issue where a trust root with multiple rekor keys was not considered valid: + Now any rekor key listed in the trust root is considered good to verify entries + [#1350](https://github.com/sigstore/sigstore-python/pull/1350) + +### Changed + +* Upgraded python-tuf dependency to 6.0: Connections to TUF repository + now use system certificates (instead of certifi) and have automatic + retries +* Updated the embedded TUF root to version 12 + ## [3.6.1] ### Fixed @@ -593,8 +608,9 @@ This is a corrective release for [2.1.1]. -[Unreleased]: https://github.com/sigstore/sigstore-python/compare/v3.6.1...HEAD -[3.6.0]: https://github.com/sigstore/sigstore-python/compare/v3.6.0...v3.6.1 +[Unreleased]: https://github.com/sigstore/sigstore-python/compare/v3.6.2...HEAD +[3.6.2]: https://github.com/sigstore/sigstore-python/compare/v3.6.1...v3.6.2 +[3.6.1]: https://github.com/sigstore/sigstore-python/compare/v3.6.0...v3.6.1 [3.6.0]: https://github.com/sigstore/sigstore-python/compare/v3.5.3...v3.6.0 [3.5.3]: https://github.com/sigstore/sigstore-python/compare/v3.5.2...v3.5.3 [3.5.2]: https://github.com/sigstore/sigstore-python/compare/v3.5.1...v3.5.2 diff --git a/Makefile b/Makefile index f2fd8258a..23ddb2cec 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,7 @@ ALL_PY_SRCS := $(shell find $(PY_MODULE) -name '*.py') \ $(shell find test -name '*.py') \ $(shell find docs/scripts -name '*.py') \ -# Optionally overriden by the user, if they're using a virtual environment manager. +# Optionally overridden by the user, if they're using a virtual environment manager. VENV ?= env # On Windows, venv scripts/shims are under `Scripts` instead of `bin`. @@ -34,7 +34,7 @@ ifneq ($(TESTS),) COV_ARGS := else TEST_ARGS := $(TEST_ARGS) -# TODO: Reenable coverage testing +# TODO: Re-enable coverage testing # COV_ARGS := --fail-under 100 endif @@ -172,3 +172,11 @@ check-readme: .PHONY: edit edit: $(EDITOR) $(ALL_PY_SRCS) + +update-embedded-root: $(VENV)/pyvenv.cfg + . $(VENV_BIN)/activate && \ + python -m sigstore plumbing update-trust-root + cp ~/.local/share/sigstore-python/tuf/https%3A%2F%2Ftuf-repo-cdn.sigstore.dev/root.json \ + sigstore/_store/prod/root.json + cp ~/.cache/sigstore-python/tuf/https%3A%2F%2Ftuf-repo-cdn.sigstore.dev/trusted_root.json \ + sigstore/_store/prod/trusted_root.json diff --git a/docs/advanced/offline.md b/docs/advanced/offline.md index bc107dbc5..346be0f30 100644 --- a/docs/advanced/offline.md +++ b/docs/advanced/offline.md @@ -9,7 +9,7 @@ Users who need to operationalize offline verification may wish to do this by distributing their own trust configuration; see - [Customn root of trust](./custom_trust.md). + [Custom root of trust](./custom_trust.md). During verification, there are two kinds of network access that `sigstore-python` *can* perform: @@ -40,4 +40,4 @@ $ sigstore --trust-config public.trustconfig.json verify identity ... ``` This will similarly result in fully offline operation, as the trust -configuration contains a full trust root. \ No newline at end of file +configuration contains a full trust root. diff --git a/docs/policy.md b/docs/policy.md index 880504669..46cf78e8d 100644 --- a/docs/policy.md +++ b/docs/policy.md @@ -44,7 +44,7 @@ the integrity and transparency of the signing process. !!! warning - This step is performed before the `Timestamping` step in the worfklow. + This step is performed before the `Timestamping` step in the workflow. ### Signing Choices diff --git a/docs/scripts/gen_ref_pages.py b/docs/scripts/gen_ref_pages.py index 6a5572b82..585b0e4c6 100644 --- a/docs/scripts/gen_ref_pages.py +++ b/docs/scripts/gen_ref_pages.py @@ -38,10 +38,9 @@ def main(args: argparse.Namespace) -> None: if any(part.startswith("_") for part in module_path.parts): continue - if args.check: - if not full_doc_path.is_file(): - print(f"File {full_doc_path} does not exist.", file=sys.stderr) - sys.exit(1) + if args.check and not full_doc_path.is_file(): + print(f"File {full_doc_path} does not exist.", file=sys.stderr) + sys.exit(1) full_doc_path.parent.mkdir(parents=True, exist_ok=True) with full_doc_path.open("w") as f: diff --git a/docs/signing.md b/docs/signing.md index 4b7b57290..673ccc2db 100644 --- a/docs/signing.md +++ b/docs/signing.md @@ -41,7 +41,7 @@ namely the Fulcio's supported identity providers and the claims expected within !!! note - The examples in the section belows are using ambient credential detection. + The examples in the section below are using ambient credential detection. When no credentials are detected, it opens a browser to perform an interactive OAuth2 authentication flow. ## Signing an artifact @@ -130,4 +130,4 @@ Transparency log entry created at index: 155019253 Sigstore bundle written to README.md.sigstore.json ``` -[SLSA]: https://slsa.dev/ \ No newline at end of file +[SLSA]: https://slsa.dev/ diff --git a/install/requirements.in b/install/requirements.in index 760ed1b74..45a702d07 100644 --- a/install/requirements.in +++ b/install/requirements.in @@ -1 +1 @@ -sigstore==3.6.0 +sigstore==3.6.1 diff --git a/install/requirements.txt b/install/requirements.txt index 28a930618..2a2e65cd0 100644 --- a/install/requirements.txt +++ b/install/requirements.txt @@ -12,9 +12,9 @@ betterproto==2.0.0b6 \ --hash=sha256:720ae92697000f6fcf049c69267d957f0871654c8b0d7458906607685daee784 \ --hash=sha256:a0839ec165d110a69d0d116f4d0e2bec8d186af4db826257931f0831dab73fcf # via sigstore-protobuf-specs -certifi==2024.8.30 \ - --hash=sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8 \ - --hash=sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9 +certifi==2024.12.14 \ + --hash=sha256:1275f7a45be9464efc1173084eaa30f866fe2e47d389406136d332ed4967ec56 \ + --hash=sha256:b650d30f370c2b724812bee08008be0c4163b163ddaec3f2546c1caf65f191db # via requests cffi==1.17.1 \ --hash=sha256:045d61c734659cc045141be4bae381a41d89b741f795af1dd018bfb532fd0df8 \ @@ -192,34 +192,38 @@ charset-normalizer==3.4.0 \ --hash=sha256:fe9f97feb71aa9896b81973a7bbada8c49501dc73e58a10fcef6663af95e5079 \ --hash=sha256:ffc519621dce0c767e96b9c53f09c5d215578e10b02c285809f76509a3931482 # via requests -cryptography==43.0.3 \ - --hash=sha256:0c580952eef9bf68c4747774cde7ec1d85a6e61de97281f2dba83c7d2c806362 \ - --hash=sha256:0f996e7268af62598f2fc1204afa98a3b5712313a55c4c9d434aef49cadc91d4 \ - --hash=sha256:1ec0bcf7e17c0c5669d881b1cd38c4972fade441b27bda1051665faaa89bdcaa \ - --hash=sha256:281c945d0e28c92ca5e5930664c1cefd85efe80e5c0d2bc58dd63383fda29f83 \ - --hash=sha256:2ce6fae5bdad59577b44e4dfed356944fbf1d925269114c28be377692643b4ff \ - --hash=sha256:315b9001266a492a6ff443b61238f956b214dbec9910a081ba5b6646a055a805 \ - --hash=sha256:443c4a81bb10daed9a8f334365fe52542771f25aedaf889fd323a853ce7377d6 \ - --hash=sha256:4a02ded6cd4f0a5562a8887df8b3bd14e822a90f97ac5e544c162899bc467664 \ - --hash=sha256:53a583b6637ab4c4e3591a15bc9db855b8d9dee9a669b550f311480acab6eb08 \ - --hash=sha256:63efa177ff54aec6e1c0aefaa1a241232dcd37413835a9b674b6e3f0ae2bfd3e \ - --hash=sha256:74f57f24754fe349223792466a709f8e0c093205ff0dca557af51072ff47ab18 \ - --hash=sha256:7e1ce50266f4f70bf41a2c6dc4358afadae90e2a1e5342d3c08883df1675374f \ - --hash=sha256:81ef806b1fef6b06dcebad789f988d3b37ccaee225695cf3e07648eee0fc6b73 \ - --hash=sha256:846da004a5804145a5f441b8530b4bf35afbf7da70f82409f151695b127213d5 \ - --hash=sha256:8ac43ae87929a5982f5948ceda07001ee5e83227fd69cf55b109144938d96984 \ - --hash=sha256:9762ea51a8fc2a88b70cf2995e5675b38d93bf36bd67d91721c309df184f49bd \ - --hash=sha256:a2a431ee15799d6db9fe80c82b055bae5a752bef645bba795e8e52687c69efe3 \ - --hash=sha256:bf7a1932ac4176486eab36a19ed4c0492da5d97123f1406cf15e41b05e787d2e \ - --hash=sha256:c2e6fc39c4ab499049df3bdf567f768a723a5e8464816e8f009f121a5a9f4405 \ - --hash=sha256:cbeb489927bd7af4aa98d4b261af9a5bc025bd87f0e3547e11584be9e9427be2 \ - --hash=sha256:d03b5621a135bffecad2c73e9f4deb1a0f977b9a8ffe6f8e002bf6c9d07b918c \ - --hash=sha256:d56e96520b1020449bbace2b78b603442e7e378a9b3bd68de65c782db1507995 \ - --hash=sha256:df6b6c6d742395dd77a23ea3728ab62f98379eff8fb61be2744d4679ab678f73 \ - --hash=sha256:e1be4655c7ef6e1bbe6b5d0403526601323420bcf414598955968c9ef3eb7d16 \ - --hash=sha256:f18c716be16bc1fea8e95def49edf46b82fccaa88587a45f8dc0ff6ab5d8e0a7 \ - --hash=sha256:f46304d6f0c6ab8e52770addfa2fc41e6629495548862279641972b6215451cd \ - --hash=sha256:f7b178f11ed3664fd0e995a47ed2b5ff0a12d893e41dd0494f406d1cf555cab7 +cryptography==44.0.1 \ + --hash=sha256:00918d859aa4e57db8299607086f793fa7813ae2ff5a4637e318a25ef82730f7 \ + --hash=sha256:1e8d181e90a777b63f3f0caa836844a1182f1f265687fac2115fcf245f5fbec3 \ + --hash=sha256:1f9a92144fa0c877117e9748c74501bea842f93d21ee00b0cf922846d9d0b183 \ + --hash=sha256:21377472ca4ada2906bc313168c9dc7b1d7ca417b63c1c3011d0c74b7de9ae69 \ + --hash=sha256:24979e9f2040c953a94bf3c6782e67795a4c260734e5264dceea65c8f4bae64a \ + --hash=sha256:2a46a89ad3e6176223b632056f321bc7de36b9f9b93b2cc1cccf935a3849dc62 \ + --hash=sha256:322eb03ecc62784536bc173f1483e76747aafeb69c8728df48537eb431cd1911 \ + --hash=sha256:436df4f203482f41aad60ed1813811ac4ab102765ecae7a2bbb1dbb66dcff5a7 \ + --hash=sha256:4f422e8c6a28cf8b7f883eb790695d6d45b0c385a2583073f3cec434cc705e1a \ + --hash=sha256:53f23339864b617a3dfc2b0ac8d5c432625c80014c25caac9082314e9de56f41 \ + --hash=sha256:5fed5cd6102bb4eb843e3315d2bf25fede494509bddadb81e03a859c1bc17b83 \ + --hash=sha256:610a83540765a8d8ce0f351ce42e26e53e1f774a6efb71eb1b41eb01d01c3d12 \ + --hash=sha256:6c8acf6f3d1f47acb2248ec3ea261171a671f3d9428e34ad0357148d492c7864 \ + --hash=sha256:6f76fdd6fd048576a04c5210d53aa04ca34d2ed63336d4abd306d0cbe298fddf \ + --hash=sha256:72198e2b5925155497a5a3e8c216c7fb3e64c16ccee11f0e7da272fa93b35c4c \ + --hash=sha256:887143b9ff6bad2b7570da75a7fe8bbf5f65276365ac259a5d2d5147a73775f2 \ + --hash=sha256:888fcc3fce0c888785a4876ca55f9f43787f4c5c1cc1e2e0da71ad481ff82c5b \ + --hash=sha256:8e6a85a93d0642bd774460a86513c5d9d80b5c002ca9693e63f6e540f1815ed0 \ + --hash=sha256:94f99f2b943b354a5b6307d7e8d19f5c423a794462bde2bf310c770ba052b1c4 \ + --hash=sha256:9b336599e2cb77b1008cb2ac264b290803ec5e8e89d618a5e978ff5eb6f715d9 \ + --hash=sha256:a2d8a7045e1ab9b9f803f0d9531ead85f90c5f2859e653b61497228b18452008 \ + --hash=sha256:b8272f257cf1cbd3f2e120f14c68bff2b6bdfcc157fafdee84a1b795efd72862 \ + --hash=sha256:bf688f615c29bfe9dfc44312ca470989279f0e94bb9f631f85e3459af8efc009 \ + --hash=sha256:d9c5b9f698a83c8bd71e0f4d3f9f839ef244798e5ffe96febfa9714717db7af7 \ + --hash=sha256:dd7c7e2d71d908dc0f8d2027e1604102140d84b155e658c20e8ad1304317691f \ + --hash=sha256:df978682c1504fc93b3209de21aeabf2375cb1571d4e61907b3e7a2540e83026 \ + --hash=sha256:e403f7f766ded778ecdb790da786b418a9f2394f36e8cc8b796cc056ab05f44f \ + --hash=sha256:eb3889330f2a4a148abead555399ec9a32b13b7c8ba969b72d8e500eb7ef84cd \ + --hash=sha256:f4daefc971c2d1f82f03097dc6f216744a6cd2ac0f04c68fb935ea2ba2a0d420 \ + --hash=sha256:f51f5705ab27898afda1aaa430f34ad90dc117421057782022edf0600bec5f14 \ + --hash=sha256:fd0ee90072861e276b0ff08bd627abec29e32a53b2be44e41dbcdf87cbee2b00 # via # pyopenssl # rfc3161-client @@ -265,21 +269,6 @@ markdown-it-py==3.0.0 \ --hash=sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1 \ --hash=sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb # via rich -maturin==1.7.8 \ - --hash=sha256:1ce48d007438b895f8665314b6748ac0dab31e4f32049a60b52281dd2dccbdde \ - --hash=sha256:2b2bdee0c3a84696b3a809054c43ead1a04b7b3321cbd5b8f5676e4ba4691d0f \ - --hash=sha256:403eebf1afa6f19b49425f089e39c53b8e597bc86a47f3a76e828dc78d27fa80 \ - --hash=sha256:649c6ef3f0fa4c5f596140d761dc5a4d577c485cc32fb5b9b344a8280352880d \ - --hash=sha256:6cafb17bf57822bdc04423d9e3e766d42918d474848fe9833e397267514ba891 \ - --hash=sha256:a4f58c2a53c2958a1bf090960b08b28e676136cd88ac2f5dfdcf1b14ea54ec06 \ - --hash=sha256:b2d4e0f674ca29864e6b86c2eb9fee8236d1c7496c25f7300e34229272468f4c \ - --hash=sha256:b8188b71259fc2bc568d9c8acc186fcfed96f42539bcb55b8e6f4ec26e411f37 \ - --hash=sha256:c23664d19dadcbf800ef70f26afb2e0485a985c62889930934f019c565534c23 \ - --hash=sha256:c5d6c0c631d1fc646cd3834795e6cfd72ab4271d289df7e0f911261a02bec75f \ - --hash=sha256:c6950fd2790acd93265e1501cea66f9249cff19724654424ca75a3b17ebb315b \ - --hash=sha256:cc92a62953205e8945b6cfe6943d6a8576a4442d30d9c67141f944f4f4640e62 \ - --hash=sha256:f98288d5c382bacf0c076871dfd50c38f1eb2248f417551e98dd6f47f6ee8afa - # via rfc3161-client mdurl==0.1.2 \ --hash=sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8 \ --hash=sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba @@ -378,9 +367,9 @@ multidict==6.1.0 \ --hash=sha256:f90c822a402cb865e396a504f9fc8173ef34212a342d92e362ca498cad308e28 \ --hash=sha256:ff3827aef427c89a25cc96ded1759271a93603aba9fb977a6d264648ebf989db # via grpclib -platformdirs==4.3.6 \ - --hash=sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907 \ - --hash=sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb +platformdirs==4.3.7 \ + --hash=sha256:a03875334331946f13c549dbd8f4bac7a13a50a895a0eb1e8c6a8ace80d40a94 \ + --hash=sha256:eb437d586b6a0986388f0d6f74aa0cde27b48d0e3d66843640bfb6bdcdb6e351 # via sigstore pyasn1==0.6.1 \ --hash=sha256:0d632f46f2ba09143da3a8afe9e33fb6f92fa2320ab7e886e2d0f7672af84629 \ @@ -390,113 +379,113 @@ pycparser==2.22 \ --hash=sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6 \ --hash=sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc # via cffi -pydantic[email]==2.10.3 \ - --hash=sha256:be04d85bbc7b65651c5f8e6b9976ed9c6f41782a55524cef079a34a0bb82144d \ - --hash=sha256:cb5ac360ce894ceacd69c403187900a02c4b20b693a9dd1d643e1effab9eadf9 +pydantic[email]==2.10.4 \ + --hash=sha256:597e135ea68be3a37552fb524bc7d0d66dcf93d395acd93a00682f1efcb8ee3d \ + --hash=sha256:82f12e9723da6de4fe2ba888b5971157b3be7ad914267dea8f05f82b28254f06 # via # sigstore # sigstore-rekor-types -pydantic-core==2.27.1 \ - --hash=sha256:00e6424f4b26fe82d44577b4c842d7df97c20be6439e8e685d0d715feceb9fb9 \ - --hash=sha256:029d9757eb621cc6e1848fa0b0310310de7301057f623985698ed7ebb014391b \ - --hash=sha256:02a3d637bd387c41d46b002f0e49c52642281edacd2740e5a42f7017feea3f2c \ - --hash=sha256:0325336f348dbee6550d129b1627cb8f5351a9dc91aad141ffb96d4937bd9529 \ - --hash=sha256:062f60e512fc7fff8b8a9d680ff0ddaaef0193dba9fa83e679c0c5f5fbd018bc \ - --hash=sha256:0b3dfe500de26c52abe0477dde16192ac39c98f05bf2d80e76102d394bd13854 \ - --hash=sha256:0e4216e64d203e39c62df627aa882f02a2438d18a5f21d7f721621f7a5d3611d \ - --hash=sha256:121ceb0e822f79163dd4699e4c54f5ad38b157084d97b34de8b232bcaad70278 \ - --hash=sha256:159cac0a3d096f79ab6a44d77a961917219707e2a130739c64d4dd46281f5c2a \ - --hash=sha256:15aae984e46de8d376df515f00450d1522077254ef6b7ce189b38ecee7c9677c \ - --hash=sha256:15cc53a3179ba0fcefe1e3ae50beb2784dede4003ad2dfd24f81bba4b23a454f \ - --hash=sha256:161c27ccce13b6b0c8689418da3885d3220ed2eae2ea5e9b2f7f3d48f1d52c27 \ - --hash=sha256:19910754e4cc9c63bc1c7f6d73aa1cfee82f42007e407c0f413695c2f7ed777f \ - --hash=sha256:1ba5e3963344ff25fc8c40da90f44b0afca8cfd89d12964feb79ac1411a260ac \ - --hash=sha256:1c00666a3bd2f84920a4e94434f5974d7bbc57e461318d6bb34ce9cdbbc1f6b2 \ - --hash=sha256:1c39b07d90be6b48968ddc8c19e7585052088fd7ec8d568bb31ff64c70ae3c97 \ - --hash=sha256:206b5cf6f0c513baffaeae7bd817717140770c74528f3e4c3e1cec7871ddd61a \ - --hash=sha256:258c57abf1188926c774a4c94dd29237e77eda19462e5bb901d88adcab6af919 \ - --hash=sha256:2cdf7d86886bc6982354862204ae3b2f7f96f21a3eb0ba5ca0ac42c7b38598b9 \ - --hash=sha256:2d4567c850905d5eaaed2f7a404e61012a51caf288292e016360aa2b96ff38d4 \ - --hash=sha256:35c14ac45fcfdf7167ca76cc80b2001205a8d5d16d80524e13508371fb8cdd9c \ - --hash=sha256:38de0a70160dd97540335b7ad3a74571b24f1dc3ed33f815f0880682e6880131 \ - --hash=sha256:3af385b0cee8df3746c3f406f38bcbfdc9041b5c2d5ce3e5fc6637256e60bbc5 \ - --hash=sha256:3b748c44bb9f53031c8cbc99a8a061bc181c1000c60a30f55393b6e9c45cc5bd \ - --hash=sha256:3bbd5d8cc692616d5ef6fbbbd50dbec142c7e6ad9beb66b78a96e9c16729b089 \ - --hash=sha256:3ccaa88b24eebc0f849ce0a4d09e8a408ec5a94afff395eb69baf868f5183107 \ - --hash=sha256:3fa80ac2bd5856580e242dbc202db873c60a01b20309c8319b5c5986fbe53ce6 \ - --hash=sha256:4228b5b646caa73f119b1ae756216b59cc6e2267201c27d3912b592c5e323b60 \ - --hash=sha256:42b0e23f119b2b456d07ca91b307ae167cc3f6c846a7b169fca5326e32fdc6cf \ - --hash=sha256:45cf8588c066860b623cd11c4ba687f8d7175d5f7ef65f7129df8a394c502de5 \ - --hash=sha256:45d9c5eb9273aa50999ad6adc6be5e0ecea7e09dbd0d31bd0c65a55a2592ca08 \ - --hash=sha256:4603137322c18eaf2e06a4495f426aa8d8388940f3c457e7548145011bb68e05 \ - --hash=sha256:46ccfe3032b3915586e469d4972973f893c0a2bb65669194a5bdea9bacc088c2 \ - --hash=sha256:4fefee876e07a6e9aad7a8c8c9f85b0cdbe7df52b8a9552307b09050f7512c7e \ - --hash=sha256:5556470f1a2157031e676f776c2bc20acd34c1990ca5f7e56f1ebf938b9ab57c \ - --hash=sha256:57866a76e0b3823e0b56692d1a0bf722bffb324839bb5b7226a7dbd6c9a40b17 \ - --hash=sha256:5897bec80a09b4084aee23f9b73a9477a46c3304ad1d2d07acca19723fb1de62 \ - --hash=sha256:58ca98a950171f3151c603aeea9303ef6c235f692fe555e883591103da709b23 \ - --hash=sha256:5ca038c7f6a0afd0b2448941b6ef9d5e1949e999f9e5517692eb6da58e9d44be \ - --hash=sha256:5f6c8a66741c5f5447e047ab0ba7a1c61d1e95580d64bce852e3df1f895c4067 \ - --hash=sha256:5f8c4718cd44ec1580e180cb739713ecda2bdee1341084c1467802a417fe0f02 \ - --hash=sha256:5fde892e6c697ce3e30c61b239330fc5d569a71fefd4eb6512fc6caec9dd9e2f \ - --hash=sha256:62a763352879b84aa31058fc931884055fd75089cccbd9d58bb6afd01141b235 \ - --hash=sha256:62ba45e21cf6571d7f716d903b5b7b6d2617e2d5d67c0923dc47b9d41369f840 \ - --hash=sha256:64c65f40b4cd8b0e049a8edde07e38b476da7e3aaebe63287c899d2cff253fa5 \ - --hash=sha256:655d7dd86f26cb15ce8a431036f66ce0318648f8853d709b4167786ec2fa4807 \ - --hash=sha256:66ff044fd0bb1768688aecbe28b6190f6e799349221fb0de0e6f4048eca14c16 \ - --hash=sha256:672ebbe820bb37988c4d136eca2652ee114992d5d41c7e4858cdd90ea94ffe5c \ - --hash=sha256:6b9af86e1d8e4cfc82c2022bfaa6f459381a50b94a29e95dcdda8442d6d83864 \ - --hash=sha256:6e0bd57539da59a3e4671b90a502da9a28c72322a4f17866ba3ac63a82c4498e \ - --hash=sha256:71a5e35c75c021aaf400ac048dacc855f000bdfed91614b4a726f7432f1f3d6a \ - --hash=sha256:7597c07fbd11515f654d6ece3d0e4e5093edc30a436c63142d9a4b8e22f19c35 \ - --hash=sha256:764be71193f87d460a03f1f7385a82e226639732214b402f9aa61f0d025f0737 \ - --hash=sha256:7699b1df36a48169cdebda7ab5a2bac265204003f153b4bd17276153d997670a \ - --hash=sha256:7ccebf51efc61634f6c2344da73e366c75e735960b5654b63d7e6f69a5885fa3 \ - --hash=sha256:7f7059ca8d64fea7f238994c97d91f75965216bcbe5f695bb44f354893f11d52 \ - --hash=sha256:8065914ff79f7eab1599bd80406681f0ad08f8e47c880f17b416c9f8f7a26d05 \ - --hash=sha256:816f5aa087094099fff7edabb5e01cc370eb21aa1a1d44fe2d2aefdfb5599b31 \ - --hash=sha256:81f2ec23ddc1b476ff96563f2e8d723830b06dceae348ce02914a37cb4e74b89 \ - --hash=sha256:84286494f6c5d05243456e04223d5a9417d7f443c3b76065e75001beb26f88de \ - --hash=sha256:8bf7b66ce12a2ac52d16f776b31d16d91033150266eb796967a7e4621707e4f6 \ - --hash=sha256:8f1edcea27918d748c7e5e4d917297b2a0ab80cad10f86631e488b7cddf76a36 \ - --hash=sha256:981fb88516bd1ae8b0cbbd2034678a39dedc98752f264ac9bc5839d3923fa04c \ - --hash=sha256:98476c98b02c8e9b2eec76ac4156fd006628b1b2d0ef27e548ffa978393fd154 \ - --hash=sha256:992cea5f4f3b29d6b4f7f1726ed8ee46c8331c6b4eed6db5b40134c6fe1768bb \ - --hash=sha256:9a3b0793b1bbfd4146304e23d90045f2a9b5fd5823aa682665fbdaf2a6c28f3e \ - --hash=sha256:9a42d6a8156ff78981f8aa56eb6394114e0dedb217cf8b729f438f643608cbcd \ - --hash=sha256:9c10c309e18e443ddb108f0ef64e8729363adbfd92d6d57beec680f6261556f3 \ - --hash=sha256:9cbd94fc661d2bab2bc702cddd2d3370bbdcc4cd0f8f57488a81bcce90c7a54f \ - --hash=sha256:9fdcf339322a3fae5cbd504edcefddd5a50d9ee00d968696846f089b4432cf78 \ - --hash=sha256:a0697803ed7d4af5e4c1adf1670af078f8fcab7a86350e969f454daf598c4960 \ - --hash=sha256:a28af0695a45f7060e6f9b7092558a928a28553366519f64083c63a44f70e618 \ - --hash=sha256:a2e02889071850bbfd36b56fd6bc98945e23670773bc7a76657e90e6b6603c08 \ - --hash=sha256:a33cd6ad9017bbeaa9ed78a2e0752c5e250eafb9534f308e7a5f7849b0b1bfb4 \ - --hash=sha256:a3cb37038123447cf0f3ea4c74751f6a9d7afef0eb71aa07bf5f652b5e6a132c \ - --hash=sha256:a57847b090d7892f123726202b7daa20df6694cbd583b67a592e856bff603d6c \ - --hash=sha256:a5a8e19d7c707c4cadb8c18f5f60c843052ae83c20fa7d44f41594c644a1d330 \ - --hash=sha256:ac3b20653bdbe160febbea8aa6c079d3df19310d50ac314911ed8cc4eb7f8cb8 \ - --hash=sha256:ac6c2c45c847bbf8f91930d88716a0fb924b51e0c6dad329b793d670ec5db792 \ - --hash=sha256:acc07b2cfc5b835444b44a9956846b578d27beeacd4b52e45489e93276241025 \ - --hash=sha256:aee66be87825cdf72ac64cb03ad4c15ffef4143dbf5c113f64a5ff4f81477bf9 \ - --hash=sha256:af52d26579b308921b73b956153066481f064875140ccd1dfd4e77db89dbb12f \ - --hash=sha256:b94d4ba43739bbe8b0ce4262bcc3b7b9f31459ad120fb595627eaeb7f9b9ca01 \ - --hash=sha256:ba630d5e3db74c79300d9a5bdaaf6200172b107f263c98a0539eeecb857b2337 \ - --hash=sha256:bed0f8a0eeea9fb72937ba118f9db0cb7e90773462af7962d382445f3005e5a4 \ - --hash=sha256:bf99c8404f008750c846cb4ac4667b798a9f7de673ff719d705d9b2d6de49c5f \ - --hash=sha256:c3027001c28434e7ca5a6e1e527487051136aa81803ac812be51802150d880dd \ - --hash=sha256:c65af9088ac534313e1963443d0ec360bb2b9cba6c2909478d22c2e363d98a51 \ - --hash=sha256:d0165ab2914379bd56908c02294ed8405c252250668ebcb438a55494c69f44ab \ - --hash=sha256:d1b26e1dff225c31897696cab7d4f0a315d4c0d9e8666dbffdb28216f3b17fdc \ - --hash=sha256:d950caa237bb1954f1b8c9227b5065ba6875ac9771bb8ec790d956a699b78676 \ - --hash=sha256:dc61505e73298a84a2f317255fcc72b710b72980f3a1f670447a21efc88f8381 \ - --hash=sha256:e173486019cc283dc9778315fa29a363579372fe67045e971e89b6365cc035ed \ - --hash=sha256:e1f735dc43da318cad19b4173dd1ffce1d84aafd6c9b782b3abc04a0d5a6f5bb \ - --hash=sha256:e9386266798d64eeb19dd3677051f5705bf873e98e15897ddb7d76f477131967 \ - --hash=sha256:f216dbce0e60e4d03e0c4353c7023b202d95cbaeff12e5fd2e82ea0a66905073 \ - --hash=sha256:f4e5658dbffe8843a0f12366a4c2d1c316dbe09bb4dfbdc9d2d9cd6031de8aae \ - --hash=sha256:f5a823165e6d04ccea61a9f0576f345f8ce40ed533013580e087bd4d7442b52c \ - --hash=sha256:f69ed81ab24d5a3bd93861c8c4436f54afdf8e8cc421562b0c7504cf3be58206 \ - --hash=sha256:f82d068a2d6ecfc6e054726080af69a6764a10015467d7d7b9f66d6ed5afa23b +pydantic-core==2.27.2 \ + --hash=sha256:00bad2484fa6bda1e216e7345a798bd37c68fb2d97558edd584942aa41b7d278 \ + --hash=sha256:0296abcb83a797db256b773f45773da397da75a08f5fcaef41f2044adec05f50 \ + --hash=sha256:03d0f86ea3184a12f41a2d23f7ccb79cdb5a18e06993f8a45baa8dfec746f0e9 \ + --hash=sha256:044a50963a614ecfae59bb1eaf7ea7efc4bc62f49ed594e18fa1e5d953c40e9f \ + --hash=sha256:05e3a55d124407fffba0dd6b0c0cd056d10e983ceb4e5dbd10dda135c31071d6 \ + --hash=sha256:08e125dbdc505fa69ca7d9c499639ab6407cfa909214d500897d02afb816e7cc \ + --hash=sha256:097830ed52fd9e427942ff3b9bc17fab52913b2f50f2880dc4a5611446606a54 \ + --hash=sha256:0d1e85068e818c73e048fe28cfc769040bb1f475524f4745a5dc621f75ac7630 \ + --hash=sha256:0d75070718e369e452075a6017fbf187f788e17ed67a3abd47fa934d001863d9 \ + --hash=sha256:14d4a5c49d2f009d62a2a7140d3064f686d17a5d1a268bc641954ba181880236 \ + --hash=sha256:172fce187655fece0c90d90a678424b013f8fbb0ca8b036ac266749c09438cb7 \ + --hash=sha256:18a101c168e4e092ab40dbc2503bdc0f62010e95d292b27827871dc85450d7ee \ + --hash=sha256:1a4207639fb02ec2dbb76227d7c751a20b1a6b4bc52850568e52260cae64ca3b \ + --hash=sha256:1c1fd185014191700554795c99b347d64f2bb637966c4cfc16998a0ca700d048 \ + --hash=sha256:1e2cb691ed9834cd6a8be61228471d0a503731abfb42f82458ff27be7b2186fc \ + --hash=sha256:1ebaf1d0481914d004a573394f4be3a7616334be70261007e47c2a6fe7e50130 \ + --hash=sha256:220f892729375e2d736b97d0e51466252ad84c51857d4d15f5e9692f9ef12be4 \ + --hash=sha256:251136cdad0cb722e93732cb45ca5299fb56e1344a833640bf93b2803f8d1bfd \ + --hash=sha256:26f0d68d4b235a2bae0c3fc585c585b4ecc51382db0e3ba402a22cbc440915e4 \ + --hash=sha256:26f32e0adf166a84d0cb63be85c562ca8a6fa8de28e5f0d92250c6b7e9e2aff7 \ + --hash=sha256:280d219beebb0752699480fe8f1dc61ab6615c2046d76b7ab7ee38858de0a4e7 \ + --hash=sha256:28ccb213807e037460326424ceb8b5245acb88f32f3d2777427476e1b32c48c4 \ + --hash=sha256:2bf14caea37e91198329b828eae1618c068dfb8ef17bb33287a7ad4b61ac314e \ + --hash=sha256:2d367ca20b2f14095a8f4fa1210f5a7b78b8a20009ecced6b12818f455b1e9fa \ + --hash=sha256:30c5f68ded0c36466acede341551106821043e9afaad516adfb6e8fa80a4e6a6 \ + --hash=sha256:337b443af21d488716f8d0b6164de833e788aa6bd7e3a39c005febc1284f4962 \ + --hash=sha256:3911ac9284cd8a1792d3cb26a2da18f3ca26c6908cc434a18f730dc0db7bfa3b \ + --hash=sha256:3d591580c34f4d731592f0e9fe40f9cc1b430d297eecc70b962e93c5c668f15f \ + --hash=sha256:3de3ce3c9ddc8bbd88f6e0e304dea0e66d843ec9de1b0042b0911c1663ffd474 \ + --hash=sha256:3de9961f2a346257caf0aa508a4da705467f53778e9ef6fe744c038119737ef5 \ + --hash=sha256:40d02e7d45c9f8af700f3452f329ead92da4c5f4317ca9b896de7ce7199ea459 \ + --hash=sha256:42c5f762659e47fdb7b16956c71598292f60a03aa92f8b6351504359dbdba6cf \ + --hash=sha256:47956ae78b6422cbd46f772f1746799cbb862de838fd8d1fbd34a82e05b0983a \ + --hash=sha256:491a2b73db93fab69731eaee494f320faa4e093dbed776be1a829c2eb222c34c \ + --hash=sha256:4c9775e339e42e79ec99c441d9730fccf07414af63eac2f0e48e08fd38a64d76 \ + --hash=sha256:4e0b4220ba5b40d727c7f879eac379b822eee5d8fff418e9d3381ee45b3b0362 \ + --hash=sha256:50a68f3e3819077be2c98110c1f9dcb3817e93f267ba80a2c05bb4f8799e2ff4 \ + --hash=sha256:519f29f5213271eeeeb3093f662ba2fd512b91c5f188f3bb7b27bc5973816934 \ + --hash=sha256:521eb9b7f036c9b6187f0b47318ab0d7ca14bd87f776240b90b21c1f4f149320 \ + --hash=sha256:57762139821c31847cfb2df63c12f725788bd9f04bc2fb392790959b8f70f118 \ + --hash=sha256:5e4f4bb20d75e9325cc9696c6802657b58bc1dbbe3022f32cc2b2b632c3fbb96 \ + --hash=sha256:5e68c4446fe0810e959cdff46ab0a41ce2f2c86d227d96dc3847af0ba7def306 \ + --hash=sha256:669e193c1c576a58f132e3158f9dfa9662969edb1a250c54d8fa52590045f046 \ + --hash=sha256:688d3fd9fcb71f41c4c015c023d12a79d1c4c0732ec9eb35d96e3388a120dcf3 \ + --hash=sha256:6fb4aadc0b9a0c063206846d603b92030eb6f03069151a625667f982887153e2 \ + --hash=sha256:7041c36f5680c6e0f08d922aed302e98b3745d97fe1589db0a3eebf6624523af \ + --hash=sha256:71b24c7d61131bb83df10cc7e687433609963a944ccf45190cfc21e0887b08c9 \ + --hash=sha256:77d1bca19b0f7021b3a982e6f903dcd5b2b06076def36a652e3907f596e29f67 \ + --hash=sha256:7969e133a6f183be60e9f6f56bfae753585680f3b7307a8e555a948d443cc05a \ + --hash=sha256:7a66efda2387de898c8f38c0cf7f14fca0b51a8ef0b24bfea5849f1b3c95af27 \ + --hash=sha256:7d0c8399fcc1848491f00e0314bd59fb34a9c008761bcb422a057670c3f65e35 \ + --hash=sha256:7d14bd329640e63852364c306f4d23eb744e0f8193148d4044dd3dacdaacbd8b \ + --hash=sha256:7e17b560be3c98a8e3aa66ce828bdebb9e9ac6ad5466fba92eb74c4c95cb1151 \ + --hash=sha256:8083d4e875ebe0b864ffef72a4304827015cff328a1be6e22cc850753bfb122b \ + --hash=sha256:82f91663004eb8ed30ff478d77c4d1179b3563df6cdb15c0817cd1cdaf34d154 \ + --hash=sha256:82f986faf4e644ffc189a7f1aafc86e46ef70372bb153e7001e8afccc6e54133 \ + --hash=sha256:83097677b8e3bd7eaa6775720ec8e0405f1575015a463285a92bfdfe254529ef \ + --hash=sha256:85210c4d99a0114f5a9481b44560d7d1e35e32cc5634c656bc48e590b669b145 \ + --hash=sha256:8c19d1ea0673cd13cc2f872f6c9ab42acc4e4f492a7ca9d3795ce2b112dd7e15 \ + --hash=sha256:8d9b3388db186ba0c099a6d20f0604a44eabdeef1777ddd94786cdae158729e4 \ + --hash=sha256:8e10c99ef58cfdf2a66fc15d66b16c4a04f62bca39db589ae8cba08bc55331bc \ + --hash=sha256:953101387ecf2f5652883208769a79e48db18c6df442568a0b5ccd8c2723abee \ + --hash=sha256:9c3ed807c7b91de05e63930188f19e921d1fe90de6b4f5cd43ee7fcc3525cb8c \ + --hash=sha256:9e0c8cfefa0ef83b4da9588448b6d8d2a2bf1a53c3f1ae5fca39eb3061e2f0b0 \ + --hash=sha256:9fdbe7629b996647b99c01b37f11170a57ae675375b14b8c13b8518b8320ced5 \ + --hash=sha256:a0fcd29cd6b4e74fe8ddd2c90330fd8edf2e30cb52acda47f06dd615ae72da57 \ + --hash=sha256:ac4dbfd1691affb8f48c2c13241a2e3b60ff23247cbcf981759c768b6633cf8b \ + --hash=sha256:b0cb791f5b45307caae8810c2023a184c74605ec3bcbb67d13846c28ff731ff8 \ + --hash=sha256:ba5dd002f88b78a4215ed2f8ddbdf85e8513382820ba15ad5ad8955ce0ca19a1 \ + --hash=sha256:bca101c00bff0adb45a833f8451b9105d9df18accb8743b08107d7ada14bd7da \ + --hash=sha256:bd8086fa684c4775c27f03f062cbb9eaa6e17f064307e86b21b9e0abc9c0f02e \ + --hash=sha256:bec317a27290e2537f922639cafd54990551725fc844249e64c523301d0822fc \ + --hash=sha256:c10eb4f1659290b523af58fa7cffb452a61ad6ae5613404519aee4bfbf1df993 \ + --hash=sha256:c33939a82924da9ed65dab5a65d427205a73181d8098e79b6b426bdf8ad4e656 \ + --hash=sha256:c61709a844acc6bf0b7dce7daae75195a10aac96a596ea1b776996414791ede4 \ + --hash=sha256:c70c26d2c99f78b125a3459f8afe1aed4d9687c24fd677c6a4436bc042e50d6c \ + --hash=sha256:c817e2b40aba42bac6f457498dacabc568c3b7a986fc9ba7c8d9d260b71485fb \ + --hash=sha256:cabb9bcb7e0d97f74df8646f34fc76fbf793b7f6dc2438517d7a9e50eee4f14d \ + --hash=sha256:cc3f1a99a4f4f9dd1de4fe0312c114e740b5ddead65bb4102884b384c15d8bc9 \ + --hash=sha256:cca63613e90d001b9f2f9a9ceb276c308bfa2a43fafb75c8031c4f66039e8c6e \ + --hash=sha256:ce8918cbebc8da707ba805b7fd0b382816858728ae7fe19a942080c24e5b7cd1 \ + --hash=sha256:d2088237af596f0a524d3afc39ab3b036e8adb054ee57cbb1dcf8e09da5b29cc \ + --hash=sha256:d262606bf386a5ba0b0af3b97f37c83d7011439e3dc1a9298f21efb292e42f1a \ + --hash=sha256:d2d63f1215638d28221f664596b1ccb3944f6e25dd18cd3b86b0a4c408d5ebb9 \ + --hash=sha256:d3e8d504bdd3f10835468f29008d72fc8359d95c9c415ce6e767203db6127506 \ + --hash=sha256:d4041c0b966a84b4ae7a09832eb691a35aec90910cd2dbe7a208de59be77965b \ + --hash=sha256:d716e2e30c6f140d7560ef1538953a5cd1a87264c737643d481f2779fc247fe1 \ + --hash=sha256:d81d2068e1c1228a565af076598f9e7451712700b673de8f502f0334f281387d \ + --hash=sha256:d9640b0059ff4f14d1f37321b94061c6db164fbe49b334b31643e0528d100d99 \ + --hash=sha256:de3cd1899e2c279b140adde9357c4495ed9d47131b4a4eaff9052f23398076b3 \ + --hash=sha256:e0fd26b16394ead34a424eecf8a31a1f5137094cabe84a1bcb10fa6ba39d3d31 \ + --hash=sha256:e2bb4d3e5873c37bb3dd58714d4cd0b0e6238cebc4177ac8fe878f8b3aa8e74c \ + --hash=sha256:eb026e5a4c1fee05726072337ff51d1efb6f59090b7da90d30ea58625b1ffb39 \ + --hash=sha256:eda3f5c2a021bbc5d976107bb302e0131351c2ba54343f8a496dc8783d3d3a6a \ + --hash=sha256:ef592d4bad47296fb11f96cd7dc898b92e795032b4894dfb4076cfccd43a9308 \ + --hash=sha256:f141ee28a0ad2123b6611b6ceff018039df17f32ada8b534e6aa039545a3efb2 \ + --hash=sha256:f66d89ba397d92f840f8654756196d93804278457b5fbede59598a1f9f90b228 \ + --hash=sha256:f6f8e111843bbb0dee4cb6594cdc73e79b3329b526037ec242a3e49012495b3b \ + --hash=sha256:fa8e459d4954f608fa26116118bb67f56b93b209c39b008277ace29937453dc9 \ + --hash=sha256:fd1aea04935a508f62e0d0ef1f5ae968774a32afc306fb8545e06f5ff5cdf3ad # via pydantic pygments==2.18.0 \ --hash=sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199 \ @@ -506,9 +495,9 @@ pyjwt==2.10.1 \ --hash=sha256:3cc5772eb20009233caf06e9d8a0577824723b44e6648ee0a2aedb6cf9381953 \ --hash=sha256:dcdd193e30abefd5debf142f9adfcdd2b58004e644f25406ffaebd50bd98dacb # via sigstore -pyopenssl==24.3.0 \ - --hash=sha256:49f7a019577d834746bc55c5fce6ecbcec0f2b4ec5ce1cf43a9a173b8138bb36 \ - --hash=sha256:e474f5a473cd7f92221cc04976e48f4d11502804657a08a989fb3be5514c904a +pyopenssl==25.0.0 \ + --hash=sha256:424c247065e46e76a37411b9ab1782541c23bb658bf003772c3405fbaa128e90 \ + --hash=sha256:cd2cef799efa3936bb08e8ccb9433a575722b9dd986023f1cabc4ae64e9dac16 # via sigstore python-dateutil==2.9.0.post0 \ --hash=sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3 \ @@ -521,20 +510,20 @@ requests==2.32.3 \ # id # sigstore # tuf -rfc3161-client==0.0.4 \ - --hash=sha256:07ce4ad1c35f3a0849a34efc78bb00b8520581c92d9cf3658539dd4604007d91 \ - --hash=sha256:0d2bb5be5c6937b15842221489d2564bc2492dfedc8c5b34ce97319e4618782d \ - --hash=sha256:3a9107572f92a0b2d6bb2e8eb0a635cebffa03d33bbd6eae69e8240b1f982922 \ - --hash=sha256:6609bb872f87da30448697234a0044a2cbe81ecc789cbd89d662b68b2d4a2021 \ - --hash=sha256:7415c816418f46d94a36a875ef0dfdcc6e2c3684383388ca92f3d2bb246766de \ - --hash=sha256:7698fbe46fc056d7aca2e790f68ae2e1ec8c2cb794d5a82e8ce583d9c48dfd91 \ - --hash=sha256:84707145debb6e6d94ca498ee9e4440cf31b0733b2c6931dfc200659967272d8 \ - --hash=sha256:8b98affc17fa4a6349cd045b6c48573f8998f254e1f1d6e8156d957cbbff8000 \ - --hash=sha256:8f9418cffb4b64c6d20505e1f48fadcf68dbafe5ce387cd57a19798ffb5a0677 \ - --hash=sha256:b97a1a73f71f5cc7b5459ca042a9267569369357da7ab9747f65d1feacbd2f19 \ - --hash=sha256:bf90cf5185ab9d7a6aa374a2ecea1b507a1326176881af1fe1e9ce067d5601bf \ - --hash=sha256:c7eefcc139e0c4ee98ea6ceaa272f11cbcaf28dfa39f61558803f173990d5dbd \ - --hash=sha256:f6d0b61b4b188d3e9607ef376762ab7c46af3c67e182ac984bfaf8f5e738e1c6 +rfc3161-client==0.1.2 \ + --hash=sha256:1e01498007779bdef720422f4481d87e340b875b851f909434822b604c856682 \ + --hash=sha256:471304f8a94f31b1e0f45aa4138bb50cf2dc38808e96465bafad9e128c75ea7b \ + --hash=sha256:590aa4a04e445589ffded1fe91782efe07d71f6fb75ff54d768a120373c7c1ff \ + --hash=sha256:5bc220bd7f1525898cd33b6d8f1508f9ba080a3008ba9d1416ab5c0a46df4326 \ + --hash=sha256:68be67081aefa787f17c11e75ff625d8b4e8245829822da5e5b240d7ef415f61 \ + --hash=sha256:741180cc1e5e093fa06c7abe71caac672b08fc9b94d2f9644fa8dd5aa48b646d \ + --hash=sha256:92e24bd34c2567712060cf7701ec9580572b35300eec3b57f886d8dcbf036dd8 \ + --hash=sha256:9f7e8b2bf955ab0e3b1f1ac2c2a1f9dbe6657cd93981d890aae5748998cd275a \ + --hash=sha256:b6b6d33c21ed3960b29997000837bf5588d01e7c85bf74a06b653e3b8a679cc4 \ + --hash=sha256:be5960c3fbd560067b6e7e57c0496c1097c689f56d0f1237acdb854ad2ee32c0 \ + --hash=sha256:c45143a0ed73845ace404c1c21d5de6345265988a247193f96db4ef81577c07b \ + --hash=sha256:e81dbd93d1e2180603d3dbd88635b6897c415a1de960818a23e14293fef033d5 \ + --hash=sha256:ed999ac4117db267e67f24f49aeb9686c3b620c86ec4957229deac6bd3cba352 # via sigstore rfc8785==0.1.4 \ --hash=sha256:520d690b448ecf0703691c76e1a34a24ddcd4fc5bc41d589cb7c58ec651bcd48 \ @@ -548,10 +537,10 @@ securesystemslib==1.2.0 \ --hash=sha256:34fa63e3296a0540b122a13bf51722ecd015be00c1d2ed45b23442e718920e76 \ --hash=sha256:fa63abcb1cf4dba4f2df964f623baa45bc39029980d7a0a2119d90731942afc6 # via tuf -sigstore==3.6.0 \ - --hash=sha256:cd84e1acaec163d4b3a837dab160fb73259bf67939b2deea3d12c40f09a6ac21 \ - --hash=sha256:e354867c21674864b4014a390e28685e1decc925be5ba1af3055f217d6d27e2c - # via -r requirements.in +sigstore==3.6.1 \ + --hash=sha256:b568b16322222e834940acabdc84fbb16c8780874c3c21c6c8dde928dae0f881 \ + --hash=sha256:ee60fdc9236fd6709271ad53b44027461360c3fde155d2af15482e4c451ff865 + # via -r install/requirements.in sigstore-protobuf-specs==0.3.2 \ --hash=sha256:50c99fa6747a3a9c5c562a43602cf76df0b199af28f0e9d4319b6775630425ea \ --hash=sha256:cae041b40502600b8a633f43c257695d0222a94efa1e5110a7ec7ada78c39d99 @@ -564,40 +553,6 @@ six==1.17.0 \ --hash=sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274 \ --hash=sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81 # via python-dateutil -tomli==2.2.1 \ - --hash=sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6 \ - --hash=sha256:02abe224de6ae62c19f090f68da4e27b10af2b93213d36cf44e6e1c5abd19fdd \ - --hash=sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c \ - --hash=sha256:2d0f2fdd22b02c6d81637a3c95f8cd77f995846af7414c5c4b8d0545afa1bc4b \ - --hash=sha256:33580bccab0338d00994d7f16f4c4ec25b776af3ffaac1ed74e0b3fc95e885a8 \ - --hash=sha256:400e720fe168c0f8521520190686ef8ef033fb19fc493da09779e592861b78c6 \ - --hash=sha256:40741994320b232529c802f8bc86da4e1aa9f413db394617b9a256ae0f9a7f77 \ - --hash=sha256:465af0e0875402f1d226519c9904f37254b3045fc5084697cefb9bdde1ff99ff \ - --hash=sha256:4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea \ - --hash=sha256:4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192 \ - --hash=sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249 \ - --hash=sha256:6972ca9c9cc9f0acaa56a8ca1ff51e7af152a9f87fb64623e31d5c83700080ee \ - --hash=sha256:7fc04e92e1d624a4a63c76474610238576942d6b8950a2d7f908a340494e67e4 \ - --hash=sha256:889f80ef92701b9dbb224e49ec87c645ce5df3fa2cc548664eb8a25e03127a98 \ - --hash=sha256:8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8 \ - --hash=sha256:8dd28b3e155b80f4d54beb40a441d366adcfe740969820caf156c019fb5c7ec4 \ - --hash=sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281 \ - --hash=sha256:a198f10c4d1b1375d7687bc25294306e551bf1abfa4eace6650070a5c1ae2744 \ - --hash=sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69 \ - --hash=sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13 \ - --hash=sha256:ac065718db92ca818f8d6141b5f66369833d4a80a9d74435a268c52bdfa73140 \ - --hash=sha256:b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e \ - --hash=sha256:c954d2250168d28797dd4e3ac5cf812a406cd5a92674ee4c8f123c889786aa8e \ - --hash=sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc \ - --hash=sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff \ - --hash=sha256:d3f5614314d758649ab2ab3a62d4f2004c825922f9e370b29416484086b264ec \ - --hash=sha256:d920f33822747519673ee656a4b6ac33e382eca9d331c87770faa3eef562aeb2 \ - --hash=sha256:db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222 \ - --hash=sha256:e59e304978767a54663af13c07b3d1af22ddee3bb2fb0618ca1593e4f593a106 \ - --hash=sha256:e85e99945e688e32d5a35c1ff38ed0b3f41f43fad8df0bdf79f72b2ba7bc5272 \ - --hash=sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a \ - --hash=sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7 - # via maturin tuf==5.1.0 \ --hash=sha256:1865737bf8e05893ae31b4511617da7f02cf070562fa3c931074d29ef5fb46d7 \ --hash=sha256:6494848d2720ced600e0d7ee23b4986623ddad1148ad8e54ffe308db18b762fe @@ -609,6 +564,7 @@ typing-extensions==4.12.2 \ # multidict # pydantic # pydantic-core + # pyopenssl # rich urllib3==2.2.3 \ --hash=sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac \ diff --git a/pyproject.toml b/pyproject.toml index 01c5bf1c7..6c0072afc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -34,13 +34,13 @@ dependencies = [ "pyjwt >= 2.1", "pyOpenSSL >= 23.0.0", "requests", - "rich ~= 13.0", + "rich >= 13,< 15", "rfc8785 ~= 0.1.2", - "rfc3161-client ~= 0.1.2", + "rfc3161-client >= 0.1.2,< 1.1.0", # NOTE(ww): Both under active development, so strictly pinned. "sigstore-protobuf-specs == 0.3.2", "sigstore-rekor-types == 0.0.18", - "tuf ~= 5.0", + "tuf ~= 6.0", "platformdirs ~= 4.2", ] requires-python = ">=3.9" @@ -62,7 +62,7 @@ lint = [ "mypy ~= 1.1", # NOTE(ww): ruff is under active development, so we pin conservatively here # and let Dependabot periodically perform this update. - "ruff < 0.8.4", + "ruff < 0.11.6", "types-requests", "types-pyOpenSSL", ] @@ -104,10 +104,11 @@ allow_redefinition = true check_untyped_defs = true disallow_incomplete_defs = true disallow_untyped_defs = true +enable_error_code = ["ignore-without-code", "redundant-expr", "truthy-bool"] ignore_missing_imports = true no_implicit_optional = true -show_error_codes = true sqlite_cache = true +strict = true strict_equality = true warn_no_return = true warn_redundant_casts = true @@ -121,8 +122,9 @@ plugins = ["pydantic.mypy"] exclude_dirs = ["./test"] [tool.ruff.lint] -# Never enforce `E501` (line length violations). -ignore = ["E501"] -# TODO: Enable "UP" here once Pydantic allows us to: -# See: https://github.com/pydantic/pydantic/issues/4146 -select = ["E", "F", "I", "W"] +extend-select = ["I", "UP"] +ignore = [ + "UP007", # https://github.com/pydantic/pydantic/issues/4146 + "UP011", + "UP015", +] diff --git a/sigstore/__init__.py b/sigstore/__init__.py index c5e18e0bf..c9743b988 100644 --- a/sigstore/__init__.py +++ b/sigstore/__init__.py @@ -25,4 +25,4 @@ * `sigstore.sign`: creation of Sigstore signatures """ -__version__ = "3.6.1" +__version__ = "3.6.2" diff --git a/sigstore/_cli.py b/sigstore/_cli.py index 218df26ed..e2b1c752a 100644 --- a/sigstore/_cli.py +++ b/sigstore/_cli.py @@ -22,7 +22,7 @@ import sys from dataclasses import dataclass from pathlib import Path -from typing import Any, Dict, NoReturn, Optional, TextIO, Union +from typing import Any, NoReturn, Optional, TextIO, Union from cryptography.hazmat.primitives.serialization import Encoding from cryptography.x509 import load_pem_x509_certificate @@ -98,7 +98,7 @@ class VerificationBundledMaterials: ] # Map of inputs -> outputs for signing operations -OutputMap: TypeAlias = Dict[Path, SigningOutputs] +OutputMap: TypeAlias = dict[Path, SigningOutputs] def _fatal(message: str) -> NoReturn: @@ -200,7 +200,7 @@ def _add_shared_verification_options(group: argparse._ArgumentGroup) -> None: def _add_shared_oidc_options( - group: Union[argparse._ArgumentGroup, argparse.ArgumentParser], + group: argparse._ArgumentGroup | argparse.ArgumentParser, ) -> None: """ Common OIDC options, shared between `sigstore sign` and `sigstore get-identity-token`. @@ -775,7 +775,7 @@ def _attest(args: argparse.Namespace) -> None: if bundle and bundle.exists() and not args.overwrite: _invalid_arguments( args, - "Refusing to overwrite outputs without --overwrite: " f"{bundle}", + f"Refusing to overwrite outputs without --overwrite: {bundle}", ) output_map[file] = SigningOutputs(bundle=bundle) @@ -833,7 +833,7 @@ def _sign(args: argparse.Namespace) -> None: args.bundle, ) - output_dir = args.output_directory if args.output_directory else file.parent + output_dir = args.output_directory or file.parent if output_dir.exists() and not output_dir.is_dir(): _invalid_arguments( args, f"Output directory exists and is not a directory: {output_dir}" @@ -895,7 +895,7 @@ def _collect_verification_state( ) # Fail if digest input is not used with `--bundle` or both `--certificate` and `--signature`. - if any((isinstance(x, Hashed) for x in args.files_or_digest)): + if any(isinstance(x, Hashed) for x in args.files_or_digest): if not args.bundle and not (args.certificate and args.signature): _invalid_arguments( args, @@ -1200,10 +1200,7 @@ def _get_identity(args: argparse.Namespace) -> Optional[IdentityToken]: def _fix_bundle(args: argparse.Namespace) -> None: # NOTE: We could support `--trusted-root` here in the future, # for custom Rekor instances. - if args.staging: - rekor = RekorClient.staging() - else: - rekor = RekorClient.production() + rekor = RekorClient.staging() if args.staging else RekorClient.production() raw_bundle = RawBundle().from_json(args.bundle.read_text()) diff --git a/sigstore/_internal/fulcio/client.py b/sigstore/_internal/fulcio/client.py index 062519186..0552628d1 100644 --- a/sigstore/_internal/fulcio/client.py +++ b/sigstore/_internal/fulcio/client.py @@ -23,7 +23,6 @@ import logging from abc import ABC from dataclasses import dataclass -from typing import List from urllib.parse import urljoin import requests @@ -33,13 +32,8 @@ CertificateSigningRequest, load_pem_x509_certificate, ) -from cryptography.x509.certificate_transparency import SignedCertificateTimestamp from sigstore._internal import USER_AGENT -from sigstore._internal.sct import ( - UnexpectedSctCountException, - _get_precertificate_signed_certificate_timestamps, -) from sigstore._utils import B64Str from sigstore.oidc import IdentityToken @@ -51,14 +45,6 @@ TRUST_BUNDLE_ENDPOINT = "/api/v2/trustBundle" -class FulcioSCTError(Exception): - """ - Raised on errors when constructing a `FulcioSignedCertificateTimestamp`. - """ - - pass - - class ExpiredCertificate(Exception): """An error raised when the Certificate is expired.""" @@ -68,15 +54,14 @@ class FulcioCertificateSigningResponse: """Certificate response""" cert: Certificate - chain: List[Certificate] - sct: SignedCertificateTimestamp + chain: list[Certificate] @dataclass(frozen=True) class FulcioTrustBundleResponse: """Trust bundle response, containing a list of certificate chains""" - trust_bundle: List[List[Certificate]] + trust_bundle: list[list[Certificate]] class FulcioClientError(Exception): @@ -148,14 +133,7 @@ def post( cert = load_pem_x509_certificate(certificates[0].encode()) chain = [load_pem_x509_certificate(c.encode()) for c in certificates[1:]] - try: - # The SignedCertificateTimestamp should be accessed by the index 0 - sct = _get_precertificate_signed_certificate_timestamps(cert)[0] - - except UnexpectedSctCountException as ex: - raise FulcioClientError(ex) - - return FulcioCertificateSigningResponse(cert, chain, sct) + return FulcioCertificateSigningResponse(cert, chain) class FulcioTrustBundle(_Endpoint): @@ -172,9 +150,9 @@ def get(self) -> FulcioTrustBundleResponse: raise FulcioClientError from http_error trust_bundle_json = resp.json() - chains: List[List[Certificate]] = [] + chains: list[list[Certificate]] = [] for certificate_chain in trust_bundle_json["chains"]: - chain: List[Certificate] = [] + chain: list[Certificate] = [] for certificate in certificate_chain["certificates"]: cert: Certificate = load_pem_x509_certificate(certificate.encode()) chain.append(cert) diff --git a/sigstore/_internal/merkle.py b/sigstore/_internal/merkle.py index b930c7def..a39bdb919 100644 --- a/sigstore/_internal/merkle.py +++ b/sigstore/_internal/merkle.py @@ -27,7 +27,6 @@ import hashlib import struct import typing -from typing import List, Tuple from sigstore._utils import HexStr from sigstore.errors import VerificationError @@ -40,7 +39,7 @@ _NODE_HASH_PREFIX = 1 -def _decomp_inclusion_proof(index: int, size: int) -> Tuple[int, int]: +def _decomp_inclusion_proof(index: int, size: int) -> tuple[int, int]: """ Breaks down inclusion proof for a leaf at the specified |index| in a tree of the specified |size| into 2 components. The splitting point between them is where paths to leaves |index| and @@ -55,7 +54,7 @@ def _decomp_inclusion_proof(index: int, size: int) -> Tuple[int, int]: return inner, border -def _chain_inner(seed: bytes, hashes: List[str], log_index: int) -> bytes: +def _chain_inner(seed: bytes, hashes: list[str], log_index: int) -> bytes: """ Computes a subtree hash for a node on or below the tree's right border. Assumes |proof| hashes are ordered from lower levels to upper, and |seed| is the initial subtree/leaf hash on the path @@ -71,7 +70,7 @@ def _chain_inner(seed: bytes, hashes: List[str], log_index: int) -> bytes: return seed -def _chain_border_right(seed: bytes, hashes: List[str]) -> bytes: +def _chain_border_right(seed: bytes, hashes: list[str]) -> bytes: """ Chains proof hashes along tree borders. This differs from inner chaining because |proof| contains only left-side subtree hashes. diff --git a/sigstore/_internal/oidc/oauth.py b/sigstore/_internal/oidc/oauth.py index cdbd8c7b6..2a2f056d4 100644 --- a/sigstore/_internal/oidc/oauth.py +++ b/sigstore/_internal/oidc/oauth.py @@ -26,7 +26,8 @@ import threading import urllib.parse import uuid -from typing import Any, Dict, List, Optional, cast +from types import TracebackType +from typing import Any, Optional, cast from id import IdentityError @@ -97,7 +98,7 @@ -""" # noqa: E501 +""" class _OAuthFlow: @@ -118,7 +119,12 @@ def __enter__(self) -> _OAuthRedirectServer: return self._server - def __exit__(self, exc_type: Any, exc_value: Any, traceback: Any) -> None: + def __exit__( + self, + exc_type: type[BaseException] | None, + exc_value: BaseException | None, + traceback: TracebackType | None, + ) -> None: self._server.shutdown() self._server_thread.join() @@ -200,7 +206,7 @@ def auth_endpoint(self, redirect_uri: str) -> str: params = self._auth_params(redirect_uri) return f"{self._issuer.oidc_config.authorization_endpoint}?{urllib.parse.urlencode(params)}" - def _auth_params(self, redirect_uri: str) -> Dict[str, Any]: + def _auth_params(self, redirect_uri: str) -> dict[str, Any]: return { "response_type": "code", "client_id": self._client_id, @@ -218,7 +224,7 @@ class _OAuthRedirectServer(http.server.HTTPServer): def __init__(self, client_id: str, client_secret: str, issuer: Issuer) -> None: super().__init__(("localhost", 0), _OAuthRedirectHandler) self.oauth_session = _OAuthSession(client_id, client_secret, issuer) - self.auth_response: Optional[Dict[str, List[str]]] = None + self.auth_response: Optional[dict[str, list[str]]] = None self._is_out_of_band = False @property diff --git a/sigstore/_internal/rekor/checkpoint.py b/sigstore/_internal/rekor/checkpoint.py index cc1389658..c630d24fa 100644 --- a/sigstore/_internal/rekor/checkpoint.py +++ b/sigstore/_internal/rekor/checkpoint.py @@ -23,7 +23,6 @@ import struct import typing from dataclasses import dataclass -from typing import List from pydantic import BaseModel, Field, StrictStr @@ -57,7 +56,7 @@ class LogCheckpoint(BaseModel): - an origin, e.g. "rekor.sigstage.dev - 8050909264565447525" - the size of the log, - the hash of the log, - - and any optional ancillary contants, e.g. "Timestamp: 1679349379012118479" + - and any optional ancillary constants, e.g. "Timestamp: 1679349379012118479" See: """ @@ -65,7 +64,7 @@ class LogCheckpoint(BaseModel): origin: StrictStr log_size: int log_hash: StrictStr - other_content: List[str] + other_content: list[str] @classmethod def from_text(cls, text: str) -> LogCheckpoint: @@ -229,5 +228,5 @@ def verify_checkpoint(rekor_keyring: RekorKeyring, entry: LogEntry) -> None: if checkpoint_hash != root_hash: raise VerificationError( "Inclusion proof contains invalid root hash signature: ", - f"expected {str(checkpoint_hash)} got {str(root_hash)}", + f"expected {checkpoint_hash} got {root_hash}", ) diff --git a/sigstore/_internal/rekor/client.py b/sigstore/_internal/rekor/client.py index 86fc0421e..b4f348300 100644 --- a/sigstore/_internal/rekor/client.py +++ b/sigstore/_internal/rekor/client.py @@ -22,7 +22,7 @@ import logging from abc import ABC from dataclasses import dataclass -from typing import Any, Dict, Optional +from typing import Any, Optional from urllib.parse import urljoin import rekor_types @@ -47,10 +47,10 @@ class RekorLogInfo: tree_size: int signed_tree_head: str tree_id: str - raw_data: dict + raw_data: dict[str, Any] @classmethod - def from_response(cls, dict_: Dict[str, Any]) -> RekorLogInfo: + def from_response(cls, dict_: dict[str, Any]) -> RekorLogInfo: """ Create a new `RekorLogInfo` from the given API response. """ diff --git a/sigstore/_internal/sct.py b/sigstore/_internal/sct.py index 8fd6cc5b2..7a0f4a794 100644 --- a/sigstore/_internal/sct.py +++ b/sigstore/_internal/sct.py @@ -19,7 +19,7 @@ import logging import struct from datetime import timezone -from typing import List, Optional +from typing import Optional from cryptography.hazmat.primitives import hashes, serialization from cryptography.hazmat.primitives.asymmetric import ec, rsa @@ -99,7 +99,7 @@ def _pack_digitally_signed( blob, one that forms the signature body of the "digitally-signed" struct for an SCT. - The format of the digitaly signed data is described in IETF's RFC 6962. + The format of the digitally signed data is described in IETF's RFC 6962. """ # No extensions are currently specified, so we treat the presence @@ -115,7 +115,7 @@ def _pack_digitally_signed( # Assemble a format string with the certificate length baked in and then pack the digitally # signed data # fmt: off - pattern = "!BBQH%dsH" % len(signed_entry) + pattern = f"!BBQH{len(signed_entry)}sH" timestamp = sct.timestamp.replace(tzinfo=timezone.utc) data = struct.pack( pattern, @@ -141,39 +141,35 @@ def _is_preissuer(issuer: Certificate) -> bool: return ExtendedKeyUsageOID.CERTIFICATE_TRANSPARENCY in ext_key_usage.value -def _get_issuer_cert(chain: List[Certificate]) -> Certificate: +def _get_issuer_cert(chain: list[Certificate]) -> Certificate: issuer = chain[0] if _is_preissuer(issuer): issuer = chain[1] return issuer -class UnexpectedSctCountException(Exception): - """ - Number of percerts scts is wrong - """ - - pass - - -def _get_precertificate_signed_certificate_timestamps( +def _get_signed_certificate_timestamp( certificate: Certificate, -) -> PrecertificateSignedCertificateTimestamps: - # Try to retrieve the embedded SCTs within the cert. +) -> SignedCertificateTimestamp: + """Retrieve the embedded SCT from the certificate. + + Raise VerificationError if certificate does not contain exactly one SCT + """ try: - precert_scts_extension = certificate.extensions.get_extension_for_class( + timestamps = certificate.extensions.get_extension_for_class( PrecertificateSignedCertificateTimestamps ).value except ExtensionNotFound: - raise ValueError( - "No PrecertificateSignedCertificateTimestamps found for the certificate" + raise VerificationError( + "Certificate does not contain a signed certificate timestamp extension" ) - if len(precert_scts_extension) != 1: - raise UnexpectedSctCountException( - f"Unexpected embedded SCT count in response: {len(precert_scts_extension)} != 1" + if len(timestamps) != 1: + raise VerificationError( + f"Expected one certificate timestamp, found {len(timestamps)}" ) - return precert_scts_extension + sct: SignedCertificateTimestamp = timestamps[0] + return sct def _cert_is_ca(cert: Certificate) -> bool: @@ -187,9 +183,8 @@ def _cert_is_ca(cert: Certificate) -> bool: def verify_sct( - sct: SignedCertificateTimestamp, cert: Certificate, - chain: List[Certificate], + chain: list[Certificate], ct_keyring: CTKeyring, ) -> None: """ @@ -201,6 +196,8 @@ def verify_sct( log to sign SCTs). """ + sct = _get_signed_certificate_timestamp(cert) + issuer_key_id = None if sct.entry_type == LogEntryType.PRE_CERTIFICATE: # If we're verifying an SCT for a precertificate, we need to diff --git a/sigstore/_internal/trust.py b/sigstore/_internal/trust.py index b359836db..b9f03d15a 100644 --- a/sigstore/_internal/trust.py +++ b/sigstore/_internal/trust.py @@ -18,11 +18,12 @@ from __future__ import annotations +from collections.abc import Iterable from dataclasses import dataclass from datetime import datetime, timezone from enum import Enum from pathlib import Path -from typing import ClassVar, Iterable, List, NewType +from typing import ClassVar, NewType import cryptography.hazmat.primitives.asymmetric.padding as padding from cryptography.exceptions import InvalidSignature @@ -159,7 +160,7 @@ class Keyring: Represents a set of keys, each of which is a potentially valid verifier. """ - def __init__(self, public_keys: List[_PublicKey] = []): + def __init__(self, public_keys: list[_PublicKey] = []): """ Create a new `Keyring`, with `keys` as the initial set of verifying keys. """ @@ -182,10 +183,7 @@ def verify(self, *, key_id: KeyID, signature: bytes, data: bytes) -> None: """ key = self._keyring.get(key_id) - if key is not None: - candidates = [key] - else: - candidates = list(self._keyring.values()) + candidates = [key] if key is not None else list(self._keyring.values()) # Try to verify each candidate key. In the happy case, this will # be exactly one candidate. @@ -384,8 +382,8 @@ def rekor_keyring(self, purpose: KeyringPurpose) -> RekorKeyring: """Return keyring with keys for Rekor.""" keys: list[_PublicKey] = list(self._get_tlog_keys(self._inner.tlogs, purpose)) - if len(keys) != 1: - raise MetadataError("Did not find one Rekor key in trusted root") + if len(keys) == 0: + raise MetadataError("Did not find any Rekor keys in trusted root") return RekorKeyring(Keyring(keys)) def ct_keyring(self, purpose: KeyringPurpose) -> CTKeyring: diff --git a/sigstore/_internal/tuf.py b/sigstore/_internal/tuf.py index 7116be700..265be87a0 100644 --- a/sigstore/_internal/tuf.py +++ b/sigstore/_internal/tuf.py @@ -25,7 +25,7 @@ import platformdirs from tuf.api import exceptions as TUFExceptions -from tuf.ngclient import Updater, UpdaterConfig +from tuf.ngclient import Updater, UpdaterConfig # type: ignore[attr-defined] from sigstore import __version__ from sigstore._utils import read_embedded @@ -87,18 +87,6 @@ def __init__(self, url: str, offline: bool = False) -> None: else: raise RootError - # Initialize metadata dir - self._metadata_dir.mkdir(parents=True, exist_ok=True) - tuf_root = self._metadata_dir / "root.json" - - if not tuf_root.exists(): - try: - root_json = read_embedded("root.json", rsrc_prefix) - except FileNotFoundError as e: - raise RootError from e - - tuf_root.write_bytes(root_json) - # Initialize targets cache dir self._targets_dir.mkdir(parents=True, exist_ok=True) trusted_root_target = self._targets_dir / "trusted_root.json" @@ -114,19 +102,24 @@ def __init__(self, url: str, offline: bool = False) -> None: _logger.debug(f"TUF metadata: {self._metadata_dir}") _logger.debug(f"TUF targets cache: {self._targets_dir}") - self._updater: None | Updater = None + self._updater: Updater | None = None if offline: _logger.warning( "TUF repository is loaded in offline mode; updates will not be performed" ) else: # Initialize and update the toplevel TUF metadata + try: + root_json = read_embedded("root.json", rsrc_prefix) + except FileNotFoundError as e: + raise RootError from e self._updater = Updater( metadata_dir=str(self._metadata_dir), metadata_base_url=self._repo_url, target_base_url=parse.urljoin(f"{self._repo_url}/", "targets/"), target_dir=str(self._targets_dir), config=UpdaterConfig(app_user_agent=f"sigstore-python/{__version__}"), + bootstrap=root_json, ) try: self._updater.refresh() diff --git a/sigstore/_store/prod/root.json b/sigstore/_store/prod/root.json index 38f80f940..2a373bd6a 100644 --- a/sigstore/_store/prod/root.json +++ b/sigstore/_store/prod/root.json @@ -1,156 +1,145 @@ { - "signed": { - "_type": "root", - "spec_version": "1.0", - "version": 5, - "expires": "2023-04-18T18:13:43Z", - "keys": { - "25a0eb450fd3ee2bd79218c963dce3f1cc6118badf251bf149f0bd07d5cabe99": { - "keytype": "ecdsa-sha2-nistp256", - "scheme": "ecdsa-sha2-nistp256", - "keyid_hash_algorithms": [ - "sha256", - "sha512" - ], - "keyval": { - "public": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEEXsz3SZXFb8jMV42j6pJlyjbjR8K\nN3Bwocexq6LMIb5qsWKOQvLN16NUefLc4HswOoumRsVVaajSpQS6fobkRw==\n-----END PUBLIC KEY-----\n" - } - }, - "2e61cd0cbf4a8f45809bda9f7f78c0d33ad11842ff94ae340873e2664dc843de": { - "keytype": "ecdsa-sha2-nistp256", - "scheme": "ecdsa-sha2-nistp256", - "keyid_hash_algorithms": [ - "sha256", - "sha512" - ], - "keyval": { - "public": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE0ghrh92Lw1Yr3idGV5WqCtMDB8Cx\n+D8hdC4w2ZLNIplVRoVGLskYa3gheMyOjiJ8kPi15aQ2//7P+oj7UvJPGw==\n-----END PUBLIC KEY-----\n" - } - }, - "45b283825eb184cabd582eb17b74fc8ed404f68cf452acabdad2ed6f90ce216b": { - "keytype": "ecdsa-sha2-nistp256", - "scheme": "ecdsa-sha2-nistp256", - "keyid_hash_algorithms": [ - "sha256", - "sha512" - ], - "keyval": { - "public": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAELrWvNt94v4R085ELeeCMxHp7PldF\n0/T1GxukUh2ODuggLGJE0pc1e8CSBf6CS91Fwo9FUOuRsjBUld+VqSyCdQ==\n-----END PUBLIC KEY-----\n" - } - }, - "7f7513b25429a64473e10ce3ad2f3da372bbdd14b65d07bbaf547e7c8bbbe62b": { - "keytype": "ecdsa-sha2-nistp256", - "scheme": "ecdsa-sha2-nistp256", - "keyid_hash_algorithms": [ - "sha256", - "sha512" - ], - "keyval": { - "public": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEinikSsAQmYkNeH5eYq/CnIzLaacO\nxlSaawQDOwqKy/tCqxq5xxPSJc21K4WIhs9GyOkKfzueY3GILzcMJZ4cWw==\n-----END PUBLIC KEY-----\n" - } - }, - "e1863ba02070322ebc626dcecf9d881a3a38c35c3b41a83765b6ad6c37eaec2a": { - "keytype": "ecdsa-sha2-nistp256", - "scheme": "ecdsa-sha2-nistp256", - "keyid_hash_algorithms": [ - "sha256", - "sha512" - ], - "keyval": { - "public": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEWRiGr5+j+3J5SsH+Ztr5nE2H2wO7\nBV+nO3s93gLca18qTOzHY1oWyAGDykMSsGTUBSt9D+An0KfKsD2mfSM42Q==\n-----END PUBLIC KEY-----\n" - } - }, - "f5312f542c21273d9485a49394386c4575804770667f2ddb59b3bf0669fddd2f": { - "keytype": "ecdsa-sha2-nistp256", - "scheme": "ecdsa-sha2-nistp256", - "keyid_hash_algorithms": [ - "sha256", - "sha512" - ], - "keyval": { - "public": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEzBzVOmHCPojMVLSI364WiiV8NPrD\n6IgRxVliskz/v+y3JER5mcVGcONliDcWMC5J2lfHmjPNPhb4H7xm8LzfSA==\n-----END PUBLIC KEY-----\n" - } - }, - "ff51e17fcf253119b7033f6f57512631da4a0969442afcf9fc8b141c7f2be99c": { - "keytype": "ecdsa-sha2-nistp256", - "scheme": "ecdsa-sha2-nistp256", - "keyid_hash_algorithms": [ - "sha256", - "sha512" - ], - "keyval": { - "public": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEy8XKsmhBYDI8Jc0GwzBxeKax0cm5\nSTKEU65HPFunUn41sT8pi0FjM4IkHz/YUmwmLUO0Wt7lxhj6BkLIK4qYAw==\n-----END PUBLIC KEY-----\n" - } - } - }, - "roles": { - "root": { - "keyids": [ - "ff51e17fcf253119b7033f6f57512631da4a0969442afcf9fc8b141c7f2be99c", - "25a0eb450fd3ee2bd79218c963dce3f1cc6118badf251bf149f0bd07d5cabe99", - "f5312f542c21273d9485a49394386c4575804770667f2ddb59b3bf0669fddd2f", - "7f7513b25429a64473e10ce3ad2f3da372bbdd14b65d07bbaf547e7c8bbbe62b", - "2e61cd0cbf4a8f45809bda9f7f78c0d33ad11842ff94ae340873e2664dc843de" - ], - "threshold": 3 - }, - "snapshot": { - "keyids": [ - "45b283825eb184cabd582eb17b74fc8ed404f68cf452acabdad2ed6f90ce216b" - ], - "threshold": 1 - }, - "targets": { - "keyids": [ - "ff51e17fcf253119b7033f6f57512631da4a0969442afcf9fc8b141c7f2be99c", - "25a0eb450fd3ee2bd79218c963dce3f1cc6118badf251bf149f0bd07d5cabe99", - "f5312f542c21273d9485a49394386c4575804770667f2ddb59b3bf0669fddd2f", - "7f7513b25429a64473e10ce3ad2f3da372bbdd14b65d07bbaf547e7c8bbbe62b", - "2e61cd0cbf4a8f45809bda9f7f78c0d33ad11842ff94ae340873e2664dc843de" - ], - "threshold": 3 - }, - "timestamp": { - "keyids": [ - "e1863ba02070322ebc626dcecf9d881a3a38c35c3b41a83765b6ad6c37eaec2a" - ], - "threshold": 1 - } - }, - "consistent_snapshot": true - }, - "signatures": [ - { - "keyid": "ff51e17fcf253119b7033f6f57512631da4a0969442afcf9fc8b141c7f2be99c", - "sig": "3045022100fc1c2be509ce50ea917bbad1d9efe9d96c8c2ebea04af2717aa3d9c6fe617a75022012eef282a19f2d8bd4818aa333ef48a06489f49d4d34a20b8fe8fc867bb25a7a" - }, - { - "keyid": "25a0eb450fd3ee2bd79218c963dce3f1cc6118badf251bf149f0bd07d5cabe99", - "sig": "30450221008a4392ae5057fc00778b651e61fea244766a4ae58db84d9f1d3810720ab0f3b702207c49e59e8031318caf02252ecea1281cecc1e5986c309a9cef61f455ecf7165d" - }, - { - "keyid": "7f7513b25429a64473e10ce3ad2f3da372bbdd14b65d07bbaf547e7c8bbbe62b", - "sig": "3046022100da1b8dc5d53aaffbbfac98de3e23ee2d2ad3446a7bed09fac0f88bae19be2587022100b681c046afc3919097dfe794e0d819be891e2e850aade315bec06b0c4dea221b" - }, - { - "keyid": "2e61cd0cbf4a8f45809bda9f7f78c0d33ad11842ff94ae340873e2664dc843de", - "sig": "3046022100b534e0030e1b271133ecfbdf3ba9fbf3becb3689abea079a2150afbb63cdb7c70221008c39a718fd9495f249b4ab8788d5b9dc269f0868dbe38b272f48207359d3ded9" - }, - { - "keyid": "2f64fb5eac0cf94dd39bb45308b98920055e9a0d8e012a7220787834c60aef97", - "sig": "3045022100fc1c2be509ce50ea917bbad1d9efe9d96c8c2ebea04af2717aa3d9c6fe617a75022012eef282a19f2d8bd4818aa333ef48a06489f49d4d34a20b8fe8fc867bb25a7a" - }, - { - "keyid": "eaf22372f417dd618a46f6c627dbc276e9fd30a004fc94f9be946e73f8bd090b", - "sig": "30450221008a4392ae5057fc00778b651e61fea244766a4ae58db84d9f1d3810720ab0f3b702207c49e59e8031318caf02252ecea1281cecc1e5986c309a9cef61f455ecf7165d" - }, - { - "keyid": "f505595165a177a41750a8e864ed1719b1edfccd5a426fd2c0ffda33ce7ff209", - "sig": "3046022100da1b8dc5d53aaffbbfac98de3e23ee2d2ad3446a7bed09fac0f88bae19be2587022100b681c046afc3919097dfe794e0d819be891e2e850aade315bec06b0c4dea221b" - }, - { - "keyid": "75e867ab10e121fdef32094af634707f43ddd79c6bab8ad6c5ab9f03f4ea8c90", - "sig": "3046022100b534e0030e1b271133ecfbdf3ba9fbf3becb3689abea079a2150afbb63cdb7c70221008c39a718fd9495f249b4ab8788d5b9dc269f0868dbe38b272f48207359d3ded9" - } - ] + "signatures": [ + { + "keyid": "6f260089d5923daf20166ca657c543af618346ab971884a99962b01988bbe0c3", + "sig": "" + }, + { + "keyid": "e71a54d543835ba86adad9460379c7641fb8726d164ea766801a1c522aba7ea2", + "sig": "3045022100b0bcf189ce1b93e7db9649d5be512a1880c0e358870e3933e426c5afb8a4061002206d214bd79b09f458ccc521a290aa960c417014fc16e606f82091b5e31814886a" + }, + { + "keyid": "22f4caec6d8e6f9555af66b3d4c3cb06a3bb23fdc7e39c916c61f462e6f52b06", + "sig": "" + }, + { + "keyid": "61643838125b440b40db6942f5cb5a31c0dc04368316eb2aaa58b95904a58222", + "sig": "3045022100a9b9e294ec21b62dfca6a16a19d084182c12572e33d9c4dcab5317fa1e8a459d022069f68e55ea1f95c5a367aac7a61a65757f93da5a006a5f4d1cf995be812d7602" + }, + { + "keyid": "a687e5bf4fab82b0ee58d46e05c9535145a2c9afb458f43d42b45ca0fdce2a70", + "sig": "30440220781178ec3915cb16aca757d40e28435ac5378d6b487acb111d1eeb339397f79a0220781cce48ae46f9e47b97a8414fcf466a986726a5896c72a0e4aba3162cb826dd" + } + ], + "signed": { + "_type": "root", + "consistent_snapshot": true, + "expires": "2025-08-19T14:33:09Z", + "keys": { + "0c87432c3bf09fd99189fdc32fa5eaedf4e4a5fac7bab73fa04a2e0fc64af6f5": { + "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/cryptoKeyVersions/1" + }, + "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" + }, + "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": [ + "0c87432c3bf09fd99189fdc32fa5eaedf4e4a5fac7bab73fa04a2e0fc64af6f5" + ], + "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": [ + "0c87432c3bf09fd99189fdc32fa5eaedf4e4a5fac7bab73fa04a2e0fc64af6f5" + ], + "threshold": 1, + "x-tuf-on-ci-expiry-period": 7, + "x-tuf-on-ci-signing-period": 6 + } + }, + "spec_version": "1.0", + "version": 12, + "x-tuf-on-ci-expiry-period": 197, + "x-tuf-on-ci-signing-period": 46 + } } \ No newline at end of file diff --git a/sigstore/_store/prod/trusted_root.json b/sigstore/_store/prod/trusted_root.json index bb4e6fcd8..b8706cb3e 100644 --- a/sigstore/_store/prod/trusted_root.json +++ b/sigstore/_store/prod/trusted_root.json @@ -44,10 +44,10 @@ "certChain": { "certificates": [ { - "rawBytes": "MIIB9zCCAXygAwIBAgIUALZNAPFdxHPwjeDloDwyYChAO/4wCgYIKoZIzj0EAwMwKjEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MREwDwYDVQQDEwhzaWdzdG9yZTAeFw0yMTEwMDcxMzU2NTlaFw0zMTEwMDUxMzU2NThaMCoxFTATBgNVBAoTDHNpZ3N0b3JlLmRldjERMA8GA1UEAxMIc2lnc3RvcmUwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAT7XeFT4rb3PQGwS4IajtLk3/OlnpgangaBclYpsYBr5i+4ynB07ceb3LP0OIOZdxexX69c5iVuyJRQ+Hz05yi+UF3uBWAlHpiS5sh0+H2GHE7SXrk1EC5m1Tr19L9gg92jYzBhMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRYwB5fkUWlZql6zJChkyLQKsXF+jAfBgNVHSMEGDAWgBRYwB5fkUWlZql6zJChkyLQKsXF+jAKBggqhkjOPQQDAwNpADBmAjEAj1nHeXZp+13NWBNa+EDsDP8G1WWg1tCMWP/WHPqpaVo0jhsweNFZgSs0eE7wYI4qAjEA2WB9ot98sIkoF3vZYdd3/VtWB5b9TNMea7Ix/stJ5TfcLLeABLE4BNJOsQ4vnBHJ" + "rawBytes": "MIICGjCCAaGgAwIBAgIUALnViVfnU0brJasmRkHrn/UnfaQwCgYIKoZIzj0EAwMwKjEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MREwDwYDVQQDEwhzaWdzdG9yZTAeFw0yMjA0MTMyMDA2MTVaFw0zMTEwMDUxMzU2NThaMDcxFTATBgNVBAoTDHNpZ3N0b3JlLmRldjEeMBwGA1UEAxMVc2lnc3RvcmUtaW50ZXJtZWRpYXRlMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE8RVS/ysH+NOvuDZyPIZtilgUF9NlarYpAd9HP1vBBH1U5CV77LSS7s0ZiH4nE7Hv7ptS6LvvR/STk798LVgMzLlJ4HeIfF3tHSaexLcYpSASr1kS0N/RgBJz/9jWCiXno3sweTAOBgNVHQ8BAf8EBAMCAQYwEwYDVR0lBAwwCgYIKwYBBQUHAwMwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQU39Ppz1YkEZb5qNjpKFWixi4YZD8wHwYDVR0jBBgwFoAUWMAeX5FFpWapesyQoZMi0CrFxfowCgYIKoZIzj0EAwMDZwAwZAIwPCsQK4DYiZYDPIaDi5HFKnfxXx6ASSVmERfsynYBiX2X6SJRnZU84/9DZdnFvvxmAjBOt6QpBlc4J/0DxvkTCqpclvziL6BCCPnjdlIB3Pu3BxsPmygUY7Ii2zbdCdliiow=" }, { - "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" } ] }, @@ -86,6 +86,5 @@ "keyId": "3T0wasbHETJjGR4cmWc3AqJKXrjePK3/h4pygC8p7o4=" } } - ], - "timestampAuthorities": [] + ] } diff --git a/sigstore/_utils.py b/sigstore/_utils.py index 86b1ccdc5..906c77213 100644 --- a/sigstore/_utils.py +++ b/sigstore/_utils.py @@ -21,7 +21,7 @@ import base64 import hashlib import sys -from typing import IO, NewType, Type, Union +from typing import IO, NewType, Union from cryptography.hazmat.primitives import serialization from cryptography.hazmat.primitives.asymmetric import ec, rsa @@ -45,7 +45,7 @@ PublicKey = Union[rsa.RSAPublicKey, ec.EllipticCurvePublicKey] -PublicKeyTypes = Union[Type[rsa.RSAPublicKey], Type[ec.EllipticCurvePublicKey]] +PublicKeyTypes = Union[type[rsa.RSAPublicKey], type[ec.EllipticCurvePublicKey]] HexStr = NewType("HexStr", str) """ @@ -187,10 +187,10 @@ def _sha256_streaming(io: IO[bytes]) -> bytes: # of systems in terms of minimizing syscall overhead. view = memoryview(bytearray(128 * 1024)) - nbytes = io.readinto(view) # type: ignore + nbytes = io.readinto(view) # type: ignore[attr-defined] while nbytes: sha256.update(view[:nbytes]) - nbytes = io.readinto(view) # type: ignore + nbytes = io.readinto(view) # type: ignore[attr-defined] return sha256.digest() @@ -242,7 +242,7 @@ def cert_is_ca(cert: Certificate) -> bool: "invalid X.509 certificate: non-critical BasicConstraints in CA" ) - ca = basic_constraints.value.ca # type: ignore + ca = basic_constraints.value.ca # type: ignore[attr-defined] except ExtensionNotFound: # No BasicConstrains means that this can't possibly be a CA. return False @@ -250,7 +250,7 @@ def cert_is_ca(cert: Certificate) -> bool: key_cert_sign = False try: key_usage = cert.extensions.get_extension_for_oid(ExtensionOID.KEY_USAGE) - key_cert_sign = key_usage.value.key_cert_sign # type: ignore + key_cert_sign = key_usage.value.key_cert_sign # type: ignore[attr-defined] except ExtensionNotFound: raise VerificationError("invalid X.509 certificate: missing KeyUsage") @@ -322,7 +322,7 @@ def cert_is_leaf(cert: Certificate) -> bool: return False key_usage = cert.extensions.get_extension_for_oid(ExtensionOID.KEY_USAGE) - digital_signature = key_usage.value.digital_signature # type: ignore + digital_signature = key_usage.value.digital_signature # type: ignore[attr-defined] if not digital_signature: raise VerificationError( @@ -337,6 +337,6 @@ def cert_is_leaf(cert: Certificate) -> bool: ExtensionOID.EXTENDED_KEY_USAGE ) - return ExtendedKeyUsageOID.CODE_SIGNING in extended_key_usage.value # type: ignore + return ExtendedKeyUsageOID.CODE_SIGNING in extended_key_usage.value # type: ignore[operator] except ExtensionNotFound: raise VerificationError("invalid X.509 certificate: missing ExtendedKeyUsage") diff --git a/sigstore/dsse/__init__.py b/sigstore/dsse/__init__.py index 0cc1136e5..ec9457a86 100644 --- a/sigstore/dsse/__init__.py +++ b/sigstore/dsse/__init__.py @@ -19,7 +19,7 @@ from __future__ import annotations import logging -from typing import Any, Dict, List, Literal, Optional, Union +from typing import Any, Literal, Optional from cryptography.exceptions import InvalidSignature from cryptography.hazmat.primitives import hashes @@ -34,14 +34,7 @@ _logger = logging.getLogger(__name__) -Digest = Union[ - Literal["sha256"], - Literal["sha384"], - Literal["sha512"], - Literal["sha3_256"], - Literal["sha3_384"], - Literal["sha3_512"], -] +Digest = Literal["sha256", "sha384", "sha512", "sha3_256", "sha3_384", "sha3_512"] """ NOTE: in-toto's DigestSet contains all kinds of hash algorithms that we intentionally do not support. This model is limited to common members of the @@ -50,7 +43,7 @@ See: """ -DigestSet = RootModel[Dict[Digest, str]] +DigestSet = RootModel[dict[Digest, str]] """ An internal validation model for in-toto subject digest sets. """ @@ -73,9 +66,9 @@ class _Statement(BaseModel): model_config = ConfigDict(populate_by_name=True) type_: Literal["https://in-toto.io/Statement/v1"] = Field(..., alias="_type") - subjects: List[Subject] = Field(..., min_length=1, alias="subject") + subjects: list[Subject] = Field(..., min_length=1, alias="subject") predicate_type: StrictStr = Field(..., alias="predicateType") - predicate: Optional[Dict[str, Any]] = Field(None, alias="predicate") + predicate: Optional[dict[str, Any]] = Field(None, alias="predicate") class Statement: @@ -141,9 +134,9 @@ class StatementBuilder: def __init__( self, - subjects: Optional[List[Subject]] = None, + subjects: Optional[list[Subject]] = None, predicate_type: Optional[str] = None, - predicate: Optional[Dict[str, Any]] = None, + predicate: Optional[dict[str, Any]] = None, ): """ Create a new `StatementBuilder`. diff --git a/sigstore/dsse/_predicate.py b/sigstore/dsse/_predicate.py index 77d2423f0..4d9fb825a 100644 --- a/sigstore/dsse/_predicate.py +++ b/sigstore/dsse/_predicate.py @@ -17,7 +17,7 @@ """ import enum -from typing import Any, Dict, List, Literal, Optional, TypeVar, Union +from typing import Any, Literal, Optional, Union from pydantic import ( BaseModel, @@ -28,6 +28,7 @@ model_validator, ) from pydantic.alias_generators import to_camel +from typing_extensions import Self from sigstore.dsse import Digest @@ -42,8 +43,8 @@ class PredicateType(str, enum.Enum): # Common models -SourceDigest = Union[Literal["sha1"], Literal["gitCommit"]] -DigestSetSource = RootModel[Dict[Union[Digest, SourceDigest], str]] +SourceDigest = Literal["sha1", "gitCommit"] +DigestSetSource = RootModel[dict[Union[Digest, SourceDigest], str]] """ Same as `dsse.DigestSet` but with `sha1` added. @@ -96,8 +97,8 @@ class Invocation(_SLSAConfigBase): """ config_source: Optional[ConfigSource] = None - parameters: Optional[Dict[str, Any]] = None - environment: Optional[Dict[str, Any]] = None + parameters: Optional[dict[str, Any]] = None + environment: Optional[dict[str, Any]] = None class Completeness(_SLSAConfigBase): @@ -140,14 +141,12 @@ class SLSAPredicateV0_2(Predicate, _SLSAConfigBase): build_type: StrictStr invocation: Optional[Invocation] = None metadata: Optional[Metadata] = None - build_config: Optional[Dict[str, Any]] = None - materials: Optional[List[Material]] = None + build_config: Optional[dict[str, Any]] = None + materials: Optional[list[Material]] = None # Models for SLSA Provenance v1.0 -Self = TypeVar("Self", bound="ResourceDescriptor") - class ResourceDescriptor(_SLSAConfigBase): """ @@ -160,7 +159,7 @@ class ResourceDescriptor(_SLSAConfigBase): content: Optional[StrictBytes] = None download_location: Optional[StrictStr] = None media_type: Optional[StrictStr] = None - annotations: Optional[Dict[StrictStr, Any]] = None + annotations: Optional[dict[StrictStr, Any]] = None @model_validator(mode="after") def check_required_fields(self: Self) -> Self: @@ -181,8 +180,8 @@ class BuilderV1_0(_SLSAConfigBase): """ id: StrictStr - builder_dependencies: Optional[List[ResourceDescriptor]] = None - version: Optional[Dict[StrictStr, StrictStr]] = None + builder_dependencies: Optional[list[ResourceDescriptor]] = None + version: Optional[dict[StrictStr, StrictStr]] = None class BuildMetadata(_SLSAConfigBase): @@ -202,7 +201,7 @@ class RunDetails(_SLSAConfigBase): builder: BuilderV1_0 metadata: Optional[BuildMetadata] = None - byproducts: Optional[List[ResourceDescriptor]] = None + byproducts: Optional[list[ResourceDescriptor]] = None class BuildDefinition(_SLSAConfigBase): @@ -211,9 +210,9 @@ class BuildDefinition(_SLSAConfigBase): """ build_type: StrictStr - external_parameters: Dict[StrictStr, Any] - internal_parameters: Optional[Dict[str, Any]] = None - resolved_dependencies: Optional[List[ResourceDescriptor]] = None + external_parameters: dict[StrictStr, Any] + internal_parameters: Optional[dict[str, Any]] = None + resolved_dependencies: Optional[list[ResourceDescriptor]] = None class SLSAPredicateV1_0(Predicate, _SLSAConfigBase): diff --git a/sigstore/errors.py b/sigstore/errors.py index 2a8838ff1..9cdbcc188 100644 --- a/sigstore/errors.py +++ b/sigstore/errors.py @@ -17,8 +17,9 @@ """ import sys +from collections.abc import Mapping from logging import Logger -from typing import Any, Mapping +from typing import Any class Error(Exception): @@ -106,7 +107,7 @@ class MetadataError(Error): def diagnostics(self) -> str: """Returns diagnostics for the error.""" - return f"""{str(self)}.""" + return f"""{self}.""" class RootError(Error): diff --git a/sigstore/models.py b/sigstore/models.py index e9693cc9f..674949cd7 100644 --- a/sigstore/models.py +++ b/sigstore/models.py @@ -23,7 +23,7 @@ import typing from enum import Enum from textwrap import dedent -from typing import Any, List, Optional +from typing import Any, Optional import rfc8785 from cryptography.hazmat.primitives.serialization import Encoding @@ -87,7 +87,7 @@ class LogInclusionProof(BaseModel): model_config = ConfigDict(populate_by_name=True) checkpoint: StrictStr = Field(..., alias="checkpoint") - hashes: List[StrictStr] = Field(..., alias="hashes") + hashes: list[StrictStr] = Field(..., alias="hashes") log_index: StrictInt = Field(..., alias="logIndex") root_hash: StrictStr = Field(..., alias="rootHash") tree_size: StrictInt = Field(..., alias="treeSize") @@ -623,10 +623,7 @@ def _to_parts( """ content: common_v1.MessageSignature | dsse.Envelope - if self._dsse_envelope: - content = self._dsse_envelope - else: - content = self._inner.message_signature + content = self._dsse_envelope or self._inner.message_signature return (self.signing_certificate, content, self.log_entry) @@ -647,7 +644,7 @@ def _from_parts( cert: Certificate, content: common_v1.MessageSignature | dsse.Envelope, log_entry: LogEntry, - signed_timestamp: Optional[List[TimeStampResponse]] = None, + signed_timestamp: Optional[list[TimeStampResponse]] = None, ) -> Bundle: """ @private diff --git a/sigstore/sign.py b/sigstore/sign.py index 6afc7d74c..550fbf0e6 100644 --- a/sigstore/sign.py +++ b/sigstore/sign.py @@ -40,9 +40,10 @@ import base64 import logging +from collections.abc import Iterator from contextlib import contextmanager from datetime import datetime, timezone -from typing import Iterator, List, Optional +from typing import Optional import cryptography.x509 as x509 import rekor_types @@ -138,7 +139,7 @@ def _signing_cert( else: _logger.debug("Retrieving signed certificate...") - # Build an X.509 Certificiate Signing Request + # Build an X.509 Certificate Signing Request builder = ( x509.CertificateSigningRequestBuilder() .subject_name( @@ -161,21 +162,15 @@ def _signing_cert( certificate_request, self._identity_token ) - # Verify the SCT - sct = certificate_response.sct - cert = certificate_response.cert - chain = certificate_response.chain - verify_sct( - sct, - cert, - chain, + certificate_response.cert, + certificate_response.chain, self._signing_ctx._trusted_root.ct_keyring(KeyringPurpose.SIGN), ) _logger.debug("Successfully verified SCT...") - return cert + return certificate_response.cert def _finalize_sign( self, @@ -312,7 +307,7 @@ def __init__( fulcio: FulcioClient, rekor: RekorClient, trusted_root: TrustedRoot, - tsa_clients: List[TimestampAuthorityClient] | None = None, + tsa_clients: list[TimestampAuthorityClient] | None = None, ): """ Create a new `SigningContext`. diff --git a/sigstore/verify/__init__.py b/sigstore/verify/__init__.py index 3a1c01eec..4a23c7e65 100644 --- a/sigstore/verify/__init__.py +++ b/sigstore/verify/__init__.py @@ -43,6 +43,7 @@ ``` """ +from sigstore.verify import policy, verifier from sigstore.verify.verifier import Verifier __all__ = [ diff --git a/sigstore/verify/policy.py b/sigstore/verify/policy.py index 2941edc24..8fa0b3280 100644 --- a/sigstore/verify/policy.py +++ b/sigstore/verify/policy.py @@ -94,10 +94,8 @@ def verify(self, cert: Certificate) -> None: ext = cert.extensions.get_extension_for_oid(self.oid).value except ExtensionNotFound: raise VerificationError( - ( - f"Certificate does not contain {self.__class__.__name__} " - f"({self.oid.dotted_string}) extension" - ) + f"Certificate does not contain {self.__class__.__name__} " + f"({self.oid.dotted_string}) extension" ) # NOTE(ww): mypy is confused by the `Extension[ExtensionType]` returned @@ -105,10 +103,8 @@ def verify(self, cert: Certificate) -> None: ext_value = ext.value.decode() # type: ignore[attr-defined] if ext_value != self._value: raise VerificationError( - ( - f"Certificate's {self.__class__.__name__} does not match " - f"(got '{ext_value}', expected '{self._value}')" - ) + f"Certificate's {self.__class__.__name__} does not match " + f"(got '{ext_value}', expected '{self._value}')" ) @@ -129,10 +125,8 @@ def verify(self, cert: Certificate) -> None: ext = cert.extensions.get_extension_for_oid(self.oid).value except ExtensionNotFound: raise VerificationError( - ( - f"Certificate does not contain {self.__class__.__name__} " - f"({self.oid.dotted_string}) extension" - ) + f"Certificate does not contain {self.__class__.__name__} " + f"({self.oid.dotted_string}) extension" ) # NOTE(ww): mypy is confused by the `Extension[ExtensionType]` returned @@ -140,10 +134,8 @@ def verify(self, cert: Certificate) -> None: ext_value = der_decode(ext.value, UTF8String)[0].decode() # type: ignore[attr-defined] if ext_value != self._value: raise VerificationError( - ( - f"Certificate's {self.__class__.__name__} does not match " - f"(got {ext_value}, expected {self._value})" - ) + f"Certificate's {self.__class__.__name__} does not match " + f"(got {ext_value}, expected {self._value})" ) diff --git a/sigstore/verify/verifier.py b/sigstore/verify/verifier.py index 59437caf1..b782f969c 100644 --- a/sigstore/verify/verifier.py +++ b/sigstore/verify/verifier.py @@ -21,7 +21,7 @@ import base64 import logging from datetime import datetime, timezone -from typing import List, cast +from typing import cast import rekor_types from cryptography.exceptions import InvalidSignature @@ -43,7 +43,6 @@ from sigstore._internal.rekor import _hashedrekord_from_parts from sigstore._internal.rekor.client import RekorClient from sigstore._internal.sct import ( - _get_precertificate_signed_certificate_timestamps, verify_sct, ) from sigstore._internal.timestamp import TimestampSource, TimestampVerificationResult @@ -77,11 +76,11 @@ def __init__(self, *, rekor: RekorClient, trusted_root: TrustedRoot): `rekor` is a `RekorClient` capable of connecting to a Rekor instance containing logs for the file(s) being verified. - `fulcio_certificate_chain` is a list of PEM-encoded X.509 certificates, - establishing the trust chain for the signing certificate and signature. + `trusted_root` is the `TrustedRoot` object containing the root of trust + for the verification process. """ self._rekor = rekor - self._fulcio_certificate_chain: List[X509] = [ + self._fulcio_certificate_chain: list[X509] = [ X509.from_cryptography(parent_cert) for parent_cert in trusted_root.get_fulcio_certs() ] @@ -91,6 +90,10 @@ def __init__(self, *, rekor: RekorClient, trusted_root: TrustedRoot): def production(cls, *, offline: bool = False) -> Verifier: """ Return a `Verifier` instance configured against Sigstore's production-level services. + + `offline` controls the Trusted Root refresh behavior: if `True`, + the verifier uses the Trusted Root in the local TUF cache. If `False`, + a TUF repository refresh is attempted. """ return cls( rekor=RekorClient.production(), @@ -101,6 +104,10 @@ def production(cls, *, offline: bool = False) -> Verifier: def staging(cls, *, offline: bool = False) -> Verifier: """ Return a `Verifier` instance configured against Sigstore's staging-level services. + + `offline` controls the Trusted Root refresh behavior: if `True`, + the verifier uses the Trusted Root in the local TUF cache. If `False`, + a TUF repository refresh is attempted. """ return cls( rekor=RekorClient.staging(), @@ -167,7 +174,7 @@ def _verify_signed_timestamp( def _verify_timestamp_authority( self, bundle: Bundle - ) -> List[TimestampVerificationResult]: + ) -> list[TimestampVerificationResult]: """ Verify that the given bundle has been timestamped by a trusted timestamp authority and that the timestamp is valid. @@ -188,14 +195,17 @@ def _verify_timestamp_authority( # The Signer sends a hash of the signature as the messageImprint in a TimeStampReq # to the Timestamping Service signature_hash = sha256_digest(bundle.signature).digest - verified_timestamps = [] - for tsr in timestamp_responses: - if verified_timestamp := self._verify_signed_timestamp(tsr, signature_hash): - verified_timestamps.append(verified_timestamp) + verified_timestamps = [ + verified_timestamp + for tsr in timestamp_responses + if ( + verified_timestamp := self._verify_signed_timestamp(tsr, signature_hash) + ) + ] return verified_timestamps - def _establish_time(self, bundle: Bundle) -> List[TimestampVerificationResult]: + def _establish_time(self, bundle: Bundle) -> list[TimestampVerificationResult]: """ Establish the time for bundle verification. @@ -243,7 +253,7 @@ def _establish_time(self, bundle: Bundle) -> List[TimestampVerificationResult]: def _verify_chain_at_time( self, certificate: X509, timestamp_result: TimestampVerificationResult - ) -> List[X509]: + ) -> list[X509]: """ Verify the validity of the certificate chain at the given time. @@ -339,10 +349,8 @@ def _verify_common_signing_cert( chain = self._verify_chain_at_time(cert_ossl, vts) # (2): verify the signing certificate's SCT. - sct = _get_precertificate_signed_certificate_timestamps(cert)[0] try: verify_sct( - sct, cert, [parent_cert.to_cryptography() for parent_cert in chain], self._trusted_root.ct_keyring(KeyringPurpose.VERIFY), diff --git a/test/assets/x509/build-testcases.py b/test/assets/x509/build-testcases.py old mode 100644 new mode 100755 diff --git a/test/conftest.py b/test/conftest.py index 349e35ed3..e8cb44f7f 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -55,12 +55,10 @@ def _has_oidc_id(): # We also skip when the repo isn't our own, since downstream # regression testers (e.g. PyCA Cryptography) don't necessarily # want to give our unit tests access to an OIDC identity. - if ( - os.getenv("GITHUB_REPOSITORY") != "sigstore/sigstore-python" - or os.getenv("GITHUB_EVENT_NAME") == "pull_request" - ): - return False - return True + return ( + os.getenv("GITHUB_REPOSITORY") == "sigstore/sigstore-python" + and os.getenv("GITHUB_EVENT_NAME") != "pull_request" + ) except AmbientCredentialError: # If ambient credential detection raises, then we *are* in an ambient # environment but one that's been configured incorrectly. We diff --git a/test/integration/cli/test_attest.py b/test/integration/cli/test_attest.py index db41ee33a..da662912c 100644 --- a/test/integration/cli/test_attest.py +++ b/test/integration/cli/test_attest.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. from pathlib import Path -from typing import List, Optional +from typing import Optional import pytest @@ -28,7 +28,7 @@ def get_cli_params( artifact_path: Path, overwrite: bool = False, bundle_path: Optional[Path] = None, -) -> List[str]: +) -> list[str]: cli_params = [ "--staging", "attest", @@ -81,7 +81,7 @@ def test_attest_success_default_output_bundle( captures = capsys.readouterr() assert captures.out.endswith( - f"Sigstore bundle written to {str(expected_output_bundle)}\n" + f"Sigstore bundle written to {expected_output_bundle}\n" ) @@ -108,7 +108,7 @@ def test_attest_success_custom_output_bundle( assert output_bundle.exists() captures = capsys.readouterr() - assert captures.out.endswith(f"Sigstore bundle written to {str(output_bundle)}\n") + assert captures.out.endswith(f"Sigstore bundle written to {output_bundle}\n") @pytest.mark.staging @@ -142,14 +142,14 @@ def test_attest_overwrite_existing_bundle( assert output_bundle.exists() captures = capsys.readouterr() assert captures.err.endswith( - f"Refusing to overwrite outputs without --overwrite: {str(output_bundle)}\n" + f"Refusing to overwrite outputs without --overwrite: {output_bundle}\n" ) cli_params.append("--overwrite") sigstore(*cli_params) assert output_bundle.exists() - assert captures.out.endswith(f"Sigstore bundle written to {str(output_bundle)}\n") + assert captures.out.endswith(f"Sigstore bundle written to {output_bundle}\n") def test_attest_invalid_predicate_type(capsys, sigstore, asset_integration, tmp_path): diff --git a/test/integration/cli/test_sign.py b/test/integration/cli/test_sign.py index 209e8d715..4d0953db7 100644 --- a/test/integration/cli/test_sign.py +++ b/test/integration/cli/test_sign.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. from pathlib import Path -from typing import List, Optional +from typing import Optional import pytest @@ -22,14 +22,14 @@ def get_cli_params( - artifact_paths: List[Path], + artifact_paths: list[Path], overwrite: bool = False, no_default_files: bool = False, output_directory: Optional[Path] = None, bundle_path: Optional[Path] = None, signature_path: Optional[Path] = None, certificate_path: Optional[Path] = None, -) -> List[str]: +) -> list[str]: cli_params = ["--staging", "sign"] if output_directory is not None: cli_params.extend(["--output-directory", str(output_directory)]) @@ -77,7 +77,7 @@ def test_sign_success_default_output_bundle(capsys, sigstore, asset_integration) captures = capsys.readouterr() assert captures.out.endswith( - f"Sigstore bundle written to {str(expected_output_bundle)}\n" + f"Sigstore bundle written to {expected_output_bundle}\n" ) @@ -104,7 +104,7 @@ def test_sign_success_custom_outputs(capsys, sigstore, asset_integration, tmp_pa captures = capsys.readouterr() assert captures.out.endswith( - f"Signature written to {str(output_signature)}\nCertificate written to {str(output_cert)}\nSigstore bundle written to {str(output_bundle)}\n" + f"Signature written to {output_signature}\nCertificate written to {output_cert}\nSigstore bundle written to {output_bundle}\n" ) @@ -125,7 +125,7 @@ def test_sign_success_custom_output_dir(capsys, sigstore, asset_integration, tmp captures = capsys.readouterr() assert captures.out.endswith( - f"Sigstore bundle written to {str(expected_output_bundle)}\n" + f"Sigstore bundle written to {expected_output_bundle}\n" ) @@ -151,7 +151,7 @@ def test_sign_success_no_default_files(capsys, sigstore, asset_integration, tmp_ captures = capsys.readouterr() assert captures.out.endswith( - f"Signature written to {str(output_signature)}\nCertificate written to {str(output_cert)}\n" + f"Signature written to {output_signature}\nCertificate written to {output_cert}\n" ) @@ -189,7 +189,7 @@ def test_sign_overwrite_existing_bundle(capsys, sigstore, asset_integration): captures = capsys.readouterr() assert captures.err.endswith( - f"Refusing to overwrite outputs without --overwrite: {str(expected_output_bundle)}\n" + f"Refusing to overwrite outputs without --overwrite: {expected_output_bundle}\n" ) expected_output_bundle.unlink() diff --git a/test/unit/conftest.py b/test/unit/conftest.py index d96e32b37..4d1b2331c 100644 --- a/test/unit/conftest.py +++ b/test/unit/conftest.py @@ -18,9 +18,10 @@ import os import re from collections import defaultdict +from collections.abc import Iterator from io import BytesIO from pathlib import Path -from typing import Callable, Iterator +from typing import Callable from urllib.parse import urlparse import jwt @@ -30,8 +31,7 @@ detect_credential, ) from tuf.api.exceptions import DownloadHTTPError -from tuf.ngclient import FetcherInterface -from tuf.ngclient.updater import requests_fetcher +from tuf.ngclient import FetcherInterface, updater from sigstore._internal import tuf from sigstore._internal.rekor import _hashedrekord_from_parts @@ -156,9 +156,7 @@ def _fetch(self, url: str) -> Iterator[bytes]: failure[filename] += 1 raise DownloadHTTPError("File not found", 404) - monkeypatch.setattr( - requests_fetcher, "RequestsFetcher", lambda app_user_agent: MockFetcher() - ) + monkeypatch.setattr(updater, "Urllib3Fetcher", lambda app_user_agent: MockFetcher()) return success, failure diff --git a/test/unit/internal/test_sct.py b/test/unit/internal/test_sct.py index 55de96e7c..e2a7fa30c 100644 --- a/test/unit/internal/test_sct.py +++ b/test/unit/internal/test_sct.py @@ -48,19 +48,16 @@ def test_pack_digitally_signed_precertificate(precert_bytes_len): _, l1, l2, l3 = struct.unpack("!4c", struct.pack("!I", len(precert_bytes))) data = sct._pack_digitally_signed(mock_sct, cert, issuer_key_hash) - assert ( - data - == ( - b"\x00" # version - b"\x00" # signature type - b"\x00\x00\x00\x00\x00\x00\x04\xd2" # timestamp - b"\x00\x01" # entry type - b"iamapublickeyshatwofivesixdigest" # issuer key hash - + l1 - + l2 - + l3 # tbs cert length - + precert_bytes # tbs cert - + b"\x00\x00" # extensions length - + b"" # extensions - ) + assert data == ( + b"\x00" # version + b"\x00" # signature type + b"\x00\x00\x00\x00\x00\x00\x04\xd2" # timestamp + b"\x00\x01" # entry type + b"iamapublickeyshatwofivesixdigest" # issuer key hash + + l1 + + l2 + + l3 # tbs cert length + + precert_bytes # tbs cert + + b"\x00\x00" # extensions length + + b"" # extensions ) diff --git a/test/unit/internal/test_trust.py b/test/unit/internal/test_trust.py index 65f9872c3..381ab8292 100644 --- a/test/unit/internal/test_trust.py +++ b/test/unit/internal/test_trust.py @@ -80,7 +80,13 @@ def test_trust_root_tuf_caches_and_requests(mock_staging_tuf, tuf_dirs): trust_root = TrustedRoot.staging() # metadata was "downloaded" from staging - expected = ["root.json", "snapshot.json", "targets.json", "timestamp.json"] + expected = [ + "root.json", + "root_history", + "snapshot.json", + "targets.json", + "timestamp.json", + ] assert sorted(os.listdir(data_dir)) == expected # Expect requests of top-level metadata (and 404 for the next root version) @@ -126,9 +132,8 @@ def test_trust_root_tuf_offline(mock_staging_tuf, tuf_dirs): trust_root = TrustedRoot.staging(offline=True) - # Only the embedded root is in local TUF metadata, nothing is downloaded - expected = ["root.json"] - assert sorted(os.listdir(data_dir)) == expected + # local TUF metadata is not initialized, nothing is downloaded + assert not os.path.exists(data_dir) assert reqs == {} assert fail_reqs == {} diff --git a/test/unit/test_models.py b/test/unit/test_models.py index f5f7e1f78..95f297f07 100644 --- a/test/unit/test_models.py +++ b/test/unit/test_models.py @@ -34,7 +34,7 @@ def test_missing_inclusion_proof(self): with pytest.raises(ValueError, match=r"inclusion_proof"): LogEntry( uuid="fake", - body=b64encode("fake".encode()), + body=b64encode(b"fake"), integrated_time=0, log_id="1234", log_index=1, diff --git a/test/unit/test_utils.py b/test/unit/test_utils.py index c5cd862c6..615ec05aa 100644 --- a/test/unit/test_utils.py +++ b/test/unit/test_utils.py @@ -75,7 +75,7 @@ def test_sha256_streaming(size): def test_load_pem_public_key_format(): - keybytes = b"-----BEGIN PUBLIC KEY-----\n" b"bleh\n" b"-----END PUBLIC KEY-----" + keybytes = b"-----BEGIN PUBLIC KEY-----\nbleh\n-----END PUBLIC KEY-----" with pytest.raises( VerificationError, match="could not load PEM-formatted public key" ): diff --git a/test/unit/verify/test_policy.py b/test/unit/verify/test_policy.py index 40ab44d5b..68c41a690 100644 --- a/test/unit/verify/test_policy.py +++ b/test/unit/verify/test_policy.py @@ -95,8 +95,7 @@ def test_certificate_extension_not_found(self): ) reason = re.escape( - "Certificate does not contain OIDCIssuer " - "(1.3.6.1.4.1.57264.1.1) extension" + "Certificate does not contain OIDCIssuer (1.3.6.1.4.1.57264.1.1) extension" ) with pytest.raises(VerificationError, match=reason): policy_.verify(cert_)