Skip to content

Commit

Permalink
Configure Github CI
Browse files Browse the repository at this point in the history
- Fix Clippy offences
  • Loading branch information
bsodmike committed Sep 8, 2024
1 parent 9448564 commit d9b60f2
Show file tree
Hide file tree
Showing 9 changed files with 201 additions and 37 deletions.
7 changes: 7 additions & 0 deletions .github/ISSUE_TEMPLATE/1-problem.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
name: Problem
about: Something does not seem right

---


7 changes: 7 additions & 0 deletions .github/ISSUE_TEMPLATE/2-suggestion.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
name: Suggestion
about: Share how Serde could support your use case better

---


7 changes: 7 additions & 0 deletions .github/ISSUE_TEMPLATE/3-documentation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
name: Documentation
about: Certainly there is room for improvement

---


7 changes: 7 additions & 0 deletions .github/ISSUE_TEMPLATE/4-other.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
name: Anything else!
about: Whatever is on your mind

---


88 changes: 88 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
name: CI

on:
push:
pull_request:
workflow_dispatch:
schedule: [cron: "40 1 * * *"]

permissions:
contents: read

env:
RUSTFLAGS: -Dwarnings

jobs:
test:
name: Test suite
runs-on: ubuntu-latest
timeout-minutes: 45
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@nightly
- run: cargo test
- uses: actions/upload-artifact@v4
if: always()
with:
name: Cargo.lock
path: Cargo.lock

stable:
name: Rust ${{matrix.rust}}
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
rust: [stable, beta]
timeout-minutes: 45
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@master
with:
toolchain: ${{matrix.rust}}
- run: cargo build

nightly:
name: Rust nightly ${{matrix.os == 'windows' && '(windows)' || ''}}
runs-on: ${{matrix.os}}-latest
strategy:
fail-fast: false
matrix:
os: [ubuntu]
timeout-minutes: 45
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@nightly
- run: cargo build

doc:
name: Documentation
runs-on: ubuntu-latest
timeout-minutes: 45
env:
RUSTDOCFLAGS: -Dwarnings
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@nightly
- uses: dtolnay/install@cargo-docs-rs
- run: cargo docs-rs

clippy:
name: Clippy
runs-on: ubuntu-latest
if: github.event_name != 'pull_request'
timeout-minutes: 45
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@clippy
- run: cargo clippy -- -Dclippy::all -Dclippy::pedantic

# miri:
# name: Miri
# runs-on: ubuntu-latest
# timeout-minutes: 45
# steps:
# - uses: actions/checkout@v4
# - uses: dtolnay/rust-toolchain@miri
# - run: cargo miri setup
# - run: cargo miri test
2 changes: 1 addition & 1 deletion examples/read_limited.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ fn main() -> LimitReaderResult<()> {
);

let data = limit_reader.buffer();
let text = String::from_utf8(data[..bytes_read].to_vec())?;
let text = String::from_utf8(data[..(bytes_read as usize)].to_vec())?;

println!("First line from README: {}", &text);

Expand Down
13 changes: 12 additions & 1 deletion src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,16 @@ use crate::{error_from, LimitReaderOutputBuilderError};
use std::{
error::Error as StdError,
fmt::{self},
num::TryFromIntError,
string::FromUtf8Error,
};

/// Boxed error, a ptr to the Error via dynamic dispatch allocated on the heap at run time.
#[allow(clippy::module_name_repetitions)]
pub type BoxError = Box<dyn StdError + Send + Sync>;

/// Default error type for create.
#[allow(clippy::module_name_repetitions)]
pub type LimitReaderError = Error;

/// Error type
Expand All @@ -19,20 +22,27 @@ pub struct Error {

#[derive(Debug)]
#[non_exhaustive]
#[allow(clippy::module_name_repetitions)]
#[allow(clippy::enum_variant_names)]
pub enum ErrorKind {
IoError,
Utf8Error,
LimitReaderOutputBuilderError,
Utf8Error,
TryFromIntError,
LimitReaderError(Box<dyn StdError + Send + Sync>),
}

impl ErrorKind {
pub(crate) fn as_str(&self) -> &'static str {
#[allow(clippy::enum_glob_use)]
use ErrorKind::*;
// tidy-alphabetical-start
match *self {
IoError => "io error",
Utf8Error => "invalid utf-8",
LimitReaderOutputBuilderError => "builder error",
TryFromIntError => "conversion error",
LimitReaderError(_) => "boxed error",
}
}
}
Expand Down Expand Up @@ -78,6 +88,7 @@ error_from!(
LimitReaderOutputBuilderError,
ErrorKind::LimitReaderOutputBuilderError
);
error_from!(TryFromIntError, ErrorKind::TryFromIntError);

