MVP hardening: review fixes, CI/release workflows, and dependency updates #1

Merged
JMR-dev merged 7 commits from feat-mvp into main 2026-06-25 01:50:56 +00:00
7 Commits
Author SHA1 Message Date
JMR-devandClaude Opus 4.8 2cdefbe45c Update rand to 0.10 with a rand_core 0.6 compatibility shim
Bump the `rand` dev-dependency to the latest (0.10), which exposes rand_core
0.10, while the latest `rsa` (0.9) still requires an rand_core 0.6 RNG for key
generation. Bridge the skew with a small, test-only adapter instead of pinning
rand back.

* Add `rand_core_06 = { package = "rand_core", version = "0.6" }` so the shim
  can implement the old traits (cargo unifies it with the rand_core 0.6 that
  rsa already uses).
* `RandCompat<R>` wraps a modern RNG and re-implements rand_core 0.6's RngCore
  + CryptoRng over it, delegating to rand_core 0.10's infallible methods.
  Implementing both satisfies rand_core 0.6's blanket CryptoRngCore impl, which
  is exactly the bound rsa keygen requires.
* The CryptoRng bound is preserved (only wraps RNGs still marked
  cryptographically secure), so the randomness is not weakened — it is purely a
  trait-version shim. Tests now use `RandCompat(rand::rng())`.

46 tests pass (incl. the RSA-based EPUB roundtrips that exercise the shim);
clippy + rustfmt clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-24 20:44:22 -05:00
JMR-devandClaude Opus 4.8 259bb4d6fa Update dependencies to latest versions
Bump dependency requirements to their current latest and migrate the code for
the breaking API changes; refresh Cargo.lock for the rest.

Notable version bumps:
* zip 2 -> 8, quick-xml 0.37 -> 0.40, toml 0.8 -> 1
* windows 0.58 -> 0.62, winreg 0.52 -> 0.56
* RustCrypto: aes 0.8 -> 0.9, cbc 0.1 -> 0.2, sha1/sha2 0.10 -> 0.11,
  md-5 0.10 -> 0.11, ctr 0.9 -> 0.10, hmac 0.12 -> 0.13, pbkdf2 0.12 -> 0.13

Code migrations:
* quick-xml 0.40: BytesText::unescape() -> xml10_content();
  Attribute::unescape_value() -> normalized_value(XmlVersion::Implicit1_0)
* windows 0.62: LocalFree now takes Option<HLOCAL>
* cipher 0.5 (aes 0.9 / cbc 0.2): BlockEncryptMut/BlockDecryptMut ->
  BlockModeEncrypt/BlockModeDecrypt; encrypt_padded_mut/decrypt_padded_mut ->
  encrypt_padded/decrypt_padded

Held back deliberately: rand stays 0.8 because the latest rsa (0.9) still needs
an rand_core 0.6 RNG for keygen, which rand 0.9+ no longer provides. rsa pinning
the older RustCrypto generation also leaves a couple of duplicate transitive
versions (digest 0.10/0.11, crypto-common 0.1/0.2) — harmless.

Verified: 46 tests pass, clippy + rustfmt clean, and a real ADEPT EPUB still
decrypts end-to-end (DPAPI key extraction + RSA/AES) to a valid DRM-free file.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-24 20:27:43 -05:00
JMR-dev 2d8f3f910d date comment update 2026-06-24 20:13:08 -05:00
JMR-devandClaude Opus 4.8 47041225a0 Pin CI/release Rust toolchain to 1.96.0 (latest stable)
Replace the floating `stable` channel with the exact current latest stable
(1.96.0, which also matches the crate's rust-version/MSRV) so builds are
reproducible and `clippy -D warnings` can't break from an unrelated toolchain
bump.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-24 20:11:24 -05:00
JMR-devandClaude Opus 4.8 f776172d57 Pin GitHub Actions to commit SHAs at their latest versions
Update each action to its current latest release and pin to the full commit
SHA (supply-chain hardening), with the version in a trailing comment:

* actions/checkout            v4 -> v7.0.0
* Swatinem/rust-cache         v2 -> v2.9.1
* actions/upload-artifact     v4 -> v7.0.1
* actions/download-artifact   v4 -> v8.0.1
* softprops/action-gh-release v2 -> v3.0.1
* dtolnay/rust-toolchain      pinned to master @ 2026-06-20 (no tagged
  releases); add explicit `toolchain: stable` since the channel can no
  longer be inferred from the @ref once pinned to a SHA.

Verified upload-artifact v7 (zips by default) and download-artifact v8
interoperate, and that every input still exists in the new majors.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-24 20:08:40 -05:00
JMR-devandClaude Opus 4.8 e5e4173ee6 Add CI and release GitHub Actions workflows
* ci.yml: on pull requests to main, runs on windows-latest and macos-latest;
  checks formatting, runs clippy (warnings denied), and runs the unit tests
  (`cargo test --workspace`).
* release.yml: manual workflow_dispatch (tag + optional prerelease inputs);
  builds release binaries for Windows (x86_64) and macOS (aarch64 + x86_64),
  then publishes them to GitHub Releases with auto-generated notes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-24 20:03:32 -05:00
JMR-devandClaude Opus 4.8 01334d31d0 Fix panic-on-malformed-input defects found in code review
Harden the decryptors against corrupt/edge-case input so a single bad file
errors cleanly instead of panicking (and, in a batch, aborting the whole run):

* ADEPT EPUB: the content-decrypt guard was `len < 16` but then sliced off the
  16-byte pad block before reading the trailing pad length; a one-block (16-byte)
  ciphertext left an empty slice and panicked on `.last().unwrap()`. Guard is
  now `len <= 16`.
* MOBI: validate the section table before indexing it — require >= 2 sections
  and reject a record count that exceeds the section count, preventing
  out-of-bounds panics on `section_offsets[1]` / `section_bounds(i)`.
* MOBI: `trailing_size` now uses saturating/checked subtraction, and the caller
  clamps the trailing size to the record length, so a corrupt trailing-size
  encoding can't underflow.
* MOBI: `normalize_pids` slices PIDs by characters, not bytes, so a non-ASCII
  `--pid` can't panic on a non-char-boundary.
* CLI: wrap the per-file decrypt in `catch_unwind` so any future panic is
  contained to that file rather than aborting a multi-file run.

Adds 5 regression tests (one per fix). 46 lib tests pass; clippy + fmt clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-24 19:57:52 -05:00