diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7645891..c31219c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,4 +18,16 @@ jobs: # and MSRV is read from rust-version. Anything that needed configuring would be # a behaviour change smuggled in by an adoption PR, so there is nothing here. ci: - uses: SecurityRonin/fleet-ci/.github/workflows/rust-ci.yml@a62ab10603151071744cec0b4e3638aa6406d4e4 + uses: SecurityRonin/fleet-ci/.github/workflows/rust-ci.yml@e4bee453e6975d5c6ddf3d5120101364ebeaf7d6 + with: + # CARRIED ACROSS. The replaced gate excluded main.rs explicitly — its own + # comment reads "main.rs (the Humble CLI shell) is excluded by the script". + # Adoption dropped that, so the strict gate began demanding 100% line + # coverage of a CLI shell this repo has never gated, and main went red on + # 10 lines that were never in scope. + # + # Also worth recording: the old gate enforced 100% LINE *and FUNCTION* + # coverage. The shared workflow has no function-coverage input, so that + # half is dropped. A real reduction, stated here rather than left to be + # found in a coverage report later. + coverage-ignore-regex: '(^|/)src/main\.rs' diff --git a/src/identify.rs b/src/identify.rs index 68ea409..1874abf 100644 --- a/src/identify.rs +++ b/src/identify.rs @@ -417,11 +417,11 @@ fn detect_utf16le(bytes: &[u8]) -> Option { .map(|c| u16::from_le_bytes([c[0], c[1]])) .collect(); if units.is_empty() { - // cov:unreachable: the guard above establishes bytes.len() >= 4 and even, and - // `body` is either `bytes` or `bytes[2..]` (BOM), so body.len() >= 2 and + // The guard above establishes bytes.len() >= 4 and even, and `body` is + // either `bytes` or `bytes[2..]` (BOM), so body.len() >= 2 and // chunks_exact(2) always yields at least one unit. Kept as a defensive // backstop in case the length guard above is ever relaxed. - return None; + return None; // cov:unreachable: body.len() >= 2, so chunks_exact(2) yields >= 1 unit } let text = String::from_utf16(&units).ok()?; if !mostly_printable(&text) { @@ -620,11 +620,11 @@ fn describe_plist(v: &plist::Value) -> String { plist::Value::Integer(_) => "integer".to_owned(), plist::Value::String(_) => "string".to_owned(), plist::Value::Uid(_) => "uid".to_owned(), - // cov:unreachable: `plist::Value` (plist 1.9.0) has exactly the nine variants - // matched above — Array, Dictionary, Boolean, Data, Date, Real, Integer, - // String, Uid. The enum is `#[non_exhaustive]`, so this arm exists only so a + // `plist::Value` (plist 1.9.0) has exactly the nine variants matched + // above — Array, Dictionary, Boolean, Data, Date, Real, Integer, String, + // Uid. The enum is `#[non_exhaustive]`, so this arm exists only so a // future plist release that adds a variant still compiles here. - _ => "value".to_owned(), + _ => "value".to_owned(), // cov:unreachable: plist 1.9.0 has only the nine variants above } } diff --git a/src/v8_value.rs b/src/v8_value.rs index 91e8bed..20b6b0d 100644 --- a/src/v8_value.rs +++ b/src/v8_value.rs @@ -774,19 +774,14 @@ impl<'a> Reader<'a> { cap: self.limits.max_nodes, }); } - // The guard above already rejected len > cap (max_nodes, 4_000_000), so len - // fits usize on every supported target; this map_err is a defense-in-depth - // backstop no input can reach. - // cov:unreachable: len <= cap after the guard makes usize::try_from infallible. - usize::try_from(len).map_err(|_| { - // cov:unreachable: the `len > cap` guard above already returned, so - // len <= cap == max_nodes as u64. Since max_nodes is a usize, any value - // <= it fits usize on every target — this closure body is dead. - V8Error::LengthCap { - offset: self.pos, - len, - cap: self.limits.max_nodes, - } + // The guard above already rejected len > cap (max_nodes, 4_000_000), so + // len <= cap == max_nodes as u64. max_nodes is a usize, so any value <= it + // fits usize on every supported target and this map_err closure is a + // defense-in-depth backstop no input can reach. + usize::try_from(len).map_err(|_| V8Error::LengthCap { + offset: self.pos, // cov:unreachable: len <= cap makes try_from infallible + len, // cov:unreachable: len <= cap makes try_from infallible + cap: self.limits.max_nodes, // cov:unreachable: len <= cap makes try_from infallible }) } } @@ -825,19 +820,19 @@ fn le_bytes_to_decimal(bytes: &[u8]) -> String { } } // Strip leading zeros (most-significant end), then render most-significant first. + // + // The schoolbook loop above never leaves a zero in the most-significant slot. + // Induction: `decimal` starts `[0]` (len 1). A digit is appended only by + // `while carry > 0`, whose final push is `carry` itself with 0 < carry < 10, so + // a pushed top digit is non-zero. Otherwise the top digit becomes + // `v = d_top * 256 + carry_in` with v < 10, which is 0 only when d_top == 0 and + // carry_in == 0 — and d_top == 0 implies len == 1 by the same induction, which + // this loop's own `len > 1` guard excludes. Verified by exhaustive replay of all + // magnitudes up to 3 bytes (16,843,009 cases) plus 200k random magnitudes up to + // 12 bytes: the loop never fires. Kept as a defensive normalizer so a future + // change to the carry loop cannot emit a leading-zero decimal. while decimal.len() > 1 && *decimal.last().unwrap_or(&0) == 0 { - // cov:unreachable: the schoolbook loop above never leaves a zero in the - // most-significant slot. Induction: `decimal` starts `[0]` (len 1). A digit is - // appended only by `while carry > 0`, whose final push is `carry` itself with - // 0 < carry < 10, so a pushed top digit is non-zero. Otherwise the top digit - // becomes `v = d_top * 256 + carry_in` with v < 10, which is 0 only when - // d_top == 0 and carry_in == 0 — and d_top == 0 implies len == 1 by the same - // induction, which this loop's own `len > 1` guard excludes. Verified by - // exhaustive replay of all magnitudes up to 3 bytes (16,843,009 cases) plus - // 200k random magnitudes up to 12 bytes: the loop never fires. Kept as a - // defensive normalizer so a future change to the carry loop cannot emit a - // leading-zero decimal. - decimal.pop(); + decimal.pop(); // cov:unreachable: the carry loop never leaves a zero on top } decimal.iter().rev().map(|d| (b'0' + d) as char).collect() }