From 4c863982d5694f0770ab8703fdfd97b8e5f540a6 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 23 Jul 2026 09:07:57 +0000 Subject: [PATCH 1/6] Add cybersecurity reinforcement analysis report Findings from a three-part audit (CI/supply chain, code-level surface, testing/fuzzing assurance) of this fork, with prioritized reinforcement recommendations and a remediation roadmap. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01DWoMomNAcBM3e8duJrb2do --- SECURITY_ANALYSIS.md | 217 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 217 insertions(+) create mode 100644 SECURITY_ANALYSIS.md diff --git a/SECURITY_ANALYSIS.md b/SECURITY_ANALYSIS.md new file mode 100644 index 000000000000..023be953492b --- /dev/null +++ b/SECURITY_ANALYSIS.md @@ -0,0 +1,217 @@ +# Security Analysis: duksh/cryptography + +A cybersecurity reinforcement analysis of this repository (a fork of +[pyca/cryptography](https://github.com/pyca/cryptography), v50.0.0-dev1, synced with +upstream as of 2026-07-22). Three areas were audited: CI/supply-chain posture, the +code-level cryptographic surface, and testing/fuzzing assurance. + +## Executive summary + +The upstream project is one of the best-hardened codebases in the Python ecosystem, and +this fork inherits that posture: SHA-pinned Actions, least-privilege workflow permissions, +OIDC trusted publishing with PEP 740 attestations, hash-pinned build requirements, +memory-safe Rust parsers, an enforced 100% coverage gate, and differential test vectors +run across five TLS backends. The most actionable reinforcement opportunities are +**fork-specific**: the release/publish pipeline is not guarded against running in a fork, +and the vulnerability-reporting channel points at the upstream project. Beyond that, +there are meaningful gaps in dependency auditing, code scanning, fuzzing, and a handful of +code-level hardening items. + +Findings are prioritized P1 (act first) through P4. + +## Baseline strengths (verified) + +| Area | Evidence | +|---|---| +| Action pinning | Every third-party action pinned to a full commit SHA (e.g. `ci.yml:72`, `pypi-publish.yml:60`) | +| Workflow permissions | Top-level `permissions: contents: read` in all main workflows; job-level elevation only where needed (`pypi-publish.yml:31-33`) | +| Checkout hygiene | `persist-credentials: false` on test/build checkouts; no `pull_request_target`; no self-hosted runners | +| Publishing | OIDC Trusted Publishing (`uv publish --trusted-publishing=always`, `pypi-publish.yml:77`); no PyPI token secret exists; PEP 740 attestations via `astral-sh/attest-action`; SBOM embedded in wheels (`wheel-builder.yml:151`) | +| Dependency pinning | `.github/requirements/build-requirements.txt` and `uv-requirements.txt` hash-pinned and consumed with `--require-hashes`; `Cargo.lock` committed with checksums; daily Dependabot for actions/cargo/uv incl. transitive deps | +| Memory safety | ASN.1/X.509/key-parsing crates are `#![forbid(unsafe_code)]` (`cryptography-x509`, `cryptography-x509-verification`, `cryptography-key-parsing`); all unsafe blocks require `// SAFETY:` comments (`clippy::undocumented_unsafe_blocks` denied); `overflow-checks = true` in release (`Cargo.toml`) | +| Test assurance | Enforced 100% combined Python+Rust coverage (`.github/bin/merge_rust_coverage.py:138-142`); wycheproof + x509-limbo vectors (pinned refs) in every matrix leg; matrix spans OpenSSL 3.0.x–master, LibreSSL, BoringSSL, AWS-LC, FIPS, `no-legacy`, free-threaded Python | +| Weak-crypto quarantine | Legacy ciphers isolated in `hazmat/decrepit/`; constant-time compares via `hmac.compare_digest` / `CRYPTO_memcmp`; OpenSSL < 3.0 is a hard compile error (`src/_cffi_src/openssl/cryptography.py:55-60`) | + +## P1 — Fork-specific risks + +### 1.1 The publish pipeline is not owner-guarded + +All scheduled bot workflows are gated with `if: github.repository_owner == 'pyca'` +(`auto-close-stale.yml:9`, `lock.yml:9`, `boring-open-awslc-bump.yml:13`, +`downstream-version-bump.yml:13`, `x509-limbo-version-bump.yml:13`), so they no-op on this +fork. The **release path is not**: + +- `wheel-builder.yml:11-13` triggers on any tag push matching `*.*` / `*.*.*` — no owner + guard. Pushing a tag like `1.0` to this fork starts a full multi-platform wheel build. +- `pypi-publish.yml:14-16` chains from Wheel Builder completion via `workflow_run`, and + its gate (`pypi-publish.yml:30`) checks only the event type and conclusion — not the + repository owner. It then requests `id-token: write` + `attestations: write` and runs + `uv publish --trusted-publishing=always`. + +On this fork the publish would only succeed if a PyPI Trusted Publisher were ever +configured for `duksh/cryptography` — safety currently rests entirely on that PyPI-side +absence, with no in-repo defense. + +**Recommendation:** add `if: github.repository_owner == 'pyca'` (or the fork owner, if +the fork intends to publish under a different name) to the `wheel-builder.yml` tag +trigger jobs and the `pypi-publish.yml` publish job, and/or disable these workflows in +the fork's Actions settings. + +### 1.2 No valid vulnerability-reporting channel + +- There is no `SECURITY.md`; the policy in `docs/security.rst:60-67` directs reporters to + the **upstream pyca** advisory page (`pyca/cryptography/security/advisories/new`). +- There is no `CODEOWNERS` file. + +**Recommendation:** add a root `SECURITY.md` stating where issues in *this fork* should +be reported (or explicitly deferring to upstream and stating the fork ships no releases), +and a `CODEOWNERS` if more than one person maintains the fork. + +### 1.3 Third-party code execution in CI + +`ci.yml:402-451` (downstream tests: paramiko, twisted, mitmproxy, scapy, certbot, +aws-encryption-sdk, sigstore-python) and `benchmark.yml:38` check out and execute +external repositories' code in this repo's CI context. Refs are pinned to commit SHAs and +the token is read-only, so exposure is limited — but on a fork this is unnecessary attack +surface and compute. + +**Recommendation:** owner-gate or disable the downstream and benchmark jobs on the fork. + +## P2 — Supply-chain hardening + +### 2.1 One unhashed install path — and it is in the publish job + +`ci-constraints-requirements.txt` is version-pinned but **not** hash-pinned (unlike the +`.github/requirements/*.txt` files). It is used to bootstrap `uv`/`nox` in CI +(`ci.yml:150,212,478`) and, notably, in the publish job (`pypi-publish.yml:58`). + +**Recommendation:** compile it with `--generate-hashes`, or bootstrap the publish job +from the already-hashed `.github/requirements/uv-requirements.txt`. + +### 2.2 No dependency-audit gates + +`Cargo.lock` is committed, but there is no `cargo-deny` / `cargo-audit` / `cargo-vet` +configuration or CI job for Rust advisory/license checking, and no `pip-audit` job — +even though `docs/security.rst:8-13` recommends osv.dev tooling to downstream users. + +**Recommendation:** add a scheduled + PR workflow running `cargo deny check advisories` +(plus optional `pip-audit` against the hashed requirements files). + +### 2.3 No code-scanning workflows + +No CodeQL, semgrep, or OpenSSF Scorecard integration exists in the repository. + +**Recommendation:** add CodeQL (Python; Rust once stable) and the Scorecard action with +results published to the Security tab. Scorecard also directly measures several items in +this report (pinning, token permissions, fuzzing, SAST). + +### 2.4 Minor items + +- `pypi-publish.yml:19` defines `PUBLISH_REQUIREMENTS_PATH=.github/requirements/publish-requirements.txt`, + which **does not exist** and is never used — dead reference; remove it or restore a + hash-pinned publish requirements file. +- `dtolnay/rust-toolchain` is SHA-pinned but lacks a version comment (`ci.yml:85`), + making drift review harder. +- `dependabot.yml` sets `open-pull-requests-limit: 1024` per ecosystem — effectively + unbounded automated-PR volume. + +## P3 — Code-level hardening + +### 3.1 No secret zeroization + +There is no `zeroize` crate usage (0 references in `Cargo.toml`/`Cargo.lock`) and no +explicit cleansing of key or plaintext buffers in `src/rust`. Secret material relies on +OpenSSL's internal handling and Rust drop semantics; owned intermediate buffers (derived +keys, seeds, decrypted PKCS#12 material) are not scrubbed. + +**Recommendation:** adopt `zeroize` (or explicit `OPENSSL_cleanse` calls through the FFI +shim) for owned secret buffers, starting in `cryptography-openssl`. + +### 3.2 Rust lint gaps + +- No `#![deny(unsafe_op_in_unsafe_fn)]` anywhere — unsafe operations inside `unsafe fn` + bodies are not individually flagged. +- No `[workspace.lints]` table; lint policy is per-crate inner attributes, so a new crate + could silently omit them. There are 66 unsafe blocks across 16 files (concentrated in + the `cryptography-openssl` FFI shim: `mlkem.rs`, `mldsa.rs`, `aead.rs`, `hmac.rs`). + +**Recommendation:** add a workspace lints table with `unsafe_op_in_unsafe_fn = "deny"` +and inherit it in all crates; keep `forbid(unsafe_code)` in every crate that doesn't +strictly need FFI. + +### 3.3 Legacy algorithm exposure gaps + +- `CAST5`, `IDEA`, `SEED`, and `Blowfish` are re-exported from + `src/cryptography/hazmat/primitives/ciphers/algorithms.py:8-28` **without** deprecation + wrappers — only `Camellia`, `ARC4`, and `TripleDES` warn (`algorithms.py:70-103`). +- `MD5` (`hashes.py:281`), `SHA1` (`hashes.py:101`), and DSA key generation + (`dsa.py:166-179`) carry no deprecation gating. +- RSA generation floor is 1024 bits (`rsa.py:180-181`), below the modern 2048 + recommendation; key loading enforces no floor. + +**Recommendation:** extend `utils.deprecated` wrappers to the remaining decrepit +re-exports; consider a `CryptographyDeprecationWarning` on RSA generation below 2048 and +on DSA generation. (For a fork, these could also be hard errors if no legacy +compatibility is needed.) + +### 3.4 No minimum-version assertion for alternative backends + +Only OpenSSL proper has a hard compile-time floor +(`src/_cffi_src/openssl/cryptography.py:55-60`). LibreSSL, BoringSSL, and AWS-LC are +detected by feature cfg only (`src/rust/build.rs:36-49`) — an old LibreSSL could compile +without any version assertion. + +**Recommendation:** add explicit minimum-version `#error`/build-fail gates for the +alternative backends matching what CI actually tests. + +### 3.5 Documented validation bypass (informational) + +`unsafe_skip_rsa_key_validation` (`src/rust/src/backend/keys.rs:12-26`) is a public +keyword-only flag that skips RSA key consistency checks on load. It is clearly named and +defaults to `False`; no change proposed, but any downstream code setting it should be +audited. + +## P4 — Assurance depth + +### 4.1 No fuzzing + +No cargo-fuzz/libFuzzer targets, no OSS-Fuzz or ClusterFuzzLite configuration exist in +the repo. The hand-rolled ASN.1 parsers (X.509 certificates/CRLs/CSRs, PKCS#7, PKCS#12) +are memory-safe Rust, but panics and logic/differential bugs remain findable by fuzzing. + +**Recommendation:** add `cargo fuzz` targets for `load_der_x509_certificate`, +`load_der_x509_crl`, `load_der_x509_csr`, and the PKCS#7/PKCS#12 parsers, and wire +ClusterFuzzLite into CI for PR-time fuzzing. + +### 4.2 No sanitizer CI legs + +No ASAN/UBSAN/MSAN jobs exist; memory-safety assurance at the CFFI/OpenSSL boundary rests +on Rust's guarantees plus backend diversity. + +**Recommendation:** add one ASAN+UBSAN matrix leg (nightly Rust `-Zsanitizer=address` +with an ASAN-built OpenSSL) on a scheduled workflow if PR latency is a concern. + +### 4.3 Minor + +`mypy` is strict-ish but not maximal (`pyproject.toml:152-164` — no +`disallow_untyped_defs`). + +## Remediation roadmap + +| # | Action | Priority | Effort | +|---|---|---|---| +| 1 | Owner-guard `wheel-builder.yml` + `pypi-publish.yml` (or disable on fork) | P1 | Small | +| 2 | Add `SECURITY.md` (+ `CODEOWNERS`) for the fork | P1 | Small | +| 3 | Owner-gate downstream/benchmark third-party CI jobs | P1 | Small | +| 4 | Hash-pin `ci-constraints-requirements.txt`; fix dead `PUBLISH_REQUIREMENTS_PATH` | P2 | Small | +| 5 | Add `cargo deny check advisories` (+ optional `pip-audit`) workflow | P2 | Small | +| 6 | Add CodeQL + OpenSSF Scorecard workflows | P2 | Small | +| 7 | Workspace `[lints]` with `unsafe_op_in_unsafe_fn = "deny"` | P3 | Small | +| 8 | Deprecation wrappers for CAST5/IDEA/SEED/Blowfish re-exports; DSA/small-RSA warnings | P3 | Medium | +| 9 | Minimum-version gates for LibreSSL/BoringSSL/AWS-LC | P3 | Medium | +| 10 | Adopt `zeroize` for owned secret buffers | P3 | Medium | +| 11 | cargo-fuzz targets + ClusterFuzzLite for the ASN.1/PKCS parsers | P4 | Medium | +| 12 | Scheduled ASAN/UBSAN CI leg | P4 | Medium | + +Items 8–10 change library behavior/internals and are best contributed upstream rather +than carried as fork-only patches. From 0a1c08938c847da4d3a3ef0dfdbf65334c3d17bf Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 23 Jul 2026 09:36:49 +0000 Subject: [PATCH 2/6] Harden fork against accidental release-pipeline runs Bucket 1 (fork-only) items from SECURITY_ANALYSIS.md: - Add SECURITY.md directing library vulnerability reports upstream and fork-specific reports to this repository's advisory page - Add CODEOWNERS - Owner-guard the publish job in pypi-publish.yml so a fork can never attempt an OIDC publish or mint attestations - Owner-guard the wheel-builder sdist job (skipping it skips the whole chain), keeping pull_request runs so workflow changes stay testable - Skip linux-downstream third-party code execution on forks, with a matching alls-green allowed-skips entry - Skip benchmark job on forks Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01DWoMomNAcBM3e8duJrb2do --- .github/CODEOWNERS | 2 ++ .github/workflows/benchmark.yml | 3 +++ .github/workflows/ci.yml | 5 +++++ .github/workflows/pypi-publish.yml | 4 +++- .github/workflows/wheel-builder.yml | 4 ++++ SECURITY.md | 24 ++++++++++++++++++++++++ 6 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 .github/CODEOWNERS create mode 100644 SECURITY.md diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 000000000000..489cc2be27ac --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,2 @@ +# Default owners for everything in this fork. +* @duksh diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index ff9dac37f881..cd670687506a 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -25,6 +25,9 @@ jobs: benchmark: runs-on: ubuntu-latest timeout-minutes: 15 + # Benchmarks check out and run code from the upstream repository; not + # useful (and unnecessary CI surface) on forks. + if: github.repository_owner == 'pyca' steps: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 timeout-minutes: 3 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2a99963ce4e6..5a3f456a4f02 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -395,6 +395,9 @@ jobs: linux-downstream: runs-on: ubuntu-latest + # Downstream tests execute third-party repositories' code; skip them on + # forks (all-green allows this skip below). + if: github.repository_owner == 'pyca' strategy: fail-fast: false matrix: @@ -515,6 +518,8 @@ jobs: uses: re-actors/alls-green@05ac9388f0aebcb5727afa17fcccfecd6f8ec5fe # v1.2.2 with: jobs: ${{ toJSON(needs) }} + # linux-downstream is skipped on forks. + allowed-skips: linux-downstream - run: pip install -c ci-constraints-requirements.txt coverage[toml] if: ${{ always() }} - name: Download coverage data diff --git a/.github/workflows/pypi-publish.yml b/.github/workflows/pypi-publish.yml index db46ceeae941..c2b7eece1a58 100644 --- a/.github/workflows/pypi-publish.yml +++ b/.github/workflows/pypi-publish.yml @@ -27,7 +27,9 @@ jobs: # We're not actually verifying that the triggering push event was for a # tag, because github doesn't expose enough information to do so. # wheel-builder.yml currently only has push events for tags. - if: github.event_name == 'workflow_dispatch' || (github.event.workflow_run.event == 'push' && github.event.workflow_run.conclusion == 'success') + # The repository_owner guard prevents this job from ever attempting a + # publish (or minting OIDC tokens/attestations) when run from a fork. + if: github.repository_owner == 'pyca' && (github.event_name == 'workflow_dispatch' || (github.event.workflow_run.event == 'push' && github.event.workflow_run.conclusion == 'success')) permissions: id-token: "write" attestations: "write" diff --git a/.github/workflows/wheel-builder.yml b/.github/workflows/wheel-builder.yml index a0cb2413f251..88d2feaefc6d 100644 --- a/.github/workflows/wheel-builder.yml +++ b/.github/workflows/wheel-builder.yml @@ -27,6 +27,10 @@ jobs: sdist: runs-on: ubuntu-latest name: sdists + # Guard release builds against running from a fork (tag pushes and manual + # dispatches). PR runs are kept so workflow changes remain testable. + # Every other job needs this one, so skipping it skips the whole chain. + if: github.repository_owner == 'pyca' || github.event_name == 'pull_request' steps: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 000000000000..a1543e1c8b12 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,24 @@ +# Security Policy + +This repository is a fork of [pyca/cryptography](https://github.com/pyca/cryptography). +It does **not** publish releases, wheels, or packages anywhere. If you obtained +`cryptography` from PyPI or a distribution, it did not come from this fork. + +## Reporting a vulnerability in the cryptography library + +Vulnerabilities in the library itself should be reported **upstream**, following +the upstream security policy: https://cryptography.io/en/latest/security/ +(report privately via https://github.com/pyca/cryptography/security/advisories/new — +not in a public issue tracker). + +## Reporting an issue specific to this fork + +For issues that exist only in this fork (for example, its CI configuration or +repository setup), please open a private security advisory on this repository: +https://github.com/duksh/cryptography/security/advisories/new + +## Supported versions + +This fork tracks the upstream `main` branch and ships nothing; there are no +supported release versions here. See the upstream policy for supported versions +of the actual library. From f631adcf5f0a334a8cff10c2cd9c1eac85e0c86f Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 23 Jul 2026 11:57:55 +0000 Subject: [PATCH 3/6] Skip ppc64le CI legs on forks ubuntu-24.04-ppc64le runners are never allocated to personal forks, so the distros ppc64le leg and the manylinux ppc64le wheel legs sit queued forever, holding the runs open and preventing all-green from reporting. Skip them when not running in the pyca org; partially-skipped matrices still aggregate as success. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01DWoMomNAcBM3e8duJrb2do --- .github/workflows/ci.yml | 3 +++ .github/workflows/wheel-builder.yml | 3 +++ 2 files changed, 6 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5a3f456a4f02..839061972883 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -168,6 +168,9 @@ jobs: distros: runs-on: ${{ matrix.IMAGE.RUNNER }} container: ghcr.io/pyca/cryptography-runner-${{ matrix.IMAGE.IMAGE }} + # ppc64le runners are not allocated to forks; skip those legs so the run + # can complete (all-green treats partially-skipped matrices as success). + if: github.repository_owner == 'pyca' || matrix.IMAGE.RUNNER != 'ubuntu-24.04-ppc64le' strategy: fail-fast: false matrix: diff --git a/.github/workflows/wheel-builder.yml b/.github/workflows/wheel-builder.yml index 88d2feaefc6d..39b053fd9b3a 100644 --- a/.github/workflows/wheel-builder.yml +++ b/.github/workflows/wheel-builder.yml @@ -59,6 +59,9 @@ jobs: manylinux: needs: [sdist] + # ppc64le runners are not allocated to forks; skip those legs so PR runs + # of this workflow can complete. + if: github.repository_owner == 'pyca' || matrix.MANYLINUX.RUNNER != 'ubuntu-24.04-ppc64le' runs-on: ${{ matrix.MANYLINUX.RUNNER }} container: image: ghcr.io/pyca/${{ matrix.MANYLINUX.CONTAINER }} From d71e3c6a92572b4cf865035cd97485974997338b Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 23 Jul 2026 12:33:48 +0000 Subject: [PATCH 4/6] Fix workflow validation error; drop ppc64le legs on fork The previous commit used the matrix context in job-level if conditions, which is not available there and made both workflow files fail validation. Remove those conditions and instead comment out the ppc64le matrix legs: ubuntu-24.04-ppc64le runners are never allocated outside the pyca org, so the legs queue forever and keep runs from completing. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01DWoMomNAcBM3e8duJrb2do --- .github/workflows/ci.yml | 8 ++++---- .github/workflows/wheel-builder.yml | 19 +++++++++---------- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 839061972883..83cc39a30031 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -168,9 +168,6 @@ jobs: distros: runs-on: ${{ matrix.IMAGE.RUNNER }} container: ghcr.io/pyca/cryptography-runner-${{ matrix.IMAGE.IMAGE }} - # ppc64le runners are not allocated to forks; skip those legs so the run - # can complete (all-green treats partially-skipped matrices as success). - if: github.repository_owner == 'pyca' || matrix.IMAGE.RUNNER != 'ubuntu-24.04-ppc64le' strategy: fail-fast: false matrix: @@ -188,7 +185,10 @@ jobs: - {IMAGE: "ubuntu-rolling:aarch64", NOXSESSION: "tests", RUNNER: "ubuntu-24.04-arm"} - {IMAGE: "ubuntu-rolling:armv7l", NOXSESSION: "tests", RUNNER: "ubuntu-24.04-arm"} - - {IMAGE: "ubuntu-rolling:ppc64le", NOXSESSION: "tests", RUNNER: "ubuntu-24.04-ppc64le"} + # Removed on this fork: ubuntu-24.04-ppc64le runners are never + # allocated outside the pyca org, so the leg queues forever and + # keeps all-green from reporting. + # - {IMAGE: "ubuntu-rolling:ppc64le", NOXSESSION: "tests", RUNNER: "ubuntu-24.04-ppc64le"} timeout-minutes: 15 env: RUSTUP_HOME: /root/.rustup diff --git a/.github/workflows/wheel-builder.yml b/.github/workflows/wheel-builder.yml index 39b053fd9b3a..0d25cba48903 100644 --- a/.github/workflows/wheel-builder.yml +++ b/.github/workflows/wheel-builder.yml @@ -59,9 +59,6 @@ jobs: manylinux: needs: [sdist] - # ppc64le runners are not allocated to forks; skip those legs so PR runs - # of this workflow can complete. - if: github.repository_owner == 'pyca' || matrix.MANYLINUX.RUNNER != 'ubuntu-24.04-ppc64le' runs-on: ${{ matrix.MANYLINUX.RUNNER }} container: image: ghcr.io/pyca/${{ matrix.MANYLINUX.CONTAINER }} @@ -89,8 +86,10 @@ jobs: - { NAME: "manylinux_2_31_armv7l", CONTAINER: "cryptography-manylinux_2_31:armv7l", RUNNER: "ubuntu-24.04-arm" } - - { NAME: "manylinux_2_28_ppc64le", CONTAINER: "cryptography-manylinux_2_28:ppc64le", RUNNER: "ubuntu-24.04-ppc64le" } - - { NAME: "manylinux_2_34_ppc64le", CONTAINER: "cryptography-manylinux_2_34:ppc64le", RUNNER: "ubuntu-24.04-ppc64le" } + # Removed on this fork: ubuntu-24.04-ppc64le runners are never + # allocated outside the pyca org, so these legs queue forever. + # - { NAME: "manylinux_2_28_ppc64le", CONTAINER: "cryptography-manylinux_2_28:ppc64le", RUNNER: "ubuntu-24.04-ppc64le" } + # - { NAME: "manylinux_2_34_ppc64le", CONTAINER: "cryptography-manylinux_2_34:ppc64le", RUNNER: "ubuntu-24.04-ppc64le" } exclude: # There are no readily available musllinux PyPy distributions @@ -109,11 +108,11 @@ jobs: - PYTHON: { VERSION: "pp311-pypy311_pp73" } MANYLINUX: { NAME: "manylinux_2_31_armv7l", CONTAINER: "cryptography-manylinux_2_31:armv7l", RUNNER: "ubuntu-24.04-arm" } - # No PyPy on ppc64le - - PYTHON: { VERSION: "pp311-pypy311_pp73" } - MANYLINUX: { NAME: "manylinux_2_34_ppc64le", CONTAINER: "cryptography-manylinux_2_34:ppc64le", RUNNER: "ubuntu-24.04-ppc64le" } - - PYTHON: { VERSION: "pp311-pypy311_pp73" } - MANYLINUX: { NAME: "manylinux_2_28_ppc64le", CONTAINER: "cryptography-manylinux_2_28:ppc64le", RUNNER: "ubuntu-24.04-ppc64le" } + # No PyPy on ppc64le (ppc64le legs removed on this fork, see above) + # - PYTHON: { VERSION: "pp311-pypy311_pp73" } + # MANYLINUX: { NAME: "manylinux_2_34_ppc64le", CONTAINER: "cryptography-manylinux_2_34:ppc64le", RUNNER: "ubuntu-24.04-ppc64le" } + # - PYTHON: { VERSION: "pp311-pypy311_pp73" } + # MANYLINUX: { NAME: "manylinux_2_28_ppc64le", CONTAINER: "cryptography-manylinux_2_28:ppc64le", RUNNER: "ubuntu-24.04-ppc64le" } name: "${{ matrix.PYTHON.VERSION }} for ${{ matrix.MANYLINUX.NAME }}" steps: From 468cdedda8e5c2ae8be356abc55b476ccf2319d3 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 24 Jul 2026 07:18:10 +0000 Subject: [PATCH 5/6] Skip scheduled linkcheck runs on forks The weekly linkcheck run fails on forks whenever an external site blocks CI traffic (eprint.iacr.org returns 403 to cloud IPs) or is slow, producing recurring noise. Keep the schedule upstream-only; pull_request runs still validate docs/conf.py and workflow changes. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01DWoMomNAcBM3e8duJrb2do --- .github/workflows/linkcheck.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/linkcheck.yml b/.github/workflows/linkcheck.yml index 698a7908eeca..e44ec0a47b83 100644 --- a/.github/workflows/linkcheck.yml +++ b/.github/workflows/linkcheck.yml @@ -18,6 +18,10 @@ jobs: docs-linkcheck: runs-on: ubuntu-latest name: "linkcheck" + # The weekly scheduled run fails on forks whenever an external site + # blocks CI traffic or is slow; keep it upstream-only. PR runs (for + # changes to docs/conf.py or this file) still work everywhere. + if: github.repository_owner == 'pyca' || github.event_name == 'pull_request' timeout-minutes: 20 steps: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 From 77e65037f9fd1a013db8210462447965001b2874 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 24 Jul 2026 07:21:26 +0000 Subject: [PATCH 6/6] Ignore CI-hostile hosts in docs linkcheck eprint.iacr.org returns 403 to CI/cloud IP ranges and alexgaynor.net consistently exceeds the 5s linkcheck timeout from GitHub-hosted runners (reproduced across runs despite linkcheck_retries=10), failing the linkcheck job on external factors. Add both to linkcheck_ignore, matching the existing entries for hosts that block non-browser requests. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01DWoMomNAcBM3e8duJrb2do --- docs/conf.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/conf.py b/docs/conf.py index e277d0f2c1c9..a04f6438394c 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -213,6 +213,10 @@ r"https://github.com", # 403s r"https://e-trust.gosuslugi.ru/", + # Returns 403 to CI/cloud IP ranges + r"https://eprint.iacr.org", + # Consistently exceeds the linkcheck timeout from CI runners + r"https://alexgaynor.net", ] autosectionlabel_prefix_document = True