From 03f6059bcc4a5193ded74e5300317f199333db2d Mon Sep 17 00:00:00 2001 From: Ryan Duguid Date: Sun, 1 Nov 2026 08:34:41 +1100 Subject: [PATCH 1/4] ci: add Codecov, Snyk and SonarCloud badges coverage.yml runs the tests under cargo-llvm-cov on pushes to develop, same-repository pull requests and manual runs, and a separate codecov job uploads the report with OIDC. snyk.yml tests the root and proxy Cargo graphs as CycloneDX SBOMs. The README gains tests, Codecov, Snyk and SonarCloud badges beside CodeQL and Codacy. The isolation test now ignores __LLVM_PROFILE_RT_INIT_ONCE, which the profiling runtime in an instrumented rtk sets for its own children. SECURITY.md sends reports to this repository's private vulnerability reporting form instead of upstream RTK's address, and CONTRIBUTING.md states the test policy and the CI test command. --- .github/workflows/CICD.md | 1 + .github/workflows/coverage.yml | 78 ++++++++++++++++++++++++++++++++++ .github/workflows/snyk.yml | 66 ++++++++++++++++++++++++++++ CONTRIBUTING.md | 2 +- README.md | 2 +- SECURITY.md | 6 +-- codecov.yml | 11 +++++ tests/isolate_rtk_test.rs | 4 +- 8 files changed, 163 insertions(+), 7 deletions(-) create mode 100644 .github/workflows/coverage.yml create mode 100644 .github/workflows/snyk.yml create mode 100644 codecov.yml diff --git a/.github/workflows/CICD.md b/.github/workflows/CICD.md index ad5deb0acc..f1d8cc2d01 100644 --- a/.github/workflows/CICD.md +++ b/.github/workflows/CICD.md @@ -36,6 +36,7 @@ Trigger: pull_request to develop or master + DCO check (independent, develop PRs only) + Dependabot (weekly: Cargo deps + GitHub Actions) + + coverage.yml (also on push to develop: the tests under cargo-llvm-cov, then Codecov) ``` ## Merge to develop — pre-release (cd.yml) diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml new file mode 100644 index 0000000000..317289e8f6 --- /dev/null +++ b/.github/workflows/coverage.yml @@ -0,0 +1,78 @@ +name: Coverage + +# ci.yml runs on pull requests only, so the test suite also runs here, under +# cargo-llvm-cov, on every push to develop. Its result is the README's tests +# badge, and its report feeds the Codecov badge. +on: + push: + branches: [develop] + pull_request: + branches: [develop] + workflow_dispatch: + +permissions: + contents: read + +env: + CARGO_TERM_COLOR: always + +jobs: + test: + name: test with coverage (ubuntu-latest) + # A fork's pull request gets no Codecov upload; ci.yml still tests it. + if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + fetch-depth: 0 + persist-credentials: false + - name: Install required search tools + run: sudo apt-get update && sudo apt-get install -y ripgrep grep + - uses: dtolnay/rust-toolchain@b725eda525362e7cf34af9a7243cac1e3f01a7ec # stable + with: + components: llvm-tools + - uses: Swatinem/rust-cache@d1527c8f67ef9af357290475d4af4b0fab8f12e0 # v2.9.3 + - name: Install the pinned cargo-llvm-cov + uses: taiki-e/install-action@1e29709c0ec63babbe8f266397a465f29a825f91 # v2.87.31 + with: + tool: cargo-llvm-cov@0.9.1 + fallback: none + # The same tests as ci.yml's `cargo test --all`. An explicit target keeps + # the cross mode ci.yml's test legs use; cargo-llvm-cov hands it to rustc, + # which has no 'host-tuple', so the host triple is named. cargo-llvm-cov + # skips doctests, and the workspace has none. + - name: Run the tests with line coverage + run: CARGO_BUILD_TARGET="$(rustc --print host-tuple)" cargo llvm-cov --locked --workspace --lcov --output-path coverage-rust.lcov + - name: Keep the Rust coverage report for the Codecov upload + uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 + with: + name: coverage-rust + path: coverage-rust.lcov + retention-days: 1 + + # The upload runs apart from the tests so the OIDC token is never available + # while test code runs. Keep it out of the required checks: a Codecov outage + # must not block merges. + codecov: + name: upload coverage to Codecov + needs: test + if: github.event_name == 'push' || github.event_name == 'workflow_dispatch' || github.event.pull_request.head.repo.full_name == github.repository + runs-on: ubuntu-latest + timeout-minutes: 10 + permissions: + contents: read + id-token: write # Authenticate the Codecov upload with OIDC; no stored token. + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + - uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2 + with: + name: coverage-rust + - uses: codecov/codecov-action@303a32d7a59b442fa8d48b6a1cc6825c09c847a5 # v7.1.1 + with: + use_oidc: true + files: coverage-rust.lcov + disable_search: true + fail_ci_if_error: true diff --git a/.github/workflows/snyk.yml b/.github/workflows/snyk.yml new file mode 100644 index 0000000000..a93f89fc88 --- /dev/null +++ b/.github/workflows/snyk.yml @@ -0,0 +1,66 @@ +name: Snyk + +# Snyk runs weekly and when a dependency file changes, which keeps it inside +# the free plan's monthly test allowance. +on: + schedule: + - cron: "23 4 * * 1" + workflow_dispatch: + push: + branches: [develop] + paths: + - "**/Cargo.lock" + - "**/Cargo.toml" + - ".github/workflows/snyk.yml" + pull_request: + paths: + - "**/Cargo.lock" + - "**/Cargo.toml" + - ".github/workflows/snyk.yml" + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + rust: + name: Snyk Rust dependencies (${{ matrix.root }}) + # Pull requests from forks, and Dependabot's (which get Dependabot secrets + # only), receive no SNYK_TOKEN; the weekly run on develop scans their changes. + if: github.event_name != 'pull_request' || (github.event.pull_request.head.repo.full_name == github.repository && github.event.pull_request.user.login != 'dependabot[bot]') + runs-on: ubuntu-latest + timeout-minutes: 15 + permissions: + contents: read + strategy: + fail-fast: false + matrix: + # proxy/ is its own workspace with its own Cargo.lock. + root: [".", proxy] + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + - uses: snyk/actions/setup@9adf32b1121593767fc3c057af55b55db032dc04 # v1.0.0 + # Snyk cannot read Cargo.lock directly, so the graph is described as a + # CycloneDX SBOM and tested with `snyk sbom test`. + - name: Install the SBOM generator + run: | + rustup toolchain install 1.91 --profile minimal + rustup default 1.91 + cargo install cargo-cyclonedx --locked --version 0.5.9 + - name: Test the Cargo graph + working-directory: ${{ matrix.root }} + env: + SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} + run: | + # shortcut: cargo-cyclonedx writes one SBOM per workspace member, and + # only the root package's is tested. It lists every third-party crate + # the members use today; if a member adds one the root lacks, test + # each member's snyk-sbom.json as well. + cargo cyclonedx --format json --spec-version 1.5 --override-filename snyk-sbom + [ -n "$SNYK_TOKEN" ] || { echo "::error::The SNYK_TOKEN repository secret is not set, so nothing was scanned."; exit 1; } + snyk sbom test --experimental --file=snyk-sbom.json diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 3232421547..b3390fed21 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -248,7 +248,7 @@ your branch --> develop (review + CI + integration testing) --> version branch - ## Testing -Every change **must** include tests. We follow **TDD (Red-Green-Refactor)**: write a failing test first, implement the minimum to pass, then refactor. +Every change **must** include tests. New functionality and bug fixes come with automated tests, in `#[cfg(test)]` modules beside the code or in `tests/`, run by `cargo test --all` in CI. We follow **TDD (Red-Green-Refactor)**: write a failing test first, implement the minimum to pass, then refactor. For how to write tests (fixtures, snapshots, token savings verification), see [docs/contributing/TECHNICAL.md — Testing](docs/contributing/TECHNICAL.md#8-testing). diff --git a/README.md b/README.md index 8f791821aa..4f7085a8f4 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@
-[![CodeQL](https://github.com/EquityBot/PascalsLetter/actions/workflows/codeql.yml/badge.svg?branch=develop)](https://github.com/EquityBot/PascalsLetter/actions/workflows/codeql.yml) [![Codacy](https://app.codacy.com/project/badge/Grade/68c5d91770634f3b86493583fd8eada6?branch=develop)](https://app.codacy.com/gh/ryanduguid/rtk/dashboard)
+[![tests](https://github.com/EquityBot/PascalsLetter/actions/workflows/coverage.yml/badge.svg?branch=develop)](https://github.com/EquityBot/PascalsLetter/actions/workflows/coverage.yml) [![Codecov](https://codecov.io/gh/EquityBot/PascalsLetter/graph/badge.svg)](https://codecov.io/gh/EquityBot/PascalsLetter) [![CodeQL](https://github.com/EquityBot/PascalsLetter/actions/workflows/codeql.yml/badge.svg?branch=develop)](https://github.com/EquityBot/PascalsLetter/actions/workflows/codeql.yml) [![Snyk](https://github.com/EquityBot/PascalsLetter/actions/workflows/snyk.yml/badge.svg?branch=develop)](https://github.com/EquityBot/PascalsLetter/actions/workflows/snyk.yml) [![SonarCloud](https://sonarcloud.io/api/project_badges/measure?project=EquityBot_rgg&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=EquityBot_rgg) [![Codacy](https://app.codacy.com/project/badge/Grade/68c5d91770634f3b86493583fd8eada6?branch=develop)](https://app.codacy.com/gh/ryanduguid/rtk/dashboard)
[![rust: 1.91+](.github/assets/badges/rust.svg)](https://www.rust-lang.org/) [![licence: Apache-2.0 AND BUSL-1.1](.github/assets/badges/licence.svg)](#licence) [![fork of: RTK](.github/assets/badges/fork-of.svg)](https://github.com/rtk-ai/rtk) [Install](#install) · [What PascalsLetter changes](#what-pascalsletter-changes) · [Inherited from RTK](#inherited-from-rtk) · [Credits](#credits) · [Licence](#licence) diff --git a/SECURITY.md b/SECURITY.md index dd5599537c..c7ee0c6ec1 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -2,11 +2,9 @@ ## Reporting a Vulnerability -If you discover a security vulnerability in RTK, please report it to the maintainers privately: +Report a vulnerability in PascalsLetter privately with GitHub's [Report a vulnerability form](https://github.com/EquityBot/PascalsLetter/security/advisories/new). Include a clear description, safe reproduction steps, the impact and any suggested mitigation. -- **Email**: security@rtk-ai.app (or create a private security advisory on GitHub) -- **Response time**: We aim to acknowledge reports within 48 hours -- **Disclosure**: We follow responsible disclosure practices (90-day embargo) +A vulnerability that upstream RTK shares can also go to RTK's maintainers, as [RTK's security policy](https://github.com/rtk-ai/rtk/blob/develop/SECURITY.md) describes. **Please do NOT:** - Open public GitHub issues for security vulnerabilities diff --git a/codecov.yml b/codecov.yml new file mode 100644 index 0000000000..c3b16c699c --- /dev/null +++ b/codecov.yml @@ -0,0 +1,11 @@ +# Codecov reports coverage for the README badge. CI sets no coverage gate, so +# Codecov's own statuses are informational and it posts no comments. +coverage: + status: + project: + default: + informational: true + patch: + default: + informational: true +comment: false diff --git a/tests/isolate_rtk_test.rs b/tests/isolate_rtk_test.rs index 281f8a1c12..5e28e21d05 100644 --- a/tests/isolate_rtk_test.rs +++ b/tests/isolate_rtk_test.rs @@ -27,10 +27,12 @@ fn key(name: &str) -> String { /// Defined by the child itself when its environment has none: cmd.exe sets `PROMPT`, and on /// macOS the CoreFoundation rtk links sets `__CF_USER_TEXT_ENCODING`, which the printer rtk -/// runs then inherits. +/// runs then inherits. Under `cargo llvm-cov`, the profiling runtime in rtk sets +/// `__LLVM_PROFILE_RT_INIT_ONCE` the same way. fn defined_by_the_child(name: &str) -> bool { (cfg!(windows) && name == "PROMPT") || (cfg!(target_os = "macos") && name == "__CF_USER_TEXT_ENCODING") + || name == "__LLVM_PROFILE_RT_INIT_ONCE" } /// Runs `cmd`, which ends in printing the environment its last child gets, and checks that From bfa2fa7f7f435c232012ff4e9dbf4608bb01a2e2 Mon Sep 17 00:00:00 2001 From: Ryan Duguid Date: Sun, 1 Nov 2026 08:46:08 +1100 Subject: [PATCH 2/4] ci: pin third-party actions, lock release builds and enforce HTTPS dtolnay/rust-toolchain and Swatinem/rust-cache are pinned by commit SHA in ci.yml and release.yml, the release and benchmark builds pass --locked, pull-requests: read moves from the workflow to the doc-review job that uses it, and install.sh's redirect-following downloads refuse anything but HTTPS. These address SonarCloud findings S7637, S8549, S8264 and S6506. --- .github/workflows/ci.yml | 37 +++++++++++++++++++---------------- .github/workflows/release.yml | 12 ++++++------ install.sh | 6 +++--- 3 files changed, 29 insertions(+), 26 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9cd8030780..5ef0d2dfcb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -6,7 +6,6 @@ on: permissions: contents: read - pull-requests: read env: CARGO_TERM_COLOR: always @@ -31,7 +30,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v7 - - uses: dtolnay/rust-toolchain@stable + - uses: dtolnay/rust-toolchain@b725eda525362e7cf34af9a7243cac1e3f01a7ec # stable with: components: rustfmt - run: cargo fmt --all -- --check @@ -42,10 +41,10 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v7 - - uses: dtolnay/rust-toolchain@stable + - uses: dtolnay/rust-toolchain@b725eda525362e7cf34af9a7243cac1e3f01a7ec # stable with: components: clippy - - uses: Swatinem/rust-cache@v2 + - uses: Swatinem/rust-cache@d1527c8f67ef9af357290475d4af4b0fab8f12e0 # v2.9.3 # `proxy/` is not a workspace member (it would break # `cargo install --git`), so it gets its own job below. Here # --workspace covers `rtk` + `engine`; a bare `cargo clippy` would @@ -58,8 +57,8 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v7 - - uses: dtolnay/rust-toolchain@stable - - uses: Swatinem/rust-cache@v2 + - uses: dtolnay/rust-toolchain@b725eda525362e7cf34af9a7243cac1e3f01a7ec # stable + - uses: Swatinem/rust-cache@d1527c8f67ef9af357290475d4af4b0fab8f12e0 # v2.9.3 - run: cargo doc --no-deps # ─── Parallel gates (all need code to compile) ─── @@ -74,10 +73,10 @@ jobs: needs: clippy steps: - uses: actions/checkout@v7 - - uses: dtolnay/rust-toolchain@stable + - uses: dtolnay/rust-toolchain@b725eda525362e7cf34af9a7243cac1e3f01a7ec # stable with: components: clippy, rustfmt - - uses: Swatinem/rust-cache@v2 + - uses: Swatinem/rust-cache@d1527c8f67ef9af357290475d4af4b0fab8f12e0 # v2.9.3 - run: cargo fmt --manifest-path proxy/Cargo.toml --all --check - run: cargo clippy --manifest-path proxy/Cargo.toml --all-targets - run: cargo test --manifest-path proxy/Cargo.toml @@ -94,10 +93,10 @@ jobs: - uses: actions/checkout@v7 - name: Install required search tools run: sudo apt-get update && sudo apt-get install -y ripgrep grep - - uses: dtolnay/rust-toolchain@stable + - uses: dtolnay/rust-toolchain@b725eda525362e7cf34af9a7243cac1e3f01a7ec # stable with: components: clippy - - uses: Swatinem/rust-cache@v2 + - uses: Swatinem/rust-cache@d1527c8f67ef9af357290475d4af4b0fab8f12e0 # v2.9.3 - run: cargo clippy --no-default-features --all-targets - run: cargo test --no-default-features # Match the crate-name column, not the whole line: the checkout path @@ -156,10 +155,10 @@ jobs: grep --version rg --version rg --pcre2-version - - 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.9.3 # `--all` is `--workspace`: `rtk` + `engine`. `proxy/` is tested in # its own job, since it is not a member. - run: cargo test --all @@ -173,9 +172,9 @@ jobs: with: fetch-depth: 0 - - uses: dtolnay/rust-toolchain@stable + - uses: dtolnay/rust-toolchain@b725eda525362e7cf34af9a7243cac1e3f01a7ec # stable - - uses: Swatinem/rust-cache@v2 + - uses: Swatinem/rust-cache@d1527c8f67ef9af357290475d4af4b0fab8f12e0 # v2.9.3 - name: Install cargo-audit run: cargo install cargo-audit @@ -308,12 +307,12 @@ jobs: steps: - uses: actions/checkout@v7 - - uses: dtolnay/rust-toolchain@stable + - uses: dtolnay/rust-toolchain@b725eda525362e7cf34af9a7243cac1e3f01a7ec # stable - - uses: Swatinem/rust-cache@v2 + - uses: Swatinem/rust-cache@d1527c8f67ef9af357290475d4af4b0fab8f12e0 # v2.9.3 - name: Build rtk - run: cargo build --release + run: cargo build --locked --release - name: Install system tools run: sudo apt-get install -y tree ripgrep @@ -338,6 +337,10 @@ jobs: name: doc review if: github.base_ref == 'develop' runs-on: ubuntu-latest + # Only this job reads the pull request, with `gh pr view` and `gh pr diff`. + permissions: + contents: read + pull-requests: read steps: - uses: actions/checkout@v7 with: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 0f4088a1f3..6cd5b7074d 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -80,7 +80,7 @@ jobs: sudo apt-get install -y musl-tools - name: Build rtk - run: cargo build --release --target ${{ matrix.target }} + run: cargo build --locked --release --target ${{ matrix.target }} env: RTK_TELEMETRY_URL: ${{ vars.RTK_TELEMETRY_URL }} RTK_TELEMETRY_TOKEN: ${{ secrets.RTK_TELEMETRY_TOKEN }} @@ -116,7 +116,7 @@ jobs: # so only LICENSE travels with it. Same binary name `rtk` inside -- an # installed hook command must keep working across editions. - name: Build rtk (Apache-2.0 edition) - run: cargo build --release --no-default-features --target ${{ matrix.target }} + run: cargo build --locked --release --no-default-features --target ${{ matrix.target }} env: RTK_TELEMETRY_URL: ${{ vars.RTK_TELEMETRY_URL }} RTK_TELEMETRY_TOKEN: ${{ secrets.RTK_TELEMETRY_TOKEN }} @@ -156,7 +156,7 @@ jobs: - name: Build rtk-proxy id: build_proxy run: > - cargo build --release + cargo build --locked --release --manifest-path proxy/Cargo.toml --target-dir target --target ${{ matrix.target }} @@ -220,7 +220,7 @@ jobs: uses: actions/checkout@v7 - name: Install Rust - uses: dtolnay/rust-toolchain@stable + uses: dtolnay/rust-toolchain@b725eda525362e7cf34af9a7243cac1e3f01a7ec # stable - name: Install cargo-deb run: cargo install cargo-deb @@ -253,7 +253,7 @@ jobs: run: cargo install cargo-generate-rpm - name: Build release - run: cargo build --release --no-default-features + run: cargo build --locked --release --no-default-features env: RTK_TELEMETRY_URL: ${{ vars.RTK_TELEMETRY_URL }} RTK_TELEMETRY_TOKEN: ${{ secrets.RTK_TELEMETRY_TOKEN }} @@ -283,7 +283,7 @@ jobs: run: cargo install cargo-generate-rpm - name: Build release - run: cargo build --release + run: cargo build --locked --release env: RTK_TELEMETRY_URL: ${{ vars.RTK_TELEMETRY_URL }} RTK_TELEMETRY_TOKEN: ${{ secrets.RTK_TELEMETRY_TOKEN }} diff --git a/install.sh b/install.sh index 35748ed3a4..d2ff118499 100644 --- a/install.sh +++ b/install.sh @@ -67,7 +67,7 @@ get_latest_version() { # Fallback to the REST API if the redirect didn't yield a tag. if [ -z "$VERSION" ]; then warn "Redirect lookup failed, falling back to GitHub API..." - VERSION=$(curl -fsSL "https://api.github.com/repos/${REPO}/releases/latest" \ + VERSION=$(curl --proto '=https' --tlsv1.2 -fsSL "https://api.github.com/repos/${REPO}/releases/latest" \ | grep '"tag_name":' \ | sed -E 's/.*"([^"]+)".*/\1/') fi @@ -106,12 +106,12 @@ install() { ASSET_NAME="${ASSET_PREFIX}-${TARGET}.tar.gz" info "Downloading from: $DOWNLOAD_URL" - if ! curl -fsSL "$DOWNLOAD_URL" -o "$ARCHIVE"; then + if ! curl --proto '=https' --tlsv1.2 -fsSL "$DOWNLOAD_URL" -o "$ARCHIVE"; then error "Failed to download binary" fi info "Downloading checksums..." - if ! curl -fsSL "$CHECKSUMS_URL" -o "$CHECKSUMS"; then + if ! curl --proto '=https' --tlsv1.2 -fsSL "$CHECKSUMS_URL" -o "$CHECKSUMS"; then error "Failed to download checksums.txt — refusing to install unverified binary (set RTK_SKIP_CHECKSUM=1 to bypass at your own risk)" fi From 23beeb5a286661cf7ed5808ec0be4cd85ee79da6 Mon Sep 17 00:00:00 2001 From: Ryan Duguid Date: Sun, 1 Nov 2026 08:53:59 +1100 Subject: [PATCH 3/4] fix: update rustls, pin benchmark tools and use a private tarball directory rustls moves to 0.23.46 (with rustls-webpki 0.103.16) in the root lock, which resolves GHSA-2mjx-qc3c-rqvc and GHSA-c8m5-c952-6cm4; proxy/ already locks 0.23.46. The benchmark job installs exact versions of ruff, pytest, mypy and golangci-lint, wheels only, and the benchmark VM helper builds its source tarball in a per-run temporary directory instead of a fixed /tmp path. --- .github/workflows/ci.yml | 4 ++-- Cargo.lock | 8 ++++---- scripts/benchmark/lib/vm.ts | 18 ++++++++++++++---- 3 files changed, 20 insertions(+), 10 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5ef0d2dfcb..c141849306 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -318,7 +318,7 @@ jobs: run: sudo apt-get install -y tree ripgrep - name: Install Python tools - run: pip install ruff pytest mypy + run: pip install --only-binary ':all:' ruff==0.17.3 pytest==9.2.0 mypy==2.4.1 - name: Install Go uses: actions/setup-go@v7 @@ -326,7 +326,7 @@ jobs: go-version: "stable" - name: Install Go tools - run: go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@latest + run: go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.15.0 - name: Run benchmark run: ./scripts/benchmark.sh diff --git a/Cargo.lock b/Cargo.lock index 3bfa885339..307159cf57 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1357,9 +1357,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.37" +version = "0.23.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "758025cb5fccfd3bc2fd74708fd4682be41d99e5dff73c377c0646c6012c73a4" +checksum = "48e13bd8c0e9365c43cfa5c9e8f9ad49d3c8444926c9aac819e0e4dc503c8fdf" dependencies = [ "log", "once_cell", @@ -1381,9 +1381,9 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.103.13" +version = "0.103.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61c429a8649f110dddef65e2a5ad240f747e85f7758a6bccc7e5777bd33f756e" +checksum = "4443b1b6d39d7c663139942cc4558262562d2c84123bb6282ef177009ca8b281" dependencies = [ "ring", "rustls-pki-types", diff --git a/scripts/benchmark/lib/vm.ts b/scripts/benchmark/lib/vm.ts index fcbf3a8156..1344735adf 100644 --- a/scripts/benchmark/lib/vm.ts +++ b/scripts/benchmark/lib/vm.ts @@ -3,6 +3,9 @@ */ import { $ } from "bun"; +import { mkdtemp, rm } from "node:fs/promises"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; const VM_NAME = "rtk-test"; const CLOUD_INIT = "scripts/benchmark/cloud-init.yaml"; @@ -101,11 +104,18 @@ export async function vmBuildRtk(projectRoot: string): Promise<{ }> { console.log("[vm] Transferring RTK source..."); - // Create tarball excluding heavy dirs and macOS resource forks (._*) - await $`COPYFILE_DISABLE=1 tar czf /tmp/rtk-src.tar.gz --exclude target --exclude .git --exclude node_modules --exclude "index.html*" --exclude "._*" -C ${projectRoot} .`; - await vmTransfer("/tmp/rtk-src.tar.gz", "/tmp/rtk-src.tar.gz"); + // Create tarball excluding heavy dirs and macOS resource forks (._*), in a + // directory made for this run so no other local user can plant the file. + const workDir = await mkdtemp(join(tmpdir(), "rtk-src-")); + const tarball = join(workDir, "rtk-src.tar.gz"); + try { + await $`COPYFILE_DISABLE=1 tar czf ${tarball} --exclude target --exclude .git --exclude node_modules --exclude "index.html*" --exclude "._*" -C ${projectRoot} .`; + await vmTransfer(tarball, "/home/ubuntu/rtk-src.tar.gz"); + } finally { + await rm(workDir, { recursive: true, force: true }); + } await vmExec( - "mkdir -p /home/ubuntu/rtk && cd /home/ubuntu/rtk && tar xzf /tmp/rtk-src.tar.gz" + "mkdir -p /home/ubuntu/rtk && cd /home/ubuntu/rtk && tar xzf /home/ubuntu/rtk-src.tar.gz" ); console.log("[vm] Building RTK (release)..."); From 735bb9a201ee8d082ef2a206988127e008645adf Mon Sep 17 00:00:00 2001 From: Ryan Duguid Date: Sun, 1 Nov 2026 09:14:00 +1100 Subject: [PATCH 4/4] ci: test every member SBOM and keep Codecov outages off the tests badge snyk.yml tests each SBOM cargo-cyclonedx writes, one per workspace member, instead of the root package's alone. The codecov job continues on error, so a failed upload no longer fails the workflow behind the tests badge; fail_ci_if_error still marks the job itself failed. --- .github/workflows/coverage.yml | 2 ++ .github/workflows/snyk.yml | 14 +++++++++----- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 317289e8f6..f8f114f481 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -58,6 +58,8 @@ jobs: name: upload coverage to Codecov needs: test if: github.event_name == 'push' || github.event_name == 'workflow_dispatch' || github.event.pull_request.head.repo.full_name == github.repository + # A Codecov outage must not turn the tests badge red. + continue-on-error: true runs-on: ubuntu-latest timeout-minutes: 10 permissions: diff --git a/.github/workflows/snyk.yml b/.github/workflows/snyk.yml index a93f89fc88..b9693b8f3b 100644 --- a/.github/workflows/snyk.yml +++ b/.github/workflows/snyk.yml @@ -57,10 +57,14 @@ jobs: env: SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} run: | - # shortcut: cargo-cyclonedx writes one SBOM per workspace member, and - # only the root package's is tested. It lists every third-party crate - # the members use today; if a member adds one the root lacks, test - # each member's snyk-sbom.json as well. + # cargo-cyclonedx writes one SBOM beside each workspace member's + # manifest; each is tested. cargo cyclonedx --format json --spec-version 1.5 --override-filename snyk-sbom [ -n "$SNYK_TOKEN" ] || { echo "::error::The SNYK_TOKEN repository secret is not set, so nothing was scanned."; exit 1; } - snyk sbom test --experimental --file=snyk-sbom.json + mapfile -t sboms < <(find . -name snyk-sbom.json -not -path './target/*' | sort) + [ "${#sboms[@]}" -gt 0 ] || { echo "::error::cargo-cyclonedx wrote no SBOM."; exit 1; } + status=0 + for sbom in "${sboms[@]}"; do + snyk sbom test --experimental --file="$sbom" || status=1 + done + exit "$status"