From 68f4ffc072c781777960436d7d25645fb3d2fada Mon Sep 17 00:00:00 2001 From: mavrick Date: Thu, 5 Nov 2026 19:38:15 -0600 Subject: [PATCH 1/3] ci(deps): check dependency sources and pin workflow actions --- .github/scripts/check-cargo-sources.py | 37 +++++++++++++++++++ .github/scripts/test_cargo_sources.py | 42 ++++++++++++++++++++++ .github/workflows/ci-label.yml | 2 +- .github/workflows/ci.yml | 34 ++++++++++-------- .github/workflows/claude-code-review.yml | 2 +- .github/workflows/docker.yml | 34 +++++++++--------- .github/workflows/docs-preview-publish.yml | 6 ++-- .github/workflows/docs-preview.yml | 12 +++---- .github/workflows/docs.yml | 8 ++--- .github/workflows/downloads-mirror.yml | 2 +- .github/workflows/fuzz.yml | 22 ++++++------ .github/workflows/nightly.yml | 8 ++--- .github/workflows/package-managers.yml | 6 ++-- .github/workflows/python.yml | 30 ++++++++-------- .github/workflows/reference.yml | 4 +-- .github/workflows/release-dry-run.yml | 2 +- .github/workflows/release.yml | 30 ++++++++-------- .github/workflows/test-python.yml | 8 ++--- .github/workflows/test-rust.yml | 6 ++-- .github/workflows/web-deploy.yml | 6 ++-- deny.toml | 11 +++++- docs/contributing.md | 10 +++++- 22 files changed, 211 insertions(+), 111 deletions(-) create mode 100644 .github/scripts/check-cargo-sources.py create mode 100644 .github/scripts/test_cargo_sources.py diff --git a/.github/scripts/check-cargo-sources.py b/.github/scripts/check-cargo-sources.py new file mode 100644 index 000000000..675fb9a84 --- /dev/null +++ b/.github/scripts/check-cargo-sources.py @@ -0,0 +1,37 @@ +#!/usr/bin/env python3 +"""Reject Cargo source/path overrides in tracked repository configuration (Python 3.11+).""" + +from pathlib import Path +import subprocess +import sys +import tomllib + + +def check(root: Path) -> list[str]: + """Inspect tracked modern and legacy configs, including those in nested workspaces.""" + paths = subprocess.check_output(["git", "ls-files", "-z"], cwd=root).decode().split("\0") + errors = [] + for name in paths: + path = Path(name) + if path.parent.name != ".cargo" or path.name not in {"config", "config.toml"}: + continue + try: + with (root / path).open("rb") as source: + config = tomllib.load(source) + except (OSError, ValueError): + errors.append(f"{name}: cannot read valid TOML") + continue + if config.get("source") or config.get("paths"): + errors.append(f"{name}: Cargo source replacements and path overrides are not allowed") + return errors + + +if __name__ == "__main__": + repo = Path(__file__).resolve().parents[2] + try: + problems = check(repo) + except subprocess.CalledProcessError: + sys.exit("cannot list tracked Cargo configuration") + for problem in problems: + print(problem, file=sys.stderr) + sys.exit(bool(problems)) diff --git a/.github/scripts/test_cargo_sources.py b/.github/scripts/test_cargo_sources.py new file mode 100644 index 000000000..505376839 --- /dev/null +++ b/.github/scripts/test_cargo_sources.py @@ -0,0 +1,42 @@ +"""Regression checks for Cargo configuration that can bypass registry source checks.""" + +import importlib.util +from pathlib import Path +import subprocess +import tempfile +import unittest + +SPEC = importlib.util.spec_from_file_location("cargo_sources", Path(__file__).with_name("check-cargo-sources.py")) +MODULE = importlib.util.module_from_spec(SPEC) +SPEC.loader.exec_module(MODULE) + + +class CargoSources(unittest.TestCase): + def check_config(self, name, text): + """Track a config in an isolated repository, with no dependency downloads or builds.""" + with tempfile.TemporaryDirectory() as folder: + root = Path(folder) + subprocess.run(["git", "init", "-q", folder], check=True) + path = root / name + path.parent.mkdir(parents=True) + path.write_text(text) + subprocess.run(["git", "add", "--", name], cwd=root, check=True) + return MODULE.check(root) + + def test_build_options_are_allowed(self): + self.assertEqual(self.check_config(".cargo/config.toml", '[alias]\nxtask = "run -p xtask --"\n'), []) + + def test_replacements_and_path_overrides_are_rejected_in_both_formats(self): + for name in [".cargo/config", "fuzz/.cargo/config.toml"]: + for text in ['[source.crates-io]\nreplace-with = "mirror"\n', 'paths = ["../dependency"]\n']: + with self.subTest(name=name, text=text): + problems = self.check_config(name, text) + self.assertEqual(len(problems), 1) + self.assertTrue(problems[0].startswith(name + ":")) + + def test_invalid_toml_is_rejected(self): + self.assertEqual(self.check_config(".cargo/config.toml", "[broken"), [".cargo/config.toml: cannot read valid TOML"]) + + +if __name__ == "__main__": + unittest.main() diff --git a/.github/workflows/ci-label.yml b/.github/workflows/ci-label.yml index e3ada4342..61b47b7f5 100644 --- a/.github/workflows/ci-label.yml +++ b/.github/workflows/ci-label.yml @@ -21,7 +21,7 @@ jobs: outputs: os: ${{ steps.os.outputs.os }} steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 with: sparse-checkout: .github/scripts - id: os diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 632dd21e6..297b0cc75 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -24,28 +24,28 @@ jobs: name: Lint (pre-commit) runs-on: ubuntu-latest steps: - - uses: actions/checkout@v7 - - uses: dtolnay/rust-toolchain@stable + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 + - uses: dtolnay/rust-toolchain@b725eda525362e7cf34af9a7243cac1e3f01a7ec # stable with: components: rustfmt, clippy - - uses: Swatinem/rust-cache@v2 + - uses: Swatinem/rust-cache@d1527c8f67ef9af357290475d4af4b0fab8f12e0 # v2 with: # Only main saves the cache (see test-rust.yml). save-if: ${{ github.ref == 'refs/heads/main' }} - - uses: actions/setup-python@v7 + - uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7 with: python-version: "3.12" - - uses: pre-commit/action@v3.0.1 + - uses: pre-commit/action@2c7b3805fd2a0fd8c1884dcaebf91fc102a13ecd # v3.0.1 wasm: name: Web app (wasm32) runs-on: ubuntu-latest steps: - - uses: actions/checkout@v7 - - uses: dtolnay/rust-toolchain@stable + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 + - uses: dtolnay/rust-toolchain@b725eda525362e7cf34af9a7243cac1e3f01a7ec # stable with: targets: wasm32-unknown-unknown - - uses: Swatinem/rust-cache@v2 + - uses: Swatinem/rust-cache@d1527c8f67ef9af357290475d4af4b0fab8f12e0 # v2 with: # Only main saves the cache (see test-rust.yml). save-if: ${{ github.ref == 'refs/heads/main' }} @@ -59,17 +59,21 @@ jobs: name: Licences runs-on: ubuntu-latest steps: - - uses: actions/checkout@v7 - - uses: dtolnay/rust-toolchain@stable - - uses: Swatinem/rust-cache@v2 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 + - uses: dtolnay/rust-toolchain@b725eda525362e7cf34af9a7243cac1e3f01a7ec # stable + - uses: Swatinem/rust-cache@d1527c8f67ef9af357290475d4af4b0fab8f12e0 # v2 with: # Only main saves the cache (see test-rust.yml). save-if: ${{ github.ref == 'refs/heads/main' }} - - uses: taiki-e/install-action@v2 + - uses: taiki-e/install-action@c509219cf42fba86913069efd0ade2458c59337b # v2 with: tool: cargo-deny,cargo-about@0.9.2 - - name: Dependency licences - run: cargo deny --locked check licenses + - name: Cargo source replacements + run: | + python3 -m unittest discover -s .github/scripts -p 'test_*.py' + python3 .github/scripts/check-cargo-sources.py + - name: Dependency licences and sources + run: cargo deny --locked check licenses sources - name: Third-party notices # Exit code 2 is stale notices (a warning); anything else (cargo-about failing, a licence # it can't work out) fails the job. @@ -88,7 +92,7 @@ jobs: outputs: os: ${{ steps.os.outputs.os }} steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 with: sparse-checkout: .github/scripts - id: os diff --git a/.github/workflows/claude-code-review.yml b/.github/workflows/claude-code-review.yml index 0ab862566..0dc388d38 100644 --- a/.github/workflows/claude-code-review.yml +++ b/.github/workflows/claude-code-review.yml @@ -185,7 +185,7 @@ jobs: echo "sha=$sha" >> "$GITHUB_OUTPUT" - name: Checkout PR head for review context (read-only; never executed) - uses: actions/checkout@v7 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 with: # Check out the PR head so Read/Grep/Glob show the *proposed* file # contents (and newly added files) that Claude is reviewing — the base diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 34c3cc20c..319011ba1 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -75,15 +75,15 @@ jobs: packages: write steps: - name: Checkout repository - uses: actions/checkout@v7 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 with: persist-credentials: false - - uses: docker/setup-buildx-action@v4 + - uses: docker/setup-buildx-action@f87e5991a6d7451dcb8d9637bfbc97413f497069 # v4 - name: Image tags and labels id: meta - uses: docker/metadata-action@v6 + uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 # v6 env: # The registry shows the index's annotations for a multi-platform image. DOCKER_METADATA_ANNOTATIONS_LEVELS: manifest,index @@ -103,7 +103,7 @@ jobs: # The image for the runner's platform, loaded into Docker to check that it serves the app. - name: Build for the smoke test - uses: docker/build-push-action@v7 + uses: docker/build-push-action@c3c9e263c25d99ce0380d002d59b67737d91b0dc # v7 with: context: . platforms: linux/amd64 @@ -132,7 +132,7 @@ jobs: - name: Sign in to the GitHub Container Registry if: env.PUBLISH == 'true' - uses: docker/login-action@v4 + uses: docker/login-action@8aa5831fb8d48d8f76594c7ddde61ae58019f550 # v4 with: registry: ghcr.io username: ${{ github.actor }} @@ -141,7 +141,7 @@ jobs: # Both platforms; the build stage is the smoke test's, from the builder's cache. - name: Publish if: env.PUBLISH == 'true' - uses: docker/build-push-action@v7 + uses: docker/build-push-action@c3c9e263c25d99ce0380d002d59b67737d91b0dc # v7 with: context: . platforms: linux/amd64,linux/arm64 @@ -169,15 +169,15 @@ jobs: runner: ubuntu-24.04-arm steps: - name: Checkout repository - uses: actions/checkout@v7 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 with: persist-credentials: false - - uses: docker/setup-buildx-action@v4 + - uses: docker/setup-buildx-action@f87e5991a6d7451dcb8d9637bfbc97413f497069 # v4 - name: Image labels id: meta - uses: docker/metadata-action@v6 + uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 # v6 with: images: ${{ env.CLI_IMAGE }} flavor: latest=false @@ -189,7 +189,7 @@ jobs: org.opencontainers.image.url=https://rustgis.app - name: Build for the smoke test - uses: docker/build-push-action@v7 + uses: docker/build-push-action@c3c9e263c25d99ce0380d002d59b67737d91b0dc # v7 with: context: . file: packaging/docker/cli.Dockerfile @@ -214,7 +214,7 @@ jobs: - name: Sign in to the GitHub Container Registry if: env.PUBLISH == 'true' - uses: docker/login-action@v4 + uses: docker/login-action@8aa5831fb8d48d8f76594c7ddde61ae58019f550 # v4 with: registry: ghcr.io username: ${{ github.actor }} @@ -224,7 +224,7 @@ jobs: - name: Publish by digest id: push if: env.PUBLISH == 'true' - uses: docker/build-push-action@v7 + uses: docker/build-push-action@c3c9e263c25d99ce0380d002d59b67737d91b0dc # v7 with: context: . file: packaging/docker/cli.Dockerfile @@ -244,7 +244,7 @@ jobs: - name: Upload the digest if: env.PUBLISH == 'true' - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7 with: name: cli-digest-${{ matrix.arch }} path: ${{ runner.temp }}/digests/* @@ -262,24 +262,24 @@ jobs: packages: write steps: - name: Download the digests - uses: actions/download-artifact@v8 + uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8 with: path: ${{ runner.temp }}/digests pattern: cli-digest-* merge-multiple: true - - uses: docker/setup-buildx-action@v4 + - uses: docker/setup-buildx-action@f87e5991a6d7451dcb8d9637bfbc97413f497069 # v4 - name: Image tags id: meta - uses: docker/metadata-action@v6 + uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 # v6 with: images: ${{ env.CLI_IMAGE }} flavor: latest=false tags: ${{ env.TAGS }} - name: Sign in to the GitHub Container Registry - uses: docker/login-action@v4 + uses: docker/login-action@8aa5831fb8d48d8f76594c7ddde61ae58019f550 # v4 with: registry: ghcr.io username: ${{ github.actor }} diff --git a/.github/workflows/docs-preview-publish.yml b/.github/workflows/docs-preview-publish.yml index 60d2d7fad..963c5dfe0 100644 --- a/.github/workflows/docs-preview-publish.yml +++ b/.github/workflows/docs-preview-publish.yml @@ -63,7 +63,7 @@ jobs: echo "has_pr=$(jq 'index("preview-pr") != null' <<< "$names")" >> "$GITHUB_OUTPUT" echo "has_site=$(jq 'index("preview-site") != null' <<< "$names")" >> "$GITHUB_OUTPUT" - - uses: actions/download-artifact@v8 + - uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8 if: steps.artifacts.outputs.has_pr == 'true' with: name: preview-pr @@ -144,7 +144,7 @@ jobs: echo "fork=${fork}" } >> "$GITHUB_OUTPUT" - - uses: actions/download-artifact@v8 + - uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8 if: steps.pr.outputs.mode == 'deploy' with: name: preview-site @@ -240,7 +240,7 @@ jobs: if: >- (steps.deploy.outcome == 'success' && steps.pr.outputs.mode == 'deploy') || steps.pr.outputs.mode == 'awaiting' - uses: actions/github-script@v9 + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9 env: PR: ${{ steps.pr.outputs.number }} MODE: ${{ steps.pr.outputs.mode }} diff --git a/.github/workflows/docs-preview.yml b/.github/workflows/docs-preview.yml index 9baca9c46..e00539a32 100644 --- a/.github/workflows/docs-preview.yml +++ b/.github/workflows/docs-preview.yml @@ -34,10 +34,10 @@ jobs: permissions: contents: read steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 with: persist-credentials: false - - uses: astral-sh/setup-uv@v7 + - uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7 with: enable-cache: false - name: Build docs with Zensical @@ -49,10 +49,10 @@ jobs: rm -f site/CNAME # Production serves the app from web.rustgis.app (web-deploy.yml); previews include it # at /app/ so a pull request's web build can be tried before merging. - - uses: dtolnay/rust-toolchain@stable + - uses: dtolnay/rust-toolchain@b725eda525362e7cf34af9a7243cac1e3f01a7ec # stable with: targets: wasm32-unknown-unknown - - uses: Swatinem/rust-cache@v2 + - uses: Swatinem/rust-cache@d1527c8f67ef9af357290475d4af4b0fab8f12e0 # v2 - name: Build the web app run: | # Pinned Trunk release, checksum-verified, installed outside root-owned directories. @@ -67,7 +67,7 @@ jobs: mkdir -p ../../site/app cp -r ../../dist/web/. ../../site/app/ - - uses: actions/upload-artifact@v7 + - uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7 with: name: preview-site path: site @@ -85,7 +85,7 @@ jobs: run: | mkdir -p preview-pr printf '%s\n' "$PR" > preview-pr/pr.txt - - uses: actions/upload-artifact@v7 + - uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7 with: name: preview-pr path: preview-pr diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 78654ac6e..ffe671d8f 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -18,8 +18,8 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v7 - - uses: astral-sh/setup-uv@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 + - uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7 with: enable-cache: false - name: Configure Google Analytics @@ -46,7 +46,7 @@ jobs: uv venv --python 3.12 uv pip install -r requirements_docs.txt .venv/bin/zensical build - - uses: actions/upload-pages-artifact@v5 + - uses: actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9 # v5 with: path: ./site @@ -58,4 +58,4 @@ jobs: url: ${{ steps.deployment.outputs.page_url }} steps: - id: deployment - uses: actions/deploy-pages@v5 + uses: actions/deploy-pages@368f82528645a54fb793d4d04e342629a3f51346 # v5 diff --git a/.github/workflows/downloads-mirror.yml b/.github/workflows/downloads-mirror.yml index 90bc4f91f..55480f705 100644 --- a/.github/workflows/downloads-mirror.yml +++ b/.github/workflows/downloads-mirror.yml @@ -48,7 +48,7 @@ jobs: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} DESTINATION_REPOSITORY: opengeos/rustgis-downloads steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 with: persist-credentials: false diff --git a/.github/workflows/fuzz.yml b/.github/workflows/fuzz.yml index 2fba0efcb..b6b52e4c0 100644 --- a/.github/workflows/fuzz.yml +++ b/.github/workflows/fuzz.yml @@ -37,11 +37,11 @@ jobs: if: (github.event_name == 'pull_request' && github.event.label.name == 'ci:fuzz') || (github.event_name != 'pull_request' && (github.repository == 'opengeos/RustGIS' || github.event_name == 'workflow_dispatch')) runs-on: ubuntu-latest steps: - - uses: actions/checkout@v7 - - uses: dtolnay/rust-toolchain@stable + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 + - uses: dtolnay/rust-toolchain@b725eda525362e7cf34af9a7243cac1e3f01a7ec # stable with: components: rustfmt - - uses: taiki-e/install-action@v2 + - uses: taiki-e/install-action@c509219cf42fba86913069efd0ade2458c59337b # v2 with: tool: cargo-deny # fuzz/deny.toml: the workspace's licences plus NCSA, for libFuzzer. @@ -63,19 +63,19 @@ jobs: SECONDS_PER_TARGET: ${{ github.event_name == 'pull_request' && '60' || inputs.seconds || '600' }} TARGET: ${{ matrix.target }} steps: - - uses: actions/checkout@v7 - - uses: dtolnay/rust-toolchain@nightly - - uses: Swatinem/rust-cache@v2 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 + - uses: dtolnay/rust-toolchain@2c76c034f9e32a5d6e2c104dc4df23a22476db04 # nightly + - uses: Swatinem/rust-cache@d1527c8f67ef9af357290475d4af4b0fab8f12e0 # v2 with: workspaces: fuzz shared-key: fuzz save-if: ${{ github.ref == 'refs/heads/main' && matrix.target == 'read_layers' }} - - uses: taiki-e/install-action@v2 + - uses: taiki-e/install-action@c509219cf42fba86913069efd0ade2458c59337b # v2 with: tool: cargo-fuzz # The corpus each target has grown, kept between nights. Restored and saved as separate steps: # the combined action saves only when the job passes, and a target with a known finding fails. - - uses: actions/cache/restore@v6 + - uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6 with: path: fuzz/corpus/${{ matrix.target }} key: fuzz-corpus-${{ matrix.target }}-${{ github.run_id }} @@ -119,13 +119,13 @@ jobs: fi - name: Keep the corpus if: ${{ !cancelled() && github.event_name != 'pull_request' }} - uses: actions/cache/save@v6 + uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6 with: path: fuzz/corpus/${{ matrix.target }} key: fuzz-corpus-${{ matrix.target }}-${{ github.run_id }} - name: Keep the failing inputs if: failure() && steps.findings.outcome == 'failure' - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7 with: name: fuzz-${{ matrix.target }} path: fuzz/artifacts/${{ matrix.target }} @@ -140,7 +140,7 @@ jobs: permissions: issues: write steps: - - uses: actions/download-artifact@v8 + - uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8 with: pattern: fuzz-* path: findings diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 8348a8f45..e5da47888 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -68,12 +68,12 @@ jobs: outputs: tested: ${{ steps.data.outputs.ok }} steps: - - uses: actions/checkout@v7 - - uses: dtolnay/rust-toolchain@stable - - uses: Swatinem/rust-cache@v2 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 + - uses: dtolnay/rust-toolchain@b725eda525362e7cf34af9a7243cac1e3f01a7ec # stable + - uses: Swatinem/rust-cache@d1527c8f67ef9af357290475d4af4b0fab8f12e0 # v2 with: save-if: false - - uses: actions/cache@v6 + - uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6 with: path: workflow-data key: workflow-data-census-2024-1 diff --git a/.github/workflows/package-managers.yml b/.github/workflows/package-managers.yml index ef6f6cbf1..357aecbdf 100644 --- a/.github/workflows/package-managers.yml +++ b/.github/workflows/package-managers.yml @@ -83,7 +83,7 @@ jobs: env: TAP_KEY: ${{ secrets.HOMEBREW_TAP_DEPLOY_KEY }} steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 if: env.TAP_KEY != '' with: persist-credentials: false @@ -122,7 +122,7 @@ jobs: env: AUR_KEY: ${{ secrets.AUR_SSH_PRIVATE_KEY }} steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 if: env.AUR_KEY != '' with: persist-credentials: false @@ -165,7 +165,7 @@ jobs: env: COPR_CONFIG: ${{ secrets.COPR_CONFIG }} steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 if: env.COPR_CONFIG != '' with: persist-credentials: false diff --git a/.github/workflows/python.yml b/.github/workflows/python.yml index f7da97686..a9f8ce846 100644 --- a/.github/workflows/python.yml +++ b/.github/workflows/python.yml @@ -41,7 +41,7 @@ jobs: outputs: os: ${{ steps.os.outputs.os }} steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 with: sparse-checkout: .github/scripts - id: os @@ -72,17 +72,17 @@ jobs: - { name: windows-x86_64, runner: windows-latest, target: x64 } - { name: windows-aarch64, runner: windows-11-arm, target: aarch64 } steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 # The Windows ARM64 image ships no Rust toolchain; maturin-action needs rustup. - - uses: dtolnay/rust-toolchain@stable + - uses: dtolnay/rust-toolchain@b725eda525362e7cf34af9a7243cac1e3f01a7ec # stable if: runner.os == 'Windows' && runner.arch == 'ARM64' - - uses: PyO3/maturin-action@v1 + - uses: PyO3/maturin-action@e83996d129638aa358a18fbd1dfb82f0b0fb5d3b # v1 with: working-directory: apps/rustgis-python target: ${{ matrix.platform.target }} manylinux: ${{ matrix.platform.manylinux || 'auto' }} args: --release --locked --out dist - - uses: actions/setup-python@v7 + - uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7 with: python-version: "3.14" # Each runner builds for its own architecture, so the wheel installs and runs here. @@ -91,7 +91,7 @@ jobs: run: | python -m pip install --no-index --find-links apps/rustgis-python/dist rustgis python -c "import rustgis; s = rustgis.Session(sample=True); assert s.layers() and s.to_png(width=64, height=32)" - - uses: actions/upload-artifact@v7 + - uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7 with: name: wheels-${{ matrix.platform.name }} path: apps/rustgis-python/dist @@ -102,9 +102,9 @@ jobs: name: Source distribution runs-on: ubuntu-latest steps: - - uses: actions/checkout@v7 - - uses: dtolnay/rust-toolchain@stable - - uses: Swatinem/rust-cache@v2 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 + - uses: dtolnay/rust-toolchain@b725eda525362e7cf34af9a7243cac1e3f01a7ec # stable + - uses: Swatinem/rust-cache@d1527c8f67ef9af357290475d4af4b0fab8f12e0 # v2 with: # Only main saves the cache (see test-rust.yml). save-if: ${{ github.ref == 'refs/heads/main' }} @@ -112,12 +112,12 @@ jobs: # reach the repository root). - name: The license copy matches LICENSE run: cmp LICENSE apps/rustgis-python/LICENSE || { echo "::error::apps/rustgis-python/LICENSE differs from LICENSE."; exit 1; } - - uses: PyO3/maturin-action@v1 + - uses: PyO3/maturin-action@e83996d129638aa358a18fbd1dfb82f0b0fb5d3b # v1 with: working-directory: apps/rustgis-python command: sdist args: --out dist - - uses: actions/setup-python@v7 + - uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7 with: python-version: "3.14" - name: Build and test from the sdist alone @@ -132,7 +132,7 @@ jobs: tar tzf ./*.tar.gz | grep -E '^[^/]+/THIRD-PARTY-LICENSES.txt$' || { echo "::error::The sdist has no THIRD-PARTY-LICENSES.txt at its root."; exit 1; } python -m pip install ./*.tar.gz pytest python -m pytest -q test_session.py - - uses: actions/upload-artifact@v7 + - uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7 with: name: wheels-sdist path: apps/rustgis-python/dist @@ -146,7 +146,7 @@ jobs: permissions: contents: write steps: - - uses: actions/download-artifact@v8 + - uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8 with: pattern: wheels-* merge-multiple: true @@ -166,11 +166,11 @@ jobs: permissions: id-token: write steps: - - uses: actions/download-artifact@v8 + - uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8 with: pattern: wheels-* merge-multiple: true path: dist - - uses: pypa/gh-action-pypi-publish@release/v1 + - uses: pypa/gh-action-pypi-publish@7245906fb61fa33a13554f9d5fb856fe61758086 # release/v1 with: packages-dir: dist diff --git a/.github/workflows/reference.yml b/.github/workflows/reference.yml index 871b4f0f3..ecd4da541 100644 --- a/.github/workflows/reference.yml +++ b/.github/workflows/reference.yml @@ -25,8 +25,8 @@ jobs: name: Reference answers match generate.py runs-on: ubuntu-latest steps: - - uses: actions/checkout@v7 - - uses: astral-sh/setup-uv@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 + - uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7 - name: Regenerate and compare working-directory: crates/analysis/tests/reference run: uv run generate.py --check diff --git a/.github/workflows/release-dry-run.yml b/.github/workflows/release-dry-run.yml index 5c734b895..6ba5932aa 100644 --- a/.github/workflows/release-dry-run.yml +++ b/.github/workflows/release-dry-run.yml @@ -53,7 +53,7 @@ jobs: # Dispatch the release workflows and read back their conclusions. actions: write steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 with: ref: ${{ inputs.ref || github.ref }} persist-credentials: false diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 86dfb95d8..4f487a379 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -45,13 +45,13 @@ jobs: - name: macOS Intel os: macos-15-intel steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 - - uses: dtolnay/rust-toolchain@stable + - uses: dtolnay/rust-toolchain@b725eda525362e7cf34af9a7243cac1e3f01a7ec # stable with: targets: ${{ matrix.target }} - - uses: Swatinem/rust-cache@v2 + - uses: Swatinem/rust-cache@d1527c8f67ef9af357290475d4af4b0fab8f12e0 # v2 - name: Version id: version @@ -267,7 +267,7 @@ jobs: rm -rf squashfs-root - name: Upload workflow artifact - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7 with: name: rustgis-${{ matrix.os }} path: dist/* @@ -277,11 +277,11 @@ jobs: name: Web app runs-on: ubuntu-latest steps: - - uses: actions/checkout@v7 - - uses: dtolnay/rust-toolchain@stable + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 + - uses: dtolnay/rust-toolchain@b725eda525362e7cf34af9a7243cac1e3f01a7ec # stable with: targets: wasm32-unknown-unknown - - uses: Swatinem/rust-cache@v2 + - uses: Swatinem/rust-cache@d1527c8f67ef9af357290475d4af4b0fab8f12e0 # v2 - name: Install Trunk run: | set -euo pipefail @@ -308,7 +308,7 @@ jobs: exit 1 fi (cd dist/web && zip -r "../RustGIS-$version-web.zip" .) - - uses: actions/upload-artifact@v7 + - uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7 with: name: rustgis-web path: dist/RustGIS-*-web.zip @@ -320,12 +320,12 @@ jobs: name: Third-party notices runs-on: ubuntu-latest steps: - - uses: actions/checkout@v7 - - uses: dtolnay/rust-toolchain@stable - - uses: Swatinem/rust-cache@v2 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 + - uses: dtolnay/rust-toolchain@b725eda525362e7cf34af9a7243cac1e3f01a7ec # stable + - uses: Swatinem/rust-cache@d1527c8f67ef9af357290475d4af4b0fab8f12e0 # v2 with: save-if: false - - uses: taiki-e/install-action@v2 + - uses: taiki-e/install-action@c509219cf42fba86913069efd0ade2458c59337b # v2 with: tool: cargo-about@0.9.2 - name: The notices are up to date @@ -336,7 +336,7 @@ jobs: needs: [build, web, notices] runs-on: ubuntu-latest steps: - - uses: actions/download-artifact@v8 + - uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8 with: path: dist merge-multiple: true @@ -345,7 +345,7 @@ jobs: working-directory: dist run: sha256sum -- * | tee SHA256SUMS - - uses: actions/upload-artifact@v7 + - uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7 with: name: rustgis-sha256sums path: dist/SHA256SUMS @@ -358,7 +358,7 @@ jobs: permissions: contents: write steps: - - uses: actions/download-artifact@v8 + - uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8 with: path: dist merge-multiple: true diff --git a/.github/workflows/test-python.yml b/.github/workflows/test-python.yml index bfaa622c9..bd96cf84d 100644 --- a/.github/workflows/test-python.yml +++ b/.github/workflows/test-python.yml @@ -40,15 +40,15 @@ jobs: matrix: include: ${{ fromJSON(needs.plan.outputs.include) }} steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 with: persist-credentials: false - - uses: dtolnay/rust-toolchain@stable - - uses: Swatinem/rust-cache@v2 + - uses: dtolnay/rust-toolchain@b725eda525362e7cf34af9a7243cac1e3f01a7ec # stable + - uses: Swatinem/rust-cache@d1527c8f67ef9af357290475d4af4b0fab8f12e0 # v2 with: # Only main saves the cache (see test-rust.yml). save-if: ${{ github.ref == 'refs/heads/main' }} - - uses: actions/setup-python@v7 + - uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7 with: python-version: ${{ matrix.python }} # rustgis.qt's tests need Qt WebEngine: one Linux job installs it (a large download) and diff --git a/.github/workflows/test-rust.yml b/.github/workflows/test-rust.yml index 9f7451e8f..718d86ca6 100644 --- a/.github/workflows/test-rust.yml +++ b/.github/workflows/test-rust.yml @@ -42,11 +42,11 @@ jobs: matrix: os: ${{ fromJSON(inputs.os) }} steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 with: persist-credentials: false - - uses: dtolnay/rust-toolchain@stable - - uses: Swatinem/rust-cache@v2 + - uses: dtolnay/rust-toolchain@b725eda525362e7cf34af9a7243cac1e3f01a7ec # stable + - uses: Swatinem/rust-cache@d1527c8f67ef9af357290475d4af4b0fab8f12e0 # v2 with: # Pull requests restore main's cache but don't save their own: saving takes minutes on # Windows, and pull request caches crowd main's out of the repository's cache space. diff --git a/.github/workflows/web-deploy.yml b/.github/workflows/web-deploy.yml index 6c0de301c..1fe191ff9 100644 --- a/.github/workflows/web-deploy.yml +++ b/.github/workflows/web-deploy.yml @@ -30,7 +30,7 @@ jobs: timeout-minutes: 30 steps: - name: Checkout repository - uses: actions/checkout@v7 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 with: ref: ${{ inputs.ref || github.sha }} persist-credentials: false @@ -39,10 +39,10 @@ jobs: id: built run: echo "sha=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT" - - uses: dtolnay/rust-toolchain@stable + - uses: dtolnay/rust-toolchain@b725eda525362e7cf34af9a7243cac1e3f01a7ec # stable with: targets: wasm32-unknown-unknown - - uses: Swatinem/rust-cache@v2 + - uses: Swatinem/rust-cache@d1527c8f67ef9af357290475d4af4b0fab8f12e0 # v2 - name: Build the web app run: | diff --git a/deny.toml b/deny.toml index 3c12fd75c..78e882a36 100644 --- a/deny.toml +++ b/deny.toml @@ -3,7 +3,7 @@ [graph] all-features = false -exclude-dev = true +exclude-dev = false [licenses] confidence-threshold = 0.8 @@ -29,3 +29,12 @@ allow = [ [licenses.private] # RustGIS's own apps and xtask (`publish = false`). ignore = true + +# Dependencies currently come only from crates.io. An intentional git or registry source must +# be reviewed here too; git sources must name a revision rather than follow a branch or tag. +[sources] +unknown-registry = "deny" +unknown-git = "deny" +allow-registry = ["https://github.com/rust-lang/crates.io-index"] +allow-git = [] +required-git-spec = "rev" diff --git a/docs/contributing.md b/docs/contributing.md index 1c3dfdecd..c385c55b8 100644 --- a/docs/contributing.md +++ b/docs/contributing.md @@ -39,7 +39,15 @@ breaks of the rules in AGENTS.md are fixed in the pull request. `cargo clippy --workspace --all-targets -- -D warnings`, `cargo test --workspace -q` and `cargo xtask layers`. The pre-commit hooks also check TOML, YAML, JSON, whitespace and large files. CI separately builds `rustgis-web` for `wasm32-unknown-unknown` and runs -`cargo deny --locked check licenses` against `deny.toml`. +`cargo deny --locked check licenses sources` against `deny.toml`, including development +dependencies. Sources are limited to crates.io; an intentional git source needs an explicit +allowlist entry and a pinned revision. CI also runs `python3 .github/scripts/check-cargo-sources.py` +to reject repository Cargo configuration that replaces sources or overrides dependency paths. +User-level Cargo mirrors are outside this repository check. + +Workflow actions are pinned to full commit SHAs with the previous version or branch in a comment. +Dependabot's existing GitHub Actions updates keep these pins current. When changing an action, +resolve the commit in that action's own repository and keep the version comment in step. Other workspace tasks: From 2c41caac670150403bf5a226f329139d54e4ac1c Mon Sep 17 00:00:00 2001 From: mavrick Date: Thu, 5 Nov 2026 20:11:33 -0600 Subject: [PATCH 2/3] fix(ci): reject indirect Cargo configuration overrides --- .github/scripts/check-cargo-sources.py | 4 ++-- .github/scripts/test_cargo_sources.py | 10 ++++++++-- docs/contributing.md | 4 +++- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/.github/scripts/check-cargo-sources.py b/.github/scripts/check-cargo-sources.py index 675fb9a84..35061c0f4 100644 --- a/.github/scripts/check-cargo-sources.py +++ b/.github/scripts/check-cargo-sources.py @@ -21,8 +21,8 @@ def check(root: Path) -> list[str]: except (OSError, ValueError): errors.append(f"{name}: cannot read valid TOML") continue - if config.get("source") or config.get("paths"): - errors.append(f"{name}: Cargo source replacements and path overrides are not allowed") + if any(config.get(key) for key in ("source", "paths", "patch", "include")): + errors.append(f"{name}: Cargo source/path/patch overrides and included configs are not allowed") return errors diff --git a/.github/scripts/test_cargo_sources.py b/.github/scripts/test_cargo_sources.py index 505376839..0ceca5708 100644 --- a/.github/scripts/test_cargo_sources.py +++ b/.github/scripts/test_cargo_sources.py @@ -26,9 +26,15 @@ def check_config(self, name, text): def test_build_options_are_allowed(self): self.assertEqual(self.check_config(".cargo/config.toml", '[alias]\nxtask = "run -p xtask --"\n'), []) - def test_replacements_and_path_overrides_are_rejected_in_both_formats(self): + def test_overrides_and_includes_are_rejected_in_both_formats(self): for name in [".cargo/config", "fuzz/.cargo/config.toml"]: - for text in ['[source.crates-io]\nreplace-with = "mirror"\n', 'paths = ["../dependency"]\n']: + for text in [ + '[source.crates-io]\nreplace-with = "mirror"\n', + 'paths = ["../dependency"]\n', + '[patch.crates-io]\nexample = { path = "../dependency" }\n', + 'include = ["other.toml"]\n', + 'include = [{ path = "other.toml", optional = true }]\n', + ]: with self.subTest(name=name, text=text): problems = self.check_config(name, text) self.assertEqual(len(problems), 1) diff --git a/docs/contributing.md b/docs/contributing.md index c385c55b8..a2ee519b6 100644 --- a/docs/contributing.md +++ b/docs/contributing.md @@ -42,7 +42,9 @@ CI separately builds `rustgis-web` for `wasm32-unknown-unknown` and runs `cargo deny --locked check licenses sources` against `deny.toml`, including development dependencies. Sources are limited to crates.io; an intentional git source needs an explicit allowlist entry and a pinned revision. CI also runs `python3 .github/scripts/check-cargo-sources.py` -to reject repository Cargo configuration that replaces sources or overrides dependency paths. +to reject repository Cargo configuration with `source`, `paths` or `patch` overrides. +Config `include` directives are also rejected so those checks cannot be bypassed by loading +another file; put intentional dependency patches in `Cargo.toml` for review. User-level Cargo mirrors are outside this repository check. Workflow actions are pinned to full commit SHAs with the previous version or branch in a comment. From a35ed518f7762284ddd65655ea8e9d7a357b25d9 Mon Sep 17 00:00:00 2001 From: mavrick Date: Thu, 5 Nov 2026 21:52:36 -0600 Subject: [PATCH 3/3] fix(ci): cover case variants and fuzz dependency sources --- .github/scripts/check-cargo-sources.py | 2 +- .github/scripts/test_cargo_sources.py | 6 +- .github/workflows/fuzz.yml | 4 +- docs/contributing.md | 6 +- fuzz/Cargo.lock | 136 +++++++++++++++++++++++++ fuzz/deny.toml | 12 ++- 6 files changed, 157 insertions(+), 9 deletions(-) diff --git a/.github/scripts/check-cargo-sources.py b/.github/scripts/check-cargo-sources.py index 35061c0f4..0744e5671 100644 --- a/.github/scripts/check-cargo-sources.py +++ b/.github/scripts/check-cargo-sources.py @@ -13,7 +13,7 @@ def check(root: Path) -> list[str]: errors = [] for name in paths: path = Path(name) - if path.parent.name != ".cargo" or path.name not in {"config", "config.toml"}: + if path.parent.name.lower() != ".cargo" or path.name.lower() not in {"config", "config.toml"}: continue try: with (root / path).open("rb") as source: diff --git a/.github/scripts/test_cargo_sources.py b/.github/scripts/test_cargo_sources.py index 0ceca5708..73ee645e8 100644 --- a/.github/scripts/test_cargo_sources.py +++ b/.github/scripts/test_cargo_sources.py @@ -24,10 +24,12 @@ def check_config(self, name, text): return MODULE.check(root) def test_build_options_are_allowed(self): - self.assertEqual(self.check_config(".cargo/config.toml", '[alias]\nxtask = "run -p xtask --"\n'), []) + for name in [".cargo/config.toml", ".Cargo/Config.toml"]: + with self.subTest(name=name): + self.assertEqual(self.check_config(name, '[alias]\nxtask = "run -p xtask --"\n'), []) def test_overrides_and_includes_are_rejected_in_both_formats(self): - for name in [".cargo/config", "fuzz/.cargo/config.toml"]: + for name in [".cargo/config", "fuzz/.cargo/config.toml", ".Cargo/Config.toml", "fuzz/.CARGO/CONFIG"]: for text in [ '[source.crates-io]\nreplace-with = "mirror"\n', 'paths = ["../dependency"]\n', diff --git a/.github/workflows/fuzz.yml b/.github/workflows/fuzz.yml index b6b52e4c0..9b1c62cc0 100644 --- a/.github/workflows/fuzz.yml +++ b/.github/workflows/fuzz.yml @@ -44,8 +44,8 @@ jobs: - uses: taiki-e/install-action@c509219cf42fba86913069efd0ade2458c59337b # v2 with: tool: cargo-deny - # fuzz/deny.toml: the workspace's licences plus NCSA, for libFuzzer. - - run: cargo deny --manifest-path fuzz/Cargo.toml --locked check licenses + # fuzz/deny.toml: the workspace's source policy and licences plus NCSA, for libFuzzer. + - run: cargo deny --manifest-path fuzz/Cargo.toml --locked check licenses sources # The workspace's `cargo fmt --all` doesn't reach this crate. - run: cargo fmt --manifest-path fuzz/Cargo.toml --check diff --git a/docs/contributing.md b/docs/contributing.md index a2ee519b6..7f7e9090f 100644 --- a/docs/contributing.md +++ b/docs/contributing.md @@ -40,9 +40,11 @@ breaks of the rules in AGENTS.md are fixed in the pull request. `cargo xtask layers`. The pre-commit hooks also check TOML, YAML, JSON, whitespace and large files. CI separately builds `rustgis-web` for `wasm32-unknown-unknown` and runs `cargo deny --locked check licenses sources` against `deny.toml`, including development -dependencies. Sources are limited to crates.io; an intentional git source needs an explicit +dependencies. The fuzz workflow applies the same source policy using `fuzz/deny.toml`, which +also permits NCSA for libFuzzer. Sources are limited to crates.io; an intentional git source needs an explicit allowlist entry and a pinned revision. CI also runs `python3 .github/scripts/check-cargo-sources.py` -to reject repository Cargo configuration with `source`, `paths` or `patch` overrides. +to reject repository Cargo configuration with `source`, `paths` or `patch` overrides, including +case variants of `.cargo/config` and `.cargo/config.toml` used on case-insensitive filesystems. Config `include` directives are also rejected so those checks cannot be bypassed by loading another file; put intentional dependency patches in `Cargo.toml` for review. User-level Cargo mirrors are outside this repository check. diff --git a/fuzz/Cargo.lock b/fuzz/Cargo.lock index 7db5c859f..a1282dbe0 100644 --- a/fuzz/Cargo.lock +++ b/fuzz/Cargo.lock @@ -410,6 +410,16 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" +[[package]] +name = "combine" +version = "4.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfc320937d09e6de266b31b9afb480f197d7a861be86be7cb2ea7e5d1bfffc5e" +dependencies = [ + "bytes", + "memchr", +] + [[package]] name = "connection-string" version = "0.2.0" @@ -1445,6 +1455,55 @@ version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" +[[package]] +name = "jni" +version = "0.22.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5efd9a482cf3a427f00d6b35f14332adc7902ce91efb778580e180ff90fa3498" +dependencies = [ + "cfg-if", + "combine", + "jni-macros", + "jni-sys", + "log", + "simd_cesu8", + "thiserror 2.0.21", + "walkdir", + "windows-link", +] + +[[package]] +name = "jni-macros" +version = "0.22.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a00109accc170f0bdb141fed3e393c565b6f5e072365c3bd58f5b062591560a3" +dependencies = [ + "proc-macro2", + "quote", + "rustc_version", + "simd_cesu8", + "syn 2.0.119", +] + +[[package]] +name = "jni-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6377a88cb3910bee9b0fa88d4f42e1d2da8e79915598f65fb0c7ee14c878af2" +dependencies = [ + "jni-sys-macros", +] + +[[package]] +name = "jni-sys-macros" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38c0b942f458fe50cdac086d2f946512305e5631e720728f2a61aabcd47a6264" +dependencies = [ + "quote", + "syn 2.0.119", +] + [[package]] name = "jobserver" version = "0.1.35" @@ -2356,6 +2415,7 @@ dependencies = [ "rustgis-geom", "rustix", "rustls", + "rustls-native-certs", "ruzstd", "serde", "serde_json", @@ -2368,6 +2428,7 @@ dependencies = [ "tokio", "tokio-postgres-rustls", "tokio-util", + "ureq", "url", "webpki-roots", "weezl 0.2.1", @@ -2547,6 +2608,33 @@ dependencies = [ "zeroize", ] +[[package]] +name = "rustls-platform-verifier" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1167586491e2b18b8bfbb293e8180ec17c201c4f076d7cb3070ca964e7598f98" +dependencies = [ + "core-foundation", + "core-foundation-sys", + "jni", + "log", + "once_cell", + "rustls", + "rustls-native-certs", + "rustls-platform-verifier-android", + "rustls-webpki", + "security-framework", + "security-framework-sys", + "webpki-root-certs", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustls-platform-verifier-android" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eec689c0bc40ff2458a5977b6619cb718087084a18e02a131c599b62d05e1a5f" + [[package]] name = "rustls-webpki" version = "0.103.15" @@ -2577,6 +2665,15 @@ version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + [[package]] name = "saturating" version = "0.1.0" @@ -2752,6 +2849,16 @@ version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3a219298ac11a56ea9a6d2120044824d6f01aeb034955e7af7bc16858527deea" +[[package]] +name = "simd_cesu8" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11031e251abf8611c80f460e19dbdeb54a66db918e49c65a7065b46ac7aec520" +dependencies = [ + "rustc_version", + "simdutf8", +] + [[package]] name = "simdutf8" version = "0.1.5" @@ -3321,6 +3428,7 @@ dependencies = [ "percent-encoding", "rustls", "rustls-pki-types", + "rustls-platform-verifier", "ureq-proto", "utf8-zero", "webpki-roots", @@ -3384,6 +3492,16 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + [[package]] name = "wasi" version = "0.9.0+wasi-snapshot-preview1" @@ -3548,6 +3666,15 @@ dependencies = [ "untrusted", ] +[[package]] +name = "webpki-root-certs" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e49d0e65abc00c142e8f9428da991da9f1a250c39be97459901eb12b9b49f62a" +dependencies = [ + "rustls-pki-types", +] + [[package]] name = "webpki-roots" version = "1.0.11" @@ -3598,6 +3725,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +[[package]] +name = "winapi-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" +dependencies = [ + "windows-sys 0.52.0", +] + [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" diff --git a/fuzz/deny.toml b/fuzz/deny.toml index 9947a6c7a..788cb9b37 100644 --- a/fuzz/deny.toml +++ b/fuzz/deny.toml @@ -1,10 +1,10 @@ -# cargo-deny for the fuzz crate (`cargo deny --manifest-path fuzz/Cargo.toml check licenses`, run by +# cargo-deny for the fuzz crate (`cargo deny --manifest-path fuzz/Cargo.toml check licenses sources`, run by # the fuzz workflow): the workspace's deny.toml, plus NCSA for libFuzzer, which `libfuzzer-sys` # compiles. Nothing here is shipped; keep the rest in step with ../deny.toml. [graph] all-features = false -exclude-dev = true +exclude-dev = false [licenses] confidence-threshold = 0.8 @@ -31,3 +31,11 @@ allow = [ [licenses.private] # RustGIS's own crates and this one (`publish = false`). ignore = true + +# Apply the workspace source policy here too; fuzz dependencies are built by CI. +[sources] +unknown-registry = "deny" +unknown-git = "deny" +allow-registry = ["https://github.com/rust-lang/crates.io-index"] +allow-git = [] +required-git-spec = "rev"