Skip to content

fix: scrub Nostr keys from 14 more log lines + add a CI check (#836) - #842

Open
ToRyVand wants to merge 5 commits into
MostroP2P:mainfrom
ToRyVand:fix/836-log-redaction-lint
Open

fix: scrub Nostr keys from 14 more log lines + add a CI check (#836)#842
ToRyVand wants to merge 5 commits into
MostroP2P:mainfrom
ToRyVand:fix/836-log-redaction-lint

Conversation

@ToRyVand

@ToRyVand ToRyVand commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Summary

Closes #836. AGENTS.md:48 says to scrub logs that might leak invoices or
Nostr keys. #834/#835 fixed 3 instances in restore_session.rs; a
/code-review pass on that fix found 5 more scattered across the daemon,
with no mechanism to stop the pattern from recurring — #836 asked for a
structural fix rather than another one-off patch.

Went with the lighter-weight of the two directions the issue proposed (a
CI check, vs. a tracing_subscriber::Layer redacting at runtime): smaller,
self-contained, faster to review. Trade-off: it only prevents new
instances at CI time, it doesn't redact anything at runtime.

  • scripts/check_log_redaction.py (new): flags any
    tracing::{trace,debug,info,warn,error}!(...) call whose arguments
    interpolate a Nostr key/identity-shaped identifier (*pubkey*,
    identity, sender, master_key, trade_key, nsec*, priv(ate)?_?key*).
    Not a full Rust parser — it balances parens while blanking string-literal
    contents (so a format string's own prose, e.g. "...taker pubkey in
    order...", can't false-positive) and searches only the real arguments.
    A // pubkey-log-allow: <reason> comment on the line above a call exempts
    a deliberate, documented exception.
  • .github/workflows/ci.yml: new log-redaction job, added to test's
    needs alongside fmt/clippy.
  • 14 call sites fixed across 8 files — the 5 #836 documented
    (scheduler.rs, app.rs ×2, last_trade_index.rs, db.rs) plus 9 the
    check itself found
    that manual review hadn't caught yet
    (admin_take_dispute.rs ×2, bond/payout.rs ×3, cancel.rs,
    rpc/service.rs, util.rs ×2 — including send_dm, which logged both
    sender and receiver on every single outbound protocol message, the
    highest-frequency call site of this pattern in the daemon). Same
    one-line-per-site treatment Nostr keys logged in cleartext in restore_session.rs (violates AGENTS.md log-scrubbing guideline) #834/fix(restore-session): scrub Nostr keys from log lines #835 used: drop the key, comment citing
    AGENTS.md:48.
  • cancel.rs: dropping taker_pubkey from one log line left the parameter
    fully unused in cancel_order_by_taker_inner and its only caller,
    cancel_order_by_taker — removed from both signatures and their 2 call
    sites rather than silenced with an underscore.

Test plan

  • python3 scripts/check_log_redaction.py — clean against the final tree.
  • cargo build — clean, no unused-variable warnings.
  • cargo clippy --all-targets --all-features -- -D warnings — clean.
  • cargo fmt --check — clean.
  • cargo test — 1045 passed, 1 pre-existing unrelated flake
    (lightning::invoice::tests::test_lnurl_validation_with_test_server
    binds a hardcoded 127.0.0.1:8080, AddrInUse on a busy port —
    unrelated to this diff).

Summary by CodeRabbit

  • Security & Privacy

    • Removed public-key and identity details from application logs across event handling, admin actions, payouts, cancellations, scheduling, and DM delivery.
    • Added automated checks to help prevent sensitive key or identity leaks in logs.
  • Tests

    • Added regression coverage for log-redaction validation, including tracing formats and approved exceptions.
  • CI

    • Updated CI to run log-redaction validation before the test suite.

…P2P#836)

AGENTS.md:48 says to scrub logs that might leak invoices or Nostr keys.
MostroP2P#834/MostroP2P#835 fixed 3 instances in restore_session.rs; a follow-up review
found 5 more scattered across the daemon (issue MostroP2P#836) but no mechanism
to stop the pattern from recurring.

Adds scripts/check_log_redaction.py, wired into ci.yml, which fails
the build on any tracing::{trace,debug,info,warn,error}! call that
interpolates a Nostr key/identity-shaped argument. Running it against
the current codebase surfaced 9 more instances beyond the 5 already
documented, including util::send_dm logging both sender and receiver
on every outbound protocol message. Fixes all 14 with the same
one-line-per-site treatment MostroP2P#834/MostroP2P#835 used, so the new check ships
green.

cancel.rs: removing taker_pubkey from one log line left the parameter
fully unused across cancel_order_by_taker_inner and its only caller,
cancel_order_by_taker — dropped from both signatures and their call
sites rather than silenced.
@coderabbitai

coderabbitai Bot commented Jul 27, 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 Plus

Run ID: 7993ef9b-3704-4eb6-805c-2683e129237b

📥 Commits

Reviewing files that changed from the base of the PR and between 3e682e9 and 4945eb8.

📒 Files selected for processing (1)
  • scripts/check_log_redaction_test.py

Walkthrough

The pull request adds a Python CI gate that detects key-like identifiers in Rust tracing calls, removes sensitive values from affected logs, updates cancellation function signatures, and requires the redaction check before tests run.

Changes

Log redaction enforcement

Layer / File(s) Summary
Tracing log scanner and regression coverage
scripts/check_log_redaction.py, scripts/check_log_redaction_test.py
Scans Rust tracing macros for suspicious identifiers, masks string contents, supports allow comments, and tests delimiter, identifier, line-number, and exemption behavior.
Rust log redaction
src/app.rs, src/app/admin_take_dispute.rs, src/app/bond/payout.rs, src/app/last_trade_index.rs, src/db.rs, src/rpc/service.rs, src/scheduler.rs, src/util.rs
Removes public keys, identities, payloads, and debug order output from affected logs.
Cancellation call-path cleanup
src/app/cancel.rs
Removes the taker public-key parameter from cancellation functions and callers while retaining cancellation behavior.
CI enforcement wiring
.github/workflows/ci.yml, .gitignore
Adds the log-redaction job, makes the test job wait for it, and ignores Python bytecode caches.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant CI
  participant LogRedactionTests
  participant LogRedactionChecker
  participant RustSource
  CI->>LogRedactionTests: Run regression tests
  LogRedactionTests->>LogRedactionChecker: Check temporary Rust snippets
  CI->>LogRedactionChecker: Scan src/**/*.rs
  LogRedactionChecker->>RustSource: Inspect tracing macro calls
  LogRedactionChecker-->>CI: Return success or violations
Loading

Possibly related PRs

Poem

A rabbit checks each tracing line,
And hides the keys that should not shine.
CI tests the code with care,
Clean logs leave secrets there—
“No pubkeys here!” the bunny cheers.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ 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 describes the key-log redactions and added CI check.
Linked Issues check ✅ Passed The PR removes key or identity data from affected logs and adds a tested CI scanner, satisfying [#836].
Out of Scope Changes check ✅ Passed All changes support log redaction, CI enforcement, scanner tests, or required call-site cleanup.
✨ 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.

@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: 3

🤖 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 `@scripts/check_log_redaction.py`:
- Around line 25-38: Update SUSPICIOUS_RE and the send_dm logging path to
prevent cleartext serialized identities or invoices from bypassing redaction
checks: cover identity_key and sender_key variants, add detection for opaque
payload/message content where feasible, and remove or redact payload logs that
cannot be reliably identified by names. Keep the existing narrowly targeted
key-name matching without broadening it to generic key variables.
- Line 23: Extend the scanner around MACRO_RE and its span-parsing logic to
recognize Rust macro calls with parentheses, braces, and angle brackets,
including whitespace before delimiters. Make tokenization/span detection
Rust-aware so comments and string syntax cannot prematurely terminate or skip
macro arguments, and add regression coverage for every supported delimiter and
edge case before using the scanner as a security gate.

In `@src/util.rs`:
- Around line 707-711: Update the logging call in the surrounding
message-sending function to remove the serialized payload from the log entirely.
Retain only the event ID or safe action metadata, ensuring no payload fields
such as identities or invoice data are written.
🪄 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 Plus

Run ID: 11c5e720-fbd8-42c1-9bfd-170af7582526

📥 Commits

Reviewing files that changed from the base of the PR and between ec4a046 and f5cbd2f.

📒 Files selected for processing (11)
  • .github/workflows/ci.yml
  • scripts/check_log_redaction.py
  • src/app.rs
  • src/app/admin_take_dispute.rs
  • src/app/bond/payout.rs
  • src/app/cancel.rs
  • src/app/last_trade_index.rs
  • src/db.rs
  • src/rpc/service.rs
  • src/scheduler.rs
  • src/util.rs

Comment thread scripts/check_log_redaction.py Outdated
Comment thread scripts/check_log_redaction.py
Comment thread src/util.rs Outdated
ToRyVand added 3 commits July 28, 2026 22:58
admin_take_dispute_action sends a Payload::Peer{pubkey} to both parties
via send_dm; the trailing info! logged that payload in full, leaking
the solver's Nostr pubkey (AGENTS.md:48).
job_cancel_orders printed the full edited Order via println!, which
carries buyer/seller/master pubkeys. tracing:: macros go through the
new log-redaction CI gate; bare println! doesn't, so this slipped
past it (AGENTS.md:48).
…y/sender_key variants

The scanner only matched name!(...) and bare identity/sender, missing
trace! {..}/trace![..] call forms and identity_key/sender_key-style
identifiers. Extend both, add regression tests for every delimiter
and identifier form, and wire the tests into the log-redaction CI job.

@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

🤖 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 `@scripts/check_log_redaction_test.py`:
- Around line 27-45: Update the positive cases in test_paren_call_flags_pubkey,
test_brace_call_flags_pubkey, test_bracket_call_flags_pubkey,
test_identity_key_variant_is_flagged, and test_sender_key_variant_is_flagged to
assert the exact reported violation tuples, including source line 1 and the
expected identifier ("pubkey", "identity_key", or "sender_key"), rather than
asserting only the violation count.
🪄 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 Plus

Run ID: f1e3764d-c601-4d83-bf15-1455847a82ba

📥 Commits

Reviewing files that changed from the base of the PR and between f5cbd2f and 3e682e9.

📒 Files selected for processing (6)
  • .github/workflows/ci.yml
  • .gitignore
  • scripts/check_log_redaction.py
  • scripts/check_log_redaction_test.py
  • src/scheduler.rs
  • src/util.rs
💤 Files with no reviewable changes (1)
  • src/scheduler.rs
🚧 Files skipped from review as they are similar to previous changes (3)
  • .github/workflows/ci.yml
  • src/util.rs
  • scripts/check_log_redaction.py

Comment thread scripts/check_log_redaction_test.py Outdated
The positive cases only checked the violation count, so the scanner
could report the wrong key name or the wrong source line and every one
of them would still pass. Assert the exact `(line, identifier)` tuples
instead.

The existing cases are all one-liners, so their line `1` would hold even
if the number were never computed — add a case with the call further
down the file so that arithmetic is actually exercised.
@ToRyVand

ToRyVand commented Aug 1, 2026

Copy link
Copy Markdown
Contributor Author

Addressed in 4945eb8.

The five positive cases now assert the exact (line, identifier) tuples rather than just the count, so a scanner reporting the wrong key name no longer slips through:

self.assertEqual(violations, [(1, "pubkey")])
self.assertEqual(violations, [(1, "identity_key")])
self.assertEqual(violations, [(1, "sender_key")])

One addition beyond the suggestion: every existing case is a one-liner, so asserting line 1 would still hold if check_file never computed a line number at all. Added a case with the call further down the file so that arithmetic is actually pinned:

def test_reported_line_is_the_macro_line_not_the_first(self):
    violations = self._violations(
        "fn x() {\n    let a = 1;\n    info!(\"{}\", pubkey);\n}"
    )
    self.assertEqual(violations, [(3, "pubkey")])

Both CI steps pass locally: python3 scripts/check_log_redaction_test.py → 8 tests OK (was 7), and python3 scripts/check_log_redaction.py → clean, exit 0.

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.

Nostr keys logged in cleartext across multiple modules — needs a structural fix, not per-line patches

1 participant