build(rust): bump to Rust 1.91.0 (#10767)

Rust 1.91 has been released and brings with it a few new lints that we
need to tidy up. In addition, it also stabilizes `BTreeMap::extract_if`:
A really nifty std-lib function that allows us to conditionally take
elements from a map. We need that in a bunch of places.
This commit is contained in:
Thomas Eizinger
2025-11-03 12:56:12 +11:00
committed by GitHub
parent 21846b81e5
commit 9016ffc9dc
17 changed files with 89 additions and 135 deletions

View File

@@ -74,10 +74,10 @@ runs:
echo "SCCACHE_AZURE_BLOB_CONTAINER=sccache" >> $GITHUB_ENV
echo "RUSTC_WRAPPER=$SCCACHE_PATH" >> $GITHUB_ENV
- name: Install nightly Rust
- name: Install nightly Rust to use for certain tools (fuzzing, cargo-udeps)
id: nightly
run: |
NIGHTLY="nightly-2025-05-30"
NIGHTLY="nightly-2025-09-30"
# Check if nightly toolchain is already installed
if ! rustup toolchain list | grep -q "$NIGHTLY"; then
rustup toolchain install $NIGHTLY
@@ -86,6 +86,16 @@ runs:
echo "nightly=$NIGHTLY" >> $GITHUB_OUTPUT
shell: bash
- name: Install nightly Rust for compiling eBPF code
run: |
NIGHTLY="nightly-2025-05-30"
# Check if nightly toolchain is already installed
if ! rustup toolchain list | grep -q "$NIGHTLY"; then
rustup toolchain install $NIGHTLY
rustup component add rust-src --toolchain $NIGHTLY
fi
shell: bash
- name: Start sccache
run: $SCCACHE_PATH --start-server
shell: bash

24
rust/Cargo.lock generated
View File

@@ -3861,17 +3861,6 @@ dependencies = [
"mach2",
]
[[package]]
name = "io-uring"
version = "0.7.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b86e202f00093dcba4275d4636b93ef9dd75d025ae560d2521b45ea28ab49013"
dependencies = [
"bitflags 2.9.1",
"cfg-if",
"libc",
]
[[package]]
name = "ip-packet"
version = "0.1.0"
@@ -8028,30 +8017,27 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
[[package]]
name = "tokio"
version = "1.47.1"
version = "1.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89e49afdadebb872d3145a5638b59eb0691ea23e46ca484037cfab3b76b95038"
checksum = "ff360e02eab121e0bc37a2d3b4d4dc622e6eda3a8e5253d5435ecf5bd4c68408"
dependencies = [
"backtrace",
"bytes",
"io-uring",
"libc",
"mio",
"parking_lot",
"pin-project-lite",
"signal-hook-registry",
"slab",
"socket2 0.6.0",
"tokio-macros",
"tracing",
"windows-sys 0.59.0",
"windows-sys 0.61.2",
]
[[package]]
name = "tokio-macros"
version = "2.5.0"
version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8"
checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5"
dependencies = [
"proc-macro2",
"quote",

View File

@@ -185,7 +185,7 @@ test-case = "3.3.1"
test-strategy = "0.4.3"
thiserror = "2.0.17"
time = "0.3.43"
tokio = "1.47"
tokio = "1.48.0"
tokio-stream = "0.1.17"
tokio-tungstenite = "0.28.0"
tokio-util = "0.7.16"

View File

@@ -63,7 +63,7 @@ COPY ${PACKAGE} .
FROM runtime AS dev
ARG PACKAGE
ARG RUST_VERSION="1.90.0" # Keep in sync with `rust-toolchain.toml`
ARG RUST_VERSION="1.91.0" # Keep in sync with `rust-toolchain.toml`
WORKDIR /app

View File

@@ -7,7 +7,7 @@ use std::{net::IpAddr, process::Command, str::FromStr};
mod etc_resolv_conf;
#[derive(clap::ValueEnum, Clone, Copy, Debug)]
#[derive(clap::ValueEnum, Clone, Copy, Debug, Default)]
pub enum DnsControlMethod {
/// Explicitly disable DNS control.
///
@@ -22,15 +22,10 @@ pub enum DnsControlMethod {
/// Cooperate with `systemd-resolved`
///
/// Suitable for most Ubuntu systems, probably
#[default]
SystemdResolved,
}
impl Default for DnsControlMethod {
fn default() -> Self {
Self::SystemdResolved
}
}
impl DnsController {
pub fn deactivate(&mut self) -> Result<()> {
tracing::debug!("Deactivating DNS control...");

View File

@@ -793,7 +793,7 @@ fn set_non_blocking(fd: RawFd) -> io::Result<()> {
}
fn create_tun_device() -> io::Result<()> {
let path = Path::new(TUN_FILE.to_str().expect("path is valid utf-8"));
let path = Path::new(TUN_FILE.to_str().map_err(io::Error::other)?);
if path.exists() {
return Ok(());

View File

@@ -8,7 +8,7 @@ use std::{
time::Duration,
};
use anyhow::{Context as _, Result};
use anyhow::{Context as _, Result, anyhow};
use backoff::ExponentialBackoffBuilder;
use firezone_logging::sentry_layer;
use firezone_telemetry::{Telemetry, analytics};
@@ -563,7 +563,7 @@ fn init_logging(log_dir: &Path, log_filter: String) -> Result<()> {
LOGGER_STATE
.set((handle, reload_handle))
.expect("Logging guard should never be initialized twice");
.map_err(|_| anyhow!("Logging guard should never be initialized twice"))?;
Ok(())
}

View File

@@ -269,7 +269,7 @@ fn get_websocket_path<E>(
{
let mut paths = api_url
.path_segments_mut()
.expect("scheme guarantees valid URL");
.map_err(|_| LoginUrlError::MissingHost)?;
paths.pop_if_empty();
paths.push(mode);
@@ -321,7 +321,7 @@ fn set_ws_scheme<E>(url: &mut Url) -> Result<(), LoginUrlError<E>> {
};
url.set_scheme(scheme)
.expect("Developer error: the match before this should make sure we can set this");
.map_err(|_| LoginUrlError::InvalidUrlScheme(scheme.to_owned()))?;
Ok(())
}

View File

@@ -1756,7 +1756,6 @@ impl PeerSocket {
matches!(self, Self::RelayToPeer { .. } | Self::RelayToRelay { .. })
}
// TODO: Return `Arguments` here once we hit 1.89
fn fmt<RId>(&self, relay: RId) -> String
where
RId: fmt::Display,

View File

@@ -49,36 +49,23 @@ where
const RECENT_DISCONNECT_TIMEOUT: Duration = Duration::from_secs(5);
pub(crate) fn handle_timeout(&mut self, events: &mut VecDeque<Event<TId>>, now: Instant) {
self.initial.retain(|id, conn| {
if conn.is_failed {
events.push_back(Event::ConnectionFailed(*id));
return false;
for (id, _) in self.initial.extract_if(.., |_, conn| conn.is_failed) {
events.push_back(Event::ConnectionFailed(id));
}
for (id, conn) in self.established.extract_if(.., |_, conn| conn.is_failed()) {
events.push_back(Event::ConnectionFailed(id));
for (index, _) in self
.established_by_wireguard_session_index
.extract_if(.., |_, c| *c == id)
{
self.disconnected_session_indices.insert(index, now);
}
true
});
self.established.retain(|id, conn| {
if conn.is_failed() {
events.push_back(Event::ConnectionFailed(*id));
self.established_by_wireguard_session_index
.retain(|index, c| {
if c == id {
self.disconnected_session_indices.insert(*index, now);
return false;
}
true
});
self.disconnected_public_keys
.insert(conn.tunnel.remote_static_public().to_bytes(), now);
self.disconnected_ids.insert(*id, now);
return false;
}
true
});
self.disconnected_public_keys
.insert(conn.tunnel.remote_static_public().to_bytes(), now);
self.disconnected_ids.insert(id, now);
}
self.disconnected_ids
.retain(|_, v| now.duration_since(*v) < Self::RECENT_DISCONNECT_TIMEOUT);

View File

@@ -174,17 +174,10 @@ impl ClientOnGateway {
let cid = self.id;
let mut any_expired = false;
// TODO: Replace with `extract_if` once we are on Rust 1.91
self.resources.retain(|rid, r| {
if r.is_allowed(&now) {
return true;
}
for (rid, _) in self.resources.extract_if(.., |_, r| !r.is_allowed(&now)) {
tracing::info!(%cid, %rid, "Access to resource expired");
any_expired = true;
false
});
}
if any_expired {
self.recalculate_filters();
@@ -252,15 +245,12 @@ impl ClientOnGateway {
}
pub(crate) fn retain_authorizations(&mut self, authorization: BTreeSet<ResourceId>) {
// TODO: Replace with `extract_if` once we are on Rust 1.91
self.resources.retain(|rid, _| {
if authorization.contains(rid) {
return true;
}
for (rid, _) in self
.resources
.extract_if(.., |rid, _| !authorization.contains(rid))
{
tracing::info!(%rid, "Revoking resource authorization");
false
});
}
self.recalculate_filters();
}

View File

@@ -1,5 +1,6 @@
#![cfg_attr(test, allow(clippy::unwrap_used))]
use anyhow::anyhow;
use clap::Parser as _;
use firezone_bin_shared::{DnsControlMethod, TOKEN_ENV_KEY};
use firezone_gui_client::service;
@@ -8,7 +9,7 @@ use std::path::PathBuf;
fn main() -> anyhow::Result<()> {
rustls::crypto::ring::default_provider()
.install_default()
.expect("Calling `install_default` only once per process should always succeed");
.map_err(|_| anyhow!("Failed to install default crypto provider"))?;
// Docs indicate that `remove_var` should actually be marked unsafe
// SAFETY: We haven't spawned any other threads, this code should be the first
@@ -58,22 +59,17 @@ pub struct Cli {
max_partition_time: Option<humantime::Duration>,
}
#[derive(clap::Subcommand)]
#[derive(clap::Subcommand, Default)]
enum Cmd {
/// Needed to test the Tunnel service on aarch64 Windows,
/// where the Tauri MSI bundler doesn't work yet
Install,
#[default]
Run,
RunDebug,
RunSmokeTest,
}
impl Default for Cmd {
fn default() -> Self {
Self::Run
}
}
#[cfg(test)]
mod tests {
use super::{Cli, Cmd};

View File

@@ -115,9 +115,10 @@ pub enum Failure {
Panic,
}
#[derive(derive_more::Debug)]
#[derive(derive_more::Debug, Default)]
pub enum Status {
/// Firezone is disconnected.
#[default]
Disconnected,
Quitting, // The user asked to quit and we're waiting for the tunnel daemon to gracefully disconnect so we can flush telemetry.
/// Firezone is ready to use.
@@ -131,12 +132,6 @@ pub enum Status {
WaitingForTunnel,
}
impl Default for Status {
fn default() -> Self {
Self::Disconnected
}
}
impl Status {
/// True if we should react to `OnUpdateResources`
fn needs_resource_updates(&self) -> bool {

View File

@@ -804,7 +804,7 @@ mod tests {
"MyCorp GitLab",
Menu::default()
.item(
Event::Url("https://gitlab.mycorp.com".parse().unwrap()),
Event::Url("https://gitlab.mycorp.com".parse()?),
"<https://gitlab.mycorp.com>",
)
.separator()
@@ -864,7 +864,7 @@ mod tests {
actual,
expected,
"{}",
serde_json::to_string_pretty(&actual).unwrap()
serde_json::to_string_pretty(&actual)?
);
Ok(())
@@ -910,7 +910,7 @@ mod tests {
"MyCorp GitLab",
Menu::default()
.item(
Event::Url("https://gitlab.mycorp.com".parse().unwrap()),
Event::Url("https://gitlab.mycorp.com".parse()?),
"<https://gitlab.mycorp.com>",
)
.separator()
@@ -946,7 +946,7 @@ mod tests {
actual,
expected,
"{}",
serde_json::to_string_pretty(&actual).unwrap(),
serde_json::to_string_pretty(&actual)?,
);
Ok(())

View File

@@ -188,7 +188,7 @@ fn main() {
fn try_main() -> Result<()> {
rustls::crypto::ring::default_provider()
.install_default()
.expect("Calling `install_default` only once per process should always succeed");
.map_err(|_| anyhow!("Failed to install default crypto provider"))?;
let cli = Cli::parse();

View File

@@ -1021,43 +1021,39 @@ where
let port = allocation.port;
self.channels_by_client_and_number
.retain(|(cs, number), c| {
if c.allocation != port {
return true;
}
for ((cs, number), c) in self
.channels_by_client_and_number
.extract_if(.., |_, c| c.allocation == port)
{
debug_assert_eq!(cs, client, "internal state should be consistent");
debug_assert_eq!(cs, &client, "internal state should be consistent");
let peer = c.peer_address;
let peer = c.peer_address;
if let Some(existing) = self
.channel_numbers_by_client_and_peer
.remove(&(client, peer))
{
debug_assert_eq!(existing, number, "internal state should be consistent");
}
if let Some(existing) = self
.channel_numbers_by_client_and_peer
.remove(&(client, peer))
{
debug_assert_eq!(existing, *number, "internal state should be consistent");
}
if let Some((existing_cs, existing_n)) = self
.channel_and_client_by_port_and_peer
.remove(&(port, peer))
{
debug_assert_eq!(existing_cs, cs, "internal state should be consistent");
debug_assert_eq!(existing_n, number, "internal state should be consistent");
}
if let Some((existing_cs, existing_n)) = self
.channel_and_client_by_port_and_peer
.remove(&(port, peer))
{
debug_assert_eq!(&existing_cs, cs, "internal state should be consistent");
debug_assert_eq!(&existing_n, number, "internal state should be consistent");
}
self.pending_commands
.push_back(Command::DeleteChannelBinding {
client: cs,
channel_number: number,
peer: c.peer_address,
allocation_port: c.allocation,
});
self.pending_commands
.push_back(Command::DeleteChannelBinding {
client: *cs,
channel_number: *number,
peer: c.peer_address,
allocation_port: c.allocation,
});
tracing::info!(%peer, %number, allocation = %port, "Deleted channel binding");
false
});
tracing::info!(%peer, %number, allocation = %port, "Deleted channel binding");
}
self.allocations_up_down_counter.add(-1, &[]);
self.pending_commands.push_back(Command::FreeAllocation {

View File

@@ -1,4 +1,4 @@
[toolchain]
channel = "1.90.0" # Keep in sync with `Dockerfile`
channel = "1.91.0" # Keep in sync with `Dockerfile`
components = ["rust-src", "rust-analyzer", "clippy"]
targets = ["x86_64-unknown-linux-musl"]