From 70241c826a3c7d6a2546fefee1d89364c1505cb5 Mon Sep 17 00:00:00 2001 From: Mingwei Zhang Date: Wed, 9 Sep 2026 09:44:01 -0700 Subject: [PATCH 1/4] fix: update suppaftp to 12.0 to address RUSTSEC-2026-0271; declare MSRV 1.88 --- CHANGELOG.md | 10 ++++++++++ Cargo.toml | 5 +++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ae5398d..1712552 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,16 @@ All notable changes to this project will be documented in this file. +## Unreleased + +### Changed + +- Updated `suppaftp` dependency from 7.0 to 12.0, addressing [RUSTSEC-2026-0271](https://rustsec.org/advisories/RUSTSEC-2026-0271.html) (FTP command injection via CRLF in control channel arguments). suppaftp 12 requires Rust 1.88; the MSRV is now declared as `rust-version = "1.88.0"`. + +### Added + +- CI: security audit job (`cargo audit`, runs on Cargo.toml/Cargo.lock changes and weekly) and MSRV check job (`cargo msrv verify` with all features). + ## v0.26.0 -- 2026-08-31 ### Added diff --git a/Cargo.toml b/Cargo.toml index 9900cdb..34967b8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,6 +3,7 @@ name = "oneio" version = "0.26.0" authors = ["Mingwei Zhang "] edition = "2021" +rust-version = "1.88.0" readme = "README.md" license = "MIT" repository = "https://github.com/bgpkit/oneio" @@ -27,7 +28,7 @@ thiserror = "2.0" # feature: remote reqwest = { version = "0.12", default-features = false, features = ["blocking", "http2", "charset", "stream"], optional = true } -suppaftp = { version = "7.0", optional = true } +suppaftp = { version = "12.0", optional = true } # feature: compressions # Turn off flate2 default-features so we can explicitly choose backend via features @@ -113,7 +114,7 @@ rustls = [ "dep:rustls_sys", "reqwest?/rustls-tls-native-roots", "reqwest?/rustls-tls-webpki-roots", - "suppaftp?/rustls", + "suppaftp?/rustls-aws-lc-rs", ] # Future: Async support From 2f3f6b6cfe4dc9805fc39c69d952f0324fed1787 Mon Sep 17 00:00:00 2001 From: Mingwei Zhang Date: Wed, 9 Sep 2026 09:44:01 -0700 Subject: [PATCH 2/4] ci: add MSRV check and security audit jobs --- .github/workflows/audit.yml | 27 +++++++++++++++++++++++++++ .github/workflows/rust.yml | 16 ++++++++++++++++ 2 files changed, 43 insertions(+) create mode 100644 .github/workflows/audit.yml diff --git a/.github/workflows/audit.yml b/.github/workflows/audit.yml new file mode 100644 index 0000000..0851a4f --- /dev/null +++ b/.github/workflows/audit.yml @@ -0,0 +1,27 @@ +name: Security audit + +on: + push: + branches: [main] + paths: + - '**/Cargo.toml' + - '**/Cargo.lock' + pull_request: + branches: [main] + paths: + - '**/Cargo.toml' + - '**/Cargo.lock' + schedule: + - cron: '0 0 * * 6' # Run every Saturday at 00:00 UTC + +jobs: + audit: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v5 + + - name: Install cargo-audit + run: cargo install cargo-audit --locked + + - name: Run cargo audit + run: cargo audit diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 21a4754..571f8b4 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -14,6 +14,22 @@ env: CARGO_TERM_COLOR: always jobs: + msrv: + name: Check MSRV + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v5 + + - uses: Swatinem/rust-cache@v2 + with: + cache-directories: ~/.cargo/bin + + - name: Install cargo-msrv + run: cargo install cargo-msrv --locked + + - name: Verify MSRV with all features + run: cargo msrv verify -- --all-features + format: name: Format runs-on: ubuntu-latest From f3098645cc1d24ffd7cc9cac06f590fd8410c840 Mon Sep 17 00:00:00 2001 From: Mingwei Zhang Date: Wed, 9 Sep 2026 09:48:15 -0700 Subject: [PATCH 3/4] fix: update rusty-s3 to 0.10 and quick-xml to 0.41 for RUSTSEC-2026-0194/0195; add FTP integration test --- CHANGELOG.md | 2 ++ Cargo.toml | 4 ++-- src/s3/mod.rs | 4 ++-- tests/ftp_tests.rs | 37 +++++++++++++++++++++++++++++++++++++ 4 files changed, 43 insertions(+), 4 deletions(-) create mode 100644 tests/ftp_tests.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index 1712552..a85399f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,10 +7,12 @@ All notable changes to this project will be documented in this file. ### Changed - Updated `suppaftp` dependency from 7.0 to 12.0, addressing [RUSTSEC-2026-0271](https://rustsec.org/advisories/RUSTSEC-2026-0271.html) (FTP command injection via CRLF in control channel arguments). suppaftp 12 requires Rust 1.88; the MSRV is now declared as `rust-version = "1.88.0"`. +- Updated `rusty-s3` from 0.9 to 0.10 and `quick-xml` from 0.38 to 0.41, addressing [RUSTSEC-2026-0194](https://rustsec.org/advisories/RUSTSEC-2026-0194.html) and [RUSTSEC-2026-0195](https://rustsec.org/advisories/RUSTSEC-2026-0195.html) (quick-xml parsing denial-of-service). rusty-s3 0.10's `parse_response` takes `&str` instead of `&[u8]`; internal call sites updated accordingly. ### Added - CI: security audit job (`cargo audit`, runs on Cargo.toml/Cargo.lock changes and weekly) and MSRV check job (`cargo msrv verify` with all features). +- Ignored integration test against `ftp.radb.net` (anonymous FTP read of `radb.db.gz`) for manual FTP-path verification. ## v0.26.0 -- 2026-08-31 diff --git a/Cargo.toml b/Cargo.toml index 34967b8..55efd80 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -47,8 +47,8 @@ serde = { version = "1.0", optional = true } serde_json = { version = "1.0", optional = true } # feature: s3 -rusty-s3 = { version = "0.9", optional = true } -quick-xml = { version = "0.38", optional = true } +rusty-s3 = { version = "0.10", optional = true } +quick-xml = { version = "0.41", optional = true } percent-encoding = { version = "2.3", optional = true } sha2 = { version = "0.10", optional = true } hmac = { version = "0.12", optional = true } diff --git a/src/s3/mod.rs b/src/s3/mod.rs index a3f9960..65b00a4 100644 --- a/src/s3/mod.rs +++ b/src/s3/mod.rs @@ -486,7 +486,7 @@ fn upload_multipart( .send() })?)?; let init_response = - rusty_s3::actions::CreateMultipartUpload::parse_response(response.text()?.as_bytes()) + rusty_s3::actions::CreateMultipartUpload::parse_response(response.text()?.as_str()) .map_err(|e| OneIoError::Network(Box::new(e)))?; let upload_id = init_response.upload_id().to_string(); @@ -905,7 +905,7 @@ pub fn s3_list( let url = action.sign(config.ttl); let response = ensure_s3_success(get_s3_client().get(url).send()?)?; - let parsed = rusty_s3::actions::ListObjectsV2::parse_response(response.text()?.as_bytes()) + let parsed = rusty_s3::actions::ListObjectsV2::parse_response(response.text()?.as_str()) .map_err(|e| OneIoError::Network(Box::new(e)))?; if dirs { diff --git a/tests/ftp_tests.rs b/tests/ftp_tests.rs new file mode 100644 index 0000000..e56f8ec --- /dev/null +++ b/tests/ftp_tests.rs @@ -0,0 +1,37 @@ +//! FTP integration tests against a real, public FTP server. +//! +//! These tests require network access and run against `ftp.radb.net` (RADB), +//! the same host that bgpkit-commons uses for IRR database downloads. +//! They are `#[ignore]`d by default; run manually with: +//! +//! ```bash +//! cargo test --test ftp_tests --features ftp -- --ignored --nocapture +//! ``` + +use std::io::Read; + +/// Stream the first bytes of a real file over anonymous FTP and verify that +/// data actually flows through the suppaftp-based reader. +#[test] +#[ignore] +fn read_radb_file_header() { + // radb.db.gz is the full RADB IRR database dump (large). We only read the + // first 64 bytes to verify connect + login + RETR streaming without + // downloading the whole file. + let mut reader = oneio::get_reader("ftp://ftp.radb.net/radb/dbase/radb.db.gz") + .expect("failed to open FTP reader"); + let mut buf = [0u8; 64]; + let n = reader + .read(&mut buf) + .expect("failed to read from FTP stream"); + assert!(n > 0, "expected at least some bytes from the FTP server"); + + let head = String::from_utf8_lossy(&buf[..n]); + // RADB dumps start with IRR text (comments or aut-num objects); after gzip + // decompression the first bytes must be printable ASCII, not binary. + assert!( + head.chars() + .all(|c| c.is_ascii_graphic() || c.is_ascii_whitespace()), + "unexpected binary data at start of decompressed stream: {head:?}" + ); +} From 402868c63aafe73c40910ab2cd8400d9185df7d5 Mon Sep 17 00:00:00 2001 From: Mingwei Zhang Date: Wed, 9 Sep 2026 10:01:56 -0700 Subject: [PATCH 4/4] ci: fix MSRV check command syntax (cargo-msrv -- takes a custom check command) --- .github/workflows/rust.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 571f8b4..325af77 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -28,7 +28,7 @@ jobs: run: cargo install cargo-msrv --locked - name: Verify MSRV with all features - run: cargo msrv verify -- --all-features + run: cargo msrv verify -- cargo check --all-features format: name: Format