Skip to content

test(restore-session): raise mutation score with pure-fn extraction#826

Open
ToRyVand wants to merge 5 commits into
MostroP2P:mainfrom
ToRyVand:fix/637-mutation-session-restore
Open

test(restore-session): raise mutation score with pure-fn extraction#826
ToRyVand wants to merge 5 commits into
MostroP2P:mainfrom
ToRyVand:fix/637-mutation-session-restore

Conversation

@ToRyVand

@ToRyVand ToRyVand commented Jul 20, 2026

Copy link
Copy Markdown

Follow-up of #618 / closes #637.

cargo mutants --file src/app/restore_session.rs went from 33.3% (4/12) to 83.3% (10/12).

Changes

  • Extracted pubkey-hex validation into util::is_valid_hex_pubkey. It replaces two inline checks in restore_session_action, and is shared with the identical check already duplicated 5x in db.rs (lines 928, 973, 1014, 1197, 1229) instead of adding a 6th private copy.
  • Extracted RESTORE_SESSION_TIMEOUT_SECS as a named constant so the 1h timeout computation (60 * 60) is directly testable without instantiating the session manager.
  • Added focused tests for send_restore_session_response/send_restore_session_timeout's early error path on an invalid trade key — no DB/network dependency needed, since both functions return Err before reaching enqueue_restore_session_msg.

Remaining survivors

The 2 mutants still surviving replace restore_session_action and handle_restore_session_results wholesale (-> Ok(()) / -> ()). Killing them needs a full AppContext (real Sqlite pool + nostr_sdk::Client + Settings + OrderMsgQueue) constructed in a test, which is out of proportion for this issue and consistent with admin_add_solver_action being untested at that same level elsewhere in the codebase — only its inner pure parse_solver_payload has unit tests.

db.rs's 5 existing copies of the hex-pubkey check were left as-is (not migrated to the new shared helper) — they're unrelated functions outside this issue's scope; migrating them is its own small refactor with its own blast radius.

Test plan

  • cargo fmt --all -- --check
  • cargo clippy --all-targets --all-features — clean
  • cargo test — 537 passed, 1 failed (test_lnurl_validation_with_test_server, pre-existing/unrelated — fails on port 8080 already in use in this environment, reproduces on main without this diff too)
  • cargo mutants --file src/app/restore_session.rs: 83.3% (10/12), up from 33.3%
  • cargo mutants on the new util::is_valid_hex_pubkey: 100% (4/4)

Summary by CodeRabbit

  • Bug Fixes
    • Improved session key validation to consistently verify both master and trade keys are well-formed hex public keys.
    • Standardized the session restoration timeout to a single one-hour setting.
  • Tests
    • Added unit tests for the new hex public key validator, including uppercase, empty, malformed, and length edge cases.
    • Added a unit test asserting the session restoration timeout constant is set to 3600 seconds.
  • Chores
    • Updated mutation testing workflow and added a dedicated Makefile target to cap test-thread parallelism and streamline CI runs.

Follow-up of MostroP2P#618. cargo mutants on src/app/restore_session.rs went from
33.3% (4/12) to 83.3% (10/12):

- Extract pubkey-hex validation into util::is_valid_hex_pubkey, shared
  with the identical check already duplicated 5x in db.rs, instead of
  adding a 6th private copy.
- Extract RESTORE_SESSION_TIMEOUT_SECS as a named constant so the 1h
  timeout computation is directly testable.
- Add focused tests for send_restore_session_response/_timeout's early
  error path on an invalid trade key (no DB/network needed).

The 2 remaining survivors replace restore_session_action and
handle_restore_session_results wholesale; killing them needs a full
AppContext (real pool + nostr client + settings), which is out of
proportion for this issue and consistent with admin_add_solver_action
being untested at that level too.

Closes MostroP2P#637
@coderabbitai

coderabbitai Bot commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: b0b4992f-472c-4a2a-8f40-833c7947c7c2

📥 Commits

Reviewing files that changed from the base of the PR and between 87b2b6f and 8c0e3f9.

📒 Files selected for processing (2)
  • .github/workflows/mutation.yml
  • Makefile
🚧 Files skipped from review as they are similar to previous changes (1)
  • Makefile

Walkthrough

The changes add shared hexadecimal pubkey validation, apply it to restore-session keys, centralize the restore timeout, and route mutation testing through a shared Make target with bounded concurrency.

Changes

Restore session validation

Layer / File(s) Summary
Shared pubkey validation
src/util.rs
Adds is_valid_hex_pubkey and tests valid, uppercase, short, long, non-hex, and empty inputs.
Restore-session validation and timeout
src/app/restore_session.rs
Uses the shared validator for master and trade keys, introduces the 3600-second timeout constant, and tests the timeout value.

Mutation testing infrastructure

Layer / File(s) Summary
Shared mutation test execution
Makefile, .cargo/mutants.toml, .github/workflows/mutation.yml, .gitignore
Adds a shared mutation-test target, limits concurrency, safely forwards file arguments, updates PR and baseline workflows, and ignores .claude entries.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related issues

  • #630 — Mutation-testing configuration and workflow changes support its mutation-testing objectives.
  • #633 — Shared mutation-testing execution can support targeted database mutation tests.

Poem

A rabbit checks each hex-lit key,
And sets the timeout carefully.
Mutation hops through Make’s new track,
With bounded threads to guide it back.
Hop, hop—tests keep sessions safe!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning The .gitignore change for .claude is unrelated to restore-session mutation testing and appears out of scope. Remove the .claude ignore tweak or split it into a separate housekeeping PR.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the restore-session mutation-testing focus and the helper extraction work.
Linked Issues check ✅ Passed The PR meets the linked goal by improving restore-session mutation coverage above 70% and addressing the targeted mutant classes.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

