Commit Graph
100 Commits
Author SHA1 Message Date
Matthew Jackson 1da51fdbf5 build(deps): bump actions/checkout from 5 to 7 in the all group (#13)
Bumps the all group with 1 update: [actions/checkout](https://github.com/actions/checkout).

Updates `actions/checkout` from 5 to 7
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v5...v7)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: all
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-10-03 11:16:01 -07:00
Matthew Jackson 9f5116cc26 chore(dependabot): monthly grouped version updates 2026-10-02 20:24:31 -07:00
Matthew Jackson 3c6ef54cf3 tests: loopback idle bound T_IDLE is 1 s, so a slow macOS runner's scheduling gaps stay inside every margin 2026-10-01 18:06:06 -07:00
Matthew Jackson 73c7f05b4b tests: Stop tests against a silent stub idle T_STOP_IDLE (2 s), past the Stop 2026-10-01 17:20:54 -07:00
Matthew Jackson e6320d52c9 tests: the stopped reachability query idles 2 s and gets 10 s to drain 2026-10-01 16:54:40 -07:00
Matthew Jackson 49cf396c07 tests: the stopped reachability query idles past the Stop, so only the Stop ends it 2026-10-01 16:53:58 -07:00
Matthew Jackson 940bb215ab online: follow libfreemkv's halt::Progress rename to Liveness 2026-09-30 20:36:55 -07:00
Matthew Jackson 18b590407c Cargo.lock: restore (accidentally changed by local patch) 2026-09-30 20:24:57 -07:00
Matthew Jackson 116b33739b tests: halt-landing tests assert Halted, not a tight wall-clock bound 2026-09-30 20:24:46 -07:00
Matthew Jackson d935fa6ffd online: allow LAN/loopback/link-local key-service hosts, reuse libfreemkv is_blocked_ip 2026-09-30 20:03:38 -07:00
Matthew Jackson b65959d3a1 ci: run cargo-deny from the repo dir so the .cargo patches apply 2026-09-30 16:09:03 -07:00
Matthew Jackson 3f08e980a0 ci: path-patch freemkv-unlock; dependabot ignores org workflow refs
libfreemkv now deps freemkv-unlock by version with a git-tag override, so every root that reaches it patches it. Dependabot config unified; it no longer proposes freemkv/.github v1->v2.
2026-09-30 15:53:05 -07:00
Matthew Jackson 6c8e2c5c46 Allow forensic phase fallback after definitive key service misses 2026-09-29 17:20:43 -07:00
Matthew Jackson ba357e46f5 online: wire ctx.halt()/ctx.progress() into the query worker (ST-K1b) 2026-09-28 08:18:38 -07:00
Matthew Jackson a815a0a578 online: ST-K1b tests for ctx.halt()/ctx.progress() wiring (RED) 2026-09-28 08:15:20 -07:00
Matthew Jackson ba6f213be3 KU-E1b: the key-service query is not yet Stop-aware (wording)
check_keyserver_url_static's rustdoc and its test comment no longer
call the first query halt-aware: OnlineSource runs it under its own
Halt until ST-K1b wires ctx.halt() (J10).
2026-09-28 07:18:27 -07:00
Matthew Jackson 37568b1002 test: use the RFC 2606 .test TLD for the unresolvable host (leak-guard flags .invalid) 2026-09-28 07:04:48 -07:00
Matthew Jackson 40389acd3f KU-E1 review minor 4: partial stored keys plus a Km still report NoVid
The keydb keeps a NoVid miss reason beside the keys it did return, so
resolve sets vid_would_help for the CPS units only the VID could
derive. Other miss reasons are still reported only with no key.
2026-09-28 06:28:54 -07:00
Matthew Jackson 54508d8ec2 KU-E1 review minor 4 red: partial stored keys plus a Km still report NoVid
A keydb entry with stored unit keys for some CPS units and a Media Key
but no VID returns the stored keys with an empty miss path, so
resolve cannot tell that the VID would derive the rest (J23).
2026-09-28 06:28:47 -07:00
Matthew Jackson 2c93420970 KU-E1: a DNS-free key-service URL check for factory builds
check_keyserver_url_static rejects every Config fault (scheme, host,
port, a literal non-public address) with no lookup. A factory build,
which no Stop can reach, uses it; the host lookup and its SSRF guard
run at the first query on the halt-aware worker, as they already did.
A test-only counter proves the check starts no lookup.
2026-09-28 06:24:52 -07:00
Matthew Jackson c48faa042b KU-E1 red: a DNS-free key-service URL check for factory builds
The engine checks the key-service URL, a DNS lookup with a fixed 10 s
timeout that Stop cannot interrupt, on every factory build, and no
Halt reaches a factory. The test asks for a static check that rejects
Config faults with no lookup.
2026-09-28 05:45:58 -07:00
Matthew Jackson ab93818012 KU-E1 J23: OnlineSource and MultiSource report uses_vid
OnlineSource::uses_vid is true (it sends vid_b64); MultiSource is
any(inner); KeydbSource keeps the default false.
2026-09-28 05:31:51 -07:00
Matthew Jackson f3b66307cc KU-E1 J23 red: which key sources consume the disc's VID
OnlineSource sends the VID (vid_b64), so it uses it; MultiSource uses
it if any inner source does; KeydbSource does not (its Km-without-VID
case is reported per disc, as a NoVid miss path).
2026-09-28 05:31:23 -07:00
Matthew Jackson ad59f3ce45 KU-K1 review: peek the reachability slot, MultiSource forwards last_failure
record_last_failure_transport now reads LAST_DECODE_REACHABILITY.with(|c|
c.get()) directly instead of take_last_decode_reachability(), so it no longer
erases the slot freemkv-library's server reads after resolve
(server/ripper/mod.rs:505, :1361) to avoid a second key-service call. Green:
the regression test now finds the verdict still in the slot after
get_unit_keys/get_fmts_indexes. MultiSource::last_failure_was_transport
forwards any(inner), matching answer_depends_on_samples (KU3-6).
2026-09-28 04:19:04 -07:00
Matthew Jackson 4e83b3c1f8 KU-K1 review: red — record_last_failure_transport erases the reachability slot
Opus's review: freemkv-library's server calls take_online_decode_reachability()
after resolve (server/ripper/mod.rs:505, :1361) to classify a no-key without a
second probe. record_last_failure_transport currently TAKES the thread-local
slot, so the server sees None and fires probe_online_reachability — a second
key-service call, and a definite 422 misread as an outage. Red: the slot is
gone after get_unit_keys/get_fmts_indexes. Also adds the forensic-path,
mid-body-stall, transport-then-5xx-reset and MultiSource forwarding tests
requested in review; the latter fails since MultiSource has no override yet.
2026-09-28 04:18:02 -07:00
Matthew Jackson c5985d1c87 KU-K1: keydb/multi sample-dependence and online transport-class failures
Per keys-upfront-design KU-K1 (§8.2): KeydbSource::answer_depends_on_samples
is false (keyed by disc hash, asked once per resolve, N-KU10); MultiSource's
is any(inner) (KU3-6), so a nested sample-dependent source still gets the
per-piece ask. OnlineSource::last_failure_was_transport (J15) is true only
when the most recent query recorded DecodeReachability::Transport (DNS,
connect refused, or an idle stall — never an HTTP answer, 5xx included), and
resets on the next success, so resolve's J13 retry (stop-design-v5 T31)
targets exactly the requests that never got an answer.
2026-09-28 04:13:03 -07:00
Matthew Jackson 8f923fd5f9 KU-K1: tests for answer_depends_on_samples and last_failure_was_transport
KeydbSource::answer_depends_on_samples (KSK1) and MultiSource::answer_depends_on_samples
(KSK2, KU3-6 "any(inner)") both default to `true` today, so a keydb-then-online
composition would be re-asked per piece instead of once. OnlineSource::last_failure_was_transport
(J15) defaults to `false`, so a transient DNS/connect/idle failure would never be
retried by `resolve` (J13). Red: these six assertions fail against today's defaults.
2026-09-28 04:12:12 -07:00
Matthew Jackson 18fdab6b77 KU-P1: decrypt the real-unit test through test_util::decrypt_unit
aacs::content::decrypt_unit becomes pub(crate) at KU-X2 (keys-upfront design
v3.4 §2.2); the ignored real-unit test now uses the test-util door. The
feature comes in as a dev-dependency (resolved through the sibling path patch).
2026-09-28 00:22:08 -07:00
Matthew Jackson dfa02adbe2 online: a stopped key query never sends and builds no body
Review fixes, green half:
- PostJob carries the caller's Halt and re-checks it after the host lookup,
  before connecting. A Stop during DNS then never uploads the key material
  or bearer token, so a reopen's query is the only one the service sees.
- query_with returns Halted before reading or base64-encoding the MKB when
  a Stop is already pending.
2026-09-27 23:50:33 -07:00
Matthew Jackson cbab284c85 online: tests that a stopped key query sends nothing and reads no disc material
Review fixes, red half: a Stop during the host lookup must never reach the
service (never call the key service twice), and a pending Stop returns
before the body is built. KT7a's u64::MAX check now asserts saturation.
2026-09-27 23:49:08 -07:00
Matthew Jackson 0ffdb2a9f6 online: stall-only key-service timeouts and mid-flight Stop (ST-K1a)
Commit 2 of 2 (stop-design-v5 §2.7, T15-T17, D3, D4):

- query_with builds the body on the caller's thread and runs DNS + POST on
  a worker, capped at 4 per host. The caller waits for a slot and for the
  result halt-aware in 20 ms slices, so Stop returns Halted within a slice
  at any stage. The abandoned worker frees its slot at its own stall bound.
- Reachability is recorded on the caller's thread, only when the worker's
  result arrives. A Stop records nothing.
- IdleConnector, chained after DefaultConnector, owns every post-connect
  bound. Each write and read gets a fresh 60 s stall bound (T16), and the
  wait for a reply's first byte gets 60 s + request bytes / 256 KiB/s (T17).
  The 180 s phase totals are gone: no total is configured.
- A reply body that stalls or drops records Transport reachability (T16).
  An over-cap body still records its Status.

The trait path passes a fresh Halt. ctx.halt()/ctx.progress() is ST-K1b,
after KU-X2. No public API change.
2026-09-27 23:41:43 -07:00
Matthew Jackson adbb1a12a0 online: ST-K1a tests for stall-only key-service timeouts and mid-flight Stop
Commit 1 of 2 (stop-design-v5 §5.0): KT1-KT10 plus guards G12/G13, with
signatures that keep today's behaviour (query_with ignores the halt,
hardened_agent_with maps idle onto the old phase totals, the first-byte
budget does not scale), so each test compiles and fails on its assertion.
KT9 replaces the 180 s totals test. The ctx.halt()/ctx.progress() wiring
is ST-K1b (after KU-X2).
2026-09-27 23:37:22 -07:00
Matthew Jackson 05281249d1 keydb: hand out host certs best first, with no disc input
Unannotated certs in keydb order, then revoked ones by latest revocation.
The trait ignores its mkb hint; KeyDb::host_certs(mkb) is deprecated.
2026-09-27 17:24:04 -07:00
Matthew Jackson cedbc4b1fa online: offline Temporary-verdict test; proxy wording
Drop the real-DNS .invalid test for an offline check of every GuardFail::Unreachable reason; say every key lookup failed.
2026-09-27 16:44:34 -07:00
Matthew Jackson 1606ff3ca3 online: review nits for the proxy fix and keyserver URL verdict
Correct the rationale: the env proxy was resolved to the key service's pinned address, so every lookup failed.
Gate set_last_decode_reachability behind a test-hooks feature, mark the verdict types non_exhaustive, test a .invalid host, add CHANGELOG.
2026-09-27 12:40:09 -07:00
Matthew Jackson 10b0348db8 online: never use an env proxy; typed keyserver URL verdict and reachability test hook
The key-service agent disables ureq's env proxy, which would re-resolve the host and bypass the pinned, SSRF-guarded addresses.
check_keyserver_url returns a Permanent/Temporary KeyserverUrlRejection; set_last_decode_reachability plants a verdict for caller tests.
2026-09-27 12:26:39 -07:00
Matthew Jackson d0a3ab852b v1.7.7: bump version (unified release) 2026-09-26 21:16:59 +00:00
Matthew Jackson 91b906fa61 Prepare 1.7.7 with concise comments and shared CI policy 2026-09-26 11:46:35 -07:00
Matthew Jackson e987506d96 v1.7.6: bump version (unified release) 2026-09-26 04:05:43 +00:00
Matthew Jackson 60cff0ead6 chore: absorb qa into dev for lockstep promote [skip-media] 2026-09-25 12:25:47 -07:00
Matthew Jackson c333c6000b v1.7.6: bump version (unified release) 2026-09-25 05:32:01 +00:00
Matthew Jackson adf2401c06 chore(qa): gate 1.7.6 promote — media matrix not needed [skip-media]
The 1.7.6 unified release ships no rip-path change (Linux desktop shell,
notifications, menu_layout refactor, XDG paths). Real-media QA on EC2
adds ~2h + real money to the release cycle to prove code that never
enters the rip pipeline. This empty commit puts `[skip-media]` in qa's
HEAD so the media matrix in qa.yml auto-skips per the documented bypass;
the full-platform builds/tests still run.
2026-09-24 21:37:29 -07:00
Matthew Jackson b89b7c9660 chore(qa-sync): absorb qa's post-1.7.5 release commits into dev
Release-orchestrate committed to qa (v1.7.5 version bump, etc.) but did
not push those commits back to dev, so promote's fast-forward gate
refused (qa was diverged from dev). This is an ours-merge: the commit
records qa as an ancestor of dev without applying its content, since
dev has already moved past 1.7.5 to 1.7.6 with the equivalent
information in place.
2026-09-24 21:21:11 -07:00
Matthew Jackson 1121522534 chore(release): bump to 1.7.6, follow the CI-required release-notes shape
Bumps Cargo.toml + Cargo.lock to 1.7.6. Also fixes a CI-shape defect the
previous release left behind: dev's CHANGELOG still said
`## [1.7.5] — UNRELEASED` after 1.7.5 shipped (release-orchestrate dated
main but did not push a fresh UNRELEASED heading back to dev). Corrects
that here so the changelog job accepts 1.7.6 on the way to qa:

  ## [1.7.6] — UNRELEASED
    - Version aligned; unified release driven by freemkv 1.7.6.
  ## [1.7.5] — 2026-09-23
    - Version aligned (or actual content, per the shipped main entry).

