From c9403c5b8308f7d1abc2828efe2eeadcfbe75625 Mon Sep 17 00:00:00 2001 From: Jan-Erik Rediger Date: Thu, 5 Jun 2025 12:18:29 +0200 Subject: [PATCH 1/3] Import sqlite storage as separate module This is a modified version of the kvstore/skv implementation: https://searchfox.org/firefox-main/rev/cced10961b53e0d29e22e635404fec37728b2644/toolkit/components/kvstore/src/skv/connection.rs Which itself is based on application-service's sql-support. It's stripped down to what we need in Glean: * A file-backed database * A schema set up on start, potentially applying migrations if we need that * A read-write connection, which is re-used for all access. --- glean-core/src/database/sqlite.rs | 442 +++++++++++++++++++ glean-core/src/database/sqlite/connection.rs | 111 +++++ glean-core/src/database/sqlite/schema.rs | 68 +++ 3 files changed, 621 insertions(+) create mode 100644 glean-core/src/database/sqlite.rs create mode 100644 glean-core/src/database/sqlite/connection.rs create mode 100644 glean-core/src/database/sqlite/schema.rs diff --git a/glean-core/src/database/sqlite.rs b/glean-core/src/database/sqlite.rs new file mode 100644 index 0000000000..59eddc11c6 --- /dev/null +++ b/glean-core/src/database/sqlite.rs @@ -0,0 +1,442 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +use std::fs; +use std::num::NonZeroU64; +use std::path::Path; +use std::str; + +use rusqlite::params; +use rusqlite::types::FromSqlError; +use rusqlite::Transaction; + +use connection::Connection; +use schema::Schema; + +use crate::common_metric_data::CommonMetricDataInternal; +use crate::metrics::Metric; +use crate::Glean; +use crate::Lifetime; +use crate::Result; + +mod connection; +mod schema; + +pub struct Database { + /// The database connection. + conn: connection::Connection, +} + +impl std::fmt::Debug for Database { + fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result { + fmt.debug_struct("Database") + .field("conn", &self.conn) + .finish() + } +} + +const DEFAULT_DATABASE_FILE_NAME: &str = "glean.sqlite"; + +impl Database { + /// Initializes the data store. + /// + /// This opens the underlying SQLite store and creates + /// the underlying directory structure. + pub fn new(data_path: &Path, _delay_ping_lifetime_io: bool) -> Result { + let path = data_path.join("db"); + log::debug!("Database path: {:?}", path.display()); + + fs::create_dir_all(&path)?; + let store_path = path.join(DEFAULT_DATABASE_FILE_NAME); + let conn = Connection::new::(&store_path).unwrap(); + + let db = Self { conn }; + + Ok(db) + } + + /// Get the initial database file size. + pub fn file_size(&self) -> Option { + None + } + + /// Get the rkv load state. + pub fn rkv_load_state(&self) -> Option { + None + } + + /// Iterates with the provided transaction function + /// over the requested data from the given storage. + /// + /// * If the storage is unavailable, the transaction function is never invoked. + /// * If the read data cannot be deserialized it will be silently skipped. + /// + /// # Arguments + /// + /// * `lifetime` - The metric lifetime to iterate over. + /// * `storage_name` - The storage name to iterate over. + /// * `transaction_fn` - Called for each entry being iterated over. It is + /// passed two arguments: `(metric_id: &[u8], metric: &Metric)`. + /// + /// # Panics + /// + /// This function will **not** panic on database errors. + pub fn iter_store(&self, lifetime: Lifetime, storage_name: &str, mut transaction_fn: F) + where + F: FnMut(&[u8], &Metric), + { + let iter_sql = r#" + SELECT id, value + FROM telemetry + WHERE + lifetime = ?1 + AND ping = ?2 + "#; + + self.conn + .read(|conn| { + let mut stmt = conn.prepare_cached(iter_sql).unwrap(); + let rows = stmt + .query_map( + params![lifetime.as_str().to_string(), storage_name], + |row| { + let id: String = row.get(0)?; + let blob: Vec = row.get(1)?; + let blob: Metric = bincode::deserialize(&blob) + .map_err(|_| FromSqlError::InvalidType)?; + Ok((id, blob)) + }, + ) + .unwrap(); + + for row in rows { + let Ok((metric_id, metric)) = row else { + continue; + }; + transaction_fn(metric_id.as_bytes(), &metric); + } + + Result::<(), ()>::Ok(()) + }) + .unwrap() + } + + /// Determines if the storage has the given metric. + /// + /// If data cannot be read it is assumed that the storage does not have the metric. + /// + /// # Arguments + /// + /// * `lifetime` - The lifetime of the metric. + /// * `storage_name` - The storage name to look in. + /// * `metric_identifier` - The metric identifier. + /// + /// # Panics + /// + /// This function will **not** panic on database errors. + pub fn has_metric( + &self, + lifetime: Lifetime, + storage_name: &str, + metric_identifier: &str, + ) -> bool { + let has_metric_sql = r#" + SELECT id + FROM telemetry + WHERE + lifetime = ?1 + AND ping = ?2 + AND id = ?3 + "#; + + self.conn + .read(|conn| { + let Ok(mut stmt) = conn.prepare_cached(has_metric_sql) else { + return Ok(false); + }; + let Ok(mut metric_iter) = + stmt.query([lifetime.as_str(), storage_name, metric_identifier]) + else { + return Ok(false); + }; + + Result::::Ok(metric_iter.next().map(|m| m.is_some()).unwrap_or(false)) + }) + .unwrap_or(false) + } + + /// Records a metric in the underlying storage system. + pub fn record(&self, glean: &Glean, data: &CommonMetricDataInternal, value: &Metric) { + // If upload is disabled we don't want to record. + if !glean.is_upload_enabled() { + return; + } + + let name = data.identifier(glean); + + _ = self.conn.write(|tx| { + for ping_name in data.storage_names() { + if let Err(e) = + self.record_per_lifetime(tx, data.inner.lifetime, ping_name, &name, value) + { + log::error!( + "Failed to record metric '{}' into {}: {:?}", + data.base_identifier(), + ping_name, + e + ); + } + } + + Ok::<(), rusqlite::Error>(()) + }); + } + + /// Records a metric in the underlying storage system, for a single lifetime. + /// + /// # Returns + /// + /// If the storage is unavailable or the write fails, no data will be stored and an error will be returned. + /// + /// Otherwise `Ok(())` is returned. + /// + /// # Panics + /// + /// This function will **not** panic on database errors. + fn record_per_lifetime( + &self, + tx: &mut Transaction, + lifetime: Lifetime, + storage_name: &str, + key: &str, + metric: &Metric, + ) -> Result<()> { + let insert_sql = r#" + INSERT INTO + telemetry (id, ping, lifetime, value) + VALUES + (?1, ?2, ?3, ?4) + ON CONFLICT(id, ping) DO UPDATE SET + lifetime = excluded.lifetime, + value = excluded.value + "#; + + let mut stmt = tx.prepare_cached(insert_sql)?; + let encoded = bincode::serialize(&metric).expect("IMPOSSIBLE: Serializing metric failed"); + stmt.execute(params![key, storage_name, lifetime.as_str(), encoded])?; + + Ok(()) + } + + /// Records the provided value, with the given lifetime, + /// after applying a transformation function. + pub fn record_with(&self, glean: &Glean, data: &CommonMetricDataInternal, mut transform: F) + where + F: FnMut(Option) -> Metric, + { + // If upload is disabled we don't want to record. + if !glean.is_upload_enabled() { + return; + } + + _ = self.conn.write(|tx| { + let name = data.identifier(glean); + for ping_name in data.storage_names() { + if let Err(e) = self.record_per_lifetime_with( + tx, + data.inner.lifetime, + ping_name, + &name, + &mut transform, + ) { + log::error!( + "Failed to record metric '{}' into {}: {:?}", + data.base_identifier(), + ping_name, + e + ); + } + } + + Result::<(), rusqlite::Error>::Ok(()) + }); + } + + /// Records a metric in the underlying storage system, + /// after applying the given transformation function, for a single lifetime. + /// + /// # Returns + /// + /// If the storage is unavailable or the write fails, no data will be stored and an error will be returned. + /// + /// Otherwise `Ok(())` is returned. + /// + /// # Panics + /// + /// This function will **not** panic on database errors. + fn record_per_lifetime_with( + &self, + tx: &mut Transaction, + lifetime: Lifetime, + storage_name: &str, + key: &str, + mut transform: F, + ) -> Result<()> + where + F: FnMut(Option) -> Metric, + { + let find_sql = r#" + SELECT value + FROM telemetry + WHERE + lifetime = ?1 + AND ping = ?2 + AND id = ?3 + LIMIT 1 + "#; + + let new_value = { + let mut stmt = tx.prepare_cached(&find_sql)?; + let mut rows = stmt.query(params![lifetime.as_str().to_string(), storage_name, key])?; + + if let Ok(Some(row)) = rows.next() { + let blob: Vec = row.get(0)?; + let old_value = bincode::deserialize(&blob).ok(); + transform(old_value) + } else { + transform(None) + } + }; + + let insert_sql = r#" + INSERT INTO + telemetry (id, ping, lifetime, value) + VALUES + (?1, ?2, ?3, ?4) + ON CONFLICT(id, ping) DO UPDATE SET + lifetime = excluded.lifetime, + value = excluded.value + "#; + + { + let mut stmt = tx.prepare_cached(insert_sql)?; + let encoded = + bincode::serialize(&new_value).expect("IMPOSSIBLE: Serializing metric failed"); + stmt.execute(params![key, storage_name, lifetime.as_str(), encoded])?; + } + + Ok(()) + } + + /// Clears a storage (only Ping Lifetime). + /// + /// # Returns + /// + /// * If the storage is unavailable an error is returned. + /// * If any individual delete fails, an error is returned, but other deletions might have + /// happened. + /// + /// Otherwise `Ok(())` is returned. + /// + /// # Panics + /// + /// This function will **not** panic on database errors. + pub fn clear_ping_lifetime_storage(&self, storage_name: &str) -> Result<()> { + let clear_sql = "DELETE FROM telemetry WHERE lifetime = ?1 AND ping = ?2"; + self.conn.write(|tx| { + let mut stmt = tx.prepare_cached(clear_sql)?; + stmt.execute([Lifetime::Ping.as_str(), storage_name])?; + Ok(()) + }) + } + + /// Removes a single metric from the storage. + /// + /// # Arguments + /// + /// * `lifetime` - the lifetime of the storage in which to look for the metric. + /// * `storage_name` - the name of the storage to store/fetch data from. + /// * `metric_id` - the metric category + name. + /// + /// # Returns + /// + /// * If the storage is unavailable an error is returned. + /// * If the metric could not be deleted, an error is returned. + /// + /// Otherwise `Ok(())` is returned. + /// + /// # Panics + /// + /// This function will **not** panic on database errors. + pub fn remove_single_metric( + &self, + lifetime: Lifetime, + storage_name: &str, + metric_id: &str, + ) -> Result<()> { + let clear_sql = "DELETE FROM telemetry WHERE lifetime = ?1 AND ping = ?2 AND id = ?3"; + self.conn.write(|tx| { + let mut stmt = tx.prepare_cached(clear_sql)?; + stmt.execute([lifetime.as_str(), storage_name, metric_id])?; + Ok(()) + }) + } + + /// Clears all the metrics in the database, for the provided lifetime. + /// + /// Errors are logged. + /// + /// # Panics + /// + /// * This function will **not** panic on database errors. + pub fn clear_lifetime(&self, lifetime: Lifetime) { + let clear_sql = "DELETE FROM telemetry WHERE lifetime = ?1"; + _ = self.conn.write(|tx| { + let mut stmt = tx.prepare_cached(clear_sql)?; + let res = stmt.execute([lifetime.as_str()]); + + if let Err(e) = res { + log::warn!("Could not clear store for lifetime {:?}: {:?}", lifetime, e); + } + Ok::<(), rusqlite::Error>(()) + }); + } + + /// Clears all metrics in the database. + /// + /// Errors are logged. + /// + /// # Panics + /// + /// * This function will **not** panic on database errors. + pub fn clear_all(&self) { + let lifetimes = &[ + Lifetime::User.as_str(), + Lifetime::Ping.as_str(), + Lifetime::Application.as_str(), + ]; + let clear_sql = + "DELETE FROM telemetry WHERE lifetime = ?1 OR lifetime = ?2 OR lifetime = ?3"; + _ = self.conn.write(|tx| { + let mut stmt = tx.prepare_cached(clear_sql)?; + let res = stmt.execute(lifetimes); + + if let Err(e) = res { + log::warn!("Could not clear store for all lifetimes: {:?}", e); + } + Ok::<(), rusqlite::Error>(()) + }); + } + + /// Persists ping_lifetime_data to disk. + /// + /// Does nothing in case there is nothing to persist. + /// + /// # Panics + /// + /// * This function will **not** panic on database errors. + pub fn persist_ping_lifetime_data(&self) -> Result<()> { + Ok(()) + } +} diff --git a/glean-core/src/database/sqlite/connection.rs b/glean-core/src/database/sqlite/connection.rs new file mode 100644 index 0000000000..7c6d1cebeb --- /dev/null +++ b/glean-core/src/database/sqlite/connection.rs @@ -0,0 +1,111 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +//! Lower-level, generic SQLite connection management. +//! +//! This module is inspired by, and borrows concepts from, the +//! Application Services `sql-support` crate. + +use std::{fmt::Debug, num::NonZeroU32, path::Path, sync::Mutex}; + +use rusqlite::{OpenFlags, Transaction, TransactionBehavior}; + +/// Sets up an SQLite database connection, and either +/// initializes an empty physical database with the latest schema, or +/// upgrades an existing physical database to the latest schema. +pub trait ConnectionOpener { + /// The highest schema version that we support. + const MAX_SCHEMA_VERSION: u32; + + type Error: From; + + /// Sets up an opened connection for use. This is a good place to + /// set pragmas and configuration options, register functions, and + /// load extensions. + fn setup(_conn: &mut rusqlite::Connection) -> Result<(), Self::Error> { + Ok(()) + } + + /// Initializes an empty physical database with the latest schema. + fn create(tx: &mut Transaction<'_>) -> Result<(), Self::Error>; + + /// Upgrades an existing physical database to the schema with + /// the given version. + fn upgrade(tx: &mut Transaction<'_>, to_version: NonZeroU32) -> Result<(), Self::Error>; +} + +/// A thread-safe wrapper around a connection to a physical SQLite database. +pub struct Connection { + /// The inner connection. + conn: Mutex, +} + +impl Connection { + /// Opens a connection to a physical database at the given path. + pub fn new(path: &Path) -> Result + where + O: ConnectionOpener, + { + let flags = OpenFlags::SQLITE_OPEN_NO_MUTEX // Send/Sync is guaranteed by Rust already + | OpenFlags::SQLITE_OPEN_EXRESCODE // Extended result codes + | OpenFlags::SQLITE_OPEN_CREATE // Create if it doesn't exist + | OpenFlags::SQLITE_OPEN_READ_WRITE; // opened for reading and writing + + let mut conn = rusqlite::Connection::open_with_flags(path, flags)?; + O::setup(&mut conn)?; + + // On open upgrade the schema to the latest version. + let mut tx = conn.transaction_with_behavior(TransactionBehavior::Exclusive)?; + match tx.query_row_and_then("PRAGMA user_version", [], |row| row.get(0)) { + Ok(mut version @ 1..) => { + while version < O::MAX_SCHEMA_VERSION { + O::upgrade(&mut tx, NonZeroU32::new(version + 1).unwrap())?; + version += 1; + } + } + Ok(0) => O::create(&mut tx)?, + Err(err) => Err(err)?, + } + // Set the schema version to the highest that we support. + // If the current version is higher than ours, downgrade it, + // so that upgrading to it again in the future can fix up any + // invariants that our version might not uphold. + tx.execute_batch(&format!("PRAGMA user_version = {}", O::MAX_SCHEMA_VERSION))?; + tx.commit()?; + Ok(Self::with_connection(conn)) + } + + fn with_connection(conn: rusqlite::Connection) -> Self { + Self { + conn: Mutex::new(conn), + } + } + + /// Accesses the database for reading. + pub fn read( + &self, + f: impl FnOnce(&rusqlite::Connection) -> Result, + ) -> Result { + let conn = self.conn.lock().unwrap(); + f(&*conn) + } + + /// Accesses the database in a transaction for reading and writing. + pub fn write(&self, f: impl FnOnce(&mut Transaction<'_>) -> Result) -> Result + where + E: From, + { + let mut conn = self.conn.lock().unwrap(); + let mut tx = conn.transaction_with_behavior(TransactionBehavior::Immediate)?; + let result = f(&mut tx)?; + tx.commit()?; + Ok(result) + } +} + +impl Debug for Connection { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str("Connection { .. }") + } +} diff --git a/glean-core/src/database/sqlite/schema.rs b/glean-core/src/database/sqlite/schema.rs new file mode 100644 index 0000000000..6bf919a074 --- /dev/null +++ b/glean-core/src/database/sqlite/schema.rs @@ -0,0 +1,68 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +//! The SQLite database schema. + +use std::num::NonZeroU32; + +use rusqlite::{config::DbConfig, Transaction}; + +use super::connection::ConnectionOpener; + +/// The schema for a physical SQLite database that contains many +/// named logical databases. +#[derive(Debug)] +pub struct Schema; + +impl ConnectionOpener for Schema { + const MAX_SCHEMA_VERSION: u32 = 1; + + type Error = SchemaError; + + fn setup(conn: &mut rusqlite::Connection) -> Result<(), Self::Error> { + conn.execute_batch( + "PRAGMA journal_mode = WAL; + PRAGMA journal_size_limit = 512000; -- 512 KB. + PRAGMA temp_store = MEMORY; + PRAGMA auto_vacuum = INCREMENTAL; + ", + )?; + + // Set hardening flags. + conn.set_db_config(DbConfig::SQLITE_DBCONFIG_DEFENSIVE, true)?; + + // Turn off misfeatures: double-quoted strings and untrusted schemas. + conn.set_db_config(DbConfig::SQLITE_DBCONFIG_DQS_DML, false)?; + conn.set_db_config(DbConfig::SQLITE_DBCONFIG_DQS_DDL, false)?; + conn.set_db_config(DbConfig::SQLITE_DBCONFIG_TRUSTED_SCHEMA, true)?; + + Ok(()) + } + + fn create(tx: &mut Transaction<'_>) -> Result<(), Self::Error> { + tx.execute_batch( + "CREATE TABLE telemetry( + id TEXT NOT NULL, + ping TEXT NOT NULL, + lifetime TEXT NOT NULL, + labels TEXT NOT NULL, -- can't be null or ON CONFLICT won't work + value BLOB, + UNIQUE(id, ping, labels) + );", + )?; + Ok(()) + } + + fn upgrade(_: &mut Transaction<'_>, to_version: NonZeroU32) -> Result<(), Self::Error> { + Err(SchemaError::UnsupportedSchemaVersion(to_version.get())) + } +} + +#[derive(thiserror::Error, Debug)] +pub enum SchemaError { + #[error("unsupported schema version: {0}")] + UnsupportedSchemaVersion(u32), + #[error("sqlite: {0}")] + Sqlite(#[from] rusqlite::Error), +} From 2f411a2111b223827573f85fd3cd08152a8a4055 Mon Sep 17 00:00:00 2001 From: Jan-Erik Rediger Date: Thu, 5 Jun 2025 12:18:29 +0200 Subject: [PATCH 2/3] Rust dependency: Add `rusqlite` --- Cargo.lock | 87 +++++++++++++++++++++++++++++---- glean-core/Cargo.toml | 1 + glean-core/benchmark/Cargo.lock | 76 +++++++++++++++++++++++++++- 3 files changed, 154 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 344b205ab7..77171672cc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -160,11 +160,11 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.4.1" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" +checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" dependencies = [ - "serde", + "serde_core", ] [[package]] @@ -230,11 +230,12 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.0.83" +version = "1.2.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +checksum = "755d2fce177175ffca841e9a06afdb2c4ab0f593d53b4dee48147dfaade85932" dependencies = [ - "libc", + "find-msvc-tools", + "shlex", ] [[package]] @@ -477,6 +478,18 @@ dependencies = [ "libc", ] +[[package]] +name = "fallible-iterator" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" + +[[package]] +name = "fallible-streaming-iterator" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" + [[package]] name = "fastrand" version = "2.3.0" @@ -494,6 +507,12 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "find-msvc-tools" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8591b0bcc8a98a64310a2fae1bb3e9b8564dd10e381e6e28010fde8e8e8568db" + [[package]] name = "flate2" version = "1.0.35" @@ -599,6 +618,7 @@ dependencies = [ "pulldown-cmark", "pulldown-cmark-to-cmark", "rkv", + "rusqlite", "serde", "serde_json", "tempfile", @@ -833,6 +853,17 @@ version = "0.2.176" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "58f929b4d672ea937a23a1ab494143d968337a5f47e56d0815df1e0890ddf174" +[[package]] +name = "libsqlite3-sys" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "133c182a6a2c87864fe97778797e46c7e999672690dc9fa3ee8e241aa4a9c13f" +dependencies = [ + "cc", + "pkg-config", + "vcpkg", +] + [[package]] name = "linux-raw-sys" version = "0.4.10" @@ -944,6 +975,12 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" +[[package]] +name = "pkg-config" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" + [[package]] name = "plain" version = "0.2.3" @@ -1020,7 +1057,7 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e8bbe1a966bd2f362681a44f6edce3c2310ac21e4d5067a6e7ec396297a6ea0" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.10.0", "memchr", "unicase", ] @@ -1115,7 +1152,7 @@ checksum = "0f67a9dbc634fcd36a2d1d800ca818065dcf71a1d907dc35130c2d1552c6e1dc" dependencies = [ "arrayref", "bincode", - "bitflags 2.4.1", + "bitflags 2.10.0", "id-arena", "lazy_static", "log", @@ -1129,6 +1166,20 @@ dependencies = [ "wr_malloc_size_of", ] +[[package]] +name = "rusqlite" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "165ca6e57b20e1351573e3729b958bc62f0e48025386970b6e4d29e7a7e71f3f" +dependencies = [ + "bitflags 2.10.0", + "fallible-iterator", + "fallible-streaming-iterator", + "hashlink", + "libsqlite3-sys", + "smallvec", +] + [[package]] name = "rustc-hash" version = "2.1.1" @@ -1141,7 +1192,7 @@ version = "0.38.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67ce50cb2e16c2903e30d1cbccfd8387a74b9d4c938b6a4c5ec6cc7556f7a8a0" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.10.0", "errno", "libc", "linux-raw-sys", @@ -1261,12 +1312,24 @@ dependencies = [ "serde_core", ] +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "siphasher" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" + [[package]] name = "smawk" version = "0.3.2" @@ -1601,6 +1664,12 @@ dependencies = [ "getrandom", ] +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + [[package]] name = "wait-timeout" version = "0.2.1" diff --git a/glean-core/Cargo.toml b/glean-core/Cargo.toml index 447fb4b67e..ba154d34c1 100644 --- a/glean-core/Cargo.toml +++ b/glean-core/Cargo.toml @@ -44,6 +44,7 @@ uniffi = { version = "0.31.0", default-features = false } env_logger = { version = "0.10.0", default-features = false, optional = true } malloc_size_of_derive = "0.1.3" malloc_size_of = { version = "0.2.2", package = "wr_malloc_size_of", default-features = false, features = ["once_cell"] } +rusqlite = { version = "0.37.0", features = ["bundled"] } [target.'cfg(target_os = "android")'.dependencies] android_logger = { version = "0.12.0", default-features = false } diff --git a/glean-core/benchmark/Cargo.lock b/glean-core/benchmark/Cargo.lock index 37be0ce779..ccdf5cd27b 100644 --- a/glean-core/benchmark/Cargo.lock +++ b/glean-core/benchmark/Cargo.lock @@ -477,6 +477,18 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "fallible-iterator" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" + +[[package]] +name = "fallible-streaming-iterator" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" + [[package]] name = "fastrand" version = "2.3.0" @@ -499,6 +511,12 @@ dependencies = [ "miniz_oxide", ] +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + [[package]] name = "form_urlencoded" version = "1.2.2" @@ -543,6 +561,7 @@ dependencies = [ "once_cell", "oslog", "rkv", + "rusqlite", "serde", "serde_json", "thiserror", @@ -624,12 +643,30 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "foldhash", +] + [[package]] name = "hashbrown" version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" +[[package]] +name = "hashlink" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7382cf6263419f2d8df38c55d7da83da5c18aef87fc7a7fc1fb1e344edfe14c1" +dependencies = [ + "hashbrown 0.15.5", +] + [[package]] name = "heck" version = "0.5.0" @@ -781,7 +818,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" dependencies = [ "equivalent", - "hashbrown", + "hashbrown 0.16.1", "serde", "serde_core", ] @@ -833,6 +870,17 @@ dependencies = [ "windows-link", ] +[[package]] +name = "libsqlite3-sys" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "133c182a6a2c87864fe97778797e46c7e999672690dc9fa3ee8e241aa4a9c13f" +dependencies = [ + "cc", + "pkg-config", + "vcpkg", +] + [[package]] name = "linux-raw-sys" version = "0.11.0" @@ -961,6 +1009,12 @@ version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" +[[package]] +name = "pkg-config" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" + [[package]] name = "plain" version = "0.2.3" @@ -1131,6 +1185,20 @@ dependencies = [ "wr_malloc_size_of", ] +[[package]] +name = "rusqlite" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "165ca6e57b20e1351573e3729b958bc62f0e48025386970b6e4d29e7a7e71f3f" +dependencies = [ + "bitflags", + "fallible-iterator", + "fallible-streaming-iterator", + "hashlink", + "libsqlite3-sys", + "smallvec", +] + [[package]] name = "rustc-hash" version = "2.1.1" @@ -1601,6 +1669,12 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + [[package]] name = "walkdir" version = "2.5.0" From d3d4e1bbab652bf31e3c8b0c2bbb5558ccebfb49 Mon Sep 17 00:00:00 2001 From: Jan-Erik Rediger Date: Fri, 20 Feb 2026 16:34:03 +0100 Subject: [PATCH 3/3] Vetting newly imported crates --- supply-chain/audits.toml | 47 ++++++++++ supply-chain/config.toml | 12 ++- supply-chain/imports.lock | 191 +++++++++++++++++++++++++++++++++++++- 3 files changed, 241 insertions(+), 9 deletions(-) diff --git a/supply-chain/audits.toml b/supply-chain/audits.toml index efb37606f6..e050266a99 100644 --- a/supply-chain/audits.toml +++ b/supply-chain/audits.toml @@ -295,6 +295,11 @@ criteria = "safe-to-deploy" delta = "2.4.0 -> 2.4.1" notes = "Only allowing new clippy lints" +[[audits.bitflags]] +who = "Jan-Erik Rediger " +criteria = "safe-to-deploy" +delta = "2.9.4 -> 2.10.0" + [[audits.bstr]] who = "Jan-Erik Rediger " criteria = "safe-to-run" @@ -321,6 +326,11 @@ who = "Jan-Erik Rediger " criteria = "safe-to-deploy" delta = "1.0.78 -> 1.0.83" +[[audits.cc]] +who = "Jan-Erik Rediger " +criteria = "safe-to-deploy" +delta = "1.2.41 -> 1.2.53" + [[audits.chrono]] who = "Lars Eggert " criteria = "safe-to-deploy" @@ -381,12 +391,27 @@ who = "Lars Eggert " criteria = "safe-to-deploy" delta = "0.3.11 -> 0.4.0" +[[audits.fallible-iterator]] +who = "Jan-Erik Rediger " +criteria = "safe-to-deploy" +version = "0.2.0" + +[[audits.fallible-streaming-iterator]] +who = "Jan-Erik Rediger " +criteria = "safe-to-deploy" +version = "0.1.9" + [[audits.fd-lock]] who = "Jan-Erik Rediger " criteria = "safe-to-deploy" delta = "3.0.12 -> 3.0.13" notes = "Dependency updates only" +[[audits.find-msvc-tools]] +who = "Jan-Erik Rediger " +criteria = "safe-to-deploy" +delta = "0.1.4 -> 0.1.8" + [[audits.flate2]] who = "Jan-Erik Rediger " criteria = "safe-to-deploy" @@ -545,6 +570,16 @@ criteria = "safe-to-deploy" delta = "0.19.0 -> 0.20.0" notes = "Removed all LMDB-specific code, added malloc_size_of integration" +[[audits.rmp]] +who = "Jan-Erik Rediger " +criteria = "safe-to-deploy" +delta = "0.8.14 -> 0.8.15" + +[[audits.rmp-serde]] +who = "Jan-Erik Rediger " +criteria = "safe-to-deploy" +delta = "1.3.0 -> 1.3.1" + [[audits.rustversion]] who = "Jan-Erik Rediger " criteria = "safe-to-deploy" @@ -754,6 +789,18 @@ criteria = "safe-to-deploy" delta = "1.1.0 -> 1.2.0" notes = "Added a file lock on the created directory" +[[trusted.cc]] +criteria = "safe-to-deploy" +user-id = 55123 # rust-lang-owner +start = "2022-10-29" +end = "2027-02-20" + +[[trusted.find-msvc-tools]] +criteria = "safe-to-deploy" +user-id = 539 # Josh Stone (cuviper) +start = "2025-08-29" +end = "2027-02-20" + [[trusted.hashbrown]] criteria = "safe-to-deploy" user-id = 55123 # rust-lang-owner diff --git a/supply-chain/config.toml b/supply-chain/config.toml index c41551eb22..1c79b7cf6f 100644 --- a/supply-chain/config.toml +++ b/supply-chain/config.toml @@ -86,10 +86,6 @@ criteria = "safe-to-deploy" [[exemptions.hashlink]] version = "0.7.0" -criteria = "safe-to-run" - -[[exemptions.hermit-abi]] -version = "0.2.6" criteria = "safe-to-deploy" [[exemptions.humantime]] @@ -112,6 +108,10 @@ criteria = "safe-to-run" version = "0.2.139" criteria = "safe-to-deploy" +[[exemptions.libsqlite3-sys]] +version = "0.26.0" +criteria = "safe-to-deploy" + [[exemptions.memchr]] version = "2.5.0" criteria = "safe-to-deploy" @@ -172,6 +172,10 @@ criteria = "safe-to-run" version = "0.6.27" criteria = "safe-to-run" +[[exemptions.rusqlite]] +version = "0.27.0" +criteria = "safe-to-deploy" + [[exemptions.scroll]] version = "0.11.0" criteria = "safe-to-deploy" diff --git a/supply-chain/imports.lock b/supply-chain/imports.lock index 9b91ce80a7..6d0c66dc6c 100644 --- a/supply-chain/imports.lock +++ b/supply-chain/imports.lock @@ -8,6 +8,12 @@ user-id = 696 user-login = "fitzgen" user-name = "Nick Fitzgerald" +[[publisher.cc]] +version = "1.2.30" +when = "2025-07-18" +user-id = 55123 +user-login = "rust-lang-owner" + [[publisher.encoding_rs]] version = "0.8.35" when = "2024-10-24" @@ -15,6 +21,13 @@ user-id = 4484 user-login = "hsivonen" user-name = "Henri Sivonen" +[[publisher.find-msvc-tools]] +version = "0.1.0" +when = "2025-08-29" +user-id = 539 +user-login = "cuviper" +user-name = "Josh Stone" + [[publisher.hashbrown]] version = "0.15.4" when = "2025-06-07" @@ -352,6 +365,21 @@ Nothing outside the realm of what one would expect from a bitflags generator, all as expected. """ +[[audits.bytecode-alliance.audits.bitflags]] +who = "Alex Crichton " +criteria = "safe-to-deploy" +delta = "2.4.1 -> 2.6.0" +notes = """ +Changes in how macros are invoked and various bits and pieces of macro-fu. +Otherwise no major changes and nothing dealing with `unsafe`. +""" + +[[audits.bytecode-alliance.audits.bitflags]] +who = "Alex Crichton " +criteria = "safe-to-deploy" +delta = "2.7.0 -> 2.9.4" +notes = "Tweaks to the macro, nothing out of order." + [[audits.bytecode-alliance.audits.camino]] who = "Pat Hickey " criteria = "safe-to-deploy" @@ -384,8 +412,8 @@ notes = "Dependency updates and minor changes, nothing suspicious." [[audits.bytecode-alliance.audits.cc]] who = "Alex Crichton " criteria = "safe-to-deploy" -version = "1.0.73" -notes = "I am the author of this crate." +delta = "1.2.30 -> 1.2.41" +notes = "This is a trusted rust-lang/rust crate" [[audits.bytecode-alliance.audits.cfg-if]] who = "Alex Crichton " @@ -432,6 +460,16 @@ criteria = "safe-to-deploy" version = "0.1.2" notes = "This should be portable to any POSIX system and seems like it should be part of the libc crate, but at any rate it's safe as is." +[[audits.bytecode-alliance.audits.fallible-iterator]] +who = "Alex Crichton " +criteria = "safe-to-deploy" +delta = "0.2.0 -> 0.3.0" +notes = """ +This major version update has a few minor breaking changes but everything +this crate has to do with iterators and `Result` and such. No `unsafe` or +anything like that, all looks good. +""" + [[audits.bytecode-alliance.audits.fastrand]] who = "Alex Crichton " criteria = "safe-to-deploy" @@ -465,6 +503,12 @@ criteria = "safe-to-deploy" delta = "3.0.10 -> 3.0.12" notes = "Just a dependency version bump" +[[audits.bytecode-alliance.audits.find-msvc-tools]] +who = "Alex Crichton " +criteria = "safe-to-deploy" +delta = "0.1.0 -> 0.1.4" +notes = "Nothing out of the ordinary for a crate finding MSVC tooling." + [[audits.bytecode-alliance.audits.foldhash]] who = "Alex Crichton " criteria = "safe-to-deploy" @@ -490,6 +534,11 @@ criteria = "safe-to-deploy" delta = "0.4.1 -> 0.5.0" notes = "Minor changes for a `no_std` upgrade but otherwise everything looks as expected." +[[audits.bytecode-alliance.audits.hermit-abi]] +who = "Chris Fallin " +criteria = "safe-to-deploy" +version = "0.1.19" + [[audits.bytecode-alliance.audits.iana-time-zone-haiku]] who = "Dan Gohman " criteria = "safe-to-deploy" @@ -621,12 +670,44 @@ a few `unsafe` blocks related to utf-8 validation which are locally verifiable as correct and otherwise this crate is good to go. """ +[[audits.bytecode-alliance.audits.pkg-config]] +who = "Pat Hickey " +criteria = "safe-to-deploy" +version = "0.3.25" +notes = "This crate shells out to the pkg-config executable, but it appears to sanitize inputs reasonably." + +[[audits.bytecode-alliance.audits.pkg-config]] +who = "Alex Crichton " +criteria = "safe-to-deploy" +delta = "0.3.26 -> 0.3.29" +notes = """ +No `unsafe` additions or anything outside of the purview of the crate in this +change. +""" + +[[audits.bytecode-alliance.audits.pkg-config]] +who = "Chris Fallin " +criteria = "safe-to-deploy" +delta = "0.3.29 -> 0.3.32" + [[audits.bytecode-alliance.audits.semver]] who = "Pat Hickey " criteria = "safe-to-deploy" version = "1.0.17" notes = "plenty of unsafe pointer and vec tricks, but in well-structured and commented code that appears to be correct" +[[audits.bytecode-alliance.audits.shlex]] +who = "Alex Crichton " +criteria = "safe-to-deploy" +version = "1.1.0" +notes = "Only minor `unsafe` code blocks which look valid and otherwise does what it says on the tin." + +[[audits.bytecode-alliance.audits.smallvec]] +who = "Alex Crichton " +criteria = "safe-to-deploy" +delta = "1.13.2 -> 1.14.0" +notes = "Minor new feature, nothing out of the ordinary." + [[audits.bytecode-alliance.audits.static_assertions]] who = "Andrew Brown " criteria = "safe-to-deploy" @@ -693,6 +774,12 @@ is similar to what it once was back then. Skimming over the crate there is nothing suspicious and it's everything you'd expect a Rust URL parser to be. """ +[[audits.bytecode-alliance.audits.vcpkg]] +who = "Pat Hickey " +criteria = "safe-to-deploy" +version = "0.2.15" +notes = "no build.rs, no macros, no unsafe. It reads the filesystem and makes copies of DLLs into OUT_DIR." + [[audits.bytecode-alliance.audits.walkdir]] who = "Andrew Brown " criteria = "safe-to-deploy" @@ -1718,6 +1805,12 @@ delta = "1.0.218 -> 1.0.219" notes = "Minor changes (clippy tweaks, using `mem::take` instead of `mem::replace`)." aggregated-from = "https://chromium.googlesource.com/chromium/src/+/main/third_party/rust/chromium_crates_io/supply-chain/audits.toml?format=TEXT" +[[audits.google.audits.smallvec]] +who = "Manish Goregaokar " +criteria = "safe-to-deploy" +version = "1.13.2" +aggregated-from = "https://chromium.googlesource.com/chromium/src/+/main/third_party/rust/chromium_crates_io/supply-chain/audits.toml?format=TEXT" + [[audits.google.audits.synstructure]] who = "Manish Goregaokar " criteria = "safe-to-deploy" @@ -2113,10 +2206,13 @@ criteria = "safe-to-deploy" delta = "2.3.3 -> 2.4.0" aggregated-from = "https://hg.mozilla.org/mozilla-central/raw-file/tip/supply-chain/audits.toml" -[[audits.mozilla.audits.cc]] -who = "Mike Hommey " +[[audits.mozilla.audits.bitflags]] +who = [ + "Teodor Tanasoaia ", + "Erich Gubler ", +] criteria = "safe-to-deploy" -delta = "1.0.73 -> 1.0.78" +delta = "2.6.0 -> 2.7.0" aggregated-from = "https://hg.mozilla.org/mozilla-central/raw-file/tip/supply-chain/audits.toml" [[audits.mozilla.audits.chrono]] @@ -2247,6 +2343,12 @@ criteria = "safe-to-deploy" delta = "0.9.1 -> 0.10.0" aggregated-from = "https://hg.mozilla.org/mozilla-central/raw-file/tip/supply-chain/audits.toml" +[[audits.mozilla.audits.hermit-abi]] +who = "Mike Hommey " +criteria = "safe-to-deploy" +delta = "0.1.19 -> 0.2.6" +aggregated-from = "https://hg.mozilla.org/mozilla-central/raw-file/tip/supply-chain/audits.toml" + [[audits.mozilla.audits.iana-time-zone]] who = "Mark Hammond " criteria = "safe-to-deploy" @@ -2272,6 +2374,30 @@ criteria = "safe-to-deploy" delta = "0.2.171 -> 0.2.176" aggregated-from = "https://hg.mozilla.org/mozilla-central/raw-file/tip/supply-chain/audits.toml" +[[audits.mozilla.audits.libsqlite3-sys]] +who = "Mark Hammond " +criteria = "safe-to-deploy" +delta = "0.26.0 -> 0.27.0" +aggregated-from = "https://hg.mozilla.org/mozilla-central/raw-file/tip/supply-chain/audits.toml" + +[[audits.mozilla.audits.libsqlite3-sys]] +who = "Mark Hammond " +criteria = "safe-to-deploy" +delta = "0.27.0 -> 0.28.0" +aggregated-from = "https://hg.mozilla.org/mozilla-central/raw-file/tip/supply-chain/audits.toml" + +[[audits.mozilla.audits.libsqlite3-sys]] +who = "Erich Gubler " +criteria = "safe-to-deploy" +delta = "0.28.0 -> 0.31.0" +aggregated-from = "https://hg.mozilla.org/mozilla-central/raw-file/tip/supply-chain/audits.toml" + +[[audits.mozilla.audits.libsqlite3-sys]] +who = "Mark Hammond " +criteria = "safe-to-deploy" +delta = "0.31.0 -> 0.35.0" +aggregated-from = "https://hg.mozilla.org/mozilla-central/raw-file/tip/supply-chain/audits.toml" + [[audits.mozilla.audits.malloc_size_of_derive]] who = "Bobby Holley " criteria = "safe-to-deploy" @@ -2309,6 +2435,12 @@ criteria = "safe-to-deploy" delta = "1.20.3 -> 1.21.1" aggregated-from = "https://hg.mozilla.org/mozilla-central/raw-file/tip/supply-chain/audits.toml" +[[audits.mozilla.audits.pkg-config]] +who = "Mike Hommey " +criteria = "safe-to-deploy" +delta = "0.3.25 -> 0.3.26" +aggregated-from = "https://hg.mozilla.org/mozilla-central/raw-file/tip/supply-chain/audits.toml" + [[audits.mozilla.audits.rayon]] who = "Josh Stone " criteria = "safe-to-deploy" @@ -2340,6 +2472,43 @@ criteria = "safe-to-deploy" version = "0.18.4" aggregated-from = "https://hg.mozilla.org/mozilla-central/raw-file/tip/supply-chain/audits.toml" +[[audits.mozilla.audits.rusqlite]] +who = "Mike Hommey " +criteria = "safe-to-deploy" +delta = "0.27.0 -> 0.28.0" +aggregated-from = "https://hg.mozilla.org/mozilla-central/raw-file/tip/supply-chain/audits.toml" + +[[audits.mozilla.audits.rusqlite]] +who = "Ben Dean-Kawamura " +criteria = "safe-to-deploy" +delta = "0.28.0 -> 0.29.0" +aggregated-from = "https://hg.mozilla.org/mozilla-central/raw-file/tip/supply-chain/audits.toml" + +[[audits.mozilla.audits.rusqlite]] +who = "Mark Hammond " +criteria = "safe-to-deploy" +delta = "0.29.0 -> 0.30.0" +aggregated-from = "https://hg.mozilla.org/mozilla-central/raw-file/tip/supply-chain/audits.toml" + +[[audits.mozilla.audits.rusqlite]] +who = "Mark Hammond " +criteria = "safe-to-deploy" +delta = "0.30.0 -> 0.31.0" +notes = "Mostly build and dependency related changes, and bump to sqlite version" +aggregated-from = "https://hg.mozilla.org/mozilla-central/raw-file/tip/supply-chain/audits.toml" + +[[audits.mozilla.audits.rusqlite]] +who = "Erich Gubler " +criteria = "safe-to-deploy" +delta = "0.31.0 -> 0.33.0" +aggregated-from = "https://hg.mozilla.org/mozilla-central/raw-file/tip/supply-chain/audits.toml" + +[[audits.mozilla.audits.rusqlite]] +who = "Mark Hammond " +criteria = "safe-to-deploy" +delta = "0.33.0 -> 0.37.0" +aggregated-from = "https://hg.mozilla.org/mozilla-central/raw-file/tip/supply-chain/audits.toml" + [[audits.mozilla.audits.rustc-hash]] who = "Bobby Holley " criteria = "safe-to-deploy" @@ -2379,6 +2548,12 @@ version = "1.0.3" notes = "Relatively simple Serde trait implementations. No IO or unsafe code." aggregated-from = "https://hg.mozilla.org/mozilla-central/raw-file/tip/supply-chain/audits.toml" +[[audits.mozilla.audits.shlex]] +who = "Max Inden " +criteria = "safe-to-deploy" +delta = "1.1.0 -> 1.3.0" +aggregated-from = "https://hg.mozilla.org/mozilla-central/raw-file/tip/supply-chain/audits.toml" + [[audits.mozilla.audits.siphasher]] who = "Emilio Cobos Álvarez " criteria = "safe-to-deploy" @@ -2386,6 +2561,12 @@ delta = "0.3.11 -> 1.0.1" notes = "Only change to the crate source is adding documentation." aggregated-from = "https://hg.mozilla.org/mozilla-central/raw-file/tip/supply-chain/audits.toml" +[[audits.mozilla.audits.smallvec]] +who = "Erich Gubler " +criteria = "safe-to-deploy" +delta = "1.14.0 -> 1.15.1" +aggregated-from = "https://hg.mozilla.org/mozilla-central/raw-file/tip/supply-chain/audits.toml" + [[audits.mozilla.audits.tempfile]] who = "Mike Hommey " criteria = "safe-to-deploy"