ToRyVand added 3 commits July 20, 2026 15:54
Resolves conflict with MostroP2P#803 (merged upstream while this branch was in
progress), which added a full TestContextBuilder-based test suite for
restore_session_action/handle_restore_session_results — the exact gap this
branch had documented as out of scope. Kept MostroP2P#803's tests as-is and folded
in the one non-redundant test this branch added (timeout constant value).
Matches the existing .idea/.vscode/.cursor pattern — this holds
per-machine tool permissions, not project config.
Uncapped parallel jobs + per-test thread fan-out exhausted RAM and
crashed the machine during a local run. Cap via CARGO_MUTANTS_JOBS=2
(Makefile, verified with strace since .cargo/config.toml's [env]
does not propagate to third-party subcommands) and
--test-threads=4 (.cargo/mutants.toml). Both CI mutation jobs now
go through the same `make mutation-test` target.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
src/app/restore_session.rs (3)

1-1: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Scrub Nostr keys from logs.

Logging trade_key exposes a Nostr key in the application logs. As per coding guidelines, logs that could expose invoices or Nostr keys must be scrubbed to protect user privacy.

  • src/app/restore_session.rs#L90-112: Remove trade_key from the tracing::info! log in send_restore_session_response.
  • src/app/restore_session.rs#L115-125: Remove trade_key from the tracing::warn! log in send_restore_session_timeout.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/app/restore_session.rs` at line 1, Remove the trade_key field from the
tracing::info! call in send_restore_session_response and the tracing::warn! call
in send_restore_session_timeout, while preserving the remaining contextual log
fields and messages.

Source: Coding guidelines


115-125: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Scrub Nostr keys from logs.

Logging trade_key exposes a Nostr key in the logs. As per coding guidelines, logs that could expose invoices or Nostr keys must be scrubbed to protect user privacy.

🛡️ Proposed fix to remove the key from the log
-    tracing::warn!("Restore session timed out for user: {}", trade_key);
+    tracing::warn!("Restore session timed out for user");
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/app/restore_session.rs` around lines 115 - 125, Remove the trade_key
value from the tracing::warn! call in send_restore_session_timeout, while
preserving the timeout warning message and existing restore-session behavior. Do
not log the parsed trade_pubkey or any other Nostr key.

Source: Coding guidelines


90-112: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Scrub Nostr keys from logs.

Logging trade_key exposes a Nostr key in the logs. As per coding guidelines, logs that could expose invoices or Nostr keys must be scrubbed to protect user privacy.

🛡️ Proposed fix to remove the key from the log
-    tracing::info!("Restore session response sent to user {}", trade_key,);
+    tracing::info!("Restore session response sent to user");
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/app/restore_session.rs` around lines 90 - 112, Remove the raw trade_key
value from the tracing::info call in send_restore_session_response, while
retaining a generic message that the restore session response was sent. Do not
alter the key parsing or response-enqueue behavior.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@Makefile`:
- Line 71: Prevent shell injection in the mutation-test invocation: in Makefile
lines 71-71, construct argv-safe quoted arguments instead of expanding ARGS
directly; in .github/workflows/mutation.yml lines 71-71, pass changed filenames
via a safe file-list or argument mechanism. Preserve mutation testing for all
changed files without allowing filename contents to execute as shell syntax.

---

Outside diff comments:
In `@src/app/restore_session.rs`:
- Line 1: Remove the trade_key field from the tracing::info! call in
send_restore_session_response and the tracing::warn! call in
send_restore_session_timeout, while preserving the remaining contextual log
fields and messages.
- Around line 115-125: Remove the trade_key value from the tracing::warn! call
in send_restore_session_timeout, while preserving the timeout warning message
and existing restore-session behavior. Do not log the parsed trade_pubkey or any
other Nostr key.
- Around line 90-112: Remove the raw trade_key value from the tracing::info call
in send_restore_session_response, while retaining a generic message that the
restore session response was sent. Do not alter the key parsing or
response-enqueue behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: ea3577ba-9f63-4f28-8a6f-c1aaaf74d417

📥 Commits

Reviewing files that changed from the base of the PR and between 066d6e3 and 87b2b6f.

📒 Files selected for processing (6)
  • .cargo/mutants.toml
  • .github/workflows/mutation.yml
  • .gitignore
  • Makefile
  • src/app/restore_session.rs
  • src/util.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/util.rs

Comment thread Makefile
Filenames from `git diff --name-only` on a PR are attacker-controlled.
The old `file_args="$file_args --file $f"` + `make mutation-test
ARGS="$file_args"` path round-tripped that string through Make's macro
substitution and a second shell parse, so a crafted "filename" could
word-split into standalone argv tokens — argument injection into
cargo-mutants/cargo/rustc's own flag surface, not classic shell
command substitution (unquoted variable expansion doesn't re-parse
$()/backticks, but it does still word-split).

Fixed by building a bash array (`file_args+=(--file "$f")`) and
expanding it with "${file_args[@]}", so each filename — however it's
spelled — can only ever land as the single value of one --file flag.
This bypasses `make mutation-test` for this call site specifically;
its $(ARGS) stays a plain string splice, fine for human-typed input
(the label-triggered baseline job, unaffected, still uses it), not
for diff-derived filenames. Comment added to the Makefile target
so that distinction doesn't get lost later.

Found by CodeRabbit on PR MostroP2P#826's post-rebase re-review.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

test: mutation testing for session restore module

1 participant