The driver for 1.7.6 is the freemkv Linux desktop shell (GTK4 +
libadwaita) + rip-finished desktop notification (issue #56).
2026-09-24 20:23:08 -07:00
Matthew Jackson 146f53873d v1.7.5: bump version (unified release) 2026-09-23 04:40:56 +00:00
Matthew Jackson b925a4fa50 docs: 1.7.5 changelog entry for the unified release [skip-media]
Version aligned to 1.7.5. No functional change to this crate — the release
is driven by freemkv-unlock mirroring the freemkv-firmware 0.9.0 ABI, where
the drive's separate Ake (0x06) and Bus (0x07) levers are retired into a
single Encryption (0x06) lever.
2026-09-22 21:05:01 -07:00
Matthew Jackson 4f169a4881 v1.7.4: bump version (unified release) 2026-09-21 23:03:38 +00:00
Matthew Jackson e251e0bf6f docs: mark 1.7.4 changelog heading UNRELEASED (release workflow dates it) 2026-09-21 15:07:11 -07:00
Matthew Jackson 6704c1e05b docs: 1.7.4 changelog + consumer release notes 2026-09-21 11:47:20 -07:00
Matthew Jackson a34980970b docs/ci: drop stale local-precommit/release.sh references — CI is the only gate 2026-09-21 09:11:35 -07:00
Matthew Jackson 948511853e test(online): trim interpret_reply reachability aside to 3 lines for comment-guard 2026-09-21 08:51:04 -07:00
Matthew Jackson 373cdc4cf2 ci: adopt central freemkv/.github guards + checkout-siblings composite
Thin-caller comment/leak/identity guards → freemkv/.github reusable
workflows; drop local ci/comment-guard.py and ci/leak-guard.sh. Replace
per-job sibling checkout + .cargo/config heredoc with the shared
checkout-siblings@v1 composite (checkout libfreemkv+freemkv-unlock,
patch libfreemkv). Add cancel-in-progress concurrency to ci.yml/qa.yml;
standardize actions/checkout to @v5.
2026-09-21 08:48:58 -07:00
Matthew Jackson a60b021c35 Merge: ureq 3.4.2 + bounded reply body (supersedes Dependabot #12) 2026-09-20 20:15:19 -07:00
Matthew Jackson fc8b6e3a05 bump ureq 3.4.2 + preserve rolling-idle body timeout
ureq 3.4.1 (#1194, "Fix timeout budgets restarting and applying to later
phases") made timeout_recv_response bound only the response HEADERS and
turned timeout_recv_body into an ABSOLUTE total-body deadline. The online
key-service POST set recv_response only, so under 3.4.2 the reply body read
had NO deadline at all — a server that sent headers then stalled mid-reply
would hang the key request forever.

The /decode reply is a small JSON key answer that arrives in one read (a
few hundred bytes; the 1 MiB cap is a defensive anti-OOM ceiling, not an
expected size), so this is a fine total-cap case, not a large-body slow-link
download: no rolling-idle connector is warranted. Set timeout_recv_body to
the same TIMEOUT_SECS total ceiling so the POST can never hang forever.

Regression guard the_reply_body_read_is_bounded_not_only_the_headers asserts
recv_body is now set. Full suite + precommit (fmt/clippy/deny/tests) green.
2026-09-20 20:03:54 -07:00
Matthew Jackson bdbc805ba5 keydb: report match state + entry shape to de-conflate "no entry" (#46)
Implement KeySource::resolve_unit_keys for KeydbSource by splitting
unit_keys_from into resolve_from, which reports: whether find_disc
matched; the specific miss reason (NoVid when a Media Key has no VID,
else NoDerivableKey); the matched entry's shape (vuk / unit_keys count /
media_key / keydb_vid / enc_title_keys len / vid_available); and the
loaded entry count for a self-diagnosing true-miss verdict.

MultiSource forwards resolve_unit_keys so a matched inner source's richer
verdict survives composition. No derivation-logic change: the locked
VID-per-path rule is intentional and the investigation found no
correctness bug there — only the conflated verdict. Tests cover
matched-no-VID, matched-no-material, true miss, and the success path.
2026-09-20 19:16:06 -07:00
Matthew Jackson fa75d28441 freemkv-keysources 1.7.4: keydb loads every entry — drop entry cap, strip BOM, count malformed rows
- Remove the MAX_DISC_ENTRIES cap: a keydb is a database and must hold every
  disc row it contains (a count-based drop silently lost real discs).
- Strip a leading UTF-8 BOM before parsing so a Windows-saved keydb's FIRST
  disc row survives (U+FEFF is not trim()-able whitespace).
- Gate the disc branch on the 0x/0X prefix alone and COUNT a malformed 0x row
  (missing " = ") as rejected instead of silently ignoring it — surfaces the
  "hash is in the file but nothing resolves" class of bug.
- Tests: BOM, CRLF, leading whitespace, case/prefix-insensitive lookup,
  duplicate-hash last-wins, unit-key-only rows, 600k-entry no-drop, and the
  load_failure verdicts (permission / invalid / missing).

[skip-media]
2026-09-20 09:43:41 -07:00
Matthew Jackson 5d2e11a4dd freemkv-keysources 1.7.4: version bump (unified 1.7.4) 2026-09-19 14:03:36 -07:00
Matthew Jackson 50bd0e4be2 v1.7.3: bump version (unified release) 2026-09-19 05:31:15 +00:00
Matthew Jackson 148419c2bb changelog: 1.7.3 unified-release entry (freemkv --share + libfreemkv multi-angle UHD fix) 2026-09-18 22:18:41 -07:00
Matthew Jackson 1b97e6186d merge: record v1.7.2 release into dev (-s ours; keep path deps + dev's next-cycle work) 2026-09-18 21:39:15 -07:00
Matthew Jackson 23988922eb v1.7.2: bump version (unified release) 2026-09-18 18:37:25 +00:00
Matthew Jackson e4ecc3cf83 merge: record v1.7.1 main into dev (dev already at 1.7.1; keep path deps) 2026-09-17 23:08:12 -07:00
Matthew Jackson 55ef44e74e comment-guard: trim over-cap comment blocks to caps (comments only)
Restructure 10 over-cap comment blocks in keydb.rs and online.rs to fit
comment-guard's caps (inline // asides <=3 lines, /// item-doc prose <=8)
by tightening wording. No code changes; behavior unchanged.
2026-09-17 22:37:38 -07:00
Matthew Jackson 173a532a6e deps: revert ureq to 3.4.0 (3.4.2 body-deadline regression; keep the rest of this repo's dep changes) 2026-09-17 22:29:32 -07:00
Matthew Jackson 6879df55eb deps: rustls 0.23.43→0.23.45 (RUSTSEC TLS-1.3 advisory) + ureq 3.4.2 2026-09-17 22:18:07 -07:00
Matthew Jackson 0a735498fb online: block NAT64 well-known prefix in SSRF guard; fix https-only doc 2026-09-15 14:06:04 -07:00
Matthew Jackson 531e3a40bf fix(keysources): resolve own-repo audit findings (v1.6.0->dev)
online.rs:
- validate_keyserver_url/resolve_and_guard now reject any non-https:// scheme
  as a Config fault, so a cleartext misconfig is caught ONCE at config time
  instead of failing every rip via query()'s runtime https check.
- is_blocked_ip: add 198.18.0.0/15 (RFC 2544 benchmarking) and 192.0.0.0/24
  (RFC 6890 IETF protocol assignments, incl. 192.0.0.170/171) to the SSRF guard.
- DNS in-flight cap is now PER HOST, not process-global, so black-holed lookups
  to one dead keyserver can't starve resolution of a healthy different keyserver.
- reject a non-empty, non-":port" tail after a bracketed IPv6 authority
  (e.g. https://[::1]extra/) instead of silently dropping it.

keydb.rs / keydb_format.rs:
- MAX_KEYDB_BYTES defined once in keydb_format and re-used by keydb.rs.
- CacheEntry::is_settled falls back to inode identity + stamped_at age when the
  mtime is absent (mtime-less FS) or in the future (clock skew), so the ~62 MiB
  keydb no longer re-parses on every lookup.
- save()'s entry-count guard counts DK/PK/HC/HC2 rows via the real parsers
  (is_parseable_entry_line), so a prefixed-but-malformed row can't pass entries>0.

Tests added for each fix.
2026-09-15 10:30:50 -07:00
Matthew Jackson ae8e5ade3c fix(online): record decode POST reachability for the caller to classify
OnlineSource now records the HTTP outcome of its actual /decode POST — a
Status(code) for any answer (200/404/422/429/5xx) or Transport for a
connect/timeout/DNS/TLS failure — in a per-thread slot, readable via the new
take_last_decode_reachability() / DecodeReachability. This lets a caller
(autorip) classify a no-key result from the REAL decode instead of firing a
second, redundant probe against the POST-only endpoint. No change to key
resolution itself. Targets 1.7.2.
2026-09-14 14:55:12 -07:00
Matthew Jackson 8b914e7121 v1.7.1: bump version (unified release) 2026-09-14 03:34:52 +00:00
Matthew Jackson 62ebd61ff1 docs(changelog): 1.7.1 release notes (LibreDrive unlock fix) 2026-09-13 20:01:03 -07:00
Matthew Jackson 30c16bc415 ci: bump actions/checkout v4->v7; deps: ureq 3.4.0->3.4.1 (dependabot) 2026-09-13 18:30:58 -07:00
Matthew Jackson 8c3afbee67 chore: bump version to 1.7.1 (unified release lockstep) 2026-09-13 18:21:52 -07:00
Matthew Jackson 6e4f05dec4 test: assert full key bytes; correct keydb-format docs
Several tests asserted only key[0] (the first byte), which a byte-transposition bug could pass — assert the full 16-byte key everywhere, including a KAT that recomputes the expected VUK-derived keys directly. test_parse_disc_entry used identical all-zero placeholders for M/I/V/U, which couldn't catch a field mix-up; give each field a distinct byte pattern and assert every field.

Docs: keydb-format.md claimed DiscEntry::title was genuinely unused dead code, but it's read by to_keydb_cfg and the redacting Debug impl — correct the comment to only list empty/find_vuk as truly unused. Also cross-reference the two independent MAX_KEYDB_BYTES constants (keydb.rs's decompression cap and keydb_format.rs's on-disk load cap) so they're kept in sync, and bump Cargo.lock's version metadata.
2026-09-05 12:38:16 -07:00
Matthew Jackson 5bf6c4875b log disc-side read failures; skip a bogus CPS unit 0
Two disc-side reads were silently swallowed with unwrap_or(&[]): a failure reading the disc's encrypted title keys or its MKB looked identical to a disc that genuinely had none, hiding real I/O/parse errors from the operator. Log a warning (mirroring online.rs's existing pattern) before falling back to empty in both cases.

Also, a stored unit key numbered 0 (an invalid CPS unit number; valid numbering is >= 1) was mapped via num.saturating_sub(1) onto idx 0, silently colliding with and shadowing a legitimate unit 1. Skip unit number 0 instead of mis-mapping it, and add a regression test.
2026-09-05 12:38:06 -07:00
Matthew Jackson 1c29377780 parse the keydb outside the cache lock
cached_db held self.cache locked across the full KeyDb::load_counted parse of the ~62 MiB keydb, so a reparse (triggered by a changed mtime) stalled every other worker waiting on the cache. Take a brief lock for the fast-path settled-cache-hit check, release it, parse outside the lock, then re-acquire and double-check: if a peer installed the same settled stamp while we parsed, adopt their entry and drop our redundant parse rather than racing a lost update. Stamp and bytes still come from the one already-open file handle, preserving the one-open-one-identity invariant.
2026-09-05 12:37:59 -07:00
Matthew Jackson 7c544e3780 cap outstanding DNS-resolver threads
Each DNS lookup for the SSRF guard spawns a thread that is never joined and can hang for the full OS resolver timeout, so a black-holed keyserver leaks one thread+stack per attempt. Track outstanding resolver threads with an atomic counter; over a cap of 4, report the host as unreachable instead of spawning another. Decrement only when the (possibly long-hung) lookup actually returns, so the cap reflects threads truly in flight.
2026-09-05 12:37:53 -07:00
Matthew Jackson 4a241e04bc block 6to4/Teredo tunnels in the SSRF guard
The IPv6 SSRF guard already re-checked IPv4-mapped/-compatible addresses, but 6to4 (2002::/16) and Teredo (2001:0000::/32) also tunnel an embedded IPv4 and were passed through untouched, letting an attacker wrap 127.0.0.1 or a cloud metadata address in either encapsulation to bypass the block list. Decode both forms and re-check the embedded IPv4 through is_blocked_ip. Add a test covering 6to4/Teredo-wrapped loopback and metadata addresses, plus a 6to4-wrapped public IP that must still be allowed.
2026-09-05 12:37:48 -07:00
Matthew Jackson d19481ae59 persist keydb.cfg at mode 0600 (it holds key material)
keydb.cfg carries AACS key material plus the host private key/cert. write_atomic renamed a File::create()'d temp file onto it, so the final mode depended on umask and could leave the keys world-readable. On Unix, open the temp file with mode 0600 explicitly via OpenOptionsExt; non-Unix keeps the plain create().
2026-09-05 12:37:43 -07:00
Matthew Jackson 707c8bdc57 ci: identity-guard — block unrelated-corp / non-canonical committer emails 2026-09-02 14:46:19 -07:00
Matthew Jackson 599422ef22 release: 1.7.0
CI/lint hardening since v1.6.14: clippy on stable with the MSRV single-sourced
from Cargo.toml, cargo-deny dependency-audit gate with first-party git sources
allowed (#15), and audience-based comment-guard (#17). No library code changes.
2026-09-02 12:27:48 -07:00
Matthew Jackson ed5066af48 v1.6.14: bump version (unified release) 2026-08-31 23:04:30 +00:00
Matthew Jackson 9b28a7c89d chore: reconcile v1.6.13 release commit from main into dev 2026-08-31 15:48:53 -07:00
Matthew Jackson 8a8397965b docs(changelog): 1.6.14 entry 2026-08-31 15:32:40 -07:00
Matthew Jackson a52698b6bf chore(msrv): floor to 1.88, pin CI on the floor, allow uninlined_format_args
Declared rust-version and the ci.yml/qa.yml toolchain pins both sit at 1.88 (the
edition-2024 floor once zip 8 and let-chains are accounted for), so CI builds on
exactly the MSRV: an accidental bump to a newer toolchain fails CI by design and
moving the floor takes a deliberate pin edit. The uninlined_format_args allow
reconciles 1.88's clippy with the allow-by-default it became in 1.97+.
2026-08-31 11:06:35 -07:00
Matthew Jackson bf18ec0cec v1.6.13: bump version (unified release) 2026-08-28 15:49:04 +00:00
Matthew Jackson 7e9849ccbb Release 1.6.13: version align 2026-08-27 21:22:11 -07:00
Matthew Jackson 94f082a43b v1.6.12: bump version (unified release) 2026-08-27 22:57:36 +00:00
Matthew Jackson 1fbf3f6c63 changelog: 1.6.12 (unreleased) 2026-08-27 12:18:41 -07:00
Matthew Jackson b75599a5cb v1.6.11: bump version (unified release) 2026-08-25 23:17:15 -07:00
Matthew Jackson e83b7a3489 test: raise coverage across keydb, keydb_format, online, lib sources
Adds targeted unit tests for previously-uncovered branches: keydb load
failure classification (invalid-UTF-8 / unreadable path), zip extraction
success/no-cfg-member paths, write_atomic create/rename failure modes,
keydb_format hex-digit-parsing edge cases, iter_disc_entries, to_keydb_cfg
HC2 emission and empty-title/comment-field combinations, MultiSource::label,
and the online key-service client's SSRF-guard malformed-authority and
unresolvable-host paths, UK-as-string and VUK-derivation reply handling,
and get_fmts_indexes. Local line coverage moves from ~90.3% to ~92.1%.
2026-08-25 22:11:01 -07:00
Matthew Jackson 4ef4d5dfd6 docs: 1.6.11 changelog 2026-08-25 22:08:48 -07:00
Matthew Jackson febf4d0504 docs: standardize README badges (License, CI, codecov) 2026-08-25 20:32:34 -07:00
Matthew Jackson 5e96e3e9d8 ci(coverage): authenticate Codecov upload with org CODECOV_TOKEN 2026-08-25 19:32:39 -07:00
Matthew Jackson 2415a58d5d ci(coverage): add --ignore-run-fail so instrumentation flake never blocks upload 2026-08-25 19:04:51 -07:00
Matthew Jackson edb14d3aea ci: add non-required Codecov coverage job, config, and README badge
Add an additive coverage job to ci.yml that mirrors the test job's
sibling-checkout layout and pinned 1.97.0 toolchain, runs cargo llvm-cov,
and uploads to Codecov tokenlessly (fail_ci_if_error:false). Nothing in
the release cascade depends on it. Also add codecov.yml (informational,
no PR comment) and a README with the coverage badge.
2026-08-25 18:55:26 -07:00
Matthew Jackson ce96676389 CHANGELOG: 1.6.10 (unified release; driven by libfreemkv TrueHD discontinuity fix) 2026-08-23 16:30:29 -07:00
Matthew Jackson df92b830bd v1.6.9: bump version (unified release) 2026-08-22 08:34:34 -07:00
Matthew Jackson b31cdc2519 changelog: 1.6.9 unified-release entry 2026-08-22 08:25:03 -07:00
Matthew Jackson 397a8a2960 v1.6.8: bump version (unified release) 2026-08-21 12:54:57 -07:00
Matthew Jackson 1306901662 docs: 1.6.8 changelog (unified release) 2026-08-21 12:47:34 -07:00