#[macro_use]
pub mod macros {
Expand Down
63 changes: 41 additions & 22 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
//!
//! Exposes [`LimitReader`] which is a limit reader, that protects against zip-bombs and other nefarious activities.
//!
//! This crate is heavily inspired by Jon Gjengset's "Crust of Rust" episode on the inner workings of git on YouTube (<https://youtu.be/u0VotuGzD_w?si=oIuV9CITSWHJXKBu&t=3503>) and mitigrating Zip-bombs.
//! This crate is heavily inspired by Jon Gjengset's "Crust of Rust" episode on the inner workings of git on `YouTube` (<https://youtu.be/u0VotuGzD_w?si=oIuV9CITSWHJXKBu&t=3503>) and mitigrating Zip-bombs.

use derive_builder::Builder;
use error::LimitReaderError;
Expand All @@ -27,17 +27,17 @@ pub(crate) mod readable;
/// Default result type for [`LimitReader`]
pub type LimitReaderResult<T> = std::result::Result<T, LimitReaderError>;

/// Re-exports
/// Re-exports Traits and macros used by most projects. Add `use better_limit_reader::prelude::*;` to your code to quickly get started with [`LimitReader`].
pub mod prelude {
//! Traits and macros used by most projects. Add `use better_limit_reader::prelude::*;` to your code to quickly get started with LimitReader.

pub use crate::{error::LimitReaderError, LimitReader, LimitReaderOutput, LimitReaderResult};
}

#[allow(dead_code)]
/// The [LimitReader] reads into `buf` which is held within the record struct.
/// The [`LimitReader`] reads into `buf` which is held within the record struct.
pub struct LimitReader {
buf: [u8; Self::DEFAULT_BUF_SIZE],
expected_size: usize,
expected_size: u64,
decode_zlib: bool,
decode_gzip: bool,
}
Expand All @@ -54,22 +54,24 @@ impl LimitReader {
pub const DEFAULT_BUF_SIZE: usize = 1024;

/// Create a new [`LimitReader`] with a [`LimitReader::DEFAULT_BUF_SIZE`] for the limit-readers max threshold.
#[must_use]
pub fn new() -> Self {
Self {
buf: [0; Self::DEFAULT_BUF_SIZE],
expected_size: Self::DEFAULT_BUF_SIZE - 1,
expected_size: (Self::DEFAULT_BUF_SIZE - 1) as u64,
decode_zlib: false,
decode_gzip: false,
}
}

/// Return a reference to the internal buffer.
#[must_use]
pub fn buffer(&self) -> &[u8; Self::DEFAULT_BUF_SIZE] {
&self.buf
}

/// Increase the allowed limit on the [`LimitReader`]
pub fn limit(&mut self, limit: usize) -> &mut Self {
pub fn limit(&mut self, limit: u64) -> &mut Self {
self.expected_size = limit;

self
Expand All @@ -86,13 +88,21 @@ impl LimitReader {
// NOTE: This is private until this is implemented in the future.
/// Enable decoding from compressed Gzip
fn enable_decode_gzip(&mut self) -> &mut Self {
unimplemented!()
// self.decode_gzip = true;
self.decode_gzip = true;

// self
self
}

/// Read from provided source file. If the source data is already Zlib compressed, optionally decode the data stream before reading it through a limit-reader.
///
/// # Panics
///
/// If the provided source file does not exist or is inaccessible, it will panic. Refer to [`std::fs::File::open`] for details. This will return [`LimitReaderError`].
///
/// # Errors
///
/// If this function encounters an error of the kind [`LimitReaderError`], this error will be returned.
///
pub fn read(&mut self, source: PathBuf) -> Result<usize> {
let f = std::fs::File::open(source).expect("Unable to open file");
if self.decode_zlib {
Expand All @@ -110,6 +120,11 @@ impl LimitReader {
}

/// Given an accessible source file, this will automatically limit the contents read to the size of the buffer itself. This will silently truncate read bytes into the buffer, without raising an error.
///
/// # Errors
///
/// If this function encounters an error of the kind [`LimitReaderError`], this error will be returned.
///
pub fn read_limited(&mut self, source: PathBuf) -> Result<LimitReaderOutput> {
let source_bytes = std::fs::metadata(&source)?.len();
let f = std::fs::File::open(source)?;
Expand Down Expand Up @@ -153,18 +168,21 @@ pub struct LimitReaderOutput {

impl LimitReaderOutput {
/// Return bytes read by the underlying reader.
pub fn bytes_read(&self) -> usize {
self.bytes_read as usize
#[must_use]
pub fn bytes_read(&self) -> u64 {
self.bytes_read
}

/// Size in bytes of the underlying file accessible to the reader.
pub fn source_size(&self) -> usize {
self.source_size as usize
#[must_use]
pub fn source_size(&self) -> u64 {
self.source_size
}

/// Unread bytes (from the underlying file accessible to the reader).
pub fn bytes_remaining(&self) -> usize {
(self.source_size - self.bytes_read) as usize
#[must_use]
pub fn bytes_remaining(&self) -> u64 {
self.source_size - self.bytes_read
}
}

Expand Down Expand Up @@ -243,12 +261,12 @@ mod tests {
writeln!(file, "{}", &text).unwrap();

let mut limit_reader = LimitReader::new();
let limit = 8_usize;
let limit = 8_u64;
limit_reader.limit(limit);

match limit_reader.read(file_path) {
Ok(read_size) => {
assert!(read_size == limit);
assert!(read_size == limit.try_into().unwrap());
}
Err(err) => {
assert_eq!("Error: too many bytes", err.to_string());
Expand Down Expand Up @@ -325,7 +343,7 @@ mod tests {
writeln!(file, "{}", &text).unwrap();

let mut limit_reader = LimitReader::new();
let limit = 8_usize;
let limit = 8_u64;
limit_reader.limit(limit);

match limit_reader.read_limited(file_path.clone()) {
Expand All @@ -350,10 +368,11 @@ mod tests {
Ok(reader_output) => {
let bytes_read = reader_output.bytes_read();
let persisted_text =
String::from_utf8(limit_reader.buf[..bytes_read].to_vec()).unwrap();
String::from_utf8(limit_reader.buf[..(bytes_read as usize)].to_vec())
.unwrap();
assert_eq!(
persisted_text,
format!("{}", &text[..bytes_read]).to_string()
format!("{}", &text[..(bytes_read as usize)]).to_string()
);
}
Err(_) => unreachable!(),
Expand All @@ -373,7 +392,7 @@ mod tests {
writeln!(file, "{}", &text).unwrap();

let mut limit_reader = LimitReader::new();
let limit = 8_usize;
let limit = 8_u64;
limit_reader
// RA block
.limit(limit)
Expand Down
Loading

0 comments on commit d9b60f2

Please sign in to comment.