From 83df31b60e32e2a77ade4029d01df859c3db634f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 23 Jun 2026 15:45:05 -0700 Subject: [PATCH 1/3] chore(deps): bump the gh-deps group across 5 directories with 2 updates (#362) Bumps the gh-deps group with 2 updates in the / directory: [actions/checkout](https://github.com/actions/checkout) and [codecov/codecov-action](https://github.com/codecov/codecov-action). Bumps the gh-deps group with 1 update in the /.github/actions/dart_package directory: [codecov/codecov-action](https://github.com/codecov/codecov-action). Bumps the gh-deps group with 1 update in the /.github/actions/flutter_package directory: [codecov/codecov-action](https://github.com/codecov/codecov-action). Bumps the gh-deps group with 1 update in the /.github/actions/publish_flutter_package directory: [actions/checkout](https://github.com/actions/checkout). Bumps the gh-deps group with 1 update in the /.github/actions/rust_crate directory: [codecov/codecov-action](https://github.com/codecov/codecov-action). Updates `actions/checkout` from 6 to 7 - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v6...v7) Updates `codecov/codecov-action` from 6 to 7 - [Release notes](https://github.com/codecov/codecov-action/releases) - [Changelog](https://github.com/codecov/codecov-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/codecov/codecov-action/compare/v6...v7) Updates `codecov/codecov-action` from 6 to 7 - [Release notes](https://github.com/codecov/codecov-action/releases) - [Changelog](https://github.com/codecov/codecov-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/codecov/codecov-action/compare/v6...v7) Updates `codecov/codecov-action` from 6 to 7 - [Release notes](https://github.com/codecov/codecov-action/releases) - [Changelog](https://github.com/codecov/codecov-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/codecov/codecov-action/compare/v6...v7) Updates `actions/checkout` from 6 to 7 - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v6...v7) Updates `codecov/codecov-action` from 6 to 7 - [Release notes](https://github.com/codecov/codecov-action/releases) - [Changelog](https://github.com/codecov/codecov-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/codecov/codecov-action/compare/v6...v7) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: '7' dependency-type: direct:production update-type: version-update:semver-major dependency-group: gh-deps - dependency-name: codecov/codecov-action dependency-version: '7' dependency-type: direct:production update-type: version-update:semver-major dependency-group: gh-deps - dependency-name: codecov/codecov-action dependency-version: '7' dependency-type: direct:production update-type: version-update:semver-major dependency-group: gh-deps - dependency-name: codecov/codecov-action dependency-version: '7' dependency-type: direct:production update-type: version-update:semver-major dependency-group: gh-deps - dependency-name: actions/checkout dependency-version: '7' dependency-type: direct:production update-type: version-update:semver-major dependency-group: gh-deps - dependency-name: codecov/codecov-action dependency-version: '7' dependency-type: direct:production update-type: version-update:semver-major dependency-group: gh-deps ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/actions/dart_package/action.yaml | 2 +- .github/actions/flutter_package/action.yaml | 2 +- .github/actions/publish_flutter_package/action.yaml | 2 +- .github/actions/rust_crate/action.yaml | 2 +- .github/workflows/_shorebird_ci_flutter.yaml | 4 ++-- .github/workflows/build_patch_artifacts.yaml | 2 +- .github/workflows/main.yaml | 6 +++--- .github/workflows/publish.yaml | 2 +- .github/workflows/shorebird_ci.yaml | 4 ++-- 9 files changed, 13 insertions(+), 13 deletions(-) diff --git a/.github/actions/dart_package/action.yaml b/.github/actions/dart_package/action.yaml index e838c05..b233d63 100644 --- a/.github/actions/dart_package/action.yaml +++ b/.github/actions/dart_package/action.yaml @@ -76,7 +76,7 @@ runs: run: echo "package_name=${PACKAGE_PATH##*/}" >> $GITHUB_OUTPUT - name: Upload Coverage - uses: codecov/codecov-action@v6 + uses: codecov/codecov-action@v7 with: flags: ${{ steps.split.outputs.package_name }} token: ${{ inputs.codecov_token }} diff --git a/.github/actions/flutter_package/action.yaml b/.github/actions/flutter_package/action.yaml index fd90aa9..a1d0fdb 100644 --- a/.github/actions/flutter_package/action.yaml +++ b/.github/actions/flutter_package/action.yaml @@ -82,7 +82,7 @@ runs: run: echo "package_name=${PACKAGE_PATH##*/}" >> $GITHUB_OUTPUT - name: Upload Coverage - uses: codecov/codecov-action@v6 + uses: codecov/codecov-action@v7 with: # We use Codecov's carryforward flags to allow our PR testing to only # run affected packages, but also allow our coverage information from diff --git a/.github/actions/publish_flutter_package/action.yaml b/.github/actions/publish_flutter_package/action.yaml index 06b3b85..281d958 100644 --- a/.github/actions/publish_flutter_package/action.yaml +++ b/.github/actions/publish_flutter_package/action.yaml @@ -10,7 +10,7 @@ runs: using: "composite" steps: - name: 📚 Git Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v7 - name: 🐦 Setup Flutter uses: subosito/flutter-action@v2 diff --git a/.github/actions/rust_crate/action.yaml b/.github/actions/rust_crate/action.yaml index eaa0318..53dd001 100644 --- a/.github/actions/rust_crate/action.yaml +++ b/.github/actions/rust_crate/action.yaml @@ -41,7 +41,7 @@ runs: run: echo "package_name=${PACKAGE_PATH##*/}" >> $GITHUB_OUTPUT - name: Upload Coverage - uses: codecov/codecov-action@v6 + uses: codecov/codecov-action@v7 with: # We use Codecov's carryforward flags to allow our PR testing to only # run affected packages, but also allow our coverage information from diff --git a/.github/workflows/_shorebird_ci_flutter.yaml b/.github/workflows/_shorebird_ci_flutter.yaml index e1afbae..f3305c1 100644 --- a/.github/workflows/_shorebird_ci_flutter.yaml +++ b/.github/workflows/_shorebird_ci_flutter.yaml @@ -34,7 +34,7 @@ jobs: ci: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 with: submodules: recursive - name: Setup Flutter @@ -64,7 +64,7 @@ jobs: working-directory: ${{ inputs.package_path }} run: flutter test --coverage - if: inputs.has_unit_tests - uses: codecov/codecov-action@v6 + uses: codecov/codecov-action@v7 with: flags: ${{ inputs.package_name }} working-directory: ${{ inputs.package_path }} diff --git a/.github/workflows/build_patch_artifacts.yaml b/.github/workflows/build_patch_artifacts.yaml index c5e589f..019df22 100644 --- a/.github/workflows/build_patch_artifacts.yaml +++ b/.github/workflows/build_patch_artifacts.yaml @@ -25,7 +25,7 @@ jobs: name: 🦀 Upload Artifacts steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - uses: taiki-e/upload-rust-binary-action@v1 with: bin: "patch" diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index 862f702..7ffc043 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -32,7 +32,7 @@ jobs: steps: - name: 📚 Git Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v7 - uses: dorny/paths-filter@v4 name: Build Detection @@ -82,7 +82,7 @@ jobs: steps: - name: 📚 Git Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v7 - name: 🦀 Build ${{ matrix.crate }} uses: ./.github/actions/rust_crate @@ -104,7 +104,7 @@ jobs: steps: - name: 📚 Git Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v7 with: submodules: recursive diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml index 462379b..cc55bf4 100644 --- a/.github/workflows/publish.yaml +++ b/.github/workflows/publish.yaml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest steps: - name: 📚 Git Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v7 with: submodules: recursive diff --git a/.github/workflows/shorebird_ci.yaml b/.github/workflows/shorebird_ci.yaml index 790f5e5..6613d9d 100644 --- a/.github/workflows/shorebird_ci.yaml +++ b/.github/workflows/shorebird_ci.yaml @@ -17,7 +17,7 @@ jobs: shorebird_code_push: ${{ steps.filter.outputs.shorebird_code_push }} shorebird_code_push_example: ${{ steps.filter.outputs.shorebird_code_push_example }} steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 with: # Full history so dorny/paths-filter can diff on push events. fetch-depth: 0 @@ -65,7 +65,7 @@ jobs: name: CSpell runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 with: submodules: recursive - uses: streetsidesoftware/cspell-action@v8 From dd213f923c6e24d84193cb7c8b41a095f0f4c4b1 Mon Sep 17 00:00:00 2001 From: Mac Date: Mon, 29 Jun 2026 18:27:15 -0600 Subject: [PATCH 2/3] fix: populate current_patch_number from running_patch, not the boot breadcrumb (#363) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: send running_patch as current_patch_number on patch check Both patch-check construction sites read current_patch_number from state.currently_booting_patch(), a transient boot-handshake breadcrumb that record_boot_success() clears to None before any Dart-initiated patch check fires. The field was therefore omitted from the wire for essentially the entire fleet. Use state.running_patch() instead: the session-scoped accessor set at report_launch_start, kept for the whole session, surviving server-driven rollbacks. This is the same value the FFI symbol shorebird_current_boot_patch_number already exposes. * test: assert patch-check request carries running_patch as current_patch_number Covers both construction sites (check_for_downloadable_update and update). Reproduces the steady state where the bug manifested — patch booted, currently_booting_patch cleared by record_boot_success — and asserts the request still carries the running patch number. Verified to fail (field omitted, captured as -1) against the pre-fix currently_booting_patch() code. * test: cover all changed lines in patch-check regression test Codecov's patch gate flagged 13 uncovered lines in the new test (78.7% patch coverage), none of them the fix: the no-op download/report closures never fired, and multi-line assert failure messages are only reached when an assertion panics. Swap the closures for the existing UNEXPECTED_DOWNLOAD/UNEXPECTED_REPORT placeholders (also asserting that path is never hit), collapse the assertions to single lines with the sentinel legend moved to comments, and tighten the module doc. Changed lines now at 100% patch coverage; fmt, clippy, and the full suite stay green. --- library/src/updater.rs | 111 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 109 insertions(+), 2 deletions(-) diff --git a/library/src/updater.rs b/library/src/updater.rs index 7b27625..1c0c42e 100644 --- a/library/src/updater.rs +++ b/library/src/updater.rs @@ -282,7 +282,7 @@ pub fn check_for_downloadable_update(channel: Option<&str>) -> anyhow::Result) -> anyhow::Resul Ok(PatchCheckRequest::new( &config, &state.client_id(), - state.currently_booting_patch().map(|p| p.number), + state.running_patch().map(|p| p.number), )) })?; @@ -4079,3 +4079,110 @@ mod multi_engine_tests { Ok(()) } } + +/// Regression tests asserting the patch-check request's `current_patch_number` +/// carries the running patch, not the boot breadcrumb (`currently_booting_patch`) +/// which `report_launch_success` clears before any patch check fires. Covers +/// both construction sites: `check_for_downloadable_update` and `update`. +#[cfg(test)] +mod patch_check_current_patch_number_tests { + use anyhow::Result; + use serial_test::serial; + use std::sync::atomic::{AtomicI64, Ordering}; + use tempfile::TempDir; + + use crate::{ + check_for_downloadable_update, + network::{ + testing_set_network_hooks, PatchCheckResponse, UNEXPECTED_DOWNLOAD, UNEXPECTED_REPORT, + }, + report_launch_start, report_launch_success, + test_utils::install_fake_patch, + update, + updater::tests::init_for_testing, + with_state, + }; + + /// `current_patch_number` was `None` on the wire (the bug we're guarding). + const FIELD_OMITTED: i64 = -1; + /// The patch-check hook never ran. + const HOOK_NOT_CALLED: i64 = i64::MIN; + + /// Last `current_patch_number` seen by the patch-check hook. Shared by + /// both tests; safe because they are `#[serial]` (only one runs at a + /// time) and `arrange_capturing_hooks` resets it before each check. + static CAPTURED: AtomicI64 = AtomicI64::new(HOOK_NOT_CALLED); + + /// Installs patch 1 and completes a full boot, then asserts the steady + /// state in which patch checks actually run: the boot breadcrumb is + /// cleared, but the process is still running patch 1. Reading + /// `currently_booting_patch` here yields `None` — that is precisely the + /// regression this guards against. + fn boot_patch_one(tmp_dir: &TempDir) -> Result<()> { + init_for_testing(tmp_dir, None); + install_fake_patch(1)?; + report_launch_start()?; + report_launch_success()?; + with_state(|state| { + // Steady state: the boot breadcrumb is cleared, yet patch 1 is + // still the running patch. + assert!(state.currently_booting_patch().is_none()); + assert_eq!(state.running_patch().map(|p| p.number), Some(1)); + Ok(()) + }) + } + + /// Installs network hooks whose patch-check leg records the request's + /// `current_patch_number` into `CAPTURED` (`None` -> `FIELD_OMITTED`) and + /// reports no available update. + fn arrange_capturing_hooks() { + CAPTURED.store(HOOK_NOT_CALLED, Ordering::SeqCst); + testing_set_network_hooks( + |_url, request| { + CAPTURED.store( + request + .current_patch_number + .map(|n| n as i64) + .unwrap_or(FIELD_OMITTED), + Ordering::SeqCst, + ); + Ok(PatchCheckResponse { + patch_available: false, + patch: None, + rolled_back_patch_numbers: None, + }) + }, + // No update is offered, so neither hook should ever fire. + UNEXPECTED_DOWNLOAD, + UNEXPECTED_REPORT, + ); + } + + #[serial] + #[test] + fn check_for_downloadable_update_sends_running_patch() -> Result<()> { + let tmp_dir = TempDir::new().unwrap(); + boot_patch_one(&tmp_dir)?; + arrange_capturing_hooks(); + + check_for_downloadable_update(None)?; + + // 1 = running patch sent; -1 = field omitted (the bug); i64::MIN = hook never ran. + assert_eq!(CAPTURED.load(Ordering::SeqCst), 1); + Ok(()) + } + + #[serial] + #[test] + fn update_sends_running_patch() -> Result<()> { + let tmp_dir = TempDir::new().unwrap(); + boot_patch_one(&tmp_dir)?; + arrange_capturing_hooks(); + + update(None)?; + + // 1 = running patch sent; -1 = field omitted (the bug); i64::MIN = hook never ran. + assert_eq!(CAPTURED.load(Ordering::SeqCst), 1); + Ok(()) + } +} From 1f85c4ab1ee5b540269b9859c75e1bffbb9050c7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 2 Jul 2026 18:30:09 -0700 Subject: [PATCH 3/3] chore(deps): update mockall requirement (#365) Updates the requirements on [mockall](https://github.com/asomers/mockall) to permit the latest version. Updates `mockall` to 0.15.0 - [Changelog](https://github.com/asomers/mockall/blob/master/CHANGELOG.md) - [Commits](https://github.com/asomers/mockall/compare/v0.14.0...v0.15.0) --- updated-dependencies: - dependency-name: mockall dependency-version: 0.15.0 dependency-type: direct:production dependency-group: library-deps ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- library/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/Cargo.toml b/library/Cargo.toml index 3205cda..ab3065a 100644 --- a/library/Cargo.toml +++ b/library/Cargo.toml @@ -73,7 +73,7 @@ oslog = "0.2.0" simple_logger = "5.0.0" [dev-dependencies] -mockall = "0.14.0" +mockall = "0.15.0" mockito = "1.2.0" mock_instant = "0.6.0" # Gives #[serial] attribute for locking all of our shorebird_init