diff --git a/.github/actions/upload-coverage/action.yml b/.github/actions/upload-coverage/action.yml index a22e1997..73850940 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@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3 + - uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4.5.0 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 0f9f7511..29011578 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -27,3 +27,14 @@ 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 new file mode 100644 index 00000000..56f2af9d --- /dev/null +++ b/.github/go.mod @@ -0,0 +1,11 @@ +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/ci.yml b/.github/workflows/ci.yml index 142214a5..de62ba21 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -61,7 +61,8 @@ jobs: - name: test (timestamp-authority) if: ${{ matrix.conf.os == 'ubuntu-latest' }} run: | - wget https://github.com/sigstore/timestamp-authority/releases/download/${SIGSTORE_TIMESTAMP}/timestamp-server-linux-amd64 -O /tmp/timestamp-server + SIGSTORE_TIMESTAMP_VERSION=$(grep "github.com/sigstore/timestamp-authority" .github/go.mod | awk '{print $2}') + 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 & @@ -70,8 +71,6 @@ jobs: # 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: - SIGSTORE_TIMESTAMP: "v1.2.3" - name: test (interactive) if: (github.event_name != 'pull_request') || !github.event.pull_request.head.repo.fork diff --git a/.github/workflows/conformance.yml b/.github/workflows/conformance.yml index 73672899..14addb38 100644 --- a/.github/workflows/conformance.yml +++ b/.github/workflows/conformance.yml @@ -24,7 +24,7 @@ jobs: - name: install sigstore-python run: python -m pip install . - - uses: sigstore/sigstore-conformance@6bd1c54e236c9517da56f7344ad16cc00439fe19 # v0.0.13 + - uses: sigstore/sigstore-conformance@b0635d4101f11dbd18a50936568a1f7f55b17760 # v0.0.14 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 10e555a8..3308498a 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -15,9 +15,7 @@ jobs: - uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0 with: - # NOTE: We use 3.10+ typing syntax via future, which pdoc only - # understands if it's actually run with Python 3.10 or newer. - python-version: ">= 3.10" + python-version: "3.x" cache: "pip" cache-dependency-path: pyproject.toml diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a9fa6835..2e7ccc20 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -74,14 +74,14 @@ jobs: done - name: Upload built packages - uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3 + uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4.5.0 with: name: built-packages path: ./dist/ if-no-files-found: warn - name: Upload smoketest-artifacts - uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3 + uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4.5.0 with: name: smoketest-artifacts path: smoketest-artifacts/ @@ -115,7 +115,6 @@ jobs: uses: pypa/gh-action-pypi-publish@67339c736fd9354cd4f8cb0b744f2b82a74b5c70 # v1.12.3 with: packages-dir: built-packages/ - attestations: true release-github: needs: [build, generate-provenance] @@ -131,7 +130,7 @@ jobs: # 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@01570a1f39cb168c169c802c3bceb9e93fb10974 # v2.1.0 + uses: softprops/action-gh-release@7b4da11513bf3f43f9999e90eabced41ab8bb048 # v2.2.0 with: # smoketest-artifacts/ contains the signatures and certificates. files: | diff --git a/.github/workflows/scorecards-analysis.yml b/.github/workflows/scorecards-analysis.yml index 10e19c75..b3b5037e 100644 --- a/.github/workflows/scorecards-analysis.yml +++ b/.github/workflows/scorecards-analysis.yml @@ -44,7 +44,7 @@ jobs: # Upload the results as artifacts (optional). - name: "Upload artifact" - uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3 + uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4.5.0 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@babb554ede22fd5605947329c4d04d8e7a0b8155 # v3.27.7 + uses: github/codeql-action/upload-sarif@df409f7d9260372bd5f19e5b04e83cb3c43714ae # v3.27.9 with: sarif_file: results.sarif diff --git a/.gitignore b/.gitignore index 5bf6416f..6e03bf7e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +.cache/ env/ pip-wheel-metadata/ *.egg-info/ diff --git a/CHANGELOG.md b/CHANGELOG.md index a5c6778e..7104a674 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,14 @@ All versions prior to 0.9.0 are untracked. ## [Unreleased] +## [3.6.1] + +### Fixed + +* Relaxed the transitive dependency on `cryptography` to allow v43 and v44 + to be resolved + ([#1251](https://github.com/sigstore/sigstore-python/pull/1251)) + ## [3.6.0] ### Added @@ -585,7 +593,8 @@ This is a corrective release for [2.1.1]. -[Unreleased]: https://github.com/sigstore/sigstore-python/compare/v3.6.0...HEAD +[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 [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 61032b67..f2fd8258 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,8 @@ SHELL := /bin/bash PY_MODULE := sigstore ALL_PY_SRCS := $(shell find $(PY_MODULE) -name '*.py') \ - $(shell find test -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. VENV ?= env @@ -67,7 +68,8 @@ lint: $(VENV)/pyvenv.cfg ruff check $(ALL_PY_SRCS) && \ mypy $(PY_MODULE) && \ bandit -c pyproject.toml -r $(PY_MODULE) && \ - interrogate --fail-under 100 -c pyproject.toml $(PY_MODULE) + interrogate --fail-under 100 -c pyproject.toml $(PY_MODULE) && \ + python docs/scripts/gen_ref_pages.py --check .PHONY: reformat reformat: $(VENV)/pyvenv.cfg @@ -97,7 +99,8 @@ gen-x509-testcases: $(VENV)/pyvenv.cfg .PHONY: doc doc: $(VENV)/pyvenv.cfg . $(VENV_BIN)/activate && \ - pdoc --output-directory html $(PY_MODULE) + python docs/scripts/gen_ref_pages.py --overwrite && \ + mkdocs build --strict --site-dir html .PHONY: package package: $(VENV)/pyvenv.cfg diff --git a/README.md b/README.md index b92d87ba..fad13d61 100644 --- a/README.md +++ b/README.md @@ -18,21 +18,13 @@ else! * [Features](#features) * [Installation](#installation) - * [GitHub Actions](#github-actions) * [Usage](#usage) * [Signing](#signing) * [Verifying](#verifying) * [Generic identities](#generic-identities) * [Signatures from GitHub Actions](#signatures-from-github-actions) * [Advanced usage](#advanced-usage) -* [Example uses](#example-uses) - * [Signing with ambient credentials](#signing-with-ambient-credentials) - * [Signing with an email identity](#signing-with-an-email-identity) - * [Signing with an explicit identity token](#signing-with-an-explicit-identity-token) - * [Verifying against a bundle](#verifying-against-a-bundle) - * [Offline verification](#offline-verification) - * [Verifying a digest instead of a file](#verifying-a-digest-instead-of-a-file) - * [Verifying signatures from GitHub Actions](#verifying-signatures-from-github-actions) +* [Documentation](#documentation) * [Licensing](#licensing) * [Community](#community) * [Contributing](#contributing) @@ -55,44 +47,17 @@ else! python -m pip install sigstore ``` -Optionally, to install `sigstore` and all its dependencies with [hash-checking mode](https://pip.pypa.io/en/stable/topics/secure-installs/#hash-checking-mode) enabled, run the following: - -```console -python -m pip install -r https://raw.githubusercontent.com/sigstore/sigstore-python/main/install/requirements.txt -``` - -This installs the requirements file located [here](https://github.com/sigstore/sigstore-python/blob/main/install/requirements.txt), which is kept up-to-date. - -### GitHub Actions - -`sigstore-python` has [an official GitHub Action](https://github.com/sigstore/gh-action-sigstore-python)! - -You can install it from the -[GitHub Marketplace](https://github.com/marketplace/actions/gh-action-sigstore-python), or -add it to your CI manually: - -```yaml -jobs: - sigstore-python: - steps: - - uses: sigstore/gh-action-sigstore-python@v3.0.0 - with: - inputs: foo.txt -``` - -See the -[action documentation](https://github.com/sigstore/gh-action-sigstore-python/blob/main/README.md) -for more details and usage examples. +See the [installation](https://sigstore.github.io/sigstore-python/installation) page in the documentation for more +installation options. ## Usage -For Python API usage, see our [documentation](https://sigstore.github.io/sigstore-python/). +For Python API usage, see our [API](https://sigstore.github.io/sigstore-python/api/). -You can run `sigstore` as a standalone program, or via `python -m`: +You can run `sigstore` as a standalone program: ```console sigstore --help -python -m sigstore --help ``` Top-level: @@ -236,12 +201,7 @@ Output options: ### Verifying -#### Generic identities - -This is the most common verification done with `sigstore`, and therefore -the one you probably want: you can use it to verify that a signature was -produced by a particular identity (like `hamilcar@example.com`), as attested -to by a particular OIDC provider (like `https://github.com/login/oauth`). +#### Identities ``` @@ -281,11 +241,6 @@ Verification options: #### Signatures from GitHub Actions -If your signatures are coming from GitHub Actions (e.g., a workflow -that uses its [ambient credentials](#signing-with-ambient-credentials)), -then you can use the `sigstore verify github` subcommand to verify -claims more precisely than `sigstore verify identity` allows: - ``` usage: sigstore verify github [-h] [-v] [--certificate FILE] @@ -330,195 +285,9 @@ Verification options: ``` -## Advanced usage - -### Configuring a custom root of trust ("BYO PKI") - -Apart from the default and "staging" Sigstore instances, `sigstore` also -supports "BYO PKI" setups, where a user maintains their own Sigstore -instance services. - -These are supported via the `--trust-config` flag, which accepts a -JSON-formatted file conforming to the `ClientTrustConfig` message -in the [Sigstore protobuf specs](https://github.com/sigstore/protobuf-specs). -This file configures the entire Sigstore instance state, *including* the URIs -used to access the CA and artifact transparency services as well as the -cryptographic root of trust itself. - -To use a custom client config, prepend `--trust-config` to any `sigstore` -command: - -```console -$ sigstore --trust-config custom.trustconfig.json sign foo.txt -$ sigstore --trust-config custom.trustconfig.json verify identity foo.txt ... -``` - -## Example uses +## Documentation -`sigstore` supports a wide variety of workflows and usages. Some common ones are -provided below. - -### Signing with ambient credentials - -For environments that support OpenID Connect, `sigstore` supports ambient credential -detection. This includes many popular CI platforms and cloud providers. See the full list of -supported environments [here](https://github.com/di/id#supported-environments). - -Sign a single file (`foo.txt`) using an ambient OpenID Connect credential, -saving the bundle to `foo.txt.sigstore.json`: - -```console -$ python -m sigstore sign foo.txt -``` - -### Signing with an email identity - -`sigstore` can use an OAuth2 + OpenID flow to establish an email identity, -allowing you to request signing certificates that attest to control over -that email. - -Sign a single file (`foo.txt`) using the OAuth2 flow, saving the -bundle to `foo.txt.sigstore.json`: - -```console -$ python -m sigstore sign foo.txt -``` - -By default, `sigstore` attempts to do -[ambient credential detection](#signing-with-ambient-credentials), which may preempt -the OAuth2 flow. To force the OAuth2 flow, you can explicitly disable ambient detection: - -```console -$ python -m sigstore sign --oidc-disable-ambient-providers foo.txt -``` - -### Signing with an explicit identity token - -If you can't use an ambient credential or the OAuth2 flow, you can pass a pre-created -identity token directly into `sigstore sign`: - -```console -$ python -m sigstore sign --identity-token YOUR-LONG-JWT-HERE foo.txt -``` - -Note that passing a custom identity token does not circumvent Fulcio's requirements, -namely the Fulcio's supported identity providers and the claims expected within the token. - -### Verifying against a bundle - -By default, `sigstore verify identity` will attempt to find a `.sigstore.json` -or `.sigstore` in the same directory as the file being verified: - -```console -# looks for foo.txt.sigstore.json -$ python -m sigstore verify identity foo.txt \ - --cert-identity 'hamilcar@example.com' \ - --cert-oidc-issuer 'https://github.com/login/oauth' -``` - -Multiple files can be verified at once: - -```console -# looks for {foo,bar}.txt.sigstore.json -$ python -m sigstore verify identity foo.txt bar.txt \ - --cert-identity 'hamilcar@example.com' \ - --cert-oidc-issuer 'https://github.com/login/oauth' -``` - -### Offline verification - -> [!IMPORTANT] -> Because `--offline` disables trust root updates, `sigstore-python` falls back -> to the latest cached trust root or, if none exists, the trust root baked -> into `sigstore-python` itself. Like with any other offline verification, -> this means that users may miss trust root changes (such as new root keys, -> or revocations) unless they separately keep the trust root up-to-date. -> -> Users who need to operationalize offline verification may wish to do this -> by distributing their own trust configuration; see -> [Configuring a custom root of trust](#configuring-a-custom-root-of-trust-byo-pki). - -During verification, there are two kinds of network access that `sigstore-python` -*can* perform: - -1. When verifying against "detached" materials (e.g. separate `.crt` and `.sig` - files), `sigstore-python` can perform an online transparency log lookup. -2. By default, during all verifications, `sigstore-python` will attempt to - refresh the locally cached root of trust via a TUF update. - -When performing bundle verification (i.e. `.sigstore` or `.sigstore.json`), -(1) does not apply. However, (2) can still result in online accesses. - -To perform **fully** offline verification, pass `--offline` to your -`sigstore verify` subcommand: - -```bash -$ python -m sigstore verify identity foo.txt \ - --offline \ - --cert-identity 'hamilcar@example.com' \ - --cert-oidc-issuer 'https://github.com/login/oauth' -``` - -Alternatively, users may choose to bypass TUF entirely by passing -an entire trust configuration to `sigstore-python` via `--trust-config`: - -```bash -$ python -m 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. - -### Verifying a digest instead of a file - -`sigstore-python` supports verifying digests directly, without requiring the artifact to be -present. The digest should be prefixed with the `sha256:` string: - -```console -$ python -m sigstore verify identity sha256:ce8ab2822671752e201ea1e19e8c85e73d497e1c315bfd9c25f380b7625d1691 \ - --cert-identity 'hamilcar@example.com' \ - --cert-oidc-issuer 'https://github.com/login/oauth' - --bundle 'foo.txt.sigstore.json' -``` - -### Verifying signatures from GitHub Actions - -`sigstore verify github` can be used to verify claims specific to signatures coming from GitHub -Actions. `sigstore-python` signs releases via GitHub Actions, so the examples below are working -examples of how you can verify a given `sigstore-python` release. - -When using `sigstore verify github`, you must pass `--cert-identity` or `--repository`, or both. -Unlike `sigstore verify identity`, `--cert-oidc-issuer` is **not** required (since it's -inferred to be GitHub Actions). - -Verifying with `--cert-identity`: - -```console -$ python -m sigstore verify github sigstore-0.10.0-py3-none-any.whl \ - --bundle sigstore-0.10.0-py3-none-any.whl.bundle \ - --cert-identity https://github.com/sigstore/sigstore-python/.github/workflows/release.yml@refs/tags/v0.10.0 -``` - -Verifying with `--repository`: - -```console -$ python -m sigstore verify github sigstore-0.10.0-py3-none-any.whl \ - --bundle sigstore-0.10.0-py3-none-any.whl.bundle \ - --repository sigstore/sigstore-python -``` - -Additional GitHub Actions specific claims can be verified like so: - -```console -$ python -m sigstore verify github sigstore-0.10.0-py3-none-any.whl \ - --bundle sigstore-0.10.0-py3-none-any.whl.bundle \ - --cert-identity https://github.com/sigstore/sigstore-python/.github/workflows/release.yml@refs/tags/v0.10.0 \ - --trigger release \ - --sha 66581529803929c3ccc45334632ccd90f06e0de4 \ - --name Release \ - --repository sigstore/sigstore-python \ - --ref refs/tags/v0.10.0 -``` +`sigstore` documentation is available on [https://sigstore.github.io/sigstore-python](https://sigstore.github.io/sigstore-python) ## Licensing @@ -544,9 +313,3 @@ Everyone interacting with this project is expected to follow the Should you discover any security issues, please refer to sigstore's [security process](https://github.com/sigstore/.github/blob/main/SECURITY.md). - -### SLSA Provenance -This project emits a SLSA provenance on its release! This enables you to verify the integrity -of the downloaded artifacts and ensured that the binary's code really comes from this source code. - -To do so, please follow the instructions [here](https://github.com/slsa-framework/slsa-github-generator#verification-of-provenance). diff --git a/docs/advanced/custom_trust.md b/docs/advanced/custom_trust.md new file mode 100644 index 00000000..87949993 --- /dev/null +++ b/docs/advanced/custom_trust.md @@ -0,0 +1,22 @@ +# Custom Root of Trust + +### Configuring a custom root of trust ("BYO PKI") + +Apart from the default and "staging" Sigstore instances, `sigstore` also +supports "BYO PKI" setups, where a user maintains their own Sigstore +instance services. + +These are supported via the `--trust-config` flag, which accepts a +JSON-formatted file conforming to the `ClientTrustConfig` message +in the [Sigstore protobuf specs](https://github.com/sigstore/protobuf-specs). +This file configures the entire Sigstore instance state, *including* the URIs +used to access the CA and artifact transparency services as well as the +cryptographic root of trust itself. + +To use a custom client config, prepend `--trust-config` to any `sigstore` +command: + +```console +$ sigstore --trust-config custom.trustconfig.json sign foo.txt +$ sigstore --trust-config custom.trustconfig.json verify identity foo.txt ... +``` \ No newline at end of file diff --git a/docs/advanced/offline.md b/docs/advanced/offline.md new file mode 100644 index 00000000..bc107dbc --- /dev/null +++ b/docs/advanced/offline.md @@ -0,0 +1,43 @@ +# Offline Verification + +!!! danger + Because `--offline` disables trust root updates, `sigstore-python` falls back + to the latest cached trust root or, if none exists, the trust root baked + into `sigstore-python` itself. Like with any other offline verification, + this means that users may miss trust root changes (such as new root keys, + or revocations) unless they separately keep the trust root up-to-date. + + 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). + +During verification, there are two kinds of network access that `sigstore-python` +*can* perform: + +1. When verifying against "detached" materials (e.g. separate `.crt` and `.sig` + files), `sigstore-python` can perform an online transparency log lookup. +2. By default, during all verifications, `sigstore-python` will attempt to + refresh the locally cached root of trust via a TUF update. + +When performing bundle verification (i.e. `.sigstore` or `.sigstore.json`), +(1) does not apply. However, (2) can still result in online accesses. + +To perform **fully** offline verification, pass `--offline` to your +`sigstore verify` subcommand: + +```bash +$ sigstore verify identity foo.txt \ + --offline \ + --cert-identity 'hamilcar@example.com' \ + --cert-oidc-issuer 'https://github.com/login/oauth' +``` + +Alternatively, users may choose to bypass TUF entirely by passing +an entire trust configuration to `sigstore-python` via `--trust-config`: + +```bash +$ 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 diff --git a/docs/api/errors.md b/docs/api/errors.md new file mode 100644 index 00000000..81a2bab9 --- /dev/null +++ b/docs/api/errors.md @@ -0,0 +1,2 @@ +:::sigstore.errors + \ No newline at end of file diff --git a/docs/api/hashes.md b/docs/api/hashes.md new file mode 100644 index 00000000..bf00a7f6 --- /dev/null +++ b/docs/api/hashes.md @@ -0,0 +1,2 @@ +:::sigstore.hashes + \ No newline at end of file diff --git a/docs/api/index.md b/docs/api/index.md new file mode 100644 index 00000000..122945b1 --- /dev/null +++ b/docs/api/index.md @@ -0,0 +1,6 @@ +!!! note + + The API reference is automatically generated from the docstrings + +:::sigstore + \ No newline at end of file diff --git a/docs/api/models.md b/docs/api/models.md new file mode 100644 index 00000000..9a75e028 --- /dev/null +++ b/docs/api/models.md @@ -0,0 +1,2 @@ +:::sigstore.models + \ No newline at end of file diff --git a/docs/api/oidc.md b/docs/api/oidc.md new file mode 100644 index 00000000..7a30ccc0 --- /dev/null +++ b/docs/api/oidc.md @@ -0,0 +1,2 @@ +:::sigstore.oidc + \ No newline at end of file diff --git a/docs/api/sign.md b/docs/api/sign.md new file mode 100644 index 00000000..a29710fc --- /dev/null +++ b/docs/api/sign.md @@ -0,0 +1,2 @@ +:::sigstore.sign + \ No newline at end of file diff --git a/docs/api/verify/policy.md b/docs/api/verify/policy.md new file mode 100644 index 00000000..0b6d133b --- /dev/null +++ b/docs/api/verify/policy.md @@ -0,0 +1,2 @@ +:::sigstore.verify.policy + \ No newline at end of file diff --git a/docs/api/verify/verifier.md b/docs/api/verify/verifier.md new file mode 100644 index 00000000..fc002d8b --- /dev/null +++ b/docs/api/verify/verifier.md @@ -0,0 +1,2 @@ +:::sigstore.verify.verifier + \ No newline at end of file diff --git a/docs/assets/images/favicon.png b/docs/assets/images/favicon.png new file mode 100644 index 00000000..b1f05e42 Binary files /dev/null and b/docs/assets/images/favicon.png differ diff --git a/docs/assets/images/logo.png b/docs/assets/images/logo.png new file mode 100644 index 00000000..5519b417 Binary files /dev/null and b/docs/assets/images/logo.png differ diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 00000000..acca7405 --- /dev/null +++ b/docs/index.md @@ -0,0 +1,44 @@ +# Home + +## Introduction + +`sigstore` is a Python tool for generating and verifying [Sigstore] signatures. +You can use it to sign and verify Python package distributions, or anything +else! + +## Features + +* Support for keyless signature generation and verification with [Sigstore](https://www.sigstore.dev/) +* Support for signing with ["ambient" OpenID Connect identities](./signing.md#signing-with-ambient-credentials) +* A comprehensive [CLI](#using-sigstore) and corresponding + [importable Python API](./api/index.md) + +## Installing `sigstore` + +```console +python -m pip install sigstore +``` + +See [installation](./installation.md) for more detailed installation instructions or options. + +## Using `sigstore` + +You can run `sigstore` as a standalone program, or via `python -m`: + +```console +sigstore --help +python -m sigstore --help +``` + +- Use `sigstore` to [sign](./signing.md) +- Use `sigstore` to [verify](./verify.md) + +## SLSA Provenance + +This project emits a [SLSA] provenance on its release! This enables you to verify the integrity +of the downloaded artifacts and ensured that the binary's code really comes from this source code. + +To do so, please follow the instructions [here](https://github.com/slsa-framework/slsa-github-generator#verification-of-provenance). + +[SLSA]: https://slsa.dev/ +[Sigstore]: https://www.sigstore.dev/ \ No newline at end of file diff --git a/docs/installation.md b/docs/installation.md new file mode 100644 index 00000000..51154f19 --- /dev/null +++ b/docs/installation.md @@ -0,0 +1,51 @@ +# Installation + +## With `pip` + +`sigstore` requires Python 3.9 or newer, and can be installed directly via `pip`: + +```console +python -m pip install sigstore +``` + +Optionally, to install `sigstore` and all its dependencies with [hash-checking mode](https://pip.pypa.io/en/stable/topics/secure-installs/#hash-checking-mode) enabled, run the following: + +```console +python -m pip install -r https://raw.githubusercontent.com/sigstore/sigstore-python/main/install/requirements.txt +``` + +This installs the requirements file located [here](https://github.com/sigstore/sigstore-python/blob/main/install/requirements.txt), which is kept up-to-date. + +## With `uv` + +!!! warning + + `sigstore` depends on `betterproto` pre-releases versions, which are by default not resolved by `uv`. + +```console +uv pip install --prerelease=allow sigstore +``` + +`sigstore` can also be used as tool: + +```console +uvx --prerelease=allow sigstore --help +``` + +## GitHub Actions + +`sigstore-python` has [an official GitHub Action](https://github.com/sigstore/gh-action-sigstore-python)! + +You can install it from the [GitHub Marketplace](https://github.com/marketplace/actions/gh-action-sigstore-python), or +add it to your CI manually: + +```yaml +jobs: + sigstore-python: + steps: + - uses: sigstore/gh-action-sigstore-python@v3.0.0 + with: + inputs: foo.txt +``` + +See the [action documentation](https://github.com/sigstore/gh-action-sigstore-python/blob/main/README.md) for more details and usage examples. \ No newline at end of file diff --git a/docs/policy.md b/docs/policy.md new file mode 100644 index 00000000..88050466 --- /dev/null +++ b/docs/policy.md @@ -0,0 +1,145 @@ +# Policies + +This document describes the set of policies followed by `sigstore-python` +when signing or verifying a bundle. + +`sigstore-python` follows the [Sigstore: Client Spec] and this document +outline mimic the one from the spec. + +## Signing + +### Authentication + +`sigstore-python` supports several authentication mechanisms : + +- An OAuth flow: this mode is preferred for interactive workflows. +- An _ambient_ detection: this mode is preferred for un-attended workflows + (i.e., continuous integration system) + +### Key generation + +`sigstore-python` uses [ECDSA] as its signing algorithm. + +### Certificate Issuance + +_using Fulcio_ + +### Signing + +When needed, the payload pre-hashing algorithm is `SHA2_256`. + +### Timestamping + +If Timestamp Authorities have been provided in the Signing Config, a +Timestamp Request using the hash of the signature is automatically sent to the +provided Timestamp Authorities. + +This step allows to attest of the signature time. + +### Submission of Signing Metadata to Transparency Service + +The Transparency Service, [rekor], is used by `sigstore-python` to provide a +public, immutable record of signing events. This step is crucial for ensuring +the integrity and transparency of the signing process. + +!!! warning + + This step is performed before the `Timestamping` step in the worfklow. + +### Signing Choices + +Here's a summary of the key choices in the `sigstore-python` signing process: + +| Option | `sigstore-python` | +|-------------------------------|------------------------------| +| Digital signature algorithm | ECDSA | +| Signature metadata format | ??? | +| Payload pre-hashing algorithm | SHA2 (256) | +| Long-lived signing keys | not used | +| Timestamping | Used if provided | +| Transparency | Always used (rekor) | +| Other workflows | no other workflows supported | + +## Verification + +`sigstore-python` supports configuring the verification process using policies +but this must be done using the [api](./api/index.md). By default, the CLI uses +the [`Identity`][sigstore.verify.policy] verification policy. + +### Establishing a Time for the Signature + +If the bundle contains one or more signed times from Timestamping Authorities, +they will be used as the time source. In this case, a Timestamp Authority +configuration must be provided in the `ClientTrustConfig`. When verifying +Timestamp Authorities Responses, at least one must be valid. + +If there is a Transparency Service Timestamp, this is also used as a source +of trusted time. + +The verification will fail if no sources of time are found. + +### Certificate + +For a signature to be considered valid, it must meet two key criteria: + +- The signature must have an associated timestamp. +- Every certificate in the chain, from the signing certificate up to the root + certificate, must be valid at the time of signing. + +This approach is known as the “hybrid model” of certificate verification, as +described by [Braun et al.]. + +This validation process is repeated for each available source of trusted time. +The signature is only considered valid if it passes the validation checks +against all of these time sources. + +#### SignedCertificateTimestamp + +The `SignedCertificateTimestamp` is extracted from the leaf certificate and +verified using the verification key from the Certificate Transparency Log. + +#### Identity Verification Policy + +The system verifies that the signing certificate conforms to the Sigstore X. 509 +profile as well as `Identity Policy`. + +### Transparency Log Entry + +The Verifier now verifies the inclusion proof and signed checkpoint for the +log entry using [rekor]. + +If there is an inclusion promise, this is also verified. + +#### Time insertion check + +The system verifies that the transparency log entry’s insertion timestamp falls +within the certificate’s validity period. + +If the insertion timestamp is outside the certificate’s validity period, it +could indicate potential backdating or use of an expired certificate, and the +verification will fail. + + +### Signature Verification + +The next verification step is to verify the actual signature. This ensures +that the signed content has not been tampered with and was indeed signed by the +claimed entity. + +The verification process differs slightly depending on the type of signed +content: + +- DSSE: The entire envelope structure is used as the verification payload. +- Artifacts: The raw bytes of the artifacts serve as the verification payload. + +#### Final step + +Finally, a last consistency check is performed to verify that the constructed +payload is indeed the one that has been signed. This step is ussed to prevent +variants of [CVE-2022-36056]. + +[Sigstore: Client Spec]: https://docs.google.com/document/d/1kbhK2qyPPk8SLavHzYSDM8-Ueul9_oxIMVFuWMWKz0E/edit?usp=sharing +[ECDSA]: https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm +[rekor]: https://github.com/sigstore/rekor +[Braun et al.]: https://research.tue.nl/en/publications/how-to-avoid-the-breakdown-of-public-key-infrastructures-forward- +[CVE-2022-36056]: https://github.com/sigstore/cosign/security/advisories/GHSA-8gw7-4j42-w388 \ No newline at end of file diff --git a/docs/scripts/gen_ref_pages.py b/docs/scripts/gen_ref_pages.py new file mode 100644 index 00000000..6a5572b8 --- /dev/null +++ b/docs/scripts/gen_ref_pages.py @@ -0,0 +1,84 @@ +# Copyright 2022 The Sigstore Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import argparse +import shutil +import sys +from pathlib import Path + +root = Path(__file__).parent.parent.parent +src = root / "sigstore" +api_root = root / "docs" / "api" + + +def main(args: argparse.Namespace) -> None: + """Main script.""" + if args.overwrite: + shutil.rmtree(api_root, ignore_errors=True) + elif not args.check and api_root.exists(): + print(f"API root {api_root} already exists, skipping.") + sys.exit(0) + + seen = set() + for path in src.rglob("*.py"): + module_path = path.relative_to(src).with_suffix("") + full_doc_path = api_root / path.relative_to(src).with_suffix(".md") + + # Exclude private entries + 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) + + full_doc_path.parent.mkdir(parents=True, exist_ok=True) + with full_doc_path.open("w") as f: + f.write(f":::sigstore.{str(module_path).replace('/', '.')}\n ") + + seen.add(full_doc_path) + + # Add the root + with (api_root / "index.md").open("w") as f: + f.write("""!!! note + + The API reference is automatically generated from the docstrings + +:::sigstore + """) + + seen.add(api_root / "index.md") + + if args.check: + if diff := set(api_root.rglob("*.md")).symmetric_difference(seen): + print(f"Found leftover documentation file: {diff}", file=sys.stderr) + sys.exit(1) + else: + print("API doc generated.") + + +if __name__ == "__main__": + parser = argparse.ArgumentParser( + description="Generate the structure for the API documentation." + ) + parser.add_argument("--overwrite", action="store_true", default=False) + parser.add_argument("--check", action="store_true", default=False) + + arguments = parser.parse_args() + + if arguments.check and arguments.overwrite: + print("You can't specify both --check and --overwrite.", file=sys.stderr) + sys.exit(1) + + main(arguments) diff --git a/docs/signing.md b/docs/signing.md new file mode 100644 index 00000000..4b7b5729 --- /dev/null +++ b/docs/signing.md @@ -0,0 +1,133 @@ +# Signing + +!!! warning + + By default signing an artifact creates a public record in `Rekor` which is publicly available. + The transparency log entry is browsable at `https://search.sigstore.dev/?logIndex=` + and disclose the signing identity. + +## Identities + +### Signing with ambient credentials + +For environments that support OpenID Connect, `sigstore` supports ambient credential +detection. This includes many popular CI platforms and cloud providers. See the full list of +supported environments [here](https://github.com/di/id#supported-environments). + +### Signing with an email identity + +`sigstore` can use an OAuth2 + OpenID flow to establish an email identity, +allowing you to request signing certificates that attest to control over +that email. + +By default, `sigstore` attempts to do [ambient credential detection](#signing-with-ambient-credentials), which may preempt +the OAuth2 flow. To force the OAuth2 flow, you can explicitly disable ambient detection: + +```console +$ sigstore sign --oidc-disable-ambient-providers foo.txt +``` + +### Signing with an explicit identity token + +If you can't use an ambient credential or the OAuth2 flow, you can pass a pre-created +identity token directly into `sigstore sign`: + +```console +$ sigstore sign --identity-token YOUR-LONG-JWT-HERE foo.txt +``` + +Note that passing a custom identity token does not circumvent Fulcio's requirements, +namely the Fulcio's supported identity providers and the claims expected within the token. + +!!! note + + The examples in the section belows are using ambient credential detection. + When no credentials are detected, it opens a browser to perform an interactive OAuth2 authentication flow. + +## Signing an artifact + +The easiest option to sign an artifact with `sigstore` is to use the `sign` command. + +For example, signing `sigstore-python` [README.md](https://github.com/sigstore/sigstore-python/blob/main/README.md). + +```console +$ sigstore sign README.md + +Waiting for browser interaction... +Using ephemeral certificate: +-----BEGIN CERTIFICATE----- +MIIC2TCCAl+gAwIBAgIUdqkRnuxTr6bgdKtNiItu3+y8UkIwCgYIKoZIzj0EAwMw +NzEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MR4wHAYDVQQDExVzaWdzdG9yZS1pbnRl +cm1lZGlhdGUwHhcNMjQxMjEyMDk1NTU5WhcNMjQxMjEyMTAwNTU5WjAAMFkwEwYH +KoZIzj0CAQYIKoZIzj0DAQcDQgAEjb33vsuuNr4phkmpkUvMB19rnXLtS9QqZGT+ +kDetyi9+wYv/g2oOFDfEm7UHPLUeZJ6Bad8Zd7H/JqGUhuJ7gaOCAX4wggF6MA4G +A1UdDwEB/wQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAzAdBgNVHQ4EFgQUJpNq +0mPqLw1ypudG98REMY7mjyowHwYDVR0jBBgwFoAU39Ppz1YkEZb5qNjpKFWixi4Y +ZD8wLgYDVR0RAQH/BCQwIoEgYWxleGlzLmNoYWxsYW5kZUB0cmFpbG9mYml0cy5j +b20wKQYKKwYBBAGDvzABAQQbaHR0cHM6Ly9hY2NvdW50cy5nb29nbGUuY29tMCsG +CisGAQQBg78wAQgEHQwbaHR0cHM6Ly9hY2NvdW50cy5nb29nbGUuY29tMIGKBgor +BgEEAdZ5AgQCBHwEegB4AHYA3T0wasbHETJjGR4cmWc3AqJKXrjePK3/h4pygC8p +7o4AAAGTukvv5QAABAMARzBFAiEA3oqdIinnZ9rGb7CTxQ60G6xi6l3T+z6vkSr2 +ERAnIp4CIHbx61camOWU8dClH2WMUfguQ11+D82IQQBnHF968g22MAoGCCqGSM49 +BAMDA2gAMGUCMQDdf8S5Y/UhAp2vd2eo+RsjtfsasXSI51kO1ppNz42rSa6b5djW +8+we6/OzVQW+THYCMBaBHPNntloKD040Pce6f8W3HpydbUzshJ24Emt/EaTPqH/g +gYd2xz5hd4vQ7Ysmsg== +-----END CERTIFICATE----- + +Transparency log entry created at index: 155016378 +MEQCIHVjH0I3iarhB5hD0MEE4AZ7GpCPZhXpdsVsSFlZIynVAiA10qzWt9FBC5pjD6+1kLRS14F+muVD1NJZNw6b+/WADQ== +Sigstore bundle written to README.md.sigstore.json + +``` + +The log entry is available at : [https://search.sigstore.dev/?logIndex=155016378](https://search.sigstore.dev/?logIndex=155016378) + +## Attest + +`sigstore` can be used to generate attestations for software artifacts using [SLSA]. + +!!! info "What is SLSA?" + + Supply-chain Levels for Software Artifacts, or SLSA ("salsa"). + It’s a security framework, a checklist of standards and controls to prevent tampering, improve integrity, and secure packages and infrastructure. It’s how you get from "safe enough" to being as resilient as possible, at any link in the chain. + + +At the moment, `sigstore` supports the following predicates types: + +- [https://slsa.dev/provenance/v1](https://slsa.dev/spec/v1.0/provenance) +- [https://slsa.dev/provenance/v0.2](https://slsa.dev/spec/v0.2/provenance) + +Example : + +```console +$ sigstore attest \ + --predicate-type "https://slsa.dev/provenance/v1" \ + --predicate ./test/assets/integration/attest/slsa_predicate_v1_0.json \ + ./README.md + +Waiting for browser interaction... +Using ephemeral certificate: +-----BEGIN CERTIFICATE----- +MIIC2TCCAmCgAwIBAgIUI1GUnwGV69rXWAixrFmwAcZ7j7IwCgYIKoZIzj0EAwMw +NzEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MR4wHAYDVQQDExVzaWdzdG9yZS1pbnRl +cm1lZGlhdGUwHhcNMjQxMjEyMTAxODUwWhcNMjQxMjEyMTAyODUwWjAAMFkwEwYH +KoZIzj0CAQYIKoZIzj0DAQcDQgAEZPieQV37ByUyf+zWMGjXmom+kM4INxPcO1Kf +DhjV3RmhTAlKOYXGU38O/KUNka5BLTb4f5r1bNwGhiEf9qcmNqOCAX8wggF7MA4G +A1UdDwEB/wQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAzAdBgNVHQ4EFgQUUexC +qnLoKejMCAAgNxN77wSlIHkwHwYDVR0jBBgwFoAU39Ppz1YkEZb5qNjpKFWixi4Y +ZD8wLgYDVR0RAQH/BCQwIoEgYWxleGlzLmNoYWxsYW5kZUB0cmFpbG9mYml0cy5j +b20wKQYKKwYBBAGDvzABAQQbaHR0cHM6Ly9hY2NvdW50cy5nb29nbGUuY29tMCsG +CisGAQQBg78wAQgEHQwbaHR0cHM6Ly9hY2NvdW50cy5nb29nbGUuY29tMIGLBgor +BgEEAdZ5AgQCBH0EewB5AHcA3T0wasbHETJjGR4cmWc3AqJKXrjePK3/h4pygC8p +7o4AAAGTumDcJAAABAMASDBGAiEAprGPiBTcRK8ZFM+x3HLE+2s82xPAecHfJo9F +RXNI+CMCIQCYzRBQtTehd+LLmwkXjPJEsJ5CpI7q1uDhhspyplVSLjAKBggqhkjO +PQQDAwNnADBkAjAjO7BG9Gx6ggm1/IP75l+LzUnAP/DP0BOBeM0/lXZN3BBUvtdq ++oTUzmmY/VpCWggCMEcCMn4UDIF/jBrVhES8ks57T8LjRX6xacpn9ufpkTlnKs6w +S8/kL6jEREOcdnpOSQ== +-----END CERTIFICATE----- + +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 diff --git a/docs/stylesheets/custom.css b/docs/stylesheets/custom.css new file mode 100644 index 00000000..a06a30cc --- /dev/null +++ b/docs/stylesheets/custom.css @@ -0,0 +1,5 @@ +/* From https://github.com/sigstore/community/blob/main/artwork/Sigstore_BrandGuide_March2023.pdf */ +:root { + --md-primary-fg-color: #2e2f71; + --md-primary-bg-color: #f9f7ef; +} \ No newline at end of file diff --git a/docs/verify.md b/docs/verify.md new file mode 100644 index 00000000..d256a391 --- /dev/null +++ b/docs/verify.md @@ -0,0 +1,95 @@ +# Verifying + +## Generic identities + +This is the most common verification done with `sigstore`, and therefore +the one you probably want: you can use it to verify that a signature was +produced by a particular identity (like `hamilcar@example.com`), as attested +to by a particular OIDC provider (like `https://github.com/login/oauth`). + +```console +$ sigstore verify identity --cert-identity --cert-oidc-issuer FILE_OR_DIGEST +``` + +The following command will verify that the bundle `tests/assets/bundle.txt.sigstore` was signed by `a@tny.town` using +the staging infrastructure of `sigstore`. + +```console +$ sigstore --staging verify identity --cert-identity "a@tny.town" --cert-oidc-issuer "https://github.com/login/oauth" test/assets/bundle.txt +``` + +## Verifying from GitHub Actions + +If your signatures are coming from GitHub Actions (e.g., a workflow that uses its [ambient credentials](./signing.md#signing-with-ambient-credentials)), +then you can use the `sigstore verify github` subcommand to verify +claims more precisely than `sigstore verify identity` allows. + +`sigstore verify github` can be used to verify claims specific to signatures coming from GitHub +Actions. `sigstore-python` signs releases via GitHub Actions, so the examples below are working +examples of how you can verify a given `sigstore-python` release. + +When using `sigstore verify github`, you must pass `--cert-identity` or `--repository`, or both. +Unlike `sigstore verify identity`, `--cert-oidc-issuer` is **not** required (since it's +inferred to be GitHub Actions). + +Verifying with `--cert-identity`: + +```console +$ sigstore verify github sigstore-0.10.0-py3-none-any.whl \ + --bundle sigstore-0.10.0-py3-none-any.whl.bundle \ + --cert-identity https://github.com/sigstore/sigstore-python/.github/workflows/release.yml@refs/tags/v0.10.0 +``` + +Verifying with `--repository`: + +```console +$ sigstore verify github sigstore-0.10.0-py3-none-any.whl \ + --bundle sigstore-0.10.0-py3-none-any.whl.bundle \ + --repository sigstore/sigstore-python +``` + +Additional GitHub Actions specific claims can be verified like so: + +```console +$ sigstore verify github sigstore-0.10.0-py3-none-any.whl \ + --bundle sigstore-0.10.0-py3-none-any.whl.bundle \ + --cert-identity https://github.com/sigstore/sigstore-python/.github/workflows/release.yml@refs/tags/v0.10.0 \ + --trigger release \ + --sha 66581529803929c3ccc45334632ccd90f06e0de4 \ + --name Release \ + --repository sigstore/sigstore-python \ + --ref refs/tags/v0.10.0 +``` + +## Verifying against a bundle + +By default, `sigstore verify identity` will attempt to find a `.sigstore.json` +or `.sigstore` in the same directory as the file being verified: + +```console +# looks for foo.txt.sigstore.json +$ sigstore verify identity foo.txt \ + --cert-identity 'hamilcar@example.com' \ + --cert-oidc-issuer 'https://github.com/login/oauth' +``` + +Multiple files can be verified at once: + +```console +# looks for {foo,bar}.txt.sigstore.json +$ python -m sigstore verify identity foo.txt bar.txt \ + --cert-identity 'hamilcar@example.com' \ + --cert-oidc-issuer 'https://github.com/login/oauth' +``` + +## Verifying a digest instead of a file + +`sigstore-python` supports verifying digests directly, without requiring the artifact to be +present. The digest should be prefixed with the `sha256:` string: + +```console +$ sigstore verify identity sha256:ce8ab2822671752e201ea1e19e8c85e73d497e1c315bfd9c25f380b7625d1691 \ + --cert-identity 'hamilcar@example.com' \ + --cert-oidc-issuer 'https://github.com/login/oauth' + --bundle 'foo.txt.sigstore.json' +``` \ No newline at end of file diff --git a/install/requirements.in b/install/requirements.in index 0d4c42b1..760ed1b7 100644 --- a/install/requirements.in +++ b/install/requirements.in @@ -1 +1 @@ -sigstore==3.5.3 +sigstore==3.6.0 diff --git a/install/requirements.txt b/install/requirements.txt index 7ef65046..28a93061 100644 --- a/install/requirements.txt +++ b/install/requirements.txt @@ -222,6 +222,7 @@ cryptography==43.0.3 \ --hash=sha256:f7b178f11ed3664fd0e995a47ed2b5ff0a12d893e41dd0494f406d1cf555cab7 # via # pyopenssl + # rfc3161-client # sigstore dnspython==2.7.0 \ --hash=sha256:b4c34b7d10b51bcc3a5071e7b8dee77939f1e878477eeecc965e9835f63c6c86 \ @@ -264,6 +265,21 @@ 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 @@ -374,9 +390,9 @@ pycparser==2.22 \ --hash=sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6 \ --hash=sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc # via cffi -pydantic[email]==2.10.2 \ - --hash=sha256:2bc2d7f17232e0841cbba4641e65ba1eb6fafb3a08de3a091ff3ce14a197c4fa \ - --hash=sha256:cfb96e45951117c3024e6b67b25cdc33a3cb7b2fa62e239f7af1378358a1d99e +pydantic[email]==2.10.3 \ + --hash=sha256:be04d85bbc7b65651c5f8e6b9976ed9c6f41782a55524cef079a34a0bb82144d \ + --hash=sha256:cb5ac360ce894ceacd69c403187900a02c4b20b693a9dd1d643e1effab9eadf9 # via # sigstore # sigstore-rekor-types @@ -505,6 +521,21 @@ 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 + # via sigstore rfc8785==0.1.4 \ --hash=sha256:520d690b448ecf0703691c76e1a34a24ddcd4fc5bc41d589cb7c58ec651bcd48 \ --hash=sha256:e545841329fe0eee4f6a3b44e7034343100c12b4ec566dc06ca9735681deb4da @@ -513,26 +544,60 @@ rich==13.9.4 \ --hash=sha256:439594978a49a09530cff7ebc4b5c7103ef57baf48d5ea3184f21d9a2befa098 \ --hash=sha256:6049d5e6ec054bf2779ab3358186963bac2ea89175919d699e378b99738c2a90 # via sigstore -securesystemslib==1.1.0 \ - --hash=sha256:100bf04e60b260e1c7c51e3232647697fde2c5ca5772fda4932d841d3fb6dd0e \ - --hash=sha256:27143a8e04b5573636f260f21d7e26b48bcedcf394e6f74ec31e9a5287e0c38b +securesystemslib==1.2.0 \ + --hash=sha256:34fa63e3296a0540b122a13bf51722ecd015be00c1d2ed45b23442e718920e76 \ + --hash=sha256:fa63abcb1cf4dba4f2df964f623baa45bc39029980d7a0a2119d90731942afc6 # via tuf -sigstore==3.5.3 \ - --hash=sha256:2547bca442201bdf07f7de2c654a0dbe5051b90fac3f8580bf1875d11b5ad498 \ - --hash=sha256:5f91e101a51bbf442a37f7c1aeea8d4501c9565680c04e06f35be5b53bc02c55 - # via -r install/requirements.in +sigstore==3.6.0 \ + --hash=sha256:cd84e1acaec163d4b3a837dab160fb73259bf67939b2deea3d12c40f09a6ac21 \ + --hash=sha256:e354867c21674864b4014a390e28685e1decc925be5ba1af3055f217d6d27e2c + # via -r requirements.in sigstore-protobuf-specs==0.3.2 \ --hash=sha256:50c99fa6747a3a9c5c562a43602cf76df0b199af28f0e9d4319b6775630425ea \ --hash=sha256:cae041b40502600b8a633f43c257695d0222a94efa1e5110a7ec7ada78c39d99 # via sigstore -sigstore-rekor-types==0.0.13 \ - --hash=sha256:377fee942d5fc66437a4f54599472157149affaece9bbc7deb05e5b42f34ceba \ - --hash=sha256:63e9306a26931ed74411911948c250da7c5adc51c53507227738170424e6ae2d +sigstore-rekor-types==0.0.18 \ + --hash=sha256:19aef25433218ebf9975a1e8b523cc84aaf3cd395ad39a30523b083ea7917ec5 \ + --hash=sha256:b62bf38c5b1a62bc0d7fe0ee51a0709e49311d137c7880c329882a8f4b2d1d78 # via sigstore -six==1.16.0 \ - --hash=sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926 \ - --hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254 +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 diff --git a/mkdocs.yml b/mkdocs.yml new file mode 100644 index 00000000..aaba03cd --- /dev/null +++ b/mkdocs.yml @@ -0,0 +1,83 @@ +# yaml-language-server: $schema=https://squidfunk.github.io/mkdocs-material/schema.json + +site_name: sigstore-python +site_url: https://sigstore.github.io/sigstore-python +repo_url: https://github.com/sigstore/sigstore-python +site_description: sigstore-python, a Sigstore client written in Python +repo_name: sigstore-python +edit_uri: edit/main/docs/ +theme: + name: material + icon: + repo: fontawesome/brands/github + logo: assets/images/logo.png + features: + - content.action.edit + - content.code.copy + - header.autohide + - navigation.instant + - navigation.instant.progress + - navigation.footer + - search.highlight + - search.suggest + palette: + primary: custom + font: + text: Inter +extra_css: + - stylesheets/custom.css +nav: + - Home: index.md + - Installation: installation.md + - Signing: signing.md + - Verifying: verify.md + - Policy: policy.md + - Advanced: + - Custom Root of Trust: advanced/custom_trust.md + - Offline Verification: advanced/offline.md + # begin-api-section + - API: + - api/index.md + - Models: api/models.md + - Errors: api/errors.md + - Hashes: api/hashes.md + - OIDC: api/oidc.md + - Sign: api/sign.md + - Verify: + - Policy: api/verify/policy.md + - Verifier: api/verify/verifier.md + # end-api-section +markdown_extensions: + - admonition + - pymdownx.details + - pymdownx.superfences +copyright: sigstore © 2024 +plugins: + - search + - social + - mkdocstrings: + handlers: + python: + options: + members_order: source + unwrap_annotated: true + modernize_annotations: true + merge_init_into_class: true + docstring_section_style: spacy + signature_crossrefs: true + show_symbol_type_toc: true + filters: + - '!^_' +validation: + omitted_files: warn + unrecognized_links: warn + anchors: warn + not_found: warn + +extra: + generator: false + social: + - icon: fontawesome/brands/slack + link: https://sigstore.slack.com + - icon: fontawesome/brands/x-twitter + link: https://twitter.com/projectsigstore \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index 1d1c55d6..01c5bf1c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -26,7 +26,7 @@ classifiers = [ "Topic :: Security :: Cryptography", ] dependencies = [ - "cryptography >= 42, < 44", + "cryptography >= 42, < 45", "id >= 1.1.0", "importlib_resources ~= 5.7; python_version < '3.11'", "pyasn1 ~= 0.6", @@ -36,8 +36,7 @@ dependencies = [ "requests", "rich ~= 13.0", "rfc8785 ~= 0.1.2", - # NOTE(dm): Under very active development, so strictly pinned. - "rfc3161-client == 0.0.4", + "rfc3161-client ~= 0.1.2", # NOTE(ww): Both under active development, so strictly pinned. "sigstore-protobuf-specs == 0.3.2", "sigstore-rekor-types == 0.0.18", @@ -63,11 +62,11 @@ 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.3", + "ruff < 0.8.4", "types-requests", "types-pyOpenSSL", ] -doc = ["pdoc"] +doc = ["mkdocs-material[imaging]", "mkdocstrings-python"] dev = ["build", "bump >= 1.3.2", "sigstore[doc,test,lint]"] [tool.coverage.run] diff --git a/sigstore/__init__.py b/sigstore/__init__.py index 82953f0d..c5e18e0b 100644 --- a/sigstore/__init__.py +++ b/sigstore/__init__.py @@ -25,4 +25,4 @@ * `sigstore.sign`: creation of Sigstore signatures """ -__version__ = "3.6.0" +__version__ = "3.6